void udp_send(struct net_driver_s *dev, struct udp_conn_s *conn) { FAR struct udp_iphdr_s *pudpbuf = UDPBUF; if (dev->d_sndlen > 0) { /* The total length to send is the size of the application data plus * the IP and UDP headers (and, eventually, the Ethernet header) */ dev->d_len = dev->d_sndlen + IPUDP_HDRLEN; /* Initialize the IP header. Note that for IPv6, the IP length field * does not include the IPv6 IP header length. */ #ifdef CONFIG_NET_IPv6 pudpbuf->vtc = 0x60; pudpbuf->tcf = 0x00; pudpbuf->flow = 0x00; pudpbuf->len[0] = (dev->d_sndlen >> 8); pudpbuf->len[1] = (dev->d_sndlen & 0xff); pudpbuf->nexthdr = IP_PROTO_UDP; pudpbuf->hoplimit = conn->ttl; net_ipaddr_copy(pudpbuf->srcipaddr, &dev->d_ipaddr); net_ipaddr_copy(pudpbuf->destipaddr, &conn->ripaddr); #else /* CONFIG_NET_IPv6 */ pudpbuf->vhl = 0x45; pudpbuf->tos = 0; pudpbuf->len[0] = (dev->d_len >> 8); pudpbuf->len[1] = (dev->d_len & 0xff); ++g_ipid; pudpbuf->ipid[0] = g_ipid >> 8; pudpbuf->ipid[1] = g_ipid & 0xff; pudpbuf->ipoffset[0] = 0; pudpbuf->ipoffset[1] = 0; pudpbuf->ttl = conn->ttl; pudpbuf->proto = IP_PROTO_UDP; net_ipaddr_hdrcopy(pudpbuf->srcipaddr, &dev->d_ipaddr); net_ipaddr_hdrcopy(pudpbuf->destipaddr, &conn->ripaddr); /* Calculate IP checksum. */ pudpbuf->ipchksum = 0; pudpbuf->ipchksum = ~(ip_chksum(dev)); #endif /* CONFIG_NET_IPv6 */ /* Initialize the UDP header */ pudpbuf->srcport = conn->lport; pudpbuf->destport = conn->rport; pudpbuf->udplen = HTONS(dev->d_sndlen + UDP_HDRLEN); #ifdef CONFIG_NET_UDP_CHECKSUMS /* Calculate UDP checksum. */ pudpbuf->udpchksum = 0; pudpbuf->udpchksum = ~(udp_chksum(dev)); if (pudpbuf->udpchksum == 0) { pudpbuf->udpchksum = 0xffff; } #else pudpbuf->udpchksum = 0; #endif nllvdbg("Outgoing UDP packet length: %d (%d)\n", dev->d_len, (pudpbuf->len[0] << 8) | pudpbuf->len[1]); #ifdef CONFIG_NET_STATISTICS g_netstats.udp.sent++; g_netstats.ip.sent++; #endif }
void icmp_input(FAR struct net_driver_s *dev) { FAR struct icmp_iphdr_s *picmp = ICMPBUF; #ifdef CONFIG_NET_STATISTICS g_netstats.icmp.recv++; #endif #ifndef CONFIG_NET_IPv6 /* ICMPv4 processing code follows. */ /* ICMP echo (i.e., ping) processing. This is simple, we only change the * ICMP type from ECHO to ECHO_REPLY and adjust the ICMP checksum before * we return the packet. */ if (picmp->type == ICMP_ECHO_REQUEST) { /* If we are configured to use ping IP address assignment, we use * the destination IP address of this ping packet and assign it to * ourself. */ #ifdef CONFIG_NET_PINGADDRCONF if (dev->d_ipaddr == 0) { dev->d_ipaddr = picmp->destipaddr; } #endif /* Change the ICMP type */ picmp->type = ICMP_ECHO_REPLY; /* Swap IP addresses. */ net_ipaddr_hdrcopy(picmp->destipaddr, picmp->srcipaddr); net_ipaddr_hdrcopy(picmp->srcipaddr, &dev->d_ipaddr); /* Recalculate the ICMP checksum */ #if 0 /* The slow way... sum over the ICMP message */ picmp->icmpchksum = 0; picmp->icmpchksum = ~icmp_chksum(dev, (((uint16_t)picmp->len[0] << 8) | (uint16_t)picmp->len[1]) - IP_HDRLEN); if (picmp->icmpchksum == 0) { picmp->icmpchksum = 0xffff; } #else /* The quick way -- Since only the type has changed, just adjust the * checksum for the change of type */ if (picmp->icmpchksum >= HTONS(0xffff - (ICMP_ECHO_REQUEST << 8))) { picmp->icmpchksum += HTONS(ICMP_ECHO_REQUEST << 8) + 1; } else { picmp->icmpchksum += HTONS(ICMP_ECHO_REQUEST << 8); } #endif 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.ip.sent++; #endif } /* If an ICMP echo reply is received then there should also be * a thread waiting to received the echo response. */ #ifdef CONFIG_NET_ICMP_PING else if (picmp->type == ICMP_ECHO_REPLY && g_echocallback) { (void)devif_callback_execute(dev, picmp, ICMP_ECHOREPLY, g_echocallback); } #endif /* Otherwise the ICMP input was not processed */ else { nlldbg("Unknown ICMP cmd: %d\n", picmp->type); goto typeerr; } return; typeerr: #ifdef CONFIG_NET_STATISTICS g_netstats.icmp.typeerr++; g_netstats.icmp.drop++; #endif dev->d_len = 0; #else /* !CONFIG_NET_IPv6 */ /* If we get a neighbor solicitation for our address we should send * a neighbor advertisement message back. */ if (picmp->type == ICMP6_NEIGHBOR_SOLICITATION) { if (net_ipaddr_cmp(picmp->icmp6data, dev->d_ipaddr)) { if (picmp->options[0] == ICMP6_OPTION_SOURCE_LINK_ADDRESS) { /* Save the sender's address in our neighbor list. */ net_neighbor_add(picmp->srcipaddr, &(picmp->options[2])); } /* We should now send a neighbor advertisement back to where the * neighbor solicitation came from. */ picmp->type = ICMP6_NEIGHBOR_ADVERTISEMENT; picmp->flags = ICMP6_FLAG_S; /* Solicited flag. */ picmp->reserved1 = picmp->reserved2 = picmp->reserved3 = 0; net_ipaddr_hdrcopy(picmp->destipaddr, picmp->srcipaddr); net_ipaddr_hdrcopy(picmp->srcipaddr, &dev->d_ipaddr); picmp->options[0] = ICMP6_OPTION_TARGET_LINK_ADDRESS; picmp->options[1] = 1; /* Options length, 1 = 8 bytes. */ memcpy(&(picmp->options[2]), &dev->d_mac, IFHWADDRLEN); picmp->icmpchksum = 0; picmp->icmpchksum = ~icmp_6chksum(dev); } else { goto drop; } } else if (picmp->type == ICMP6_ECHO_REQUEST) { /* ICMP echo (i.e., ping) processing. This is simple, we only * change the ICMP type from ECHO to ECHO_REPLY and update the * ICMP checksum before we return the packet. */ picmp->type = ICMP6_ECHO_REPLY; net_ipaddr_hdrcopy(picmp->destipaddr, picmp->srcipaddr); net_ipaddr_hdrcopy(picmp->srcipaddr, &dev->d_ipaddr); picmp->icmpchksum = 0; picmp->icmpchksum = ~icmp_6chksum(dev); } /* If an ICMP echo reply is received then there should also be * a thread waiting to received the echo response. */ #ifdef CONFIG_NET_ICMP_PING else if (picmp->type == ICMP6_ECHO_REPLY && g_echocallback) { uint16_t flags = ICMP_ECHOREPLY; if (g_echocallback) { /* Dispatch the ECHO reply to the waiting thread */ flags = devif_callback_execute(dev, picmp, flags, g_echocallback); } /* If the ECHO reply was not handled, then drop the packet */ if (flags == ICMP_ECHOREPLY) { /* The ECHO reply was not handled */ goto drop; } } #endif else { nlldbg("Unknown ICMP6 cmd: %d\n", picmp->type); goto typeerr; } nllvdbg("Outgoing ICMP6 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.ip.sent++; #endif return; typeerr: #ifdef CONFIG_NET_STATISTICS g_netstats.icmp.typeerr++; #endif drop: #ifdef CONFIG_NET_STATISTICS g_netstats.icmp.drop++; #endif dev->d_len = 0; #endif /* !CONFIG_NET_IPv6 */ }
void icmp_send(FAR struct net_driver_s *dev, FAR net_ipaddr_t *destaddr) { FAR struct icmp_iphdr_s *picmp = ICMPBUF; if (dev->d_sndlen > 0) { /* 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. Note that for IPv6, the IP length field * does not include the IPv6 IP header length. */ #ifdef CONFIG_NET_IPv6 picmp->vtc = 0x60; picmp->tcf = 0x00; picmp->flow = 0x00; picmp->len[0] = (dev->d_sndlen >> 8); picmp->len[1] = (dev->d_sndlen & 0xff); picmp->nexthdr = IP_PROTO_ICMP; picmp->hoplimit = IP_TTL; net_ipaddr_copy(picmp->srcipaddr, &dev->d_ipaddr); net_ipaddr_copy(picmp->destipaddr, destaddr); #else /* CONFIG_NET_IPv6 */ 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] = TCPFLAG_DONTFRAG >> 8; picmp->ipoffset[1] = TCPFLAG_DONTFRAG & 0xff; picmp->ttl = IP_TTL; picmp->proto = IP_PROTO_ICMP; net_ipaddr_hdrcopy(picmp->srcipaddr, &dev->d_ipaddr); net_ipaddr_hdrcopy(picmp->destipaddr, destaddr); /* Calculate IP checksum. */ picmp->ipchksum = 0; picmp->ipchksum = ~(ip_chksum(dev)); #endif /* CONFIG_NET_IPv6 */ /* 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.ip.sent++; #endif }
void arp_arpin(FAR struct net_driver_s *dev) { FAR struct arp_hdr_s *parp = ARPBUF; in_addr_t ipaddr; if (dev->d_len < (sizeof(struct arp_hdr_s) + NET_LL_HDRLEN)) { nlldbg("Too small\n"); dev->d_len = 0; return; } dev->d_len = 0; ipaddr = net_ip4addr_conv32(parp->ah_dipaddr); switch(parp->ah_opcode) { case HTONS(ARP_REQUEST): nllvdbg("ARP request for IP %04lx\n", (long)ipaddr); /* ARP request. If it asked for our address, we send out a reply. */ if (net_ipaddr_cmp(ipaddr, dev->d_ipaddr)) { struct eth_hdr_s *peth = ETHBUF; /* First, we register the one who made the request in our ARP * table, since it is likely that we will do more communication * with this host in the future. */ arp_update(parp->ah_sipaddr, parp->ah_shwaddr); parp->ah_opcode = HTONS(ARP_REPLY); memcpy(parp->ah_dhwaddr, parp->ah_shwaddr, ETHER_ADDR_LEN); memcpy(parp->ah_shwaddr, dev->d_mac.ether_addr_octet, ETHER_ADDR_LEN); memcpy(peth->src, dev->d_mac.ether_addr_octet, ETHER_ADDR_LEN); memcpy(peth->dest, parp->ah_dhwaddr, ETHER_ADDR_LEN); parp->ah_dipaddr[0] = parp->ah_sipaddr[0]; parp->ah_dipaddr[1] = parp->ah_sipaddr[1]; net_ipaddr_hdrcopy(parp->ah_sipaddr, &dev->d_ipaddr); arp_dump(parp); peth->type = HTONS(ETHTYPE_ARP); dev->d_len = sizeof(struct arp_hdr_s) + NET_LL_HDRLEN; } break; case HTONS(ARP_REPLY): nllvdbg("ARP reply for IP %04lx\n", (long)ipaddr); /* ARP reply. We insert or update the ARP table if it was meant * for us. */ if (net_ipaddr_cmp(ipaddr, dev->d_ipaddr)) { /* Yes... Insert the address mapping in the ARP table */ arp_update(parp->ah_sipaddr, parp->ah_shwaddr); /* Then notify any logic waiting for the ARP result */ arp_notify(net_ip4addr_conv32(parp->ah_sipaddr)); } break; } }