net/: Now handles reception of IPv4 packets with larger IPv4 headers containing options.
This commit is contained in:
parent
9bdde04636
commit
a52ceac13e
@ -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.
|
||||
*/
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user