net/: Now handles reception of IPv4 packets with larger IPv4 headers containing options.

This commit is contained in:
Gregory Nutt 2019-08-31 12:25:30 -06:00
parent 9bdde04636
commit a52ceac13e
13 changed files with 233 additions and 148 deletions

View File

@ -118,40 +118,6 @@ struct icmp_hdr_s
uint16_t seqno; /* " " "" " " " " " " " " */ 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 /* The structure holding the ICMP statistics that are gathered if
* CONFIG_NET_STATISTICS is defined. * CONFIG_NET_STATISTICS is defined.
*/ */

View File

@ -3,7 +3,7 @@
* The definitions in this header file are intended only for internal use * The definitions in this header file are intended only for internal use
* by the NuttX network stack. * 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 <gnutt@nuttx.org> * Author: Gregory Nutt <gnutt@nuttx.org>
* *
* The NuttX implementation of IGMP was inspired by the IGMP add-on for the * 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 IGMPv3_MEMBERSHIP_REPORT 0x22 /* IGMP Ver. 3 Membership Report */
#define IGMP_LEAVE_GROUP 0x17 /* Leave Group */ #define IGMP_LEAVE_GROUP 0x17 /* Leave Group */
/* Header sizes: /* Size of IGMP header in bytes */
*
* IGMP_HDRLEN - Size of IGMP header in bytes
* IPIGMP_HDRLEN - Size of IP + Size of IGMP header + Size of router alert
*/
#define IGMP_HDRLEN 8 #define IGMP_HDRLEN 8
#define IPIGMP_HDRLEN (IGMP_HDRLEN + IPv4_HDRLEN + 4)
/* Time-to-Live must be one */ /* Time-to-Live must be one */
@ -89,13 +84,7 @@
* Public Types * Public Types
****************************************************************************/ ****************************************************************************/
/* IGMPv2 packet structure as defined by RFC 2236. /* Convenience [re-]definition of the IPv4 header with the router alert */
*
* 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_iphdr_s struct igmp_iphdr_s
{ {
@ -115,7 +104,18 @@ struct igmp_iphdr_s
/* Router Alert IP header option */ /* Router Alert IP header option */
uint16_t ra[2]; /* RFC 2113 */ 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: /* IGMPv2 header:
* *
* 0 1 2 3 * 0 1 2 3

View File

@ -86,6 +86,7 @@
#ifdef CONFIG_NET_IPv4 #ifdef CONFIG_NET_IPv4
# define IPv4_HDRLEN 20 /* Size of IPv4 header (without options) */ # define IPv4_HDRLEN 20 /* Size of IPv4 header (without options) */
# define IPv4_HLMASK 0x0f /* Isolates headler length in VHL field */
#endif #endif
#ifdef CONFIG_NET_IPv6 #ifdef CONFIG_NET_IPv6

View File

@ -2,7 +2,7 @@
* net/devif/ipv4_input.c * net/devif/ipv4_input.c
* Device driver IPv4 packet receipt interface * 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. * reserved.
* Author: Gregory Nutt <gnutt@nuttx.org> * Author: Gregory Nutt <gnutt@nuttx.org>
* *
@ -332,8 +332,8 @@ int ipv4_input(FAR struct net_driver_s *dev)
{ {
FAR struct ipv4_hdr_s *ipv4 = BUF; FAR struct ipv4_hdr_s *ipv4 = BUF;
in_addr_t destipaddr; in_addr_t destipaddr;
uint16_t hdrlen; uint16_t llhdrlen;
uint16_t iplen; uint16_t totlen;
/* This is where the input processing starts. */ /* 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. * 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. */ /* IP version and header length. */
@ -364,14 +365,14 @@ int ipv4_input(FAR struct net_driver_s *dev)
/* Get the size of the packet minus the size of link layer header */ /* Get the size of the packet minus the size of link layer header */
hdrlen = NET_LL_HDRLEN(dev); llhdrlen = NET_LL_HDRLEN(dev);
if ((hdrlen + IPv4_HDRLEN) > dev->d_len) if ((llhdrlen + IPv4_HDRLEN) > dev->d_len)
{ {
nwarn("WARNING: Packet shorter than IPv4 header\n"); nwarn("WARNING: Packet shorter than IPv4 header\n");
goto drop; 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 * smaller the size reported in the IP header, we assume that the packet
@ -380,10 +381,10 @@ int ipv4_input(FAR struct net_driver_s *dev)
* we set d_len to the correct value. * we set d_len to the correct value.
*/ */
iplen = (ipv4->len[0] << 8) + ipv4->len[1]; totlen = (ipv4->len[0] << 8) + ipv4->len[1];
if (iplen <= dev->d_len) if (totlen <= dev->d_len)
{ {
dev->d_len = iplen; dev->d_len = totlen;
} }
else else
{ {

View File

@ -68,9 +68,8 @@
****************************************************************************/ ****************************************************************************/
#define IPv4BUF ((FAR struct ipv4_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)]) #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(hl) ((FAR struct icmp_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev) + (hl)])
#define ICMPBUF ((FAR struct icmp_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev) + IPv4_HDRLEN]) #define ICMPSIZE(hl) ((dev)->d_len - (hl))
#define ICMPSIZE ((dev)->d_len - IPv4_HDRLEN)
/**************************************************************************** /****************************************************************************
* Private Functions * Private Functions
@ -104,6 +103,7 @@ static uint16_t icmp_datahandler(FAR struct net_driver_s *dev,
FAR struct iob_s *iob; FAR struct iob_s *iob;
uint16_t offset; uint16_t offset;
uint16_t buflen; uint16_t buflen;
uint16_t iphdrlen;
uint8_t addrsize; uint8_t addrsize;
int ret; int ret;
@ -164,11 +164,15 @@ static uint16_t icmp_datahandler(FAR struct net_driver_s *dev,
offset += sizeof(struct sockaddr_in); 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) */ /* Copy the new ICMP reply into the I/O buffer chain (without waiting) */
buflen = ICMPSIZE; buflen = ICMPSIZE(iphdrlen);
ret = iob_trycopyin(iob, (FAR uint8_t *)ICMPBUF, buflen, offset, true, ret = iob_trycopyin(iob, (FAR uint8_t *)ICMPBUF(iphdrlen), buflen, offset,
IOBUSER_NET_SOCK_ICMP); true, IOBUSER_NET_SOCK_ICMP);
if (ret < 0) if (ret < 0)
{ {
/* On a failure, iob_copyin return a negated error value but does /* 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) 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 #ifdef CONFIG_NET_STATISTICS
g_netstats.icmp.recv++; g_netstats.icmp.recv++;
#endif #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 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 * ICMP type from ECHO to ECHO_REPLY and adjust the ICMP checksum before
* we return the packet. * we return the packet.
*/ */
if (ipicmp->type == ICMP_ECHO_REQUEST) if (icmp->type == ICMP_ECHO_REQUEST)
{ {
/* Change the ICMP type */ /* Change the ICMP type */
ipicmp->type = ICMP_ECHO_REPLY; icmp->type = ICMP_ECHO_REPLY;
/* Swap IP addresses. */ /* Swap IP addresses. */
net_ipv4addr_hdrcopy(ipicmp->destipaddr, ipicmp->srcipaddr); net_ipv4addr_hdrcopy(ipv4->destipaddr, ipv4->srcipaddr);
net_ipv4addr_hdrcopy(ipicmp->srcipaddr, &dev->d_ipaddr); net_ipv4addr_hdrcopy(ipv4->srcipaddr, &dev->d_ipaddr);
/* Recalculate the ICMP checksum */ /* Recalculate the ICMP checksum */
#if 0 #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 */ /* The slow way... sum over the ICMP message */
ipicmp->icmpchksum = 0; icmp->icmpchksum = 0;
ipicmp->icmpchksum = ~icmp_chksum(dev, (((uint16_t)ipicmp->len[0] << 8) | icmp->icmpchksum = ~icmp_chksum(dev, (((uint16_t)ipv4->len[0] << 8) |
(uint16_t)ipicmp->len[1]) - IPv4_HDRLEN); (uint16_t)ipv4->len[1]) - iphdrlen);
if (ipicmp->icmpchksum == 0) if (icmp->icmpchksum == 0)
{ {
ipicmp->icmpchksum = 0xffff; icmp->icmpchksum = 0xffff;
} }
#else #else
/* The quick way -- Since only the type has changed, just adjust the /* The quick way -- Since only the type has changed, just adjust the
* checksum for the change of type * 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 else
{ {
ipicmp->icmpchksum += HTONS(ICMP_ECHO_REQUEST << 8); icmp->icmpchksum += HTONS(ICMP_ECHO_REQUEST << 8);
} }
#endif #endif
ninfo("Outgoing ICMP packet length: %d (%d)\n", 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 #ifdef CONFIG_NET_STATISTICS
g_netstats.icmp.sent++; 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. * 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; FAR struct icmp_conn_s *conn;
uint16_t flags; 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? */ /* Is there any connection that might expect this reply? */
conn = icmp_findconn(dev, ipicmp->id); conn = icmp_findconn(dev, icmp->id);
if (conn == NULL) if (conn == NULL)
{ {
/* No.. drop the packet */ /* No.. drop the packet */
@ -334,7 +352,7 @@ void icmp_input(FAR struct net_driver_s *dev)
else else
{ {
nwarn("WARNING: Unknown ICMP cmd: %d\n", ipicmp->type); nwarn("WARNING: Unknown ICMP cmd: %d\n", icmp->type);
goto typeerr; goto typeerr;
} }

View File

@ -62,7 +62,8 @@
* Pre-processor Definitions * 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 * Public Functions
@ -112,16 +113,27 @@
void igmp_input(struct net_driver_s *dev) 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; FAR struct igmp_group_s *group;
in_addr_t destipaddr; in_addr_t destipaddr;
in_addr_t grpaddr; in_addr_t grpaddr;
uint16_t iphdrlen;
unsigned int ticks; 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 */ /* 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); IGMP_STATINCR(g_netstats.igmp.length_errors);
nwarn("WARNING: Length error\n"); nwarn("WARNING: Length error\n");
@ -130,7 +142,7 @@ void igmp_input(struct net_driver_s *dev)
/* Calculate and check the IGMP checksum */ /* 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); IGMP_STATINCR(g_netstats.igmp.chksum_errors);
nwarn("WARNING: Checksum error\n"); 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. */ /* 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); group = igmp_grpallocfind(dev, &destipaddr);
if (group == NULL) 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 */ /* Now handle the message based on the IGMP message type */
switch (IGMPBUF->type) switch (igmp->type)
{ {
case IGMP_MEMBERSHIP_QUERY: case IGMP_MEMBERSHIP_QUERY:
/* RFC 2236, 2.2. ax Response Time /* RFC 2236, 2.2. ax Response Time
@ -181,17 +193,17 @@ void igmp_input(struct net_driver_s *dev)
* Query." * Query."
*/ */
if (IGMPBUF->grpaddr == 0) if (igmp->grpaddr == 0)
{ {
FAR struct igmp_group_s *member; FAR struct igmp_group_s *member;
/* This is the general query */ /* This is the general query */
ninfo("General multicast query\n"); ninfo("General multicast query\n");
if (IGMPBUF->maxresp == 0) if (igmp->maxresp == 0)
{ {
IGMP_STATINCR(g_netstats.igmp.v1_received); IGMP_STATINCR(g_netstats.igmp.v1_received);
IGMPBUF->maxresp = 10; igmp->maxresp = 10;
nwarn("WARNING: V1 not implemented\n"); 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)) 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) || if (IS_IDLEMEMBER(member->flags) ||
igmp_cmptimer(member, ticks)) 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"); 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); IGMP_STATINCR(g_netstats.igmp.ucast_query);
grpaddr = net_ip4addr_conv32(IGMPBUF->grpaddr); grpaddr = net_ip4addr_conv32(igmp->grpaddr);
group = igmp_grpallocfind(dev, &grpaddr); group = igmp_grpallocfind(dev, &grpaddr);
if (group != NULL) if (group != NULL)
{ {
ticks = net_dsec2tick((int)IGMPBUF->maxresp); ticks = net_dsec2tick((int)igmp->maxresp);
if (IS_IDLEMEMBER(group->flags) || igmp_cmptimer(group, ticks)) 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"); 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)) if (IS_IDLEMEMBER(group->flags) || igmp_cmptimer(group, ticks))
{ {
igmp_startticks(group, ticks); igmp_startticks(group, ticks);
@ -278,7 +290,7 @@ void igmp_input(struct net_driver_s *dev)
default: default:
{ {
nwarn("WARNING: Unexpected msg %02x\n", IGMPBUF->type); nwarn("WARNING: Unexpected msg %02x\n", igmp->type);
} }
break; break;
} }

View File

@ -1,7 +1,7 @@
/**************************************************************************** /****************************************************************************
* net/igmp/igmp_poll.c * 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 <gnutt@nuttx.org> * Author: Gregory Nutt <gnutt@nuttx.org>
* *
* The NuttX implementation of IGMP was inspired by the IGMP add-on for the * The NuttX implementation of IGMP was inspired by the IGMP add-on for the
@ -57,6 +57,16 @@
#ifdef CONFIG_NET_IGMP #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 * 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) void igmp_poll(FAR struct net_driver_s *dev)
{ {
FAR struct igmp_group_s *group; FAR struct igmp_group_s *group;
uint16_t iphdrlen;
/* Setup the poll operation */ /* 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_len = 0;
dev->d_sndlen = 0; dev->d_sndlen = 0;

View File

@ -77,7 +77,8 @@
/* Buffer layout */ /* Buffer layout */
#define RASIZE (4) #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 * 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, void igmp_send(FAR struct net_driver_s *dev, FAR struct igmp_group_s *group,
FAR in_addr_t *destipaddr, uint8_t msgid) 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); 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 /* 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) * 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 */ /* 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); ipv4->ra[0] = HTONS(IPOPT_RA >> 16);
IGMPBUF->ra[1] = HTONS(IPOPT_RA & 0xffff); ipv4->ra[1] = HTONS(IPOPT_RA & 0xffff);
/* Initialize the IPv4 header */ /* Initialize the IPv4 header */
IGMPBUF->vhl = 0x46; /* 4->IP; 6->24 bytes */ ipv4->vhl = 0x46; /* 4->IP; 6->24 bytes */
IGMPBUF->tos = 0; ipv4->tos = 0;
IGMPBUF->len[0] = (dev->d_len >> 8); ipv4->len[0] = (dev->d_len >> 8);
IGMPBUF->len[1] = (dev->d_len & 0xff); ipv4->len[1] = (dev->d_len & 0xff);
++g_ipid; ++g_ipid;
IGMPBUF->ipid[0] = g_ipid >> 8; ipv4->ipid[0] = g_ipid >> 8;
IGMPBUF->ipid[1] = g_ipid & 0xff; ipv4->ipid[1] = g_ipid & 0xff;
IGMPBUF->ipoffset[0] = IP_FLAG_DONTFRAG >> 8; ipv4->ipoffset[0] = IP_FLAG_DONTFRAG >> 8;
IGMPBUF->ipoffset[1] = IP_FLAG_DONTFRAG & 0xff; ipv4->ipoffset[1] = IP_FLAG_DONTFRAG & 0xff;
IGMPBUF->ttl = IGMP_TTL; ipv4->ttl = IGMP_TTL;
IGMPBUF->proto = IP_PROTO_IGMP; ipv4->proto = IP_PROTO_IGMP;
net_ipv4addr_hdrcopy(IGMPBUF->srcipaddr, &dev->d_ipaddr); net_ipv4addr_hdrcopy(ipv4->srcipaddr, &dev->d_ipaddr);
net_ipv4addr_hdrcopy(IGMPBUF->destipaddr, destipaddr); net_ipv4addr_hdrcopy(ipv4->destipaddr, destipaddr);
/* Calculate IP checksum. */ /* Calculate IP checksum. */
IGMPBUF->ipchksum = 0; ipv4->ipchksum = 0;
IGMPBUF->ipchksum = ~igmp_chksum((FAR uint8_t *)IGMPBUF, IPv4_HDRLEN + RASIZE); ipv4->ipchksum = ~igmp_chksum((FAR uint8_t *)igmp, iphdrlen);
/* Set up the IGMP message */ /* Set up the IGMP message */
IGMPBUF->type = msgid; igmp->type = msgid;
IGMPBUF->maxresp = 0; igmp->maxresp = 0;
net_ipv4addr_hdrcopy(IGMPBUF->grpaddr, &group->grpaddr); net_ipv4addr_hdrcopy(igmp->grpaddr, &group->grpaddr);
/* Calculate the IGMP checksum. */ /* Calculate the IGMP checksum. */
IGMPBUF->chksum = 0; igmp->chksum = 0;
IGMPBUF->chksum = ~igmp_chksum(&IGMPBUF->type, IGMP_HDRLEN); igmp->chksum = ~igmp_chksum(&igmp->type, IGMP_HDRLEN);
IGMP_STATINCR(g_netstats.igmp.poll_send); IGMP_STATINCR(g_netstats.igmp.poll_send);
IGMP_STATINCR(g_netstats.ipv4.sent); IGMP_STATINCR(g_netstats.ipv4.sent);
ninfo("Outgoing IGMP packet length: %d (%d)\n", ninfo("Outgoing IGMP packet length: %d (%d)\n",
dev->d_len, (IGMPBUF->len[0] << 8) | IGMPBUF->len[1]); dev->d_len, (ipv4->len[0] << 8) | ipvr->len[1]);
igmp_dumppkt(RA, IPIGMP_HDRLEN + RASIZE); igmp_dumppkt(RA, iphdrlen + IGMP_HDRLEN);
} }
#endif /* CONFIG_NET_IGMP */ #endif /* CONFIG_NET_IGMP */

View File

@ -80,7 +80,13 @@
#ifdef CONFIG_DEBUG_NET_WARN #ifdef CONFIG_DEBUG_NET_WARN
static int ipv4_hdrsize(FAR struct ipv4_hdr_s *ipv4) 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) switch (ipv4->proto)
{ {
@ -88,7 +94,7 @@ static int ipv4_hdrsize(FAR struct ipv4_hdr_s *ipv4)
case IP_PROTO_TCP: case IP_PROTO_TCP:
{ {
FAR struct tcp_hdr_s *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; unsigned int tcpsize;
/* The TCP header length is encoded in the top 4 bits of the /* 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; tcpsize = ((uint16_t)tcp->tcpoffset >> 4) << 2;
return IPv4_HDRLEN + tcpsize; return iphdrlen + tcpsize;
} }
break; break;
#endif #endif
#ifdef CONFIG_NET_UDP #ifdef CONFIG_NET_UDP
case IP_PROTO_UDP: case IP_PROTO_UDP:
return IPv4_HDRLEN + UDP_HDRLEN; return iphdrlen + UDP_HDRLEN;
break; break;
#endif #endif
#ifdef CONFIG_NET_ICMP #ifdef CONFIG_NET_ICMP
case IP_PROTO_ICMP: case IP_PROTO_ICMP:
return IPv4_HDRLEN + ICMP_HDRLEN; return iphdrlen + ICMP_HDRLEN;
break; break;
#endif #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) static int ipv4_decr_ttl(FAR struct ipv4_hdr_s *ipv4)
{ {
FAR struct ipv4_hdr_s *ipv4 = IPv4BUF;
uint16_t iphdrlen;
uint16_t sum; uint16_t sum;
int ttl = (int)ipv4->ttl - 1; int ttl
/* Check time-to-live (TTL) */
ttl = (int)ipv4->ttl - 1;
if (ttl <= 0) if (ttl <= 0)
{ {
#ifdef CONFIG_NET_ICMP #ifdef CONFIG_NET_ICMP
@ -165,13 +176,17 @@ static int ipv4_decr_ttl(FAR struct ipv4_hdr_s *ipv4)
ipv4->ttl = ttl; 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 /* Re-calculate the IPv4 checksum. This checksum is the Internet checksum
* of the 20 bytes of the IPv4 header. This checksum will be different * of the 20 bytes of the IPv4 header. This checksum will be different
* because we just modify the IPv4 TTL. * because we just modify the IPv4 TTL.
*/ */
ipv4->ipchksum = 0; 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) if (sum == 0)
{ {
sum = 0xffff; sum = 0xffff;

View File

@ -2,7 +2,7 @@
* net/tcp/tcp_input.c * net/tcp/tcp_input.c
* Handling incoming TCP input * 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 <gnutt@nuttx.org> * Author: Gregory Nutt <gnutt@nuttx.org>
* *
* Adapted for NuttX from logic in uIP which also has a BSD-like license: * Adapted for NuttX from logic in uIP which also has a BSD-like license:
@ -62,6 +62,12 @@
#include "utils/utils.h" #include "utils/utils.h"
#include "tcp/tcp.h" #include "tcp/tcp.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define IPv4BUF ((FAR struct ipv4_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)])
/**************************************************************************** /****************************************************************************
* Private Functions * Private Functions
****************************************************************************/ ****************************************************************************/
@ -1037,13 +1043,20 @@ drop:
#ifdef CONFIG_NET_IPv4 #ifdef CONFIG_NET_IPv4
void tcp_ipv4_input(FAR struct net_driver_s *dev) 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 */ /* Configure to receive an TCP IPv4 packet */
tcp_ipv4_select(dev); 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 */ /* Then process in the TCP IPv4 input */
tcp_input(dev, PF_INET, IPv4_HDRLEN); tcp_input(dev, PF_INET, iphdrlen);
} }
#endif #endif

View File

@ -2,7 +2,8 @@
* net/udp/udp_input.c * net/udp/udp_input.c
* Handling incoming UDP input * 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 <gnutt@nuttx.org> * Author: Gregory Nutt <gnutt@nuttx.org>
* *
* Adapted for NuttX from logic in uIP which also has a BSD-like license: * Adapted for NuttX from logic in uIP which also has a BSD-like license:
@ -56,6 +57,12 @@
#include "utils/utils.h" #include "utils/utils.h"
#include "udp/udp.h" #include "udp/udp.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define IPv4BUF ((FAR struct ipv4_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)])
/**************************************************************************** /****************************************************************************
* Private Functions * Private Functions
****************************************************************************/ ****************************************************************************/
@ -254,13 +261,20 @@ static int udp_input(FAR struct net_driver_s *dev, unsigned int iplen)
#ifdef CONFIG_NET_IPv4 #ifdef CONFIG_NET_IPv4
int udp_ipv4_input(FAR struct net_driver_s *dev) 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 */ /* Configure to receive an UDP IPv4 packet */
udp_ipv4_select(dev); 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 */ /* Then process in the UDP IPv4 input */
return udp_input(dev, IPv4_HDRLEN); return udp_input(dev, iphdrlen);
} }
#endif #endif

View File

@ -53,7 +53,8 @@
* Pre-processor Definitions * Pre-processor Definitions
****************************************************************************/ ****************************************************************************/
#define ICMPBUF ((struct icmp_iphdr_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)]) #define ICMPv6BUF ((struct icmp_ipv6hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)])
/**************************************************************************** /****************************************************************************
@ -71,7 +72,17 @@
#if defined(CONFIG_NET_ICMP) && defined(CONFIG_NET_ICMP_SOCKET) #if defined(CONFIG_NET_ICMP) && defined(CONFIG_NET_ICMP_SOCKET)
uint16_t icmp_chksum(FAR struct net_driver_s *dev, int len) 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); return net_chksum((FAR uint16_t *)&icmp->type, len);
} }
#endif /* CONFIG_NET_ICMP && CONFIG_NET_ICMP_SOCKET */ #endif /* CONFIG_NET_ICMP && CONFIG_NET_ICMP_SOCKET */

View File

@ -1,7 +1,7 @@
/**************************************************************************** /****************************************************************************
* net/utils/net_ipchksum.c * 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. * rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org> * Author: Gregory Nutt <gnutt@nuttx.org>
* *
@ -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; FAR struct ipv4_hdr_s *ipv4 = IPv4BUF;
uint16_t upperlen; uint16_t upperlen;
uint16_t iphdrlen;
uint16_t sum; 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 /* 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 * 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. * 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 */ /* 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 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); return (sum == 0) ? 0xffff : htons(sum);
} }
#endif /* CONFIG_NET_ARCH_CHKSUM */ #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) #if defined(CONFIG_NET_IPv4) && !defined(CONFIG_NET_ARCH_CHKSUM)
uint16_t ipv4_chksum(FAR struct net_driver_s *dev) uint16_t ipv4_chksum(FAR struct net_driver_s *dev)
{ {
FAR struct ipv4_hdr_s *ipv4 = IPv4BUF;
uint16_t iphdrlen;
uint16_t sum; 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); return (sum == 0) ? 0xffff : htons(sum);
} }
#endif /* CONFIG_NET_ARCH_CHKSUM */ #endif /* CONFIG_NET_ARCH_CHKSUM */