void icmp_send(FAR struct net_driver_s *dev, FAR in_addr_t *destaddr) { FAR struct icmp_iphdr_s *picmp = ICMPBUF; if (dev->d_sndlen > 0) { IFF_SET_IPv4(dev->d_flags); /* The total length to send is the size of the application data plus * the IP and ICMP headers (and, eventually, the Ethernet header) */ dev->d_len = dev->d_sndlen + IPICMP_HDRLEN; /* The total size of the data (for ICMP checksum calculation) includes * the size of the ICMP header */ dev->d_sndlen += ICMP_HDRLEN; /* Initialize the IP header. */ picmp->vhl = 0x45; picmp->tos = 0; picmp->len[0] = (dev->d_len >> 8); picmp->len[1] = (dev->d_len & 0xff); ++g_ipid; picmp->ipid[0] = g_ipid >> 8; picmp->ipid[1] = g_ipid & 0xff; picmp->ipoffset[0] = IP_FLAG_DONTFRAG >> 8; picmp->ipoffset[1] = IP_FLAG_DONTFRAG & 0xff; picmp->ttl = IP_TTL; picmp->proto = IP_PROTO_ICMP; net_ipv4addr_hdrcopy(picmp->srcipaddr, &dev->d_ipaddr); net_ipv4addr_hdrcopy(picmp->destipaddr, destaddr); /* Calculate IP checksum. */ picmp->ipchksum = 0; picmp->ipchksum = ~(ipv4_chksum(dev)); /* Calculate the ICMP checksum. */ picmp->icmpchksum = 0; picmp->icmpchksum = ~(icmp_chksum(dev, dev->d_sndlen)); if (picmp->icmpchksum == 0) { picmp->icmpchksum = 0xffff; } nllvdbg("Outgoing ICMP packet length: %d (%d)\n", dev->d_len, (picmp->len[0] << 8) | picmp->len[1]); #ifdef CONFIG_NET_STATISTICS g_netstats.icmp.sent++; g_netstats.ipv4.sent++; #endif }
void udp_ipv4_select(FAR struct net_driver_s *dev) { /* Clear a bit in the d_flags to distinguish this from an IPv6 packet */ IFF_SET_IPv4(dev->d_flags); /* Set the offset to the beginning of the UDP data payload */ dev->d_appdata = &dev->d_buf[IPv4UDP_HDRLEN + NET_LL_HDRLEN(dev)]; }
int ipv4_input(FAR struct net_driver_s *dev) { FAR struct ipv4_hdr_s *pbuf = BUF; uint16_t iplen; /* This is where the input processing starts. */ #ifdef CONFIG_NET_STATISTICS g_netstats.ipv4.recv++; #endif /* Start of IP input header processing code. */ /* Check validity of the IP header. */ if (pbuf->vhl != 0x45) { /* IP version and header length. */ #ifdef CONFIG_NET_STATISTICS g_netstats.ipv4.drop++; g_netstats.ipv4.vhlerr++; #endif nlldbg("Invalid IP version or header length: %02x\n", pbuf->vhl); goto drop; } /* Check the size of the packet. If the size reported to us in d_len is * smaller the size reported in the IP header, we assume that the packet * has been corrupted in transit. If the size of d_len is larger than the * size reported in the IP packet header, the packet has been padded and * we set d_len to the correct value. */ iplen = (pbuf->len[0] << 8) + pbuf->len[1]; if (iplen <= dev->d_len) { dev->d_len = iplen; } else { nlldbg("IP packet shorter than length in IP header\n"); goto drop; } /* Check the fragment flag. */ if ((pbuf->ipoffset[0] & 0x3f) != 0 || pbuf->ipoffset[1] != 0) { #if defined(CONFIG_NET_TCP_REASSEMBLY) dev->d_len = devif_reassembly(); if (dev->d_len == 0) { goto drop; } #else /* CONFIG_NET_TCP_REASSEMBLY */ #ifdef CONFIG_NET_STATISTICS g_netstats.ipv4.drop++; g_netstats.ipv4.fragerr++; #endif nlldbg("IP fragment dropped\n"); goto drop; #endif /* CONFIG_NET_TCP_REASSEMBLY */ } /* If IP broadcast support is configured, we check for a broadcast * UDP packet, which may be destined to us (even if there is no IP * address yet assigned to the device as is the case when we are * negotiating over DHCP for an address). */ #if defined(CONFIG_NET_BROADCAST) && defined(CONFIG_NET_UDP_STACK) if (pbuf->proto == IP_PROTO_UDP && net_ipv4addr_cmp(net_ip4addr_conv32(pbuf->destipaddr), g_ipv4_alloneaddr)) { return udp_ipv4_input(dev); } /* In most other cases, the device must be assigned a non-zero IP * address. Another exception is when CONFIG_NET_PINGADDRCONF is * enabled... */ else #endif #ifdef CONFIG_NET_ICMP if (net_ipv4addr_cmp(dev->d_ipaddr, g_ipv4_allzeroaddr)) { /* If we are configured to use ping IP address configuration and * hasn't been assigned an IP address yet, we accept all ICMP * packets. */ #ifdef CONFIG_NET_PINGADDRCONF if (pbuf->proto == IP_PROTO_ICMP) { nlldbg("Possible ping config packet received\n"); icmp_input(dev); goto drop; } else #endif { nlldbg("No IP address assigned\n"); goto drop; } } /* Check if the packet is destined for out IP address */ else #endif { /* Check if the packet is destined for our IP address. */ if (!net_ipv4addr_cmp(net_ip4addr_conv32(pbuf->destipaddr), dev->d_ipaddr)) { #ifdef CONFIG_NET_IGMP in_addr_t destip = net_ip4addr_conv32(pbuf->destipaddr); if (igmp_grpfind(dev, &destip) == NULL) #endif { #ifdef CONFIG_NET_STATISTICS g_netstats.ipv4.drop++; #endif goto drop; } } } if (ipv4_chksum(dev) != 0xffff) { /* Compute and check the IP header checksum. */ #ifdef CONFIG_NET_STATISTICS g_netstats.ipv4.drop++; g_netstats.ipv4.chkerr++; #endif nlldbg("Bad IP checksum\n"); goto drop; } /* Make sure that all packet processing logic knows that there is an IPv4 * packet in the device buffer. */ IFF_SET_IPv4(dev->d_flags); /* Now process the incoming packet according to the protocol. */ switch (pbuf->proto) { #ifdef CONFIG_NET_TCP_STACK case IP_PROTO_TCP: /* TCP input */ tcp_ipv4_input(dev); break; #endif #ifdef CONFIG_NET_UDP_STACK case IP_PROTO_UDP: /* UDP input */ udp_ipv4_input(dev); break; #endif /* Check for ICMP input */ #ifdef CONFIG_NET_ICMP case IP_PROTO_ICMP: /* ICMP input */ icmp_input(dev); break; #endif /* Check for IGMP input */ #ifdef CONFIG_NET_IGMP case IP_PROTO_IGMP: /* IGMP input */ igmp_input(dev); break; #endif default: /* Unrecognized/unsupported protocol */ #ifdef CONFIG_NET_STATISTICS g_netstats.ipv4.drop++; g_netstats.ipv4.protoerr++; #endif nlldbg("Unrecognized IP protocol\n"); goto drop; } /* Return and let the caller do any pending transmission. */ return OK; /* Drop the packet. NOTE that OK is returned meaning that the * packet has been processed (although processed unsuccessfully). */ drop: dev->d_len = 0; return OK; }