static bool run_tests(void) { struct net_pkt *pkt, *pkt2; struct net_buf *frag; struct net_if *iface; struct net_if_addr *ifaddr; struct net_arp_hdr *arp_hdr; struct net_ipv4_hdr *ipv4; struct net_eth_hdr *eth_hdr; int len; struct in_addr dst = { { { 192, 168, 0, 2 } } }; struct in_addr dst_far = { { { 10, 11, 12, 13 } } }; struct in_addr dst_far2 = { { { 172, 16, 14, 186 } } }; struct in_addr src = { { { 192, 168, 0, 1 } } }; struct in_addr netmask = { { { 255, 255, 255, 0 } } }; struct in_addr gw = { { { 192, 168, 0, 42 } } }; net_arp_init(); iface = net_if_get_default(); net_if_ipv4_set_gw(iface, &gw); net_if_ipv4_set_netmask(iface, &netmask); /* Unicast test */ ifaddr = net_if_ipv4_addr_add(iface, &src, NET_ADDR_MANUAL, 0); ifaddr->addr_state = NET_ADDR_PREFERRED; /* Application data for testing */ pkt = net_pkt_get_reserve_tx(sizeof(struct net_eth_hdr), K_FOREVER); if (!pkt) { printk("Out of mem TX\n"); return false; } frag = net_pkt_get_frag(pkt, K_FOREVER); if (!frag) { printk("Out of mem DATA\n"); return false; } net_pkt_frag_add(pkt, frag); net_pkt_set_iface(pkt, iface); setup_eth_header(iface, pkt, &hwaddr, NET_ETH_PTYPE_IP); len = strlen(app_data); if (net_pkt_ll_reserve(pkt) != sizeof(struct net_eth_hdr)) { printk("LL reserve invalid, should be %zd was %d\n", sizeof(struct net_eth_hdr), net_pkt_ll_reserve(pkt)); return false; } ipv4 = (struct net_ipv4_hdr *)net_buf_add(frag, sizeof(struct net_ipv4_hdr)); net_ipaddr_copy(&ipv4->src, &src); net_ipaddr_copy(&ipv4->dst, &dst); memcpy(net_buf_add(frag, len), app_data, len); pkt2 = net_arp_prepare(pkt); /* pkt2 is the ARP packet and pkt is the IPv4 packet and it was * stored in ARP table. */ if (pkt2 == pkt) { /* The packets cannot be the same as the ARP cache has * still room for the pkt. */ printk("ARP cache should still have free space\n"); return false; } if (!pkt2) { printk("ARP pkt is empty\n"); return false; } /* The ARP cache should now have a link to pending net_pkt * that is to be sent after we have got an ARP reply. */ if (!pkt->frags) { printk("Pending pkt fragment is NULL\n"); return false; } pending_pkt = pkt; /* pkt2 should contain the arp header, verify it */ if (memcmp(net_pkt_ll(pkt2), net_eth_broadcast_addr(), sizeof(struct net_eth_addr))) { printk("ARP ETH dest address invalid\n"); net_hexdump("ETH dest wrong ", net_pkt_ll(pkt2), sizeof(struct net_eth_addr)); net_hexdump("ETH dest correct", (u8_t *)net_eth_broadcast_addr(), sizeof(struct net_eth_addr)); return false; } if (memcmp(net_pkt_ll(pkt2) + sizeof(struct net_eth_addr), iface->link_addr.addr, sizeof(struct net_eth_addr))) { printk("ARP ETH source address invalid\n"); net_hexdump("ETH src correct", iface->link_addr.addr, sizeof(struct net_eth_addr)); net_hexdump("ETH src wrong ", net_pkt_ll(pkt2) + sizeof(struct net_eth_addr), sizeof(struct net_eth_addr)); return false; } arp_hdr = NET_ARP_HDR(pkt2); eth_hdr = NET_ETH_HDR(pkt2); if (eth_hdr->type != htons(NET_ETH_PTYPE_ARP)) { printk("ETH type 0x%x, should be 0x%x\n", eth_hdr->type, htons(NET_ETH_PTYPE_ARP)); return false; } if (arp_hdr->hwtype != htons(NET_ARP_HTYPE_ETH)) { printk("ARP hwtype 0x%x, should be 0x%x\n", arp_hdr->hwtype, htons(NET_ARP_HTYPE_ETH)); return false; } if (arp_hdr->protocol != htons(NET_ETH_PTYPE_IP)) { printk("ARP protocol 0x%x, should be 0x%x\n", arp_hdr->protocol, htons(NET_ETH_PTYPE_IP)); return false; } if (arp_hdr->hwlen != sizeof(struct net_eth_addr)) { printk("ARP hwlen 0x%x, should be 0x%zx\n", arp_hdr->hwlen, sizeof(struct net_eth_addr)); return false; } if (arp_hdr->protolen != sizeof(struct in_addr)) { printk("ARP IP addr len 0x%x, should be 0x%zx\n", arp_hdr->protolen, sizeof(struct in_addr)); return false; } if (arp_hdr->opcode != htons(NET_ARP_REQUEST)) { printk("ARP opcode 0x%x, should be 0x%x\n", arp_hdr->opcode, htons(NET_ARP_REQUEST)); return false; } if (!net_ipv4_addr_cmp(&arp_hdr->dst_ipaddr, &NET_IPV4_HDR(pkt)->dst)) { char out[sizeof("xxx.xxx.xxx.xxx")]; snprintk(out, sizeof(out), "%s", net_sprint_ipv4_addr(&arp_hdr->dst_ipaddr)); printk("ARP IP dest invalid %s, should be %s", out, net_sprint_ipv4_addr(&NET_IPV4_HDR(pkt)->dst)); return false; } if (!net_ipv4_addr_cmp(&arp_hdr->src_ipaddr, &NET_IPV4_HDR(pkt)->src)) { char out[sizeof("xxx.xxx.xxx.xxx")]; snprintk(out, sizeof(out), "%s", net_sprint_ipv4_addr(&arp_hdr->src_ipaddr)); printk("ARP IP src invalid %s, should be %s", out, net_sprint_ipv4_addr(&NET_IPV4_HDR(pkt)->src)); return false; } /* We could have send the new ARP request but for this test we * just free it. */ net_pkt_unref(pkt2); if (pkt->ref != 2) { printk("ARP cache should own the original packet\n"); return false; } /* Then a case where target is not in the same subnet */ net_ipaddr_copy(&ipv4->dst, &dst_far); pkt2 = net_arp_prepare(pkt); if (pkt2 == pkt) { printk("ARP cache should not find anything\n"); return false; } if (!pkt2) { printk("ARP pkt2 is empty\n"); return false; } arp_hdr = NET_ARP_HDR(pkt2); if (!net_ipv4_addr_cmp(&arp_hdr->dst_ipaddr, &iface->ipv4.gw)) { char out[sizeof("xxx.xxx.xxx.xxx")]; snprintk(out, sizeof(out), "%s", net_sprint_ipv4_addr(&arp_hdr->dst_ipaddr)); printk("ARP IP dst invalid %s, should be %s\n", out, net_sprint_ipv4_addr(&iface->ipv4.gw)); return false; } net_pkt_unref(pkt2); /* Try to find the same destination again, this should fail as there * is a pending request in ARP cache. */ net_ipaddr_copy(&ipv4->dst, &dst_far); /* Make sure prepare will not free the pkt because it will be * needed in the later test case. */ net_pkt_ref(pkt); pkt2 = net_arp_prepare(pkt); if (!pkt2) { printk("ARP cache is not sending the request again\n"); return false; } net_pkt_unref(pkt2); /* Try to find the different destination, this should fail too * as the cache table should be full. */ net_ipaddr_copy(&ipv4->dst, &dst_far2); /* Make sure prepare will not free the pkt because it will be * needed in the next test case. */ net_pkt_ref(pkt); pkt2 = net_arp_prepare(pkt); if (!pkt2) { printk("ARP cache did not send a req\n"); return false; } /* Restore the original address so that following test case can * work properly. */ net_ipaddr_copy(&ipv4->dst, &dst); /* The arp request packet is now verified, create an arp reply. * The previous value of pkt is stored in arp table and is not lost. */ pkt = net_pkt_get_reserve_rx(sizeof(struct net_eth_hdr), K_FOREVER); if (!pkt) { printk("Out of mem RX reply\n"); return false; } printk("%d pkt %p\n", __LINE__, pkt); frag = net_pkt_get_frag(pkt, K_FOREVER); if (!frag) { printk("Out of mem DATA reply\n"); return false; } printk("%d frag %p\n", __LINE__, frag); net_pkt_frag_add(pkt, frag); net_pkt_set_iface(pkt, iface); arp_hdr = NET_ARP_HDR(pkt); net_buf_add(frag, sizeof(struct net_arp_hdr)); net_ipaddr_copy(&arp_hdr->dst_ipaddr, &dst); net_ipaddr_copy(&arp_hdr->src_ipaddr, &src); pkt2 = prepare_arp_reply(iface, pkt, &hwaddr); if (!pkt2) { printk("ARP reply generation failed."); return false; } /* The pending packet should now be sent */ switch (net_arp_input(pkt2)) { case NET_OK: case NET_CONTINUE: break; case NET_DROP: break; } /* Yielding so that network interface TX thread can proceed. */ k_yield(); if (send_status < 0) { printk("ARP reply was not sent\n"); return false; } if (pkt->ref != 1) { printk("ARP cache should no longer own the original packet\n"); return false; } net_pkt_unref(pkt); /* Then feed in ARP request */ pkt = net_pkt_get_reserve_rx(sizeof(struct net_eth_hdr), K_FOREVER); if (!pkt) { printk("Out of mem RX request\n"); return false; } frag = net_pkt_get_frag(pkt, K_FOREVER); if (!frag) { printk("Out of mem DATA request\n"); return false; } net_pkt_frag_add(pkt, frag); net_pkt_set_iface(pkt, iface); send_status = -EINVAL; arp_hdr = NET_ARP_HDR(pkt); net_buf_add(frag, sizeof(struct net_arp_hdr)); net_ipaddr_copy(&arp_hdr->dst_ipaddr, &src); net_ipaddr_copy(&arp_hdr->src_ipaddr, &dst); setup_eth_header(iface, pkt, &hwaddr, NET_ETH_PTYPE_ARP); pkt2 = prepare_arp_request(iface, pkt, &hwaddr); if (!pkt2) { printk("ARP request generation failed."); return false; } req_test = true; switch (net_arp_input(pkt2)) { case NET_OK: case NET_CONTINUE: break; case NET_DROP: break; } /* Yielding so that network interface TX thread can proceed. */ k_yield(); if (send_status < 0) { printk("ARP req was not sent\n"); return false; } net_pkt_unref(pkt); printk("Network ARP checks passed\n"); return true; }
/* TODO: Handles only DHCPv4 OFFER and ACK messages */ static inline void handle_dhcpv4_reply(struct net_if *iface, uint8_t msg_type) { /* * Check for previous state, reason behind this check is, if client * receives multiple OFFER messages, first one will be handled. * Rest of the replies are discarded. */ if (iface->dhcpv4.state == NET_DHCPV4_DISCOVER) { if (msg_type != NET_DHCPV4_OFFER) { NET_DBG("Reply not handled %d", msg_type); return; } /* Send DHCPv4 Request Message */ k_delayed_work_cancel(&iface->dhcpv4_timeout); send_request(iface, false); } else if (iface->dhcpv4.state == NET_DHCPV4_REQUEST || iface->dhcpv4.state == NET_DHCPV4_RENEWAL) { if (msg_type != NET_DHCPV4_ACK) { NET_DBG("Reply not handled %d", msg_type); return; } k_delayed_work_cancel(&iface->dhcpv4_timeout); switch (iface->dhcpv4.state) { case NET_DHCPV4_REQUEST: NET_INFO("Received: %s", net_sprint_ipv4_addr( &iface->dhcpv4.requested_ip)); if (!net_if_ipv4_addr_add(iface, &iface->dhcpv4.requested_ip, NET_ADDR_DHCP, iface->dhcpv4.lease_time)) { NET_DBG("Failed to add IPv4 addr to iface %p", iface); return; } break; case NET_DHCPV4_RENEWAL: /* TODO: if the renewal is success, update only * vlifetime on iface */ break; default: break; } iface->dhcpv4.attempts = 0; iface->dhcpv4.state = NET_DHCPV4_ACK; /* Start renewal time */ k_delayed_work_init(&iface->dhcpv4_t1_timer, dhcpv4_t1_timeout); k_delayed_work_submit(&iface->dhcpv4_t1_timer, get_dhcpv4_renewal_time(iface)); } }
void run_tests(void) { k_thread_priority_set(k_current_get(), K_PRIO_COOP(7)); test_failed = false; struct net_conn_handle *handlers[CONFIG_NET_MAX_CONN]; struct net_if *iface = net_if_get_default(); struct net_if_addr *ifaddr; struct ud *ud; int ret, i = 0; bool st; struct sockaddr_in6 any_addr6; const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; struct sockaddr_in6 my_addr6; struct in6_addr in6addr_my = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; struct sockaddr_in6 peer_addr6; struct in6_addr in6addr_peer = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0x4e, 0x11, 0, 0, 0x2 } } }; struct sockaddr_in any_addr4; const struct in_addr in4addr_any = { { { 0 } } }; struct sockaddr_in my_addr4; struct in_addr in4addr_my = { { { 192, 0, 2, 1 } } }; struct sockaddr_in peer_addr4; struct in_addr in4addr_peer = { { { 192, 0, 2, 9 } } }; net_ipaddr_copy(&any_addr6.sin6_addr, &in6addr_any); any_addr6.sin6_family = AF_INET6; net_ipaddr_copy(&my_addr6.sin6_addr, &in6addr_my); my_addr6.sin6_family = AF_INET6; net_ipaddr_copy(&peer_addr6.sin6_addr, &in6addr_peer); peer_addr6.sin6_family = AF_INET6; net_ipaddr_copy(&any_addr4.sin_addr, &in4addr_any); any_addr4.sin_family = AF_INET; net_ipaddr_copy(&my_addr4.sin_addr, &in4addr_my); my_addr4.sin_family = AF_INET; net_ipaddr_copy(&peer_addr4.sin_addr, &in4addr_peer); peer_addr4.sin_family = AF_INET; k_sem_init(&recv_lock, 0, UINT_MAX); ifaddr = net_if_ipv6_addr_add(iface, &in6addr_my, NET_ADDR_MANUAL, 0); if (!ifaddr) { printk("Cannot add %s to interface %p\n", net_sprint_ipv6_addr(&in6addr_my), iface); zassert_true(0, "exiting"); } ifaddr = net_if_ipv4_addr_add(iface, &in4addr_my, NET_ADDR_MANUAL, 0); if (!ifaddr) { printk("Cannot add %s to interface %p\n", net_sprint_ipv4_addr(&in4addr_my), iface); zassert_true(0, "exiting"); } #define REGISTER(family, raddr, laddr, rport, lport) \ ({ \ static struct ud user_data; \ \ user_data.remote_addr = (struct sockaddr *)raddr; \ user_data.local_addr = (struct sockaddr *)laddr; \ user_data.remote_port = rport; \ user_data.local_port = lport; \ user_data.test = "DST="#raddr"-SRC="#laddr"-RP="#rport \ "-LP="#lport; \ \ set_port(family, (struct sockaddr *)raddr, \ (struct sockaddr *)laddr, rport, lport); \ \ ret = net_udp_register((struct sockaddr *)raddr, \ (struct sockaddr *)laddr, \ rport, lport, \ test_ok, &user_data, \ &handlers[i]); \ if (ret) { \ printk("UDP register %s failed (%d)\n", \ user_data.test, ret); \ zassert_true(0, "exiting"); \ } \ user_data.handle = handlers[i++]; \ &user_data; \ }) #define REGISTER_FAIL(raddr, laddr, rport, lport) \ ret = net_udp_register((struct sockaddr *)raddr, \ (struct sockaddr *)laddr, \ rport, lport, \ test_fail, INT_TO_POINTER(0), NULL); \ if (!ret) { \ printk("UDP register invalid match %s failed\n", \ "DST="#raddr"-SRC="#laddr"-RP="#rport"-LP="#lport); \ zassert_true(0, "exiting"); \ } #define UNREGISTER(ud) \ ret = net_udp_unregister(ud->handle); \ if (ret) { \ printk("UDP unregister %p failed (%d)\n", ud->handle, \ ret); \ zassert_true(0, "exiting"); \ } #define TEST_IPV6_OK(ud, raddr, laddr, rport, lport) \ st = send_ipv6_udp_msg(iface, raddr, laddr, rport, lport, ud, \ false); \ if (!st) { \ printk("%d: UDP test \"%s\" fail\n", __LINE__, \ ud->test); \ zassert_true(0, "exiting"); \ } #define TEST_IPV6_LONG_OK(ud, raddr, laddr, rport, lport) \ st = send_ipv6_udp_long_msg(iface, raddr, laddr, rport, lport, ud, \ false); \ if (!st) { \ printk("%d: UDP long test \"%s\" fail\n", __LINE__, \ ud->test); \ zassert_true(0, "exiting"); \ } #define TEST_IPV4_OK(ud, raddr, laddr, rport, lport) \ st = send_ipv4_udp_msg(iface, raddr, laddr, rport, lport, ud, \ false); \ if (!st) { \ printk("%d: UDP test \"%s\" fail\n", __LINE__, \ ud->test); \ zassert_true(0, "exiting"); \ } #define TEST_IPV6_FAIL(ud, raddr, laddr, rport, lport) \ st = send_ipv6_udp_msg(iface, raddr, laddr, rport, lport, ud, \ true); \ if (!st) { \ printk("%d: UDP neg test \"%s\" fail\n", __LINE__, \ ud->test); \ zassert_true(0, "exiting"); \ } #define TEST_IPV4_FAIL(ud, raddr, laddr, rport, lport) \ st = send_ipv4_udp_msg(iface, raddr, laddr, rport, lport, ud, \ true); \ if (!st) { \ printk("%d: UDP neg test \"%s\" fail\n", __LINE__, \ ud->test); \ zassert_true(0, "exiting"); \ } ud = REGISTER(AF_INET6, &any_addr6, &any_addr6, 1234, 4242); TEST_IPV6_OK(ud, &in6addr_peer, &in6addr_my, 1234, 4242); TEST_IPV6_OK(ud, &in6addr_peer, &in6addr_my, 1234, 4242); TEST_IPV6_LONG_OK(ud, &in6addr_peer, &in6addr_my, 1234, 4242); TEST_IPV6_LONG_OK(ud, &in6addr_peer, &in6addr_my, 1234, 4242); TEST_IPV6_FAIL(ud, &in6addr_peer, &in6addr_my, 1234, 61400); TEST_IPV6_FAIL(ud, &in6addr_peer, &in6addr_my, 1234, 61400); UNREGISTER(ud); ud = REGISTER(AF_INET, &any_addr4, &any_addr4, 1234, 4242); TEST_IPV4_OK(ud, &in4addr_peer, &in4addr_my, 1234, 4242); TEST_IPV4_OK(ud, &in4addr_peer, &in4addr_my, 1234, 4242); TEST_IPV4_FAIL(ud, &in4addr_peer, &in4addr_my, 1234, 4325); TEST_IPV4_FAIL(ud, &in4addr_peer, &in4addr_my, 1234, 4325); UNREGISTER(ud); ud = REGISTER(AF_INET6, &any_addr6, NULL, 1234, 4242); TEST_IPV6_OK(ud, &in6addr_peer, &in6addr_my, 1234, 4242); TEST_IPV6_OK(ud, &in6addr_peer, &in6addr_my, 1234, 4242); TEST_IPV6_FAIL(ud, &in6addr_peer, &in6addr_my, 1234, 61400); TEST_IPV6_FAIL(ud, &in6addr_peer, &in6addr_my, 1234, 61400); UNREGISTER(ud); ud = REGISTER(AF_INET6, NULL, &any_addr6, 1234, 4242); TEST_IPV6_OK(ud, &in6addr_peer, &in6addr_my, 1234, 4242); TEST_IPV6_OK(ud, &in6addr_peer, &in6addr_my, 1234, 4242); TEST_IPV6_LONG_OK(ud, &in6addr_peer, &in6addr_my, 1234, 4242); TEST_IPV6_LONG_OK(ud, &in6addr_peer, &in6addr_my, 1234, 4242); TEST_IPV6_FAIL(ud, &in6addr_peer, &in6addr_my, 1234, 61400); TEST_IPV6_FAIL(ud, &in6addr_peer, &in6addr_my, 1234, 61400); UNREGISTER(ud); ud = REGISTER(AF_INET6, &peer_addr6, &my_addr6, 1234, 4242); TEST_IPV6_OK(ud, &in6addr_peer, &in6addr_my, 1234, 4242); TEST_IPV6_FAIL(ud, &in6addr_peer, &in6addr_my, 1234, 4243); ud = REGISTER(AF_INET, &peer_addr4, &my_addr4, 1234, 4242); TEST_IPV4_OK(ud, &in4addr_peer, &in4addr_my, 1234, 4242); TEST_IPV4_FAIL(ud, &in4addr_peer, &in4addr_my, 1234, 4243); ud = REGISTER(AF_UNSPEC, NULL, NULL, 1234, 42423); TEST_IPV4_OK(ud, &in4addr_peer, &in4addr_my, 1234, 42423); TEST_IPV6_OK(ud, &in6addr_peer, &in6addr_my, 1234, 42423); ud = REGISTER(AF_UNSPEC, NULL, NULL, 1234, 0); TEST_IPV4_OK(ud, &in4addr_peer, &in4addr_my, 1234, 42422); TEST_IPV6_OK(ud, &in6addr_peer, &in6addr_my, 1234, 42422); TEST_IPV4_OK(ud, &in4addr_peer, &in4addr_my, 1234, 42422); TEST_IPV6_OK(ud, &in6addr_peer, &in6addr_my, 1234, 42422); TEST_IPV4_FAIL(ud, &in4addr_peer, &in4addr_my, 12345, 42421); TEST_IPV6_FAIL(ud, &in6addr_peer, &in6addr_my, 12345, 42421); ud = REGISTER(AF_UNSPEC, NULL, NULL, 0, 0); TEST_IPV4_OK(ud, &in4addr_peer, &in4addr_my, 12345, 42421); TEST_IPV6_OK(ud, &in6addr_peer, &in6addr_my, 12345, 42421); TEST_IPV6_LONG_OK(ud, &in6addr_peer, &in6addr_my, 12345, 42421); /* Remote addr same as local addr, these two will never match */ REGISTER(AF_INET6, &my_addr6, NULL, 1234, 4242); REGISTER(AF_INET, &my_addr4, NULL, 1234, 4242); /* IPv4 remote addr and IPv6 remote addr, impossible combination */ REGISTER_FAIL(&my_addr4, &my_addr6, 1234, 4242); /**TESTPOINT: Check if tests passed*/ zassert_false(fail, "Tests failed"); i--; while (i) { ret = net_udp_unregister(handlers[i]); if (ret < 0 && ret != -ENOENT) { printk("Cannot unregister udp %d\n", i); zassert_true(0, "exiting"); } i--; } zassert_true((net_udp_unregister(NULL) < 0), "Unregister udp failed"); zassert_false(test_failed, "udp tests failed"); }
/* * Parse DHCPv4 options and retrieve relavant information * as per RFC 2132. */ static enum net_verdict parse_options(struct net_if *iface, struct net_buf *buf, uint16_t offset, uint8_t *msg_type) { struct net_buf *frag; uint8_t cookie[4]; uint8_t length; uint8_t type; uint16_t pos; bool end = false; frag = net_nbuf_read(buf, offset, &pos, sizeof(magic_cookie), (uint8_t *)cookie); if (!frag || memcmp(magic_cookie, cookie, sizeof(magic_cookie))) { NET_DBG("Incorrect magic cookie"); return NET_DROP; } while (frag) { frag = net_nbuf_read_u8(frag, pos, &pos, &type); if (type == DHCPV4_OPTIONS_END) { NET_DBG("options_end"); end = true; return NET_OK; } frag = net_nbuf_read_u8(frag, pos, &pos, &length); if (!frag) { NET_ERR("option parsing, bad length"); return NET_DROP; } switch (type) { case DHCPV4_OPTIONS_SUBNET_MASK: { struct in_addr netmask; if (length != 4) { NET_ERR("options_subnet_mask, bad length"); return NET_DROP; } frag = net_nbuf_read(frag, pos, &pos, length, netmask.s4_addr); if (!frag && pos) { NET_ERR("options_subnet_mask, short packet"); return NET_DROP; } net_if_ipv4_set_netmask(iface, &netmask); NET_DBG("options_subnet_mask %s", net_sprint_ipv4_addr(&netmask)); break; } case DHCPV4_OPTIONS_ROUTER: { struct in_addr router; /* Router option may present 1 or more * addresses for routers on the clients * subnet. Routers should be listed in order * of preference. Hence we choose the first * and skip the rest. */ if (length % 4 != 0 || length < 4) { NET_ERR("options_router, bad length"); return NET_DROP; } frag = net_nbuf_read(frag, pos, &pos, 4, router.s4_addr); frag = net_nbuf_skip(frag, pos, &pos, length - 4); if (!frag && pos) { NET_ERR("options_router, short packet"); return NET_DROP; } NET_DBG("options_router: %s", net_sprint_ipv4_addr(&router)); net_if_ipv4_set_gw(iface, &router); break; } case DHCPV4_OPTIONS_LEASE_TIME: if (length != 4) { NET_ERR("options_lease_time, bad length"); return NET_DROP; } frag = net_nbuf_read_be32(frag, pos, &pos, &iface->dhcpv4.lease_time); NET_DBG("options_lease_time: %u", iface->dhcpv4.lease_time); if (!iface->dhcpv4.lease_time) { return NET_DROP; } break; case DHCPV4_OPTIONS_RENEWAL: if (length != 4) { NET_DBG("options_renewal, bad length"); return NET_DROP; } frag = net_nbuf_read_be32(frag, pos, &pos, &iface->dhcpv4.renewal_time); NET_DBG("options_renewal: %u", iface->dhcpv4.renewal_time); if (!iface->dhcpv4.renewal_time) { return NET_DROP; } break; case DHCPV4_OPTIONS_SERVER_ID: if (length != 4) { NET_DBG("options_server_id, bad length"); return NET_DROP; } frag = net_nbuf_read(frag, pos, &pos, length, iface->dhcpv4.server_id.s4_addr); NET_DBG("options_server_id: %s", net_sprint_ipv4_addr(&iface->dhcpv4.server_id)); break; case DHCPV4_OPTIONS_MSG_TYPE: if (length != 1) { NET_DBG("options_msg_type, bad length"); return NET_DROP; } frag = net_nbuf_read_u8(frag, pos, &pos, msg_type); break; default: NET_DBG("option unknown: %d", type); frag = net_nbuf_skip(frag, pos, &pos, length); break; } if (!frag && pos) { return NET_DROP; } } if (!end) { return NET_DROP; } return NET_OK; }
enum net_verdict net_ipv4_process_pkt(struct net_pkt *pkt) { struct net_ipv4_hdr *hdr = NET_IPV4_HDR(pkt); int real_len = net_pkt_get_len(pkt); int pkt_len = (hdr->len[0] << 8) + hdr->len[1]; enum net_verdict verdict = NET_DROP; if (real_len != pkt_len) { NET_DBG("IPv4 packet size %d pkt len %d", pkt_len, real_len); goto drop; } #if defined(CONFIG_NET_DEBUG_IPV4) do { char out[sizeof("xxx.xxx.xxx.xxx")]; snprintk(out, sizeof(out), "%s", net_sprint_ipv4_addr(&hdr->dst)); NET_DBG("IPv4 packet received from %s to %s", net_sprint_ipv4_addr(&hdr->src), out); } while (0); #endif /* CONFIG_NET_DEBUG_IPV4 */ net_pkt_set_ip_hdr_len(pkt, sizeof(struct net_ipv4_hdr)); if (!net_is_my_ipv4_addr(&hdr->dst)) { #if defined(CONFIG_NET_DHCPV4) if (hdr->proto == IPPROTO_UDP && net_ipv4_addr_cmp(&hdr->dst, net_ipv4_broadcast_address())) { verdict = net_conn_input(IPPROTO_UDP, pkt); if (verdict != NET_DROP) { return verdict; } } #endif NET_DBG("IPv4 packet in pkt %p not for me", pkt); goto drop; } switch (hdr->proto) { case IPPROTO_ICMP: verdict = process_icmpv4_pkt(pkt, hdr); break; case IPPROTO_UDP: verdict = net_conn_input(IPPROTO_UDP, pkt); break; case IPPROTO_TCP: verdict = net_conn_input(IPPROTO_TCP, pkt); break; } if (verdict != NET_DROP) { return verdict; } drop: net_stats_update_ipv4_drop(); return NET_DROP; }