static bool peer_addr_exist(struct sockaddr *peer_addr) { bool ret = false; int i; /* look for duplicate peer_addr */ for (i = 0; i < client_count; i++) { #if defined(CONFIG_NET_IPV6) if (peer_addr->family == AF_INET6 && net_ipv6_addr_cmp( &net_sin6(&clients[i].bs_server)->sin6_addr, &net_sin6(peer_addr)->sin6_addr)) { ret = true; break; } if (peer_addr->family == AF_INET6 && net_ipv6_addr_cmp( &net_sin6(&clients[i].reg_server)->sin6_addr, &net_sin6(peer_addr)->sin6_addr)) { ret = true; break; } #endif #if defined(CONFIG_NET_IPV4) if (peer_addr->family == AF_INET && net_ipv4_addr_cmp( &net_sin(&clients[i].bs_server)->sin_addr, &net_sin(peer_addr)->sin_addr)) { ret = true; break; } if (peer_addr->family == AF_INET && net_ipv4_addr_cmp( &net_sin(&clients[i].reg_server)->sin_addr, &net_sin(peer_addr)->sin_addr)) { ret = true; break; } #endif } return ret; }
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; }
/* Check if the IPv{4|6} addresses are proper. As this can be expensive, * make this optional. */ static inline int check_ip_addr(struct net_pkt *pkt) { #if defined(CONFIG_NET_IPV6) if (net_pkt_family(pkt) == AF_INET6) { if (net_ipv6_addr_cmp(&NET_IPV6_HDR(pkt)->dst, net_ipv6_unspecified_address())) { NET_DBG("IPv6 dst address missing"); return -EADDRNOTAVAIL; } /* If the destination address is our own, then route it * back to us. */ if (net_is_ipv6_addr_loopback(&NET_IPV6_HDR(pkt)->dst) || net_is_my_ipv6_addr(&NET_IPV6_HDR(pkt)->dst)) { struct in6_addr addr; /* Swap the addresses so that in receiving side * the packet is accepted. */ net_ipaddr_copy(&addr, &NET_IPV6_HDR(pkt)->src); net_ipaddr_copy(&NET_IPV6_HDR(pkt)->src, &NET_IPV6_HDR(pkt)->dst); net_ipaddr_copy(&NET_IPV6_HDR(pkt)->dst, &addr); return 1; } /* The source check must be done after the destination check * as having src ::1 is perfectly ok if dst is ::1 too. */ if (net_is_ipv6_addr_loopback(&NET_IPV6_HDR(pkt)->src)) { NET_DBG("IPv6 loopback src address"); return -EADDRNOTAVAIL; } } else #endif /* CONFIG_NET_IPV6 */ #if defined(CONFIG_NET_IPV4) if (net_pkt_family(pkt) == AF_INET) { if (net_ipv4_addr_cmp(&NET_IPV4_HDR(pkt)->dst, net_ipv4_unspecified_address())) { return -EADDRNOTAVAIL; } /* If the destination address is our own, then route it * back to us. */ if (net_is_ipv4_addr_loopback(&NET_IPV4_HDR(pkt)->dst) || net_is_my_ipv4_addr(&NET_IPV4_HDR(pkt)->dst)) { struct in_addr addr; /* Swap the addresses so that in receiving side * the packet is accepted. */ net_ipaddr_copy(&addr, &NET_IPV4_HDR(pkt)->src); net_ipaddr_copy(&NET_IPV4_HDR(pkt)->src, &NET_IPV4_HDR(pkt)->dst); net_ipaddr_copy(&NET_IPV4_HDR(pkt)->dst, &addr); return 1; } /* The source check must be done after the destination check * as having src 127.0.0.0/8 is perfectly ok if dst is in * localhost subnet too. */ if (net_is_ipv4_addr_loopback(&NET_IPV4_HDR(pkt)->src)) { NET_DBG("IPv4 loopback src address"); return -EADDRNOTAVAIL; } } else #endif /* CONFIG_NET_IPV4 */ { ; } return 0; }
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; }