B001_01.jpg


안녕하세요.

 

유형석입니다.

 

이번시간에는 이더넷 패킷을 받아서 출력해 봅시다!



1. 주의

    

    저번시간에 설명 드렸던것 다시 한번 주의 하시라고 적어 봤습니다~


    일단 저는 회사 보드의 부트로더에서 작업을 했습니다.

    커널로 진입한뒤 어플로 실행하면 여러가지 간섭도 발생하기 때문에

    부트로더에서 테스트를 하는게 더 좋을 것이라고 생각되네요.


    그리고 참고 하실점은 이더넷 디바이스 드라이버로 쓰는 인터페이스 함수가 필요한데요.

    이건 디바이스 드라이버 작성한 사람에 따라 틀려질수 있으니 유의하시길 바랍니다.


    뭐 그렇다고 해도 왠만하면 가능하다고 봅니다.


    일단 상황은 fd_eth_main 이라는 변수가 디바이스 드라이버에 등록되 있는 상태를 가정으로 진행 합니다.


2. 진행

    
    일단 전에 설명 드렸던 이더넷 패킷을 위한 구조체 만들기 와 동일하게 구조체를 만들어 줘야겠죠?


struct _eth_test_packet {
    ETH_HDR eth_hdr;
    ETHARP_HDR etharp_hdr;
}__attribute__((packed));
typedef struct _eth_test_packet ETH_TEST_PACKET;



    그리고 나서 일단 소스가 나오겠습니다.


             char buff[2048];
            ETH_TEST_PACKET *test_packet = NULL;
            test_packet = (ETH_TEST_PACKET *)buff;
            int  rx_size;
            
            while(1)
            {
                    memset(test_packet, 0, sizeof((ETH_TEST_PACKET *)test_packet));
                    memset(buff, 0, sizeof(buff) );
              
                    rx_size = read( fd_eth_main, buff, sizeof( buff ) );
                    if( rx_size < 0 )
                    {
                        printf( "fd_eth_main read error\n" );
                        break;
                    }
                    if( rx_size == 0 ) continue;

                    printf("Ethernet header:\n");
                    printf("+-------------------+\n");
                    printf("| %02X:%02X:%02X:%02X:%02X:%02X | (dest)\n",
                            test_packet->eth_hdr.dest[0],
                            test_packet->eth_hdr.dest[1],
                            test_packet->eth_hdr.dest[2],
                            test_packet->eth_hdr.dest[3],
                            test_packet->eth_hdr.dest[4],
                            test_packet->eth_hdr.dest[5]);
                    printf("+-------------------+\n");
                    printf("| %02X:%02X:%02X:%02X:%02X:%02X | (src)\n",
                            test_packet->eth_hdr.src[0],
                            test_packet->eth_hdr.src[1],
                            test_packet->eth_hdr.src[2],
                            test_packet->eth_hdr.src[3],
                            test_packet->eth_hdr.src[4],
                            test_packet->eth_hdr.src[5]);
                    printf("+-------------------+\n");
                    printf("| %04X | ", htons(test_packet->eth_hdr.type));
                    printf("\n");

                    if(htons(test_packet->eth_hdr.type) == ETHTYPE_ARP)
                    {
                        printf("EthernetARP header:\n");
                        printf("+-------------------+\n");
                        printf("|       %04X        | (hwtype)\n", htons(test_packet->etharp_hdr.hwtype));
                        printf("+-------------------+\n");
                        printf("|       %04X        | (proto)\n", test_packet->etharp_hdr.proto);
                        printf("+-------------------+\n");
                        printf("|        %02X         | (hwlen)\n", test_packet->etharp_hdr.hwlen);
                        printf("+-------------------+\n");
                        printf("|        %02X         | (protolen)\n", test_packet->etharp_hdr.protolen);
                        printf("+-------------------+\n");
                        printf("|       %04X        | (opcode)\n", htons(test_packet->etharp_hdr.opcode));
                        printf("+-------------------+\n");
                        printf("| %02X:%02X:%02X:%02X:%02X:%02X | (src MAC)\n",
                                test_packet->etharp_hdr.shwaddr.addr[0],
                                test_packet->etharp_hdr.shwaddr.addr[1],
                                test_packet->etharp_hdr.shwaddr.addr[2],
                                test_packet->etharp_hdr.shwaddr.addr[3],
                                test_packet->etharp_hdr.shwaddr.addr[4],
                                test_packet->etharp_hdr.shwaddr.addr[5]);
                        printf("+-------------------+\n");
                        printf("|  %3hu.%3hu.%3hu.%3hu  | (src IP)\n",
                                ip4_addr1_16(&test_packet->etharp_hdr.sipaddr.addrw),
                                ip4_addr2_16(&test_packet->etharp_hdr.sipaddr.addrw),
                                ip4_addr3_16(&test_packet->etharp_hdr.sipaddr.addrw),
                                ip4_addr4_16(&test_packet->etharp_hdr.sipaddr.addrw));
                        printf("+-------------------+\n");
                        printf("| %02X:%02X:%02X:%02X:%02X:%02X | (dest MAC)\n",
                                test_packet->etharp_hdr.dhwaddr.addr[0],
                                test_packet->etharp_hdr.dhwaddr.addr[1],
                                test_packet->etharp_hdr.dhwaddr.addr[2],
                                test_packet->etharp_hdr.dhwaddr.addr[3],
                                test_packet->etharp_hdr.dhwaddr.addr[4],
                                test_packet->etharp_hdr.dhwaddr.addr[5]);
                        printf("+-------------------+\n");
              
                        printf("|  %3hu.%3hu.%3hu.%3hu  | (dest IP)\n",
                                ip4_addr1_16(&test_packet->etharp_hdr.dipaddr.addrw),
                                ip4_addr2_16(&test_packet->etharp_hdr.dipaddr.addrw),
                                ip4_addr3_16(&test_packet->etharp_hdr.dipaddr.addrw),
                                ip4_addr4_16(&test_packet->etharp_hdr.dipaddr.addrw));
                        printf("+-------------------+\n");
                    }
              }


    구조체를 초기화 시켜줍니다.

    안하면 데이터가 요상하게 나올수도 있습니다~


     memset(test_packet, 0, sizeof((ETH_TEST_PACKET *)test_packet));
    memset(buff, 0, sizeof(buff) );


    출력 방법은 간단 합니다.

    소스에서 보이듯이 그냥 받아온 변수 값을 하나씩 이쁘게 출력해주면 됩니다.

    (이쁘게 보이기 위한 노가다의 산물입니다. orz)


    printf("| %04X | ", htons(test_packet->eth_hdr.type));


    중간에 이런게 보이실겁니다.

    저번에 설명 드렸다시피 엔디안의 차이로 0608으로 날려주고

    받는 쪽에서 htons라는 함수를 사용해서 0806으로 다시 변경 시켜 주는 작업입니다.


     printf("|  %3hu.%3hu.%3hu.%3hu  | (dest IP)\n",
        ip4_addr1_16(&test_packet->etharp_hdr.dipaddr.addrw),
        ip4_addr2_16(&test_packet->etharp_hdr.dipaddr.addrw),
        ip4_addr3_16(&test_packet->etharp_hdr.dipaddr.addrw),
        ip4_addr4_16(&test_packet->etharp_hdr.dipaddr.addrw));


    ip4_addr1_x 라고 적혀 있는 부분은 아래와 같이 되어 있습니다.


 /* Get one byte from the 4-byte address */
#define ip4_addr1(ipaddr) (((u8_t*)(ipaddr))[0])
#define ip4_addr2(ipaddr) (((u8_t*)(ipaddr))[1])
#define ip4_addr3(ipaddr) (((u8_t*)(ipaddr))[2])
#define ip4_addr4(ipaddr) (((u8_t*)(ipaddr))[3])

#define ip4_addr1_16(ipaddr) ((u16_t)ip4_addr1(ipaddr))
#define ip4_addr2_16(ipaddr) ((u16_t)ip4_addr2(ipaddr))
#define ip4_addr3_16(ipaddr) ((u16_t)ip4_addr3(ipaddr))
#define ip4_addr4_16(ipaddr) ((u16_t)ip4_addr4(ipaddr))


    이 부분은 받아온 데이터를 ipv4 형식에 맞도록 u8 형식 4개로 바꿔줍니다.


    요기서 수신까지 끝마치겠습니다~


    짧은 글 읽어 주셔서 감사합니다!

 

이미지 출처 : 위키피디아