#include "test_dhcp.h" #include "lwip/netif.h" #include "lwip/dhcp.h" #include "netif/etharp.h" struct netif net_test; static u8_t broadcast[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; static u8_t magic_cookie[] = { 0x63, 0x82, 0x53, 0x63 }; static u8_t dhcp_offer[] = { 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, // To unit 0x00, 0x0F, 0xEE, 0x30, 0xAB, 0x22, // From Remote host 0x08, 0x00, // Protocol: IP 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00, 0x80, 0x11, 0x36, 0xcc, 0xc3, 0xaa, 0xbd, 0xab, 0xc3, 0xaa, 0xbd, 0xc8, // IP header 0x00, 0x43, 0x00, 0x44, 0x01, 0x34, 0x6a, 0xa9, // UDP header 0x02, // Type == Boot reply 0x01, 0x06, // Hw Ethernet, 6 bytes addrlen 0x00, // 0 hops 0xAA, 0xAA, 0xAA, 0xAA, // Transaction id, will be overwritten 0x00, 0x00, // 0 seconds elapsed 0x00, 0x00, // Flags (unicast) 0x00, 0x00, 0x00, 0x00, // Client ip 0xc3, 0xaa, 0xbd, 0xc8, // Your IP 0xc3, 0xaa, 0xbd, 0xab, // DHCP server ip 0x00, 0x00, 0x00, 0x00, // relay agent 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // MAC addr + padding // Empty server name and boot file name 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x82, 0x53, 0x63, // Magic cookie 0x35, 0x01, 0x02, // Message type: Offer 0x36, 0x04, 0xc3, 0xaa, 0xbd, 0xab, // Server identifier (IP) 0x33, 0x04, 0x00, 0x00, 0x00, 0x78, // Lease time 2 minutes 0x03, 0x04, 0xc3, 0xaa, 0xbd, 0xab, // Router IP 0x01, 0x04, 0xff, 0xff, 0xff, 0x00, // Subnet mask 0xff, // End option 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Padding }; static u8_t dhcp_ack[] = { 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, // To unit 0x00, 0x0f, 0xEE, 0x30, 0xAB, 0x22, // From remote host 0x08, 0x00, // Proto IP 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00, 0x80, 0x11, 0x36, 0xcc, 0xc3, 0xaa, 0xbd, 0xab, 0xc3, 0xaa, 0xbd, 0xc8, // IP header 0x00, 0x43, 0x00, 0x44, 0x01, 0x34, 0x67, 0xa8, // UDP header 0x02, // Bootp reply 0x01, 0x06, // Hw type Eth, len 6 0x00, // 0 hops 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, // 0 seconds elapsed 0x00, 0x00, // Flags (unicast) 0x00, 0x00, 0x00, 0x00, // Client IP 0xc3, 0xaa, 0xbd, 0xc8, // Your IP 0xc3, 0xaa, 0xbd, 0xab, // DHCP server IP 0x00, 0x00, 0x00, 0x00, // Relay agent 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Macaddr + padding // Empty server name and boot file name 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x82, 0x53, 0x63, // Magic cookie 0x35, 0x01, 0x05, // Dhcp message type ack 0x36, 0x04, 0xc3, 0xaa, 0xbd, 0xab, // DHCP server identifier 0x33, 0x04, 0x00, 0x00, 0x00, 0x78, // Lease time 2 minutes 0x03, 0x04, 0xc3, 0xaa, 0xbd, 0xab, // Router IP 0x01, 0x04, 0xff, 0xff, 0xff, 0x00, // Netmask 0xff, // End marker 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Padding }; static u8_t arpreply[] = { 0x00, 0x23, 0xC1, 0xDE, 0xD0, 0x0D, // dst mac 0x00, 0x32, 0x44, 0x20, 0x01, 0x02, // src mac 0x08, 0x06, // proto arp 0x00, 0x01, // hw eth 0x08, 0x00, // proto ip 0x06, // hw addr len 6 0x04, // proto addr len 4 0x00, 0x02, // arp reply 0x00, 0x32, 0x44, 0x20, 0x01, 0x02, // sender mac 0xc3, 0xaa, 0xbd, 0xc8, // sender ip 0x00, 0x23, 0xC1, 0xDE, 0xD0, 0x0D, // target mac 0x00, 0x00, 0x00, 0x00, // target ip }; static int txpacket; static enum tcase { TEST_LWIP_DHCP, TEST_LWIP_DHCP_NAK, TEST_LWIP_DHCP_RELAY, } tcase; static int debug = 0; static void setdebug(int a) {debug = a;} static int tick = 0; static void tick_lwip() { tick++; if (tick % 5 == 0) { dhcp_fine_tmr(); } if (tick % 600 == 0) { dhcp_coarse_tmr(); } } static void send_pkt(struct netif *netif, u8_t *data, u32_t len) { struct pbuf *p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); struct pbuf *q; if (debug) { // Dump data u32_t i; printf("RX data (len %d)", p->tot_len); for (i = 0; i < len; i++) { printf(" %02X", data[i]); } printf("\n"); } fail_unless(p != NULL); for(q = p; q != NULL; q = q->next) { memcpy(q->payload, data, q->len); data += q->len; } netif->input(p, netif); } static err_t lwip_tx_func(struct netif *netif, struct pbuf *p); static err_t testif_init(struct netif *netif) { netif->name[0] = 'c'; netif->name[1] = 'h'; netif->output = etharp_output; netif->linkoutput = lwip_tx_func; netif->mtu = 1500; netif->hwaddr_len = 6; netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP; netif->hwaddr[0] = 0x00; netif->hwaddr[1] = 0x23; netif->hwaddr[2] = 0xC1; netif->hwaddr[3] = 0xDE; netif->hwaddr[4] = 0xD0; netif->hwaddr[5] = 0x0D; return ERR_OK; } static void dhcp_setup() { txpacket = 0; } static void dhcp_teardown() { } static void check_pkt(struct pbuf *p, u32_t pos, u8_t *mem, u32_t len) { fail_if((pos + len) > p->tot_len); while (pos > p->len && p->next) { pos -= p->len; p = p->next; } fail_if(p == NULL); fail_unless(pos + len <= p->len); // All data we seek within same pbuf u8_t *data = p->payload; fail_if(memcmp(&data[pos], mem, len), "data at pos %d, len %d in packet %d did not match", pos, len, txpacket); } static void check_pkt_fuzzy(struct pbuf *p, u32_t startpos, u8_t *mem, u32_t len) { fail_if((startpos + len) > p->tot_len); while (startpos > p->len && p->next) { startpos -= p->len; p = p->next; } fail_if(p == NULL); fail_unless(startpos + len <= p->len); // All data we seek within same pbuf int found = 0; u32_t i; u8_t *data = p->payload; for (i = startpos; i <= (p->len - len); i++) { if (memcmp(&data[i], mem, len) == 0) { found = 1; break; } } fail_unless(found); } static err_t lwip_tx_func(struct netif *netif, struct pbuf *p) { fail_unless(netif == &net_test); txpacket++; if (debug) { // Dump data printf("TX data (pkt %d, len %d, tick %d)", txpacket, p->tot_len, tick); struct pbuf *pp = p; do { int i; for (i = 0; i < pp->len; i++) { printf(" %02X", ((u8_t *) pp->payload)[i]); } if (pp->next) { pp = pp->next; } } while (pp->next); printf("\n"); } switch (tcase) { case TEST_LWIP_DHCP: switch (txpacket) { case 1: case 2: { check_pkt(p, 0, broadcast, 6); // eth level dest: broadcast check_pkt(p, 6, netif->hwaddr, 6); // eth level src: unit mac u8_t ipproto[] = { 0x08, 0x00 }; check_pkt(p, 12, ipproto, sizeof(ipproto)); // eth level proto: ip u8_t bootp_start[] = { 0x01, 0x01, 0x06, 0x00}; // bootp request, eth, hwaddr len 6, 0 hops check_pkt(p, 42, bootp_start, sizeof(bootp_start)); u8_t ipaddrs[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; check_pkt(p, 53, ipaddrs, sizeof(ipaddrs)); check_pkt(p, 70, netif->hwaddr, 6); // mac addr inside bootp check_pkt(p, 278, magic_cookie, sizeof(magic_cookie)); // Check dchp message type, can be at different positions if (txpacket == 1) { u8_t dhcp_discover_opt[] = { 0x35, 0x01, 0x01 }; check_pkt_fuzzy(p, 282, dhcp_discover_opt, sizeof(dhcp_discover_opt)); } else if (txpacket == 2) { u8_t dhcp_request_opt[] = { 0x35, 0x01, 0x03 }; check_pkt_fuzzy(p, 282, dhcp_request_opt, sizeof(dhcp_request_opt)); u8_t requested_ipaddr[] = { 0x32, 0x04, 0xc3, 0xaa, 0xbd, 0xc8 }; // Ask for offered IP check_pkt_fuzzy(p, 282, requested_ipaddr, sizeof(requested_ipaddr)); } break; } case 3: case 4: case 5: { check_pkt(p, 0, broadcast, 6); // eth level dest: broadcast check_pkt(p, 6, netif->hwaddr, 6); // eth level src: unit mac u8_t arpproto[] = { 0x08, 0x06 }; check_pkt(p, 12, arpproto, sizeof(arpproto)); // eth level proto: ip break; } } break; case TEST_LWIP_DHCP_NAK: { fail_unless(txpacket == 4); check_pkt(p, 0, broadcast, 6); // eth level dest: broadcast check_pkt(p, 6, netif->hwaddr, 6); // eth level src: unit mac u8_t ipproto[] = { 0x08, 0x00 }; check_pkt(p, 12, ipproto, sizeof(ipproto)); // eth level proto: ip u8_t bootp_start[] = { 0x01, 0x01, 0x06, 0x00}; // bootp request, eth, hwaddr len 6, 0 hops check_pkt(p, 42, bootp_start, sizeof(bootp_start)); u8_t ipaddrs[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; check_pkt(p, 53, ipaddrs, sizeof(ipaddrs)); check_pkt(p, 70, netif->hwaddr, 6); // mac addr inside bootp check_pkt(p, 278, magic_cookie, sizeof(magic_cookie)); u8_t dhcp_nak_opt[] = { 0x35, 0x01, 0x04 }; check_pkt_fuzzy(p, 282, dhcp_nak_opt, sizeof(dhcp_nak_opt)); // NAK the ack u8_t requested_ipaddr[] = { 0x32, 0x04, 0xc3, 0xaa, 0xbd, 0xc8 }; // offered IP check_pkt_fuzzy(p, 282, requested_ipaddr, sizeof(requested_ipaddr)); break; } case TEST_LWIP_DHCP_RELAY: switch (txpacket) { case 1: case 2: { check_pkt(p, 0, broadcast, 6); // eth level dest: broadcast check_pkt(p, 6, netif->hwaddr, 6); // eth level src: unit mac u8_t ipproto[] = { 0x08, 0x00 }; check_pkt(p, 12, ipproto, sizeof(ipproto)); // eth level proto: ip u8_t bootp_start[] = { 0x01, 0x01, 0x06, 0x00}; // bootp request, eth, hwaddr len 6, 0 hops check_pkt(p, 42, bootp_start, sizeof(bootp_start)); u8_t ipaddrs[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; check_pkt(p, 53, ipaddrs, sizeof(ipaddrs)); check_pkt(p, 70, netif->hwaddr, 6); // mac addr inside bootp check_pkt(p, 278, magic_cookie, sizeof(magic_cookie)); // Check dchp message type, can be at different positions if (txpacket == 1) { u8_t dhcp_discover_opt[] = { 0x35, 0x01, 0x01 }; check_pkt_fuzzy(p, 282, dhcp_discover_opt, sizeof(dhcp_discover_opt)); } else if (txpacket == 2) { u8_t dhcp_request_opt[] = { 0x35, 0x01, 0x03 }; check_pkt_fuzzy(p, 282, dhcp_request_opt, sizeof(dhcp_request_opt)); u8_t requested_ipaddr[] = { 0x32, 0x04, 0x4f, 0x8a, 0x33, 0x05 }; // Ask for offered IP check_pkt_fuzzy(p, 282, requested_ipaddr, sizeof(requested_ipaddr)); } break; } case 3: case 4: case 5: { check_pkt(p, 0, broadcast, 6); // eth level dest: broadcast check_pkt(p, 6, netif->hwaddr, 6); // eth level src: unit mac u8_t arpproto[] = { 0x08, 0x06 }; check_pkt(p, 12, arpproto, sizeof(arpproto)); // eth level proto: ip break; } case 6: { u8_t fake_arp[6] = { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xab }; check_pkt(p, 0, fake_arp, 6); // eth level dest: broadcast check_pkt(p, 6, netif->hwaddr, 6); // eth level src: unit mac u8_t ipproto[] = { 0x08, 0x00 }; check_pkt(p, 12, ipproto, sizeof(ipproto)); // eth level proto: ip u8_t bootp_start[] = { 0x01, 0x01, 0x06, 0x00}; // bootp request, eth, hwaddr len 6, 0 hops check_pkt(p, 42, bootp_start, sizeof(bootp_start)); u8_t ipaddrs[] = { 0x00, 0x4f, 0x8a, 0x33, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; check_pkt(p, 53, ipaddrs, sizeof(ipaddrs)); check_pkt(p, 70, netif->hwaddr, 6); // mac addr inside bootp check_pkt(p, 278, magic_cookie, sizeof(magic_cookie)); // Check dchp message type, can be at different positions u8_t dhcp_request_opt[] = { 0x35, 0x01, 0x03 }; check_pkt_fuzzy(p, 282, dhcp_request_opt, sizeof(dhcp_request_opt)); break; } } break; default: break; } return ERR_OK; } /* * Test basic happy flow DHCP session. * Validate that xid is checked. */ START_TEST(test_dhcp) { struct ip_addr addr; struct ip_addr netmask; struct ip_addr gw; int i; tcase = TEST_LWIP_DHCP; setdebug(0); IP4_ADDR(&addr, 0, 0, 0, 0); IP4_ADDR(&netmask, 0, 0, 0, 0); IP4_ADDR(&gw, 0, 0, 0, 0); netif_add(&net_test, &addr, &netmask, &gw, &net_test, testif_init, ethernet_input); dhcp_start(&net_test); fail_unless(txpacket == 1); // DHCP discover sent u32_t xid = net_test.dhcp->xid; // Write bad xid, not using htonl! memcpy(&dhcp_offer[46], &xid, 4); send_pkt(&net_test, dhcp_offer, sizeof(dhcp_offer)); // Interface down fail_if(netif_is_up(&net_test)); // IP addresses should be zero fail_if(memcmp(&addr, &net_test.ip_addr, sizeof(struct ip_addr))); fail_if(memcmp(&netmask, &net_test.netmask, sizeof(struct ip_addr))); fail_if(memcmp(&gw, &net_test.gw, sizeof(struct ip_addr))); fail_unless(txpacket == 1, "TX %d packets, expected 1", txpacket); // Nothing more sent xid = htonl(net_test.dhcp->xid); memcpy(&dhcp_offer[46], &xid, 4); // insert correct transaction id send_pkt(&net_test, dhcp_offer, sizeof(dhcp_offer)); fail_unless(txpacket == 2, "TX %d packets, expected 2", txpacket); // DHCP request sent xid = net_test.dhcp->xid; // Write bad xid, not using htonl! memcpy(&dhcp_ack[46], &xid, 4); send_pkt(&net_test, dhcp_ack, sizeof(dhcp_ack)); fail_unless(txpacket == 2, "TX %d packets, still expected 2", txpacket); // No more sent xid = htonl(net_test.dhcp->xid); // xid updated memcpy(&dhcp_ack[46], &xid, 4); // insert transaction id send_pkt(&net_test, dhcp_ack, sizeof(dhcp_ack)); for (i = 0; i < 20; i++) tick_lwip(); fail_unless(txpacket == 4, "TX %d packets, expected 4", txpacket); // ARP requests sent // Interface up fail_unless(netif_is_up(&net_test)); // Now it should have taken the IP IP4_ADDR(&addr, 195, 170, 189, 200); IP4_ADDR(&netmask, 255, 255, 255, 0); IP4_ADDR(&gw, 195, 170, 189, 171); fail_if(memcmp(&addr, &net_test.ip_addr, sizeof(struct ip_addr))); fail_if(memcmp(&netmask, &net_test.netmask, sizeof(struct ip_addr))); fail_if(memcmp(&gw, &net_test.gw, sizeof(struct ip_addr))); netif_remove(&net_test); } END_TEST /* * Test that IP address is not taken and NAK is sent if someone * replies to ARP requests for the offered address. */ START_TEST(test_dhcp_nak) { struct ip_addr addr; struct ip_addr netmask; struct ip_addr gw; tcase = TEST_LWIP_DHCP; setdebug(0); IP4_ADDR(&addr, 0, 0, 0, 0); IP4_ADDR(&netmask, 0, 0, 0, 0); IP4_ADDR(&gw, 0, 0, 0, 0); netif_add(&net_test, &addr, &netmask, &gw, &net_test, testif_init, ethernet_input); dhcp_start(&net_test); fail_unless(txpacket == 1); // DHCP discover sent u32_t xid = net_test.dhcp->xid; // Write bad xid, not using htonl! memcpy(&dhcp_offer[46], &xid, 4); send_pkt(&net_test, dhcp_offer, sizeof(dhcp_offer)); // Interface down fail_if(netif_is_up(&net_test)); // IP addresses should be zero fail_if(memcmp(&addr, &net_test.ip_addr, sizeof(struct ip_addr))); fail_if(memcmp(&netmask, &net_test.netmask, sizeof(struct ip_addr))); fail_if(memcmp(&gw, &net_test.gw, sizeof(struct ip_addr))); fail_unless(txpacket == 1); // Nothing more sent xid = htonl(net_test.dhcp->xid); memcpy(&dhcp_offer[46], &xid, 4); // insert correct transaction id send_pkt(&net_test, dhcp_offer, sizeof(dhcp_offer)); fail_unless(txpacket == 2); // DHCP request sent xid = net_test.dhcp->xid; // Write bad xid, not using htonl! memcpy(&dhcp_ack[46], &xid, 4); send_pkt(&net_test, dhcp_ack, sizeof(dhcp_ack)); fail_unless(txpacket == 2); // No more sent xid = htonl(net_test.dhcp->xid); // xid updated memcpy(&dhcp_ack[46], &xid, 4); // insert transaction id send_pkt(&net_test, dhcp_ack, sizeof(dhcp_ack)); fail_unless(txpacket == 3); // ARP request sent tcase = TEST_LWIP_DHCP_NAK; // Switch testcase // Send arp reply, mark offered IP as taken send_pkt(&net_test, arpreply, sizeof(arpreply)); fail_unless(txpacket == 4); // DHCP nak sent netif_remove(&net_test); } END_TEST /* * Test case based on captured data where * replies are sent from a different IP than the * one the client unicasted to. */ START_TEST(test_dhcp_relayed) { u8_t relay_offer[] = { 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, 0x00, 0x22, 0x93, 0x5a, 0xf7, 0x60, 0x08, 0x00, 0x45, 0x00, 0x01, 0x38, 0xfd, 0x53, 0x00, 0x00, 0x40, 0x11, 0x78, 0x46, 0x4f, 0x8a, 0x32, 0x02, 0x4f, 0x8a, 0x33, 0x05, 0x00, 0x43, 0x00, 0x44, 0x01, 0x24, 0x38, 0x72, 0x02, 0x01, 0x06, 0x00, 0x51, 0x35, 0xb6, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x8a, 0x33, 0x05, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xb5, 0x04, 0x01, 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x82, 0x53, 0x63, 0x01, 0x04, 0xff, 0xff, 0xfe, 0x00, 0x03, 0x04, 0x4f, 0x8a, 0x32, 0x01, 0x06, 0x08, 0x4f, 0x8a, 0x00, 0xb4, 0x55, 0x08, 0x1f, 0xd1, 0x1c, 0x04, 0x4f, 0x8a, 0x33, 0xff, 0x33, 0x04, 0x00, 0x00, 0x54, 0x49, 0x35, 0x01, 0x02, 0x36, 0x04, 0x0a, 0xb5, 0x04, 0x01, 0xff }; u8_t relay_ack1[] = { 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, 0x00, 0x22, 0x93, 0x5a, 0xf7, 0x60, 0x08, 0x00, 0x45, 0x00, 0x01, 0x38, 0xfd, 0x55, 0x00, 0x00, 0x40, 0x11, 0x78, 0x44, 0x4f, 0x8a, 0x32, 0x02, 0x4f, 0x8a, 0x33, 0x05, 0x00, 0x43, 0x00, 0x44, 0x01, 0x24, 0x35, 0x71, 0x02, 0x01, 0x06, 0x00, 0x51, 0x35, 0xb6, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x8a, 0x33, 0x05, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xb5, 0x04, 0x01, 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x82, 0x53, 0x63, 0x01, 0x04, 0xff, 0xff, 0xfe, 0x00, 0x03, 0x04, 0x4f, 0x8a, 0x32, 0x01, 0x06, 0x08, 0x4f, 0x8a, 0x00, 0xb4, 0x55, 0x08, 0x1f, 0xd1, 0x1c, 0x04, 0x4f, 0x8a, 0x33, 0xff, 0x33, 0x04, 0x00, 0x00, 0x54, 0x49, 0x35, 0x01, 0x05, 0x36, 0x04, 0x0a, 0xb5, 0x04, 0x01, 0xff }; u8_t relay_ack2[] = { 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, 0x00, 0x22, 0x93, 0x5a, 0xf7, 0x60, 0x08, 0x00, 0x45, 0x00, 0x01, 0x38, 0xfa, 0x18, 0x00, 0x00, 0x40, 0x11, 0x7b, 0x81, 0x4f, 0x8a, 0x32, 0x02, 0x4f, 0x8a, 0x33, 0x05, 0x00, 0x43, 0x00, 0x44, 0x01, 0x24, 0x02, 0x6b, 0x02, 0x01, 0x06, 0x00, 0x49, 0x8b, 0x6e, 0xab, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x8a, 0x33, 0x05, 0x4f, 0x8a, 0x33, 0x05, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xb5, 0x04, 0x01, 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x82, 0x53, 0x63, 0x01, 0x04, 0xff, 0xff, 0xfe, 0x00, 0x03, 0x04, 0x4f, 0x8a, 0x32, 0x01, 0x06, 0x08, 0x4f, 0x8a, 0x00, 0xb4, 0x55, 0x08, 0x1f, 0xd1, 0x1c, 0x04, 0x4f, 0x8a, 0x33, 0xff, 0x33, 0x04, 0x00, 0x00, 0x54, 0x60, 0x35, 0x01, 0x05, 0x36, 0x04, 0x0a, 0xb5, 0x04, 0x01, 0xff }; u8_t arp_resp[] = { 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, // DEST 0x00, 0x22, 0x93, 0x5a, 0xf7, 0x60, // SRC 0x08, 0x06, // Type: ARP 0x00, 0x01, // HW: Ethernet 0x08, 0x00, // PROTO: IP 0x06, // HW size 0x04, // PROTO size 0x00, 0x02, // OPCODE: Reply 0x12, 0x34, 0x56, 0x78, 0x9a, 0xab, // Target MAC 0x4f, 0x8a, 0x32, 0x01, // Target IP 0x00, 0x23, 0xc1, 0x00, 0x06, 0x50, // src mac 0x4f, 0x8a, 0x33, 0x05, // src ip // Padding follows.. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; struct ip_addr addr; struct ip_addr netmask; struct ip_addr gw; int i; tcase = TEST_LWIP_DHCP_RELAY; setdebug(0); IP4_ADDR(&addr, 0, 0, 0, 0); IP4_ADDR(&netmask, 0, 0, 0, 0); IP4_ADDR(&gw, 0, 0, 0, 0); netif_add(&net_test, &addr, &netmask, &gw, &net_test, testif_init, ethernet_input); dhcp_start(&net_test); fail_unless(txpacket == 1); // DHCP discover sent // Interface down fail_if(netif_is_up(&net_test)); // IP addresses should be zero fail_if(memcmp(&addr, &net_test.ip_addr, sizeof(struct ip_addr))); fail_if(memcmp(&netmask, &net_test.netmask, sizeof(struct ip_addr))); fail_if(memcmp(&gw, &net_test.gw, sizeof(struct ip_addr))); fail_unless(txpacket == 1); // Nothing more sent u32_t xid = htonl(net_test.dhcp->xid); memcpy(&relay_offer[46], &xid, 4); // insert correct transaction id send_pkt(&net_test, relay_offer, sizeof(relay_offer)); // request sent? fail_unless(txpacket == 2, "txpkt = %d, should be 2", txpacket); xid = htonl(net_test.dhcp->xid); // xid updated memcpy(&relay_ack1[46], &xid, 4); // insert transaction id send_pkt(&net_test, relay_ack1, sizeof(relay_ack1)); for (i = 0; i < 25; i++) tick_lwip(); fail_unless(txpacket == 4, "txpkt should be 5, is %d", txpacket); // ARP requests sent // Interface up fail_unless(netif_is_up(&net_test)); // Now it should have taken the IP IP4_ADDR(&addr, 79, 138, 51, 5); IP4_ADDR(&netmask, 255, 255, 254, 0); IP4_ADDR(&gw, 79, 138, 50, 1); fail_if(memcmp(&addr, &net_test.ip_addr, sizeof(struct ip_addr))); fail_if(memcmp(&netmask, &net_test.netmask, sizeof(struct ip_addr))); fail_if(memcmp(&gw, &net_test.gw, sizeof(struct ip_addr))); fail_unless(txpacket == 4, "txpacket = %d", txpacket); for (i = 0; i < 108000 - 25; i++) { tick_lwip(); } fail_unless(netif_is_up(&net_test)); fail_unless(txpacket == 5, "txpacket = %d", txpacket); // We need to send arp response here.. send_pkt(&net_test, arp_resp, sizeof(arp_resp)); fail_unless(txpacket == 6, "txpacket = %d", txpacket); fail_unless(netif_is_up(&net_test)); xid = htonl(net_test.dhcp->xid); // xid updated memcpy(&relay_ack2[46], &xid, 4); // insert transaction id send_pkt(&net_test, relay_ack2, sizeof(relay_ack2)); for (i = 0; i < 100000; i++) { tick_lwip(); } fail_unless(txpacket == 6, "txpacket = %d", txpacket); netif_remove(&net_test); } END_TEST /** Create the suite including all tests for this module */ Suite * dhcp_suite(void) { TFun tests[] = { test_dhcp, test_dhcp_nak, test_dhcp_relayed }; return create_suite("DHCP", tests, sizeof(tests)/sizeof(TFun), dhcp_setup, dhcp_teardown); }