diff --git a/include/nuttx/net/icmp.h b/include/nuttx/net/icmp.h index 8b54e8290a..914ab1900e 100644 --- a/include/nuttx/net/icmp.h +++ b/include/nuttx/net/icmp.h @@ -118,40 +118,6 @@ struct icmp_hdr_s uint16_t seqno; /* " " "" " " " " " " " " */ }; -/* The ICMP and IPv4 headers */ - -struct icmp_iphdr_s -{ - /* IPv4 IP header */ - - uint8_t vhl; /* 8-bit Version (4) and header length (5 or 6) */ - uint8_t tos; /* 8-bit Type of service (e.g., 6=TCP) */ - uint8_t len[2]; /* 16-bit Total length */ - uint8_t ipid[2]; /* 16-bit Identification */ - uint8_t ipoffset[2]; /* 16-bit IP flags + fragment offset */ - uint8_t ttl; /* 8-bit Time to Live */ - uint8_t proto; /* 8-bit Protocol */ - uint16_t ipchksum; /* 16-bit Header checksum */ - uint16_t srcipaddr[2]; /* 32-bit Source IP address */ - uint16_t destipaddr[2]; /* 32-bit Destination IP address */ - - /* ICMP header */ - - uint8_t type; /* Defines the format of the ICMP message */ - uint8_t icode; /* Further qualifies the ICMP messsage */ - uint16_t icmpchksum; /* Checksum of ICMP header and data */ - - /* All ICMP packets have an 8-byte header and variable-sized data section. - * The first 4 bytes of the header have fixed format, while the last 4 bytes - * depend on the type/code of that ICMP packet. - */ - - /* ICMP_ECHO_REQUEST and ICMP_ECHO_REPLY data */ - - uint16_t id; /* Used to match requests with replies */ - uint16_t seqno; /* " " "" " " " " " " " " */ -}; - /* The structure holding the ICMP statistics that are gathered if * CONFIG_NET_STATISTICS is defined. */ diff --git a/include/nuttx/net/igmp.h b/include/nuttx/net/igmp.h index 4f513ffd9f..d4dabf9dd1 100644 --- a/include/nuttx/net/igmp.h +++ b/include/nuttx/net/igmp.h @@ -3,7 +3,7 @@ * The definitions in this header file are intended only for internal use * by the NuttX network stack. * - * Copyright (C) 2010, 2012, 2014 Gregory Nutt. All rights reserved. + * Copyright (C) 2010, 2012, 2014, 2019 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * The NuttX implementation of IGMP was inspired by the IGMP add-on for the @@ -72,14 +72,9 @@ #define IGMPv3_MEMBERSHIP_REPORT 0x22 /* IGMP Ver. 3 Membership Report */ #define IGMP_LEAVE_GROUP 0x17 /* Leave Group */ -/* Header sizes: - * - * IGMP_HDRLEN - Size of IGMP header in bytes - * IPIGMP_HDRLEN - Size of IP + Size of IGMP header + Size of router alert - */ +/* Size of IGMP header in bytes */ #define IGMP_HDRLEN 8 -#define IPIGMP_HDRLEN (IGMP_HDRLEN + IPv4_HDRLEN + 4) /* Time-to-Live must be one */ @@ -89,13 +84,7 @@ * Public Types ****************************************************************************/ -/* IGMPv2 packet structure as defined by RFC 2236. - * - * The Max Response Time (maxresp) specifies the time limit for the - * corresponding report. The field has a resolution of 100 miliseconds, the - * value is taken directly. This field is meaningful only in Membership Query - * (0x11); in other messages it is set to 0 and ignored by the receiver. - */ +/* Convenience [re-]definition of the IPv4 header with the router alert */ struct igmp_iphdr_s { @@ -115,7 +104,18 @@ struct igmp_iphdr_s /* Router Alert IP header option */ uint16_t ra[2]; /* RFC 2113 */ +}; +/* IGMPv2 packet structure as defined by RFC 2236. + * + * The Max Response Time (maxresp) specifies the time limit for the + * corresponding report. The field has a resolution of 100 miliseconds, the + * value is taken directly. This field is meaningful only in Membership Query + * (0x11); in other messages it is set to 0 and ignored by the receiver. + */ + +struct igmp_hdr_s +{ /* IGMPv2 header: * * 0 1 2 3 diff --git a/include/nuttx/net/ip.h b/include/nuttx/net/ip.h index 942e4d946a..0a2d39d106 100644 --- a/include/nuttx/net/ip.h +++ b/include/nuttx/net/ip.h @@ -86,6 +86,7 @@ #ifdef CONFIG_NET_IPv4 # define IPv4_HDRLEN 20 /* Size of IPv4 header (without options) */ +# define IPv4_HLMASK 0x0f /* Isolates headler length in VHL field */ #endif #ifdef CONFIG_NET_IPv6 diff --git a/net/devif/ipv4_input.c b/net/devif/ipv4_input.c index c012337d34..2a6abe22cc 100644 --- a/net/devif/ipv4_input.c +++ b/net/devif/ipv4_input.c @@ -2,7 +2,7 @@ * net/devif/ipv4_input.c * Device driver IPv4 packet receipt interface * - * Copyright (C) 2007-2009, 2013-2015, 2018 Gregory Nutt. All rights + * Copyright (C) 2007-2009, 2013-2015, 2018-2019 Gregory Nutt. All rights * reserved. * Author: Gregory Nutt * @@ -332,8 +332,8 @@ int ipv4_input(FAR struct net_driver_s *dev) { FAR struct ipv4_hdr_s *ipv4 = BUF; in_addr_t destipaddr; - uint16_t hdrlen; - uint16_t iplen; + uint16_t llhdrlen; + uint16_t totlen; /* This is where the input processing starts. */ @@ -349,7 +349,8 @@ int ipv4_input(FAR struct net_driver_s *dev) * 32-bit words in the HL nibble of the VHL. */ - if (ipv4->vhl != 0x45) + if ((ipv4->vhl & IP_VERSION_MASK) != 0x40 || + (ipv4->vhl & IPv4_HLMASK) < 5) { /* IP version and header length. */ @@ -364,26 +365,26 @@ int ipv4_input(FAR struct net_driver_s *dev) /* Get the size of the packet minus the size of link layer header */ - hdrlen = NET_LL_HDRLEN(dev); - if ((hdrlen + IPv4_HDRLEN) > dev->d_len) + llhdrlen = NET_LL_HDRLEN(dev); + if ((llhdrlen + IPv4_HDRLEN) > dev->d_len) { nwarn("WARNING: Packet shorter than IPv4 header\n"); goto drop; } - dev->d_len -= hdrlen; + dev->d_len -= llhdrlen; - /* Check the size of the packet. If the size reported to us in d_len is + /* 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 + * 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 = (ipv4->len[0] << 8) + ipv4->len[1]; - if (iplen <= dev->d_len) + totlen = (ipv4->len[0] << 8) + ipv4->len[1]; + if (totlen <= dev->d_len) { - dev->d_len = iplen; + dev->d_len = totlen; } else { diff --git a/net/icmp/icmp_input.c b/net/icmp/icmp_input.c index 50d9553026..0d2fdb96b0 100644 --- a/net/icmp/icmp_input.c +++ b/net/icmp/icmp_input.c @@ -67,10 +67,9 @@ * Pre-processor Definitions ****************************************************************************/ -#define IPv4BUF ((FAR struct ipv4_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)]) -#define IPICMPBUF ((FAR struct icmp_iphdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)]) -#define ICMPBUF ((FAR struct icmp_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev) + IPv4_HDRLEN]) -#define ICMPSIZE ((dev)->d_len - IPv4_HDRLEN) +#define IPv4BUF ((FAR struct ipv4_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)]) +#define ICMPBUF(hl) ((FAR struct icmp_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev) + (hl)]) +#define ICMPSIZE(hl) ((dev)->d_len - (hl)) /**************************************************************************** * Private Functions @@ -104,6 +103,7 @@ static uint16_t icmp_datahandler(FAR struct net_driver_s *dev, FAR struct iob_s *iob; uint16_t offset; uint16_t buflen; + uint16_t iphdrlen; uint8_t addrsize; int ret; @@ -164,11 +164,15 @@ static uint16_t icmp_datahandler(FAR struct net_driver_s *dev, offset += sizeof(struct sockaddr_in); + /* Get the IP header length (accounting for possible options). */ + + iphdrlen = (ipv4->vhl & IPv4_HLMASK) << 2; + /* Copy the new ICMP reply into the I/O buffer chain (without waiting) */ - buflen = ICMPSIZE; - ret = iob_trycopyin(iob, (FAR uint8_t *)ICMPBUF, buflen, offset, true, - IOBUSER_NET_SOCK_ICMP); + buflen = ICMPSIZE(iphdrlen); + ret = iob_trycopyin(iob, (FAR uint8_t *)ICMPBUF(iphdrlen), buflen, offset, + true, IOBUSER_NET_SOCK_ICMP); if (ret < 0) { /* On a failure, iob_copyin return a negated error value but does @@ -227,57 +231,71 @@ drop: void icmp_input(FAR struct net_driver_s *dev) { - FAR struct icmp_iphdr_s *ipicmp = IPICMPBUF; + FAR struct ipv4_hdr_s *ipv4 = IPv4BUF; + FAR struct icmp_hdr_s *icmp; + uint16_t iphdrlen; #ifdef CONFIG_NET_STATISTICS g_netstats.icmp.recv++; #endif + /* Get the IP header length (accounting for possible options). */ + + iphdrlen = (ipv4->vhl & IPv4_HLMASK) << 2; + + /* The ICMP header immediately follows the IP header */ + + icmp = ICMPBUF(iphdrlen); + /* 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 (ipicmp->type == ICMP_ECHO_REQUEST) + if (icmp->type == ICMP_ECHO_REQUEST) { /* Change the ICMP type */ - ipicmp->type = ICMP_ECHO_REPLY; + icmp->type = ICMP_ECHO_REPLY; /* Swap IP addresses. */ - net_ipv4addr_hdrcopy(ipicmp->destipaddr, ipicmp->srcipaddr); - net_ipv4addr_hdrcopy(ipicmp->srcipaddr, &dev->d_ipaddr); + net_ipv4addr_hdrcopy(ipv4->destipaddr, ipv4->srcipaddr); + net_ipv4addr_hdrcopy(ipv4->srcipaddr, &dev->d_ipaddr); /* Recalculate the ICMP checksum */ #if 0 + /* Get the IP header length (accounting for possible options). */ + + iphdrlen = (ipv4->vhl & IPv4_HLMASK) << 2; + /* The slow way... sum over the ICMP message */ - ipicmp->icmpchksum = 0; - ipicmp->icmpchksum = ~icmp_chksum(dev, (((uint16_t)ipicmp->len[0] << 8) | - (uint16_t)ipicmp->len[1]) - IPv4_HDRLEN); - if (ipicmp->icmpchksum == 0) + icmp->icmpchksum = 0; + icmp->icmpchksum = ~icmp_chksum(dev, (((uint16_t)ipv4->len[0] << 8) | + (uint16_t)ipv4->len[1]) - iphdrlen); + if (icmp->icmpchksum == 0) { - ipicmp->icmpchksum = 0xffff; + icmp->icmpchksum = 0xffff; } #else /* The quick way -- Since only the type has changed, just adjust the * checksum for the change of type */ - if (ipicmp->icmpchksum >= HTONS(0xffff - (ICMP_ECHO_REQUEST << 8))) + if (icmp->icmpchksum >= HTONS(0xffff - (ICMP_ECHO_REQUEST << 8))) { - ipicmp->icmpchksum += HTONS(ICMP_ECHO_REQUEST << 8) + 1; + icmp->icmpchksum += HTONS(ICMP_ECHO_REQUEST << 8) + 1; } else { - ipicmp->icmpchksum += HTONS(ICMP_ECHO_REQUEST << 8); + icmp->icmpchksum += HTONS(ICMP_ECHO_REQUEST << 8); } #endif ninfo("Outgoing ICMP packet length: %d (%d)\n", - dev->d_len, (ipicmp->len[0] << 8) | ipicmp->len[1]); + dev->d_len, (ipv4->len[0] << 8) | ipv4->len[1]); #ifdef CONFIG_NET_STATISTICS g_netstats.icmp.sent++; @@ -290,7 +308,7 @@ void icmp_input(FAR struct net_driver_s *dev) * a thread waiting to received the echo response. */ - else if (ipicmp->type == ICMP_ECHO_REPLY) + else if (icmp->type == ICMP_ECHO_REPLY) { FAR struct icmp_conn_s *conn; uint16_t flags; @@ -302,7 +320,7 @@ void icmp_input(FAR struct net_driver_s *dev) /* Is there any connection that might expect this reply? */ - conn = icmp_findconn(dev, ipicmp->id); + conn = icmp_findconn(dev, icmp->id); if (conn == NULL) { /* No.. drop the packet */ @@ -334,7 +352,7 @@ void icmp_input(FAR struct net_driver_s *dev) else { - nwarn("WARNING: Unknown ICMP cmd: %d\n", ipicmp->type); + nwarn("WARNING: Unknown ICMP cmd: %d\n", icmp->type); goto typeerr; } diff --git a/net/igmp/igmp_input.c b/net/igmp/igmp_input.c index 5a8674b5f2..691095da69 100644 --- a/net/igmp/igmp_input.c +++ b/net/igmp/igmp_input.c @@ -62,7 +62,8 @@ * Pre-processor Definitions ****************************************************************************/ -#define IGMPBUF ((struct igmp_iphdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)]) +#define IPv4BUF ((FAR struct igmp_iphdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)]) +#define IGMPBUF(hl) ((FAR struct igmp_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev) + (hl)]) /**************************************************************************** * Public Functions @@ -112,16 +113,27 @@ void igmp_input(struct net_driver_s *dev) { + FAR struct igmp_iphdr_s *ipv4 = IPv4BUF; + FAR struct igmp_hdr_s *igmp; FAR struct igmp_group_s *group; in_addr_t destipaddr; in_addr_t grpaddr; + uint16_t iphdrlen; unsigned int ticks; - ninfo("IGMP message: %04x%04x\n", IGMPBUF->destipaddr[1], IGMPBUF->destipaddr[0]); + ninfo("IGMP message: %04x%04x\n", ipv4->destipaddr[1], ipv4->destipaddr[0]); + + /* Get the IP header length (accounting for possible options). */ + + iphdrlen = (ipv4->vhl & IPv4_HLMASK) << 2; + + /* The IGMP header immediately follows the IP header */ + + igmp = IGMPBUF(iphdrlen); /* Verify the message length */ - if (dev->d_len < NET_LL_HDRLEN(dev) + IPIGMP_HDRLEN) + if (dev->d_len < NET_LL_HDRLEN(dev) + (iphdrlen + IGMP_HDRLEN)) { IGMP_STATINCR(g_netstats.igmp.length_errors); nwarn("WARNING: Length error\n"); @@ -130,7 +142,7 @@ void igmp_input(struct net_driver_s *dev) /* Calculate and check the IGMP checksum */ - if (net_chksum((FAR uint16_t *)&IGMPBUF->type, IGMP_HDRLEN) != 0) + if (net_chksum((FAR uint16_t *)igmp, IGMP_HDRLEN) != 0) { IGMP_STATINCR(g_netstats.igmp.chksum_errors); nwarn("WARNING: Checksum error\n"); @@ -139,7 +151,7 @@ void igmp_input(struct net_driver_s *dev) /* Find the group (or create a new one) using the incoming IP address. */ - destipaddr = net_ip4addr_conv32(IGMPBUF->destipaddr); + destipaddr = net_ip4addr_conv32(ipv4->destipaddr); group = igmp_grpallocfind(dev, &destipaddr); if (group == NULL) @@ -150,7 +162,7 @@ void igmp_input(struct net_driver_s *dev) /* Now handle the message based on the IGMP message type */ - switch (IGMPBUF->type) + switch (igmp->type) { case IGMP_MEMBERSHIP_QUERY: /* RFC 2236, 2.2. ax Response Time @@ -181,17 +193,17 @@ void igmp_input(struct net_driver_s *dev) * Query." */ - if (IGMPBUF->grpaddr == 0) + if (igmp->grpaddr == 0) { FAR struct igmp_group_s *member; /* This is the general query */ ninfo("General multicast query\n"); - if (IGMPBUF->maxresp == 0) + if (igmp->maxresp == 0) { IGMP_STATINCR(g_netstats.igmp.v1_received); - IGMPBUF->maxresp = 10; + igmp->maxresp = 10; nwarn("WARNING: V1 not implemented\n"); } @@ -206,7 +218,7 @@ void igmp_input(struct net_driver_s *dev) if (!net_ipv4addr_cmp(member->grpaddr, g_ipv4_allsystems)) { - ticks = net_dsec2tick((int)IGMPBUF->maxresp); + ticks = net_dsec2tick((int)igmp->maxresp); if (IS_IDLEMEMBER(member->flags) || igmp_cmptimer(member, ticks)) { @@ -216,7 +228,7 @@ void igmp_input(struct net_driver_s *dev) } } } - else /* if (IGMPBUF->grpaddr != 0) */ + else /* if (igmp->grpaddr != 0) */ { ninfo("Group-specific multicast query\n"); @@ -226,12 +238,12 @@ void igmp_input(struct net_driver_s *dev) IGMP_STATINCR(g_netstats.igmp.ucast_query); - grpaddr = net_ip4addr_conv32(IGMPBUF->grpaddr); + grpaddr = net_ip4addr_conv32(igmp->grpaddr); group = igmp_grpallocfind(dev, &grpaddr); if (group != NULL) { - ticks = net_dsec2tick((int)IGMPBUF->maxresp); + ticks = net_dsec2tick((int)igmp->maxresp); if (IS_IDLEMEMBER(group->flags) || igmp_cmptimer(group, ticks)) { @@ -251,7 +263,7 @@ void igmp_input(struct net_driver_s *dev) ninfo("Query to a specific group with the group address as destination\n"); - ticks = net_dsec2tick((int)IGMPBUF->maxresp); + ticks = net_dsec2tick((int)igmp->maxresp); if (IS_IDLEMEMBER(group->flags) || igmp_cmptimer(group, ticks)) { igmp_startticks(group, ticks); @@ -278,7 +290,7 @@ void igmp_input(struct net_driver_s *dev) default: { - nwarn("WARNING: Unexpected msg %02x\n", IGMPBUF->type); + nwarn("WARNING: Unexpected msg %02x\n", igmp->type); } break; } diff --git a/net/igmp/igmp_poll.c b/net/igmp/igmp_poll.c index d4c66e96cd..c1752aba4f 100644 --- a/net/igmp/igmp_poll.c +++ b/net/igmp/igmp_poll.c @@ -1,7 +1,7 @@ /**************************************************************************** * net/igmp/igmp_poll.c * - * Copyright (C) 2010, 2018 Gregory Nutt. All rights reserved. + * Copyright (C) 2010, 2018-2019 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * The NuttX implementation of IGMP was inspired by the IGMP add-on for the @@ -57,6 +57,16 @@ #ifdef CONFIG_NET_IGMP +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/* Buffer layout */ + +#define RASIZE (4) +#define IPv4BUF ((FAR struct igmp_iphdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)]) +#define IGMPBUF(hl) ((FAR struct igmp_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev) + (hl)]) + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -141,10 +151,13 @@ static inline void igmp_sched_send(FAR struct net_driver_s *dev, void igmp_poll(FAR struct net_driver_s *dev) { FAR struct igmp_group_s *group; + uint16_t iphdrlen; /* Setup the poll operation */ - dev->d_appdata = &dev->d_buf[NET_LL_HDRLEN(dev) + IPIGMP_HDRLEN]; + iphdrlen = IPv4_HDRLEN + RASIZE; + + dev->d_appdata = &dev->d_buf[NET_LL_HDRLEN(dev) + iphdrlen + IGMP_HDRLEN]; dev->d_len = 0; dev->d_sndlen = 0; diff --git a/net/igmp/igmp_send.c b/net/igmp/igmp_send.c index e67f8ee2d1..139d06c288 100644 --- a/net/igmp/igmp_send.c +++ b/net/igmp/igmp_send.c @@ -77,7 +77,8 @@ /* Buffer layout */ #define RASIZE (4) -#define IGMPBUF ((struct igmp_iphdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)]) +#define IPv4BUF ((FAR struct igmp_iphdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)]) +#define IGMPBUF(hl) ((FAR struct igmp_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev) + (hl)]) /**************************************************************************** * Private Functions @@ -118,62 +119,71 @@ static uint16_t igmp_chksum(FAR uint8_t *buffer, int buflen) void igmp_send(FAR struct net_driver_s *dev, FAR struct igmp_group_s *group, FAR in_addr_t *destipaddr, uint8_t msgid) { + FAR struct igmp_iphdr_s *ipv4 = IPv4BUF; + FAR struct igmp_hdr_s *igmp; + uint16_t iphdrlen; + ninfo("msgid: %02x destipaddr: %08x\n", msgid, (int)*destipaddr); + /* The IGMP header immediately follows the IP header */ + + iphdrlen = IPv4_HDRLEN + RASIZE; + igmp = IGMPBUF(iphdrlen); + /* The total length to send is the size of the IP and IGMP headers and 4 * bytes for the ROUTER ALERT (and, eventually, the Ethernet header) */ - dev->d_len = IPIGMP_HDRLEN; + dev->d_len = iphdrlen + IGMP_HDRLEN; /* The total size of the data is the size of the IGMP header */ - dev->d_sndlen = IGMP_HDRLEN; + dev->d_sndlen = IGMP_HDRLEN; - /* Add the router alert option (RFC 2113) */ + /* Add the router alert option to the IPv4 header (RFC 2113) */ - IGMPBUF->ra[0] = HTONS(IPOPT_RA >> 16); - IGMPBUF->ra[1] = HTONS(IPOPT_RA & 0xffff); + ipv4->ra[0] = HTONS(IPOPT_RA >> 16); + ipv4->ra[1] = HTONS(IPOPT_RA & 0xffff); /* Initialize the IPv4 header */ - IGMPBUF->vhl = 0x46; /* 4->IP; 6->24 bytes */ - IGMPBUF->tos = 0; - IGMPBUF->len[0] = (dev->d_len >> 8); - IGMPBUF->len[1] = (dev->d_len & 0xff); + ipv4->vhl = 0x46; /* 4->IP; 6->24 bytes */ + ipv4->tos = 0; + ipv4->len[0] = (dev->d_len >> 8); + ipv4->len[1] = (dev->d_len & 0xff); ++g_ipid; - IGMPBUF->ipid[0] = g_ipid >> 8; - IGMPBUF->ipid[1] = g_ipid & 0xff; - IGMPBUF->ipoffset[0] = IP_FLAG_DONTFRAG >> 8; - IGMPBUF->ipoffset[1] = IP_FLAG_DONTFRAG & 0xff; - IGMPBUF->ttl = IGMP_TTL; - IGMPBUF->proto = IP_PROTO_IGMP; + ipv4->ipid[0] = g_ipid >> 8; + ipv4->ipid[1] = g_ipid & 0xff; + ipv4->ipoffset[0] = IP_FLAG_DONTFRAG >> 8; + ipv4->ipoffset[1] = IP_FLAG_DONTFRAG & 0xff; + ipv4->ttl = IGMP_TTL; + ipv4->proto = IP_PROTO_IGMP; - net_ipv4addr_hdrcopy(IGMPBUF->srcipaddr, &dev->d_ipaddr); - net_ipv4addr_hdrcopy(IGMPBUF->destipaddr, destipaddr); + net_ipv4addr_hdrcopy(ipv4->srcipaddr, &dev->d_ipaddr); + net_ipv4addr_hdrcopy(ipv4->destipaddr, destipaddr); /* Calculate IP checksum. */ - IGMPBUF->ipchksum = 0; - IGMPBUF->ipchksum = ~igmp_chksum((FAR uint8_t *)IGMPBUF, IPv4_HDRLEN + RASIZE); + ipv4->ipchksum = 0; + ipv4->ipchksum = ~igmp_chksum((FAR uint8_t *)igmp, iphdrlen); /* Set up the IGMP message */ - IGMPBUF->type = msgid; - IGMPBUF->maxresp = 0; - net_ipv4addr_hdrcopy(IGMPBUF->grpaddr, &group->grpaddr); + igmp->type = msgid; + igmp->maxresp = 0; + net_ipv4addr_hdrcopy(igmp->grpaddr, &group->grpaddr); /* Calculate the IGMP checksum. */ - IGMPBUF->chksum = 0; - IGMPBUF->chksum = ~igmp_chksum(&IGMPBUF->type, IGMP_HDRLEN); + igmp->chksum = 0; + igmp->chksum = ~igmp_chksum(&igmp->type, IGMP_HDRLEN); IGMP_STATINCR(g_netstats.igmp.poll_send); IGMP_STATINCR(g_netstats.ipv4.sent); ninfo("Outgoing IGMP packet length: %d (%d)\n", - dev->d_len, (IGMPBUF->len[0] << 8) | IGMPBUF->len[1]); - igmp_dumppkt(RA, IPIGMP_HDRLEN + RASIZE); + dev->d_len, (ipv4->len[0] << 8) | ipvr->len[1]); + igmp_dumppkt(RA, iphdrlen + IGMP_HDRLEN); } #endif /* CONFIG_NET_IGMP */ diff --git a/net/ipforward/ipv4_forward.c b/net/ipforward/ipv4_forward.c index ce9dd16af6..19e365b5b2 100644 --- a/net/ipforward/ipv4_forward.c +++ b/net/ipforward/ipv4_forward.c @@ -80,7 +80,13 @@ #ifdef CONFIG_DEBUG_NET_WARN static int ipv4_hdrsize(FAR struct ipv4_hdr_s *ipv4) { - /* Size is determined by the following protocol header, */ + uint16_t iphdrlen; + + /* Get the IP header length (accounting for possible options). */ + + iphdrlen = (ipv4->vhl & IPv4_HLMASK) << 2; + + /* Size is also determined by the following protocol header, */ switch (ipv4->proto) { @@ -88,7 +94,7 @@ static int ipv4_hdrsize(FAR struct ipv4_hdr_s *ipv4) case IP_PROTO_TCP: { FAR struct tcp_hdr_s *tcp = - (FAR struct tcp_hdr_s *)((FAR uint8_t *)ipv4 + IPv4_HDRLEN); + (FAR struct tcp_hdr_s *)((FAR uint8_t *)ipv4 + iphdrlen); unsigned int tcpsize; /* The TCP header length is encoded in the top 4 bits of the @@ -96,20 +102,20 @@ static int ipv4_hdrsize(FAR struct ipv4_hdr_s *ipv4) */ tcpsize = ((uint16_t)tcp->tcpoffset >> 4) << 2; - return IPv4_HDRLEN + tcpsize; + return iphdrlen + tcpsize; } break; #endif #ifdef CONFIG_NET_UDP case IP_PROTO_UDP: - return IPv4_HDRLEN + UDP_HDRLEN; + return iphdrlen + UDP_HDRLEN; break; #endif #ifdef CONFIG_NET_ICMP case IP_PROTO_ICMP: - return IPv4_HDRLEN + ICMP_HDRLEN; + return iphdrlen + ICMP_HDRLEN; break; #endif @@ -146,9 +152,14 @@ static int ipv4_hdrsize(FAR struct ipv4_hdr_s *ipv4) static int ipv4_decr_ttl(FAR struct ipv4_hdr_s *ipv4) { + FAR struct ipv4_hdr_s *ipv4 = IPv4BUF; + uint16_t iphdrlen; uint16_t sum; - int ttl = (int)ipv4->ttl - 1; + int ttl + /* Check time-to-live (TTL) */ + + ttl = (int)ipv4->ttl - 1; if (ttl <= 0) { #ifdef CONFIG_NET_ICMP @@ -165,13 +176,17 @@ static int ipv4_decr_ttl(FAR struct ipv4_hdr_s *ipv4) ipv4->ttl = ttl; + /* Get the IP header length (accounting for possible options). */ + + iphdrlen = (ipv4->vhl & IPv4_HLMASK) << 2; + /* Re-calculate the IPv4 checksum. This checksum is the Internet checksum * of the 20 bytes of the IPv4 header. This checksum will be different * because we just modify the IPv4 TTL. */ ipv4->ipchksum = 0; - sum = chksum(0, (FAR const uint8_t *)ipv4, IPv4_HDRLEN); + sum = chksum(0, (FAR const uint8_t *)ipv4, iphdrlen); if (sum == 0) { sum = 0xffff; diff --git a/net/tcp/tcp_input.c b/net/tcp/tcp_input.c index a30ba4dab5..7443e9b779 100644 --- a/net/tcp/tcp_input.c +++ b/net/tcp/tcp_input.c @@ -2,7 +2,7 @@ * net/tcp/tcp_input.c * Handling incoming TCP input * - * Copyright (C) 2007-2014, 2017-2018 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2014, 2017-2019 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Adapted for NuttX from logic in uIP which also has a BSD-like license: @@ -62,6 +62,12 @@ #include "utils/utils.h" #include "tcp/tcp.h" +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define IPv4BUF ((FAR struct ipv4_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)]) + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -1037,13 +1043,20 @@ drop: #ifdef CONFIG_NET_IPv4 void tcp_ipv4_input(FAR struct net_driver_s *dev) { + FAR struct ipv4_hdr_s *ipv4 = IPv4BUF; + uint16_t iphdrlen; + /* Configure to receive an TCP IPv4 packet */ tcp_ipv4_select(dev); + /* Get the IP header length (accounting for possible options). */ + + iphdrlen = (ipv4->vhl & IPv4_HLMASK) << 2; + /* Then process in the TCP IPv4 input */ - tcp_input(dev, PF_INET, IPv4_HDRLEN); + tcp_input(dev, PF_INET, iphdrlen); } #endif diff --git a/net/udp/udp_input.c b/net/udp/udp_input.c index 09efec1260..fdb439d193 100644 --- a/net/udp/udp_input.c +++ b/net/udp/udp_input.c @@ -2,7 +2,8 @@ * net/udp/udp_input.c * Handling incoming UDP input * - * Copyright (C) 2007-2009, 2011, 2018 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2011, 2018-2019 Gregory Nutt. All rights + * reserved. * Author: Gregory Nutt * * Adapted for NuttX from logic in uIP which also has a BSD-like license: @@ -56,6 +57,12 @@ #include "utils/utils.h" #include "udp/udp.h" +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define IPv4BUF ((FAR struct ipv4_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)]) + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -254,13 +261,20 @@ static int udp_input(FAR struct net_driver_s *dev, unsigned int iplen) #ifdef CONFIG_NET_IPv4 int udp_ipv4_input(FAR struct net_driver_s *dev) { + FAR struct ipv4_hdr_s *ipv4 = IPv4BUF; + uint16_t iphdrlen; + /* Configure to receive an UDP IPv4 packet */ udp_ipv4_select(dev); + /* Get the IP header length (accounting for possible options). */ + + iphdrlen = (ipv4->vhl & IPv4_HLMASK) << 2; + /* Then process in the UDP IPv4 input */ - return udp_input(dev, IPv4_HDRLEN); + return udp_input(dev, iphdrlen); } #endif diff --git a/net/utils/net_icmpchksum.c b/net/utils/net_icmpchksum.c index 5c0ca3d4c7..b17f5328c9 100644 --- a/net/utils/net_icmpchksum.c +++ b/net/utils/net_icmpchksum.c @@ -53,8 +53,9 @@ * Pre-processor Definitions ****************************************************************************/ -#define ICMPBUF ((struct icmp_iphdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)]) -#define ICMPv6BUF ((struct icmp_ipv6hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)]) +#define IPv4BUF ((FAR struct ipv4_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)]) +#define ICMPBUF(hl) ((FAR struct icmp_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev) + (hl)]) +#define ICMPv6BUF ((struct icmp_ipv6hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)]) /**************************************************************************** * Public Functions @@ -71,7 +72,17 @@ #if defined(CONFIG_NET_ICMP) && defined(CONFIG_NET_ICMP_SOCKET) uint16_t icmp_chksum(FAR struct net_driver_s *dev, int len) { - FAR struct icmp_iphdr_s *icmp = ICMPBUF; + FAR struct ipv4_hdr_s *ipv4 = IPv4BUF; + FAR struct icmp_hdr_s *icmp; + uint16_t iphdrlen; + + /* Get the IP header length (accounting for possible options). */ + + iphdrlen = (ipv4->vhl & IPv4_HLMASK) << 2; + + /* The ICMP header immediately follows the IP header */ + + icmp = ICMPBUF(iphdrlen); return net_chksum((FAR uint16_t *)&icmp->type, len); } #endif /* CONFIG_NET_ICMP && CONFIG_NET_ICMP_SOCKET */ diff --git a/net/utils/net_ipchksum.c b/net/utils/net_ipchksum.c index 15c62b1fa6..1ec295173c 100644 --- a/net/utils/net_ipchksum.c +++ b/net/utils/net_ipchksum.c @@ -1,7 +1,7 @@ /**************************************************************************** * net/utils/net_ipchksum.c * - * Copyright (C) 2007-2010, 2012, 2014-2015, 2017-2018 Gregory Nutt. All + * Copyright (C) 2007-2010, 2012, 2014-2015, 2017-2019 Gregory Nutt. All * rights reserved. * Author: Gregory Nutt * @@ -55,8 +55,8 @@ * Pre-processor Definitions ****************************************************************************/ -#define IPv4BUF ((struct ipv4_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)]) -#define IPv6BUF ((struct ipv6_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)]) +#define IPv4BUF ((struct ipv4_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)]) +#define IPv6BUF ((struct ipv6_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)]) /**************************************************************************** * Public Functions @@ -84,14 +84,19 @@ uint16_t ipv4_upperlayer_chksum(FAR struct net_driver_s *dev, uint8_t proto) { FAR struct ipv4_hdr_s *ipv4 = IPv4BUF; uint16_t upperlen; + uint16_t iphdrlen; uint16_t sum; + /* Get the IP header length (accounting for possible options). */ + + iphdrlen = (ipv4->vhl & IPv4_HLMASK) << 2; + /* The length reported in the IPv4 header is the length of both the IPv4 * header and the payload that follows the header. We need to subtract * the size of the IPv4 header to get the size of the payload. */ - upperlen = (((uint16_t)(ipv4->len[0]) << 8) + ipv4->len[1]) - IPv4_HDRLEN; + upperlen = (((uint16_t)(ipv4->len[0]) << 8) + ipv4->len[1]) - iphdrlen; /* Verify some minimal assumptions */ @@ -113,7 +118,7 @@ uint16_t ipv4_upperlayer_chksum(FAR struct net_driver_s *dev, uint8_t proto) /* Sum IP payload data. */ - sum = chksum(sum, &dev->d_buf[IPv4_HDRLEN + NET_LL_HDRLEN(dev)], upperlen); + sum = chksum(sum, &dev->d_buf[iphdrlen + NET_LL_HDRLEN(dev)], upperlen); return (sum == 0) ? 0xffff : htons(sum); } #endif /* CONFIG_NET_ARCH_CHKSUM */ @@ -205,9 +210,15 @@ uint16_t ipv6_upperlayer_chksum(FAR struct net_driver_s *dev, #if defined(CONFIG_NET_IPv4) && !defined(CONFIG_NET_ARCH_CHKSUM) uint16_t ipv4_chksum(FAR struct net_driver_s *dev) { + FAR struct ipv4_hdr_s *ipv4 = IPv4BUF; + uint16_t iphdrlen; uint16_t sum; - sum = chksum(0, &dev->d_buf[NET_LL_HDRLEN(dev)], IPv4_HDRLEN); + /* Get the IP header length (accounting for possible options). */ + + iphdrlen = (ipv4->vhl & IPv4_HLMASK) << 2; + + sum = chksum(0, &dev->d_buf[NET_LL_HDRLEN(dev)], iphdrlen); return (sum == 0) ? 0xffff : htons(sum); } #endif /* CONFIG_NET_ARCH_CHKSUM */