static inline enum net_verdict process_data(struct net_pkt *pkt, bool is_loopback) { int ret; bool locally_routed = false; #if defined(CONFIG_NET_IPV6_FRAGMENT) /* If the packet is routed back to us when we have reassembled * an IPv6 packet, then do not pass it to L2 as the packet does * not have link layer headers in it. */ if (net_pkt_ipv6_fragment_start(pkt)) { locally_routed = true; } #endif /* If there is no data, then drop the packet. */ if (!pkt->frags) { NET_DBG("Corrupted packet (frags %p)", pkt->frags); net_stats_update_processing_error(); return NET_DROP; } if (!is_loopback && !locally_routed) { ret = net_if_recv_data(net_pkt_iface(pkt), pkt); if (ret != NET_CONTINUE) { if (ret == NET_DROP) { NET_DBG("Packet %p discarded by L2", pkt); net_stats_update_processing_error(); } return ret; } } /* IP version and header length. */ switch (NET_IPV6_HDR(pkt)->vtc & 0xf0) { #if defined(CONFIG_NET_IPV6) case 0x60: net_stats_update_ipv6_recv(); net_pkt_set_family(pkt, PF_INET6); return net_ipv6_process_pkt(pkt); #endif #if defined(CONFIG_NET_IPV4) case 0x40: net_stats_update_ipv4_recv(); net_pkt_set_family(pkt, PF_INET); return net_ipv4_process_pkt(pkt); #endif } NET_DBG("Unknown IP family packet (0x%x)", NET_IPV6_HDR(pkt)->vtc & 0xf0); net_stats_update_ip_errors_protoerr(); net_stats_update_ip_errors_vhlerr(); return NET_DROP; }
static int loopback_send(struct net_if *iface, struct net_pkt *pkt) { struct net_pkt *cloned; int res; if (!pkt->frags) { SYS_LOG_ERR("No data to send"); return -ENODATA; } /* We need to swap the IP addresses because otherwise * the packet will be dropped. */ if (net_pkt_family(pkt) == AF_INET6) { struct in6_addr addr; 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); } else { struct in_addr addr; 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); } /* We should simulate normal driver meaning that if the packet is * properly sent (which is always in this driver), then the packet * must be dropped. This is very much needed for TCP packets where * the packet is reference counted in various stages of sending. */ cloned = net_pkt_clone(pkt, K_MSEC(100)); if (!cloned) { res = -ENOMEM; goto out; } res = net_recv_data(iface, cloned); if (res < 0) { SYS_LOG_ERR("Data receive failed."); goto out; } net_pkt_unref(pkt); out: /* Let the receiving thread run now */ k_yield(); return res; }
static void setup_ipv6_udp(struct net_pkt *pkt, struct in6_addr *remote_addr, struct in6_addr *local_addr, u16_t remote_port, u16_t local_port) { NET_IPV6_HDR(pkt)->vtc = 0x60; NET_IPV6_HDR(pkt)->tcflow = 0; NET_IPV6_HDR(pkt)->flow = 0; NET_IPV6_HDR(pkt)->len[0] = 0; NET_IPV6_HDR(pkt)->len[1] = NET_UDPH_LEN + strlen(payload); NET_IPV6_HDR(pkt)->nexthdr = IPPROTO_UDP; NET_IPV6_HDR(pkt)->hop_limit = 255; net_ipaddr_copy(&NET_IPV6_HDR(pkt)->src, remote_addr); net_ipaddr_copy(&NET_IPV6_HDR(pkt)->dst, local_addr); net_pkt_set_ip_hdr_len(pkt, sizeof(struct net_ipv6_hdr)); net_pkt_set_ipv6_ext_len(pkt, 0); net_buf_add(pkt->frags, net_pkt_ip_hdr_len(pkt) + sizeof(struct net_udp_hdr)); NET_UDP_HDR(pkt)->src_port = htons(remote_port); NET_UDP_HDR(pkt)->dst_port = htons(local_port); net_buf_add_mem(pkt->frags, payload, strlen(payload)); }
static inline void set_dst_addr(sa_family_t family, struct net_pkt *pkt, struct sockaddr *dst_addr) { net_ipaddr_copy(&net_sin6(dst_addr)->sin6_addr, &NET_IPV6_HDR(pkt)->src); net_sin6(dst_addr)->sin6_family = AF_INET6; net_sin6(dst_addr)->sin6_port = NET_UDP_HDR(pkt)->src_port; }
u16_t net_calc_chksum(struct net_pkt *pkt, u8_t proto) { u16_t upper_layer_len; u16_t sum; switch (net_pkt_family(pkt)) { #if defined(CONFIG_NET_IPV4) case AF_INET: upper_layer_len = (NET_IPV4_HDR(pkt)->len[0] << 8) + NET_IPV4_HDR(pkt)->len[1] - net_pkt_ipv6_ext_len(pkt) - net_pkt_ip_hdr_len(pkt); if (proto == IPPROTO_ICMP) { return htons(calc_chksum(0, net_pkt_ip_data(pkt) + net_pkt_ip_hdr_len(pkt), upper_layer_len)); } else { sum = calc_chksum(upper_layer_len + proto, (u8_t *)&NET_IPV4_HDR(pkt)->src, 2 * sizeof(struct in_addr)); } break; #endif #if defined(CONFIG_NET_IPV6) case AF_INET6: upper_layer_len = (NET_IPV6_HDR(pkt)->len[0] << 8) + NET_IPV6_HDR(pkt)->len[1] - net_pkt_ipv6_ext_len(pkt); sum = calc_chksum(upper_layer_len + proto, (u8_t *)&NET_IPV6_HDR(pkt)->src, 2 * sizeof(struct in6_addr)); break; #endif default: NET_DBG("Unknown protocol family %d", net_pkt_family(pkt)); return 0; } sum = calc_chksum_pkt(sum, pkt, upper_layer_len); sum = (sum == 0) ? 0xffff : htons(sum); return sum; }
static inline void set_dst_addr(sa_family_t family, struct net_pkt *pkt, struct sockaddr *dst_addr) { #if defined(CONFIG_NET_IPV6) if (family == AF_INET6) { net_ipaddr_copy(&net_sin6(dst_addr)->sin6_addr, &NET_IPV6_HDR(pkt)->src); net_sin6(dst_addr)->sin6_family = AF_INET6; net_sin6(dst_addr)->sin6_port = NET_UDP_HDR(pkt)->src_port; } #endif /* CONFIG_NET_IPV6) */ #if defined(CONFIG_NET_IPV4) if (family == AF_INET) { net_ipaddr_copy(&net_sin(dst_addr)->sin_addr, &NET_IPV4_HDR(pkt)->src); net_sin(dst_addr)->sin_family = AF_INET; net_sin(dst_addr)->sin_port = NET_UDP_HDR(pkt)->src_port; } #endif /* CONFIG_NET_IPV6) */ }
/* 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; }
static void set_client_address(struct sockaddr *addr, struct net_pkt *rx_pkt) { net_ipaddr_copy(&net_sin6(addr)->sin6_addr, &NET_IPV6_HDR(rx_pkt)->src); net_sin6(addr)->sin6_family = AF_INET6; net_sin6(addr)->sin6_port = NET_UDP_HDR(rx_pkt)->src_port; }