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; /* " " "" " " " " " " " " */
};
/* 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.
*/

View File

@ -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 <gnutt@nuttx.org>
*
* 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

View File

@ -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

View File

@ -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 <gnutt@nuttx.org>
*
@ -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
{

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 <gnutt@nuttx.org>
*
* 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;

View File

@ -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 */

View File

@ -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;

View File

@ -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 <gnutt@nuttx.org>
*
* 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

View File

@ -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 <gnutt@nuttx.org>
*
* 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

View File

@ -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 */

View File

@ -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 <gnutt@nuttx.org>
*
@ -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 */