mirror of
https://github.com/apache/nuttx.git
synced 2026-05-20 12:33:27 +08:00
Support fragmentation and reassembly
Signed-off-by: luojun1 <luojun1@xiaomi.com>
This commit is contained in:
@@ -114,6 +114,11 @@
|
||||
#define ICMP_PREC_CUTOFF 15 /* Precedence cut off */
|
||||
#define NR_ICMP_UNREACH 15 /* instead of hardcoding immediate value */
|
||||
|
||||
/* Codes for TIME_EXCEEDED. */
|
||||
|
||||
#define ICMP_EXC_TTL 0 /* TTL count exceeded */
|
||||
#define ICMP_EXC_FRAGTIME 1 /* Fragment Reassembly time exceeded */
|
||||
|
||||
/****************************************************************************
|
||||
* Public Type Definitions
|
||||
****************************************************************************/
|
||||
|
||||
@@ -141,6 +141,11 @@
|
||||
#define ICMPv6_POLICY_FAIL 5
|
||||
#define ICMPv6_REJECT_ROUTE 6
|
||||
|
||||
/* Codes for Time Exceeded */
|
||||
|
||||
#define ICMPV6_EXC_HOPLIMIT 0
|
||||
#define ICMPV6_EXC_FRAGTIME 1
|
||||
|
||||
/****************************************************************************
|
||||
* Public Type Definitions
|
||||
****************************************************************************/
|
||||
|
||||
@@ -217,6 +217,8 @@ struct ipv6_stats_s
|
||||
net_stats_t sent; /* Number of sent packets at the IP layer */
|
||||
net_stats_t vhlerr; /* Number of packets dropped due to wrong
|
||||
* IP version or header length */
|
||||
net_stats_t fragerr; /* Number of packets dropped since they
|
||||
* were IP fragments */
|
||||
net_stats_t protoerr; /* Number of packets dropped since they
|
||||
* were neither ICMP, UDP nor TCP */
|
||||
};
|
||||
|
||||
@@ -124,6 +124,14 @@
|
||||
|
||||
#define EXTHDR_LEN(hdrlen) ((hdrlen + 1) << 3)
|
||||
|
||||
/* Fragment header has no length field and has a fixed size */
|
||||
|
||||
#define EXTHDR_FRAG_LEN 8
|
||||
|
||||
/* More frags flag bits in 16-bit flags in fragment header */
|
||||
|
||||
#define FRAGHDR_FRAG_MOREFRAGS 0x0001
|
||||
|
||||
/* Values of the Two High-Order Bits in the Hop-to-hop Option Type Field */
|
||||
|
||||
#define HOPBYHOP_TYPE_MASK 0xc0
|
||||
@@ -217,4 +225,24 @@ struct ipv6_router_alert_s
|
||||
uint8_t pad[4]; /* Pad to a multiple of 8 bytes */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ipv6_exthdr
|
||||
*
|
||||
* Description:
|
||||
* Check whether it is an IPv6 extension header.
|
||||
*
|
||||
* Input Parameters:
|
||||
* The next header value extracted from an IPv6 frame.
|
||||
*
|
||||
* Returned Value:
|
||||
* Return true if the next header value is an IPv6 extension header.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
bool ipv6_exthdr(uint8_t nxthdr);
|
||||
|
||||
#endif /* __INCLUDE_NUTTX_NET_IPV6EXT_H */
|
||||
|
||||
@@ -320,6 +320,12 @@ struct net_driver_s
|
||||
|
||||
FAR struct iob_s *d_iob;
|
||||
|
||||
/* Remember the outgoing fragments waiting to be sent */
|
||||
|
||||
#ifdef CONFIG_NET_IPFRAG
|
||||
FAR struct iob_queue_s d_fragout;
|
||||
#endif
|
||||
|
||||
/* The d_buf array is used to hold incoming and outgoing packets. The
|
||||
* device driver should place incoming data into this buffer. When sending
|
||||
* data, the device driver should read the link level headers and the
|
||||
|
||||
@@ -331,6 +331,7 @@ source "net/sixlowpan/Kconfig"
|
||||
source "net/ipforward/Kconfig"
|
||||
source "net/nat/Kconfig"
|
||||
source "net/netfilter/Kconfig"
|
||||
source "net/ipfrag/Kconfig"
|
||||
|
||||
endmenu # Internet Protocol Selection
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ NET_CSRCS = net_initialize.c
|
||||
|
||||
include socket/Make.defs
|
||||
include inet/Make.defs
|
||||
include ipfrag/Make.defs
|
||||
include netdev/Make.defs
|
||||
include arp/Make.defs
|
||||
include icmp/Make.defs
|
||||
|
||||
@@ -11,6 +11,7 @@ Directory Structure
|
||||
+- arp - Address resolution protocol (IPv4)
|
||||
+- bluetooth - PF_BLUETOOTH socket interface
|
||||
+- devif - Stack/device interface layer
|
||||
+- ipfrag - Fragmentation and reassembly
|
||||
+- icmp - Internet Control Message Protocol (IPv4)
|
||||
+- icmpv6 - Internet Control Message Protocol (IPv6)
|
||||
+- ieee802154 - PF_IEEE802154 socket interface
|
||||
|
||||
@@ -511,6 +511,21 @@ void devif_out(FAR struct net_driver_s *dev);
|
||||
int devif_poll_out(FAR struct net_driver_s *dev,
|
||||
devif_poll_callback_t callback);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: devif_is_loopback
|
||||
*
|
||||
* Description:
|
||||
* The function checks the destination address of the packet to see
|
||||
* whether the target of packet is ourself.
|
||||
*
|
||||
* Returned Value:
|
||||
* true is returned if the packet need loop back to ourself, otherwise
|
||||
* false is returned.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
bool devif_is_loopback(FAR struct net_driver_s *dev);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: devif_loopback
|
||||
*
|
||||
|
||||
@@ -56,19 +56,29 @@ void devif_iob_send(FAR struct net_driver_s *dev, FAR struct iob_s *iob,
|
||||
unsigned int len, unsigned int offset,
|
||||
unsigned int target_offset)
|
||||
{
|
||||
#ifndef CONFIG_NET_IPFRAG
|
||||
unsigned int limit = NETDEV_PKTSIZE(dev) -
|
||||
NET_LL_HDRLEN(dev) - target_offset;
|
||||
#endif
|
||||
int ret;
|
||||
|
||||
#ifndef CONFIG_NET_IPFRAG
|
||||
if (dev == NULL || len == 0 || len > limit)
|
||||
#else
|
||||
if (dev == NULL || len == 0)
|
||||
#endif
|
||||
{
|
||||
if (dev->d_iob == NULL)
|
||||
{
|
||||
iob_free_chain(iob);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_NET_IPFRAG
|
||||
nerr("devif_iob_send error, %p, send len: %u, limit len: %u\n",
|
||||
dev, len, limit);
|
||||
#else
|
||||
nerr("devif_iob_send error, %p, send len: %u\n", dev, len);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,10 +32,23 @@
|
||||
#include <nuttx/net/netdev.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
static bool is_loopback(FAR struct net_driver_s *dev)
|
||||
/****************************************************************************
|
||||
* Name: devif_is_loopback
|
||||
*
|
||||
* Description:
|
||||
* The function checks the destination address of the packet to see
|
||||
* whether the target of packet is ourself.
|
||||
*
|
||||
* Returned Value:
|
||||
* true is returned if the packet need loop back to ourself, otherwise
|
||||
* false is returned.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
bool devif_is_loopback(FAR struct net_driver_s *dev)
|
||||
{
|
||||
if (dev->d_len > 0)
|
||||
{
|
||||
@@ -76,7 +89,7 @@ static bool is_loopback(FAR struct net_driver_s *dev)
|
||||
|
||||
int devif_loopback(FAR struct net_driver_s *dev)
|
||||
{
|
||||
if (!is_loopback(dev))
|
||||
if (!devif_is_loopback(dev))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
+99
-3
@@ -33,6 +33,7 @@
|
||||
#include <nuttx/net/net.h>
|
||||
|
||||
#include "devif/devif.h"
|
||||
#include "netdev/netdev.h"
|
||||
#include "arp/arp.h"
|
||||
#include "can/can.h"
|
||||
#include "tcp/tcp.h"
|
||||
@@ -46,6 +47,7 @@
|
||||
#include "mld/mld.h"
|
||||
#include "ipforward/ipforward.h"
|
||||
#include "sixlowpan/sixlowpan.h"
|
||||
#include "ipfrag/ipfrag.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
@@ -616,6 +618,79 @@ static inline int devif_poll_tcp_connections(FAR struct net_driver_s *dev,
|
||||
# define devif_poll_tcp_connections(dev, callback) (0)
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: devif_poll_ipfrag
|
||||
*
|
||||
* Description:
|
||||
* Poll all ip fragments for available packets to send.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - NIC Device instance.
|
||||
* callback - the actual sending API provided by each NIC driver.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero indicated the polling will continue, else stop the polling.
|
||||
*
|
||||
* Assumptions:
|
||||
* This function is called from the MAC device driver with the network
|
||||
* locked.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NET_IPFRAG
|
||||
static int devif_poll_ipfrag(FAR struct net_driver_s *dev,
|
||||
devif_poll_callback_t callback)
|
||||
{
|
||||
FAR struct iob_s *frag;
|
||||
bool reused = false;
|
||||
int bstop = false;
|
||||
|
||||
while (!bstop)
|
||||
{
|
||||
/* Dequeue outgoing fragment from dev->d_fragout */
|
||||
|
||||
frag = iob_remove_queue(&dev->d_fragout);
|
||||
if (frag == NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/* Frag buffer could be reused for other protocols */
|
||||
|
||||
reused = true;
|
||||
|
||||
/* Replace original iob */
|
||||
|
||||
netdev_iob_replace(dev, frag);
|
||||
|
||||
/* build L2 headers */
|
||||
|
||||
devif_out(dev);
|
||||
|
||||
/* Call back into the driver */
|
||||
|
||||
bstop = callback(dev);
|
||||
}
|
||||
|
||||
/* Notify the device driver that ip fragments is available. */
|
||||
|
||||
if (iob_peek_queue(&dev->d_fragout) != NULL)
|
||||
{
|
||||
netdev_txnotify_dev(dev);
|
||||
}
|
||||
|
||||
/* Reuse iob buffer */
|
||||
|
||||
if (!bstop && reused)
|
||||
{
|
||||
iob_update_pktlen(dev->d_iob, 0);
|
||||
netdev_iob_prepare(dev, true, 0);
|
||||
}
|
||||
|
||||
return bstop;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: devif_poll_connections
|
||||
*
|
||||
@@ -654,10 +729,19 @@ static int devif_poll_connections(FAR struct net_driver_s *dev,
|
||||
* action.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_NET_ARP_SEND
|
||||
/* Check for pending ARP requests */
|
||||
#ifdef CONFIG_NET_IPFRAG
|
||||
/* Traverse all of ip fragments for available packets to transfer */
|
||||
|
||||
bstop = devif_poll_ipfrag(dev, callback);
|
||||
if (!bstop)
|
||||
#endif
|
||||
#ifdef CONFIG_NET_ARP_SEND
|
||||
{
|
||||
/* Check for pending ARP requests */
|
||||
|
||||
bstop = arp_poll(dev, callback);
|
||||
}
|
||||
|
||||
bstop = arp_poll(dev, callback);
|
||||
if (!bstop)
|
||||
#endif
|
||||
#ifdef CONFIG_NET_PKT
|
||||
@@ -1048,6 +1132,18 @@ int devif_poll_out(FAR struct net_driver_s *dev,
|
||||
|
||||
if (callback)
|
||||
{
|
||||
#ifdef CONFIG_NET_IPFRAG
|
||||
if (ip_fragout(dev) != OK)
|
||||
{
|
||||
netdev_iob_release(dev);
|
||||
return 1;
|
||||
}
|
||||
else if (iob_peek_queue(&dev->d_fragout) != NULL)
|
||||
{
|
||||
return devif_poll_ipfrag(dev, callback);
|
||||
}
|
||||
#endif
|
||||
|
||||
return callback(dev);
|
||||
}
|
||||
|
||||
|
||||
@@ -105,6 +105,7 @@
|
||||
#include "ipforward/ipforward.h"
|
||||
#include "devif/devif.h"
|
||||
#include "nat/nat.h"
|
||||
#include "ipfrag/ipfrag.h"
|
||||
#include "utils/utils.h"
|
||||
|
||||
/****************************************************************************
|
||||
@@ -219,6 +220,13 @@ static int ipv4_in(FAR struct net_driver_s *dev)
|
||||
|
||||
if ((ipv4->ipoffset[0] & 0x3f) != 0 || ipv4->ipoffset[1] != 0)
|
||||
{
|
||||
#ifdef CONFIG_NET_IPFRAG
|
||||
if (ipv4_fragin(dev) == OK)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifdef CONFIG_NET_STATISTICS
|
||||
g_netstats.ipv4.drop++;
|
||||
g_netstats.ipv4.fragerr++;
|
||||
@@ -434,6 +442,11 @@ static int ipv4_in(FAR struct net_driver_s *dev)
|
||||
(defined(CONFIG_NET_BROADCAST) && defined(NET_UDP_HAVE_STACK))
|
||||
done:
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_IPFRAG
|
||||
ip_fragout(dev);
|
||||
#endif
|
||||
|
||||
devif_out(dev);
|
||||
|
||||
/* Return and let the caller do any pending transmission. */
|
||||
|
||||
+75
-32
@@ -51,6 +51,7 @@
|
||||
#include "ipforward/ipforward.h"
|
||||
#include "inet/inet.h"
|
||||
#include "devif/devif.h"
|
||||
#include "ipfrag/ipfrag.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
@@ -62,37 +63,6 @@
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ipv6_exthdr
|
||||
*
|
||||
* Description:
|
||||
* Return true if the next header value is an IPv6 extension header.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static bool ipv6_exthdr(uint8_t nxthdr)
|
||||
{
|
||||
switch (nxthdr)
|
||||
{
|
||||
case NEXT_HOPBYBOT_EH: /* Hop-by-Hop Options Header */
|
||||
case NEXT_ENCAP_EH: /* Encapsulated IPv6 Header */
|
||||
case NEXT_ROUTING_EH: /* Routing Header */
|
||||
case NEXT_FRAGMENT_EH: /* Fragment Header */
|
||||
case NEXT_RRSVP_EH: /* Resource ReSerVation Protocol */
|
||||
case NEXT_ENCAPSEC_EH: /* Encapsulating Security Payload */
|
||||
case NEXT_AUTH_EH: /* Authentication Header */
|
||||
case NEXT_DESTOPT_EH: /* Destination Options Header */
|
||||
case NEXT_MOBILITY_EH: /* Mobility */
|
||||
case NEXT_HOSTID_EH: /* Host Identity Protocol */
|
||||
case NEXT_SHIM6_EH: /* Shim6 Protocol */
|
||||
return true;
|
||||
|
||||
case NEXT_NOHEADER: /* No next header */
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: check_dev_destipaddr
|
||||
*
|
||||
@@ -228,6 +198,9 @@ static int ipv6_in(FAR struct net_driver_s *dev)
|
||||
#ifdef CONFIG_NET_IPFORWARD
|
||||
int ret;
|
||||
#endif
|
||||
#ifdef CONFIG_NET_IPFRAG
|
||||
bool isfrag = false;
|
||||
#endif
|
||||
|
||||
/* This is where the input processing starts. */
|
||||
|
||||
@@ -312,7 +285,18 @@ static int ipv6_in(FAR struct net_driver_s *dev)
|
||||
/* Just skip over the extension header */
|
||||
|
||||
exthdr = (FAR struct ipv6_extension_s *)payload;
|
||||
extlen = EXTHDR_LEN((unsigned int)exthdr->len);
|
||||
if (nxthdr == NEXT_FRAGMENT_EH)
|
||||
{
|
||||
extlen = EXTHDR_FRAG_LEN;
|
||||
#ifdef CONFIG_NET_IPFRAG
|
||||
isfrag = true;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
extlen = EXTHDR_LEN((unsigned int)exthdr->len);
|
||||
}
|
||||
|
||||
payload += extlen;
|
||||
iphdrlen += extlen;
|
||||
nxthdr = exthdr->nxthdr;
|
||||
@@ -418,6 +402,23 @@ static int ipv6_in(FAR struct net_driver_s *dev)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_IPFRAG
|
||||
if (isfrag)
|
||||
{
|
||||
if (ipv6_fragin(dev) == OK)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef CONFIG_NET_STATISTICS
|
||||
g_netstats.ipv6.fragerr++;
|
||||
#endif
|
||||
goto drop;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Now process the incoming packet according to the protocol specified in
|
||||
* the next header IPv6 field.
|
||||
*/
|
||||
@@ -519,6 +520,11 @@ static int ipv6_in(FAR struct net_driver_s *dev)
|
||||
#ifdef CONFIG_NET_IPFORWARD
|
||||
done:
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_IPFRAG
|
||||
ip_fragout(dev);
|
||||
#endif
|
||||
|
||||
devif_out(dev);
|
||||
|
||||
/* Return and let the caller do any pending transmission. */
|
||||
@@ -541,6 +547,43 @@ drop:
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ipv6_exthdr
|
||||
*
|
||||
* Description:
|
||||
* Check whether it is an IPv6 extension header.
|
||||
*
|
||||
* Input Parameters:
|
||||
* The next header value extracted from an IPv6 frame.
|
||||
*
|
||||
* Returned Value:
|
||||
* Return true if the next header value is an IPv6 extension header.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
bool ipv6_exthdr(uint8_t nxthdr)
|
||||
{
|
||||
switch (nxthdr)
|
||||
{
|
||||
case NEXT_HOPBYBOT_EH: /* Hop-by-Hop Options Header */
|
||||
case NEXT_ENCAP_EH: /* Encapsulated IPv6 Header */
|
||||
case NEXT_ROUTING_EH: /* Routing Header */
|
||||
case NEXT_FRAGMENT_EH: /* Fragment Header */
|
||||
case NEXT_RRSVP_EH: /* Resource ReSerVation Protocol */
|
||||
case NEXT_ENCAPSEC_EH: /* Encapsulating Security Payload */
|
||||
case NEXT_AUTH_EH: /* Authentication Header */
|
||||
case NEXT_DESTOPT_EH: /* Destination Options Header */
|
||||
case NEXT_MOBILITY_EH: /* Mobility */
|
||||
case NEXT_HOSTID_EH: /* Host Identity Protocol */
|
||||
case NEXT_SHIM6_EH: /* Shim6 Protocol */
|
||||
return true;
|
||||
|
||||
case NEXT_NOHEADER: /* No next header */
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ipv6_input
|
||||
*
|
||||
|
||||
@@ -321,6 +321,7 @@ ssize_t icmp_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg,
|
||||
goto errout;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_NET_IPFRAG
|
||||
/* Sanity check if the request len is greater than the net payload len */
|
||||
|
||||
if (len > NETDEV_PKTSIZE(dev) - (NET_LL_HDRLEN(dev) + IPv4_HDRLEN))
|
||||
@@ -328,6 +329,7 @@ ssize_t icmp_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg,
|
||||
nerr("ERROR: Invalid packet length\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If we are no longer processing the same ping ID, then flush any pending
|
||||
* packets from the read-ahead buffer.
|
||||
|
||||
@@ -308,6 +308,7 @@ ssize_t icmpv6_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg,
|
||||
goto errout;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_NET_IPFRAG
|
||||
/* Sanity check if the request len is greater than the net payload len */
|
||||
|
||||
if (len > NETDEV_PKTSIZE(dev) - (NET_LL_HDRLEN(dev) + IPv6_HDRLEN))
|
||||
@@ -315,6 +316,7 @@ ssize_t icmpv6_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg,
|
||||
nerr("ERROR: Invalid packet length\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If we are no longer processing the same ping ID, then flush any pending
|
||||
* packets from the read-ahead buffer.
|
||||
|
||||
@@ -214,11 +214,15 @@ static int ipv4_dev_forward(FAR struct net_driver_s *dev,
|
||||
#endif
|
||||
int ret;
|
||||
|
||||
/* Verify that the full packet will fit within the forwarding devices MTU.
|
||||
* We provide no support for fragmenting forwarded packets.
|
||||
/* Verify that the full packet will fit within the forwarding device's MTU
|
||||
* if DF is set.
|
||||
*/
|
||||
|
||||
if (NET_LL_HDRLEN(fwddev) + dev->d_len > NETDEV_PKTSIZE(fwddev))
|
||||
if (NET_LL_HDRLEN(fwddev) + dev->d_len > NETDEV_PKTSIZE(fwddev)
|
||||
#ifdef CONFIG_NET_IPFRAG
|
||||
&& (ipv4->ipoffset[0] & (IP_FLAG_DONTFRAG >> 8))
|
||||
#endif
|
||||
)
|
||||
{
|
||||
nwarn("WARNING: Packet > MTU... Dropping\n");
|
||||
ret = -EFBIG;
|
||||
@@ -490,7 +494,7 @@ drop:
|
||||
|
||||
case -EMULTIHOP:
|
||||
icmp_reply_type = ICMP_TIME_EXCEEDED;
|
||||
icmp_reply_code = 0;
|
||||
icmp_reply_code = ICMP_EXC_TTL;
|
||||
goto reply;
|
||||
|
||||
default:
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/mm/iob.h>
|
||||
#include <nuttx/net/ipv6ext.h>
|
||||
#include <nuttx/net/net.h>
|
||||
#include <nuttx/net/netdev.h>
|
||||
#include <nuttx/net/netstats.h>
|
||||
@@ -106,6 +107,12 @@ static int ipv6_hdrsize(FAR struct ipv6_hdr_s *ipv6)
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_IPFRAG
|
||||
case NEXT_FRAGMENT_EH:
|
||||
return IPv6_HDRLEN + EXTHDR_FRAG_LEN;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
nwarn("WARNING: Unrecognized proto: %u\n", ipv6->proto);
|
||||
return -EPROTONOSUPPORT;
|
||||
@@ -636,7 +643,8 @@ drop:
|
||||
return OK;
|
||||
|
||||
case -EMULTIHOP:
|
||||
icmpv6_reply(dev, ICMPv6_PACKET_TIME_EXCEEDED, 0, 0);
|
||||
icmpv6_reply(dev, ICMPv6_PACKET_TIME_EXCEEDED, ICMPV6_EXC_HOPLIMIT,
|
||||
0);
|
||||
return OK;
|
||||
|
||||
default:
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
#
|
||||
# For a description of the syntax of this configuration file,
|
||||
# see the file kconfig-language.txt in the NuttX tools repository.
|
||||
#
|
||||
|
||||
config NET_IPFRAG
|
||||
bool "IP fragmentation support"
|
||||
default n
|
||||
depends on (NET_IPv4 || NET_IPv6)
|
||||
---help---
|
||||
Enable support IP packet fragmentation and IP packet reassembly of
|
||||
fragmented IP packets.
|
||||
|
||||
if NET_IPFRAG
|
||||
|
||||
config NET_IPFRAG_REASS_MAXAGE
|
||||
int "IP fragmentation timeout"
|
||||
default 20
|
||||
---help---
|
||||
The maximum time an IP fragment should wait in the reassembly buffer
|
||||
before it is dropped. Units are deci-seconds. Default: 2 seconds.
|
||||
|
||||
endif # NET_IPFRAG
|
||||
Executable
+40
@@ -0,0 +1,40 @@
|
||||
############################################################################
|
||||
# net/ipfrag/Make.defs
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership. The
|
||||
# ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance with the
|
||||
# License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
ifeq ($(CONFIG_NET_IPFRAG),y)
|
||||
|
||||
# fragment processing source files
|
||||
|
||||
NET_CSRCS += ipfrag.c
|
||||
|
||||
ifeq ($(CONFIG_NET_IPv4),y)
|
||||
NET_CSRCS += ipv4_frag.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_NET_IPv6),y)
|
||||
NET_CSRCS += ipv6_frag.c
|
||||
endif
|
||||
|
||||
# Include fragment build support
|
||||
|
||||
DEPPATH += --dep-path ipfrag
|
||||
VPATH += :ipfrag
|
||||
|
||||
endif # CONFIG_NET_IPFRAG
|
||||
Executable
+1283
File diff suppressed because it is too large
Load Diff
Executable
+388
@@ -0,0 +1,388 @@
|
||||
/****************************************************************************
|
||||
* net/ipfrag/ipfrag.h
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __NET_IPFRAG_IPFRAG_H
|
||||
#define __NET_IPFRAG_IPFRAG_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <nuttx/mutex.h>
|
||||
#include <nuttx/queue.h>
|
||||
#include <nuttx/mm/iob.h>
|
||||
#include <nuttx/net/ip.h>
|
||||
#include <nuttx/net/net.h>
|
||||
#include <nuttx/net/netdev.h>
|
||||
|
||||
#include "devif/devif.h"
|
||||
|
||||
#if defined(CONFIG_NET_IPFRAG)
|
||||
|
||||
/****************************************************************************
|
||||
* Public types
|
||||
****************************************************************************/
|
||||
|
||||
enum ip_fragverify_e
|
||||
{
|
||||
/* Indicates whether received all fragments */
|
||||
|
||||
IP_FRAGVERIFY_RECVDALLFRAGS = 0x01 << 0,
|
||||
|
||||
/* Indicates whether received the first fragment which is used to:
|
||||
* 1.construct the ICMP time exceeded msg(type=11, code=1) when reassembly
|
||||
* timeout, but if the first fragment has not been received when timeout,
|
||||
* no ICMP error message will be sent;
|
||||
* 2.build NAT entry with the L4 port number and do forwarding.
|
||||
*/
|
||||
|
||||
IP_FRAGVERIFY_RECVDZEROFRAG = 0x01 << 1,
|
||||
|
||||
/* Indicates whether the tail fragment is received(which morefrag flag is
|
||||
* set to 0)
|
||||
*/
|
||||
|
||||
IP_FRAGVERIFY_RECVDTAILFRAG = 0x01 << 2,
|
||||
};
|
||||
|
||||
struct ip_fraglink_s
|
||||
{
|
||||
/* This link is used to maintain a single-linked list of ip_fraglink_s,
|
||||
* it links all framgents with the same IP ID
|
||||
*/
|
||||
|
||||
FAR struct ip_fraglink_s *flink;
|
||||
|
||||
FAR struct ip_fragsnode_s *fragsnode; /* Point to parent struct */
|
||||
FAR struct iob_s *frag; /* Point to fragment data */
|
||||
uint8_t isipv4; /* IPv4 or IPv6 */
|
||||
uint16_t fragoff; /* Fragment offset */
|
||||
uint16_t fraglen; /* Payload length */
|
||||
uint16_t morefrags; /* The more frag flag */
|
||||
|
||||
/* The identification field is 16 bits in IPv4 header but 32 bits in IPv6
|
||||
* fragment header
|
||||
*/
|
||||
|
||||
uint32_t ipid;
|
||||
};
|
||||
|
||||
struct ip_fragsnode_s
|
||||
{
|
||||
/* This link is used to maintain a single-linked list of ip_fragsnode_s.
|
||||
* Must be the first field in the structure due to flink type casting.
|
||||
*/
|
||||
|
||||
FAR struct ip_fragsnode_s *flink;
|
||||
|
||||
/* Another link which connects all ip_fragsnode_s in order of addition
|
||||
* time
|
||||
*/
|
||||
|
||||
FAR sq_entry_t *flinkat;
|
||||
|
||||
/* Interface understood by the network */
|
||||
|
||||
FAR struct net_driver_s *dev;
|
||||
|
||||
/* IP Identification (IP ID) field defined in ipv4 header or in ipv6
|
||||
* fragment header.
|
||||
*/
|
||||
|
||||
uint32_t ipid;
|
||||
|
||||
/* Count ticks, used by ressembly timer */
|
||||
|
||||
clock_t tick;
|
||||
|
||||
/* Remember some running flags */
|
||||
|
||||
uint16_t verifyflag;
|
||||
|
||||
/* Remember the total number of I/O buffers of this node */
|
||||
|
||||
uint32_t bufcnt;
|
||||
|
||||
/* Linked all fragments with the same IP ID. */
|
||||
|
||||
FAR struct ip_fraglink_s *frags;
|
||||
|
||||
/* Points to the reassembled outgoing IP frame */
|
||||
|
||||
FAR struct iob_s *outgoframe;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
# define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
# define EXTERN extern
|
||||
#endif
|
||||
|
||||
/* Only one thread can access g_assemblyhead_ipid and g_assemblyhead_time
|
||||
* at a time
|
||||
*/
|
||||
|
||||
extern mutex_t g_ipfrag_lock;
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ip_frag_remnode
|
||||
*
|
||||
* Description:
|
||||
* free ip_fragsnode_s
|
||||
*
|
||||
* Input Parameters:
|
||||
* node - node of the upper-level linked list, it maintains
|
||||
* information about all fragments belonging to an IP datagram
|
||||
*
|
||||
* Returned Value:
|
||||
* I/O buffer count of this node
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
uint32_t ip_frag_remnode(FAR struct ip_fragsnode_s *node);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ip_fragin_enqueue
|
||||
*
|
||||
* Description:
|
||||
* Enqueue one fragment.
|
||||
* All fragments belonging to one IP frame are organized in a linked list
|
||||
* form, that is a ip_fragsnode_s node. All ip_fragsnode_s nodes are also
|
||||
* organized in an upper-level linked list.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - NIC Device instance
|
||||
* curfraglink - node of the lower-level linked list, it maintains
|
||||
* information of one fragment
|
||||
*
|
||||
* Returned Value:
|
||||
* Whether queue is empty before enqueue the new node
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
bool ip_fragin_enqueue(FAR struct net_driver_s *dev,
|
||||
FAR struct ip_fraglink_s *curfraglink);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ipv4_fragin
|
||||
*
|
||||
* Description:
|
||||
* Handling incoming IPv4 fragment input, the input data
|
||||
* (dev->d_iob) can be an I/O buffer chain
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - The NIC device that the fragmented data comes from
|
||||
*
|
||||
* Returned Value:
|
||||
* ENOMEM - No memory
|
||||
* OK - The input fragment is processed as expected
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int32_t ipv4_fragin(FAR struct net_driver_s *dev);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ipv6_fragin
|
||||
*
|
||||
* Description:
|
||||
* Handling incoming IPv6 fragment input, the input data
|
||||
* (dev->d_iob) can be an I/O buffer chain
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - The NIC device that the fragmented data comes from
|
||||
*
|
||||
* Returned Value:
|
||||
* ENOMEM - No memory
|
||||
* OK - The input fragment is processed as expected
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int32_t ipv6_fragin(FAR struct net_driver_s *dev);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ip_fragout_slice
|
||||
*
|
||||
* Description:
|
||||
* According to the MTU of a given NIC, split the original data into
|
||||
* multiple data pieces, and the space for filling the L3 header is
|
||||
* reserved at the forefront of each piece. Each piece is stored in
|
||||
* independent I/O buffer(s) and eventually forms an I/O buffer queue.
|
||||
* Note:
|
||||
* 1.About the 'piece' above
|
||||
* 1).If MTU < CONFIG_IOB_BUFSIZE, a piece consists of an I/O buffer;
|
||||
* 2).If MTU >= CONFIG_IOB_BUFSIZE, a piece consists of multiple I/O
|
||||
* buffers.
|
||||
* 2.This function split and gathers the incoming data into outgoing
|
||||
* I/O buffers according to the MTU, but is not responsible for
|
||||
* building the L3 header related to the fragmentation.
|
||||
*
|
||||
* Input Parameters:
|
||||
* iob - The data comes from
|
||||
* domain - PF_INET or PF_INET6
|
||||
* mtu - MTU of given NIC
|
||||
* unfraglen - The starting position to fragmentation processing
|
||||
* fragq - Those output slices
|
||||
*
|
||||
* Returned Value:
|
||||
* Number of fragments
|
||||
*
|
||||
* Assumptions:
|
||||
* Data length(iob->io_pktlen) is grater than the MTU of current NIC
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int32_t ip_fragout_slice(FAR struct iob_s *iob, uint8_t domain, uint16_t mtu,
|
||||
uint16_t unfraglen, FAR struct iob_queue_s *fragq);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ipv4_fragout
|
||||
*
|
||||
* Description:
|
||||
* Execute the ipv4 fragment function. After this work is done, all
|
||||
* fragments are maintained by dev->d_fragout. In order to reduce the
|
||||
* cyclomatic complexity and facilitate maintenance, fragmentation is
|
||||
* performed in two steps:
|
||||
* 1. Reconstruct I/O Buffer according to MTU, which will reserve
|
||||
* the space for the L3 header;
|
||||
* 2. Fill the L3 header into the reserved space.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - The NIC device
|
||||
* mtu - The MTU of current NIC
|
||||
*
|
||||
* Returned Value:
|
||||
* 0 if success or a negative value if fail.
|
||||
*
|
||||
* Assumptions:
|
||||
* Data length(dev->d_iob->io_pktlen) is grater than the MTU of
|
||||
* current NIC
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int32_t ipv4_fragout(FAR struct net_driver_s *dev, uint16_t mtu);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ipv6_fragout
|
||||
*
|
||||
* Description:
|
||||
* Execute the ipv6 fragment function. After this work is done, all
|
||||
* fragments are maintained by dev->d_fragout. In order to reduce the
|
||||
* cyclomatic complexity and facilitate maintenance, fragmentation is
|
||||
* performed in two steps:
|
||||
* 1. Reconstruct I/O Buffer according to MTU, which will reserve
|
||||
* the space for the L3 header;
|
||||
* 2. Fill the L3 header into the reserved space.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - The NIC device
|
||||
* mtu - The MTU of current NIC
|
||||
*
|
||||
* Returned Value:
|
||||
* 0 if success or a negative value if fail.
|
||||
*
|
||||
* Assumptions:
|
||||
* Data length(dev->d_iob->io_pktlen) is grater than the MTU of
|
||||
* current NIC
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int32_t ipv6_fragout(FAR struct net_driver_s *dev, uint16_t mtu);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ip_frag_startwdog
|
||||
*
|
||||
* Description:
|
||||
* Start the reassembly timeout timer
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void ip_frag_startwdog(void);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ip_frag_stop
|
||||
*
|
||||
* Description:
|
||||
* Stop the fragment process function for the specified NIC.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - NIC Device instance which will be bring down
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void ip_frag_stop(FAR struct net_driver_s *dev);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ip_frag_remallfrags
|
||||
*
|
||||
* Description:
|
||||
* Release all I/O Buffers used by fragment processing module when
|
||||
* I/O Buffer resources are exhausted.
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void ip_frag_remallfrags(void);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ip_fragout
|
||||
*
|
||||
* Description:
|
||||
* Fragout processing
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - The NIC device
|
||||
*
|
||||
* Returned Value:
|
||||
* A non-negative value is returned on success; negative value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int32_t ip_fragout(FAR struct net_driver_s *dev);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_NET_IPFRAG */
|
||||
#endif /* __NET_IPFRAG_IPFRAG_H */
|
||||
Executable
+443
@@ -0,0 +1,443 @@
|
||||
/****************************************************************************
|
||||
* net/ipfrag/ipv4_frag.c
|
||||
* Handling incoming IPv4 fragment input
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#if defined(CONFIG_NET_IPv4) && defined (CONFIG_NET_IPFRAG)
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <debug.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <netinet/in.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <nuttx/net/netconfig.h>
|
||||
#include <nuttx/net/netdev.h>
|
||||
#include <nuttx/net/netstats.h>
|
||||
#include <nuttx/net/ip.h>
|
||||
|
||||
#include "netdev/netdev.h"
|
||||
#include "inet/inet.h"
|
||||
#include "utils/utils.h"
|
||||
#include "ipfrag.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static inline int32_t
|
||||
ipv4_fragin_getinfo(FAR struct iob_s *iob,
|
||||
FAR struct ip_fraglink_s *fraglink);
|
||||
static uint32_t ipv4_fragin_reassemble(FAR struct ip_fragsnode_s *node);
|
||||
static inline void
|
||||
ipv4_fragout_buildipv4header(FAR struct ipv4_hdr_s *ref,
|
||||
FAR struct ipv4_hdr_s *ipv4,
|
||||
uint16_t len, uint16_t ipoff);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ipv4_fragin_getinfo
|
||||
*
|
||||
* Description:
|
||||
* Polulate fragment information from the input ipv4 packet data.
|
||||
*
|
||||
* Input Parameters:
|
||||
* iob - An IPv4 fragment
|
||||
* fraglink - node of the lower-level linked list, it maintains information
|
||||
* of one fragment
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline int32_t
|
||||
ipv4_fragin_getinfo(FAR struct iob_s *iob,
|
||||
FAR struct ip_fraglink_s *fraglink)
|
||||
{
|
||||
FAR struct ipv4_hdr_s *ipv4 = (FAR struct ipv4_hdr_s *)
|
||||
(iob->io_data + iob->io_offset);
|
||||
uint16_t offset;
|
||||
|
||||
fraglink->flink = NULL;
|
||||
fraglink->fragsnode = NULL;
|
||||
fraglink->isipv4 = true;
|
||||
|
||||
offset = (ipv4->ipoffset[0] << 8) + ipv4->ipoffset[1];
|
||||
fraglink->morefrags = offset & IP_FLAG_MOREFRAGS;
|
||||
fraglink->fragoff = ((offset & 0x1fff) << 3);
|
||||
|
||||
fraglink->fraglen = (ipv4->len[0] << 8) + ipv4->len[1] - IPv4_HDRLEN;
|
||||
fraglink->ipid = (ipv4->ipid[0] << 8) + ipv4->ipid[1];
|
||||
fraglink->frag = iob;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ipv4_fragin_reassemble
|
||||
*
|
||||
* Description:
|
||||
* Reassemble all ipv4 fragments to build an IP frame.
|
||||
*
|
||||
* Input Parameters:
|
||||
* node - node of the upper-level linked list, it maintains
|
||||
* information about all fragments belonging to an IP datagram
|
||||
*
|
||||
* Returned Value:
|
||||
* The length of the reassembled IP frame
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static uint32_t ipv4_fragin_reassemble(FAR struct ip_fragsnode_s *node)
|
||||
{
|
||||
FAR struct iob_s *head;
|
||||
FAR struct ipv4_hdr_s *ipv4;
|
||||
FAR struct ip_fraglink_s *fraglink;
|
||||
|
||||
/* Loop to walk through the fragment list and reassemble those fragments,
|
||||
* the fraglink list was ordered by fragment offset value
|
||||
*/
|
||||
|
||||
fraglink = node->frags;
|
||||
node->frags = NULL;
|
||||
|
||||
while (fraglink != NULL)
|
||||
{
|
||||
FAR struct ip_fraglink_s *linknext;
|
||||
FAR struct iob_s *iob = fraglink->frag;
|
||||
|
||||
if (fraglink->fragoff != 0)
|
||||
{
|
||||
uint16_t iphdrlen;
|
||||
|
||||
/* Get IPv4 header length from IPv4 header (it may carry some
|
||||
* IPv4 options)
|
||||
*/
|
||||
|
||||
ipv4 = (FAR struct ipv4_hdr_s *)(head->io_data + head->io_offset);
|
||||
iphdrlen = (ipv4->vhl & IPv4_HLMASK) << 2;
|
||||
|
||||
/* Just modify the offset and length of all none zero fragments */
|
||||
|
||||
iob->io_offset += iphdrlen;
|
||||
iob->io_len -= iphdrlen;
|
||||
iob->io_pktlen -= iphdrlen;
|
||||
|
||||
/* Concatenate this iob to the reassembly chain */
|
||||
|
||||
iob_concat(head, iob);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Remember the head iob */
|
||||
|
||||
head = iob;
|
||||
}
|
||||
|
||||
linknext = fraglink->flink;
|
||||
kmm_free(fraglink);
|
||||
|
||||
fraglink = linknext;
|
||||
}
|
||||
|
||||
/* Remember the reassembled outgoing IP frame */
|
||||
|
||||
node->outgoframe = head;
|
||||
|
||||
/* Get pointer of the new IPv4 header */
|
||||
|
||||
ipv4 = (FAR struct ipv4_hdr_s *)(head->io_data + head->io_offset);
|
||||
|
||||
/* Update the length value in the IP Header */
|
||||
|
||||
ipv4->len[0] = head->io_pktlen >> 8;
|
||||
ipv4->len[1] = head->io_pktlen & 0xff;
|
||||
|
||||
/* Set ipoffset to zero */
|
||||
|
||||
ipv4->ipoffset[0] = 0;
|
||||
ipv4->ipoffset[1] = 0;
|
||||
|
||||
/* Calculate IP checksum. */
|
||||
|
||||
ipv4->ipchksum = 0;
|
||||
ipv4->ipchksum = ~(ipv4_chksum(ipv4));
|
||||
|
||||
return head->io_pktlen;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ipv4_fragout_buildipv4header
|
||||
*
|
||||
* Description:
|
||||
* Build IPv4 header for an IPv4 fragment.
|
||||
*
|
||||
* Input Parameters:
|
||||
* ref - The reference IPv4 Header
|
||||
* ipv4 - The pointer of the newly generated IPv4 Header
|
||||
* len - Total Length of this IP frame
|
||||
* ipoff - Fragment offset
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline void
|
||||
ipv4_fragout_buildipv4header(FAR struct ipv4_hdr_s *ref,
|
||||
FAR struct ipv4_hdr_s *ipv4,
|
||||
uint16_t len, uint16_t ipoff)
|
||||
{
|
||||
if (ref != ipv4)
|
||||
{
|
||||
uint32_t iphdrlen = (ref->vhl & IPv4_HLMASK) << 2;
|
||||
memcpy(ipv4, ref, iphdrlen);
|
||||
}
|
||||
|
||||
ipv4->len[0] = len >> 8;
|
||||
ipv4->len[1] = len & 0xff;
|
||||
|
||||
ipv4->ipoffset[0] = ipoff >> 8;
|
||||
ipv4->ipoffset[1] = ipoff & 0xff;
|
||||
|
||||
/* Calculate IP checksum. */
|
||||
|
||||
ipv4->ipchksum = 0;
|
||||
ipv4->ipchksum = ~(ipv4_chksum(ipv4));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ipv4_fragin
|
||||
*
|
||||
* Description:
|
||||
* Handling incoming IPv4 and IPv6 fragment input, the input data
|
||||
* (dev->d_iob) can be an I/O buffer chain
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - The NIC device that the fragmented data comes from
|
||||
*
|
||||
* Returned Value:
|
||||
* ENOMEM - No memory
|
||||
* OK - The input fragment is processed as expected
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int32_t ipv4_fragin(FAR struct net_driver_s *dev)
|
||||
{
|
||||
FAR struct ip_fragsnode_s *node;
|
||||
FAR struct ip_fraglink_s *fraginfo;
|
||||
bool restartwdog;
|
||||
|
||||
if (dev->d_len != dev->d_iob->io_pktlen)
|
||||
{
|
||||
nerr("ERROR: Parameters error.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fraginfo = kmm_malloc(sizeof(struct ip_fraglink_s));
|
||||
if (fraginfo == NULL)
|
||||
{
|
||||
nerr("ERROR: Failed to allocate buffer.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Polulate fragment information from input packet data */
|
||||
|
||||
ipv4_fragin_getinfo(dev->d_iob, fraginfo);
|
||||
|
||||
nxmutex_lock(&g_ipfrag_lock);
|
||||
|
||||
/* Need to restart reassembly worker if the original linked list is empty */
|
||||
|
||||
restartwdog = ip_fragin_enqueue(dev, fraginfo);
|
||||
|
||||
node = fraginfo->fragsnode;
|
||||
|
||||
if (node->verifyflag & IP_FRAGVERIFY_RECVDALLFRAGS)
|
||||
{
|
||||
/* Well, all fragments of an IP frame have been received, remove
|
||||
* node from link list first, then reassemble and dispatch to the
|
||||
* stack.
|
||||
*/
|
||||
|
||||
ip_frag_remnode(node);
|
||||
|
||||
/* All fragments belonging to one IP frame have been separated
|
||||
* from the fragment processing module, unlocks mutex as soon
|
||||
* as possible
|
||||
*/
|
||||
|
||||
nxmutex_unlock(&g_ipfrag_lock);
|
||||
|
||||
/* Reassemble fragments to one IP frame and set the resulting
|
||||
* IP frame to dev->d_iob
|
||||
*/
|
||||
|
||||
ipv4_fragin_reassemble(node);
|
||||
netdev_iob_replace(dev, node->outgoframe);
|
||||
|
||||
/* Free the memory of node */
|
||||
|
||||
kmm_free(node);
|
||||
|
||||
return ipv4_input(dev);
|
||||
}
|
||||
|
||||
nxmutex_unlock(&g_ipfrag_lock);
|
||||
|
||||
if (restartwdog)
|
||||
{
|
||||
/* Restart the work queue for fragment processing */
|
||||
|
||||
ip_frag_startwdog();
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ipv4_fragout
|
||||
*
|
||||
* Description:
|
||||
* Execute the ipv4 fragment function. After this work is done, all
|
||||
* fragments are maintained by dev->d_fragout. In order to reduce the
|
||||
* cyclomatic complexity and facilitate maintenance, fragmentation is
|
||||
* performed in two steps:
|
||||
* 1. Reconstruct I/O Buffer according to MTU, which will reserve
|
||||
* the space for the L3 header;
|
||||
* 2. Fill the L3 header into the reserved space.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - The NIC device
|
||||
* mtu - The MTU of current NIC
|
||||
*
|
||||
* Returned Value:
|
||||
* 0 if success or a negative value if fail.
|
||||
*
|
||||
* Assumptions:
|
||||
* Data length(dev->d_iob->io_pktlen) is grater than the MTU of
|
||||
* current NIC
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int32_t ipv4_fragout(FAR struct net_driver_s *dev, uint16_t mtu)
|
||||
{
|
||||
uint32_t iter;
|
||||
uint32_t nfrags;
|
||||
uint16_t offset = 0;
|
||||
uint16_t hdrlen;
|
||||
FAR struct iob_s *frag;
|
||||
FAR struct ipv4_hdr_s *ref;
|
||||
struct iob_queue_s fragq =
|
||||
{
|
||||
NULL, NULL
|
||||
};
|
||||
|
||||
/* Get the total length of L3 Header(if IPv4 options are present, then this
|
||||
* length includes the size of all the IPv4 options)
|
||||
*/
|
||||
|
||||
hdrlen = (IPv4BUF->vhl & IPv4_HLMASK) << 2;
|
||||
|
||||
/* Reconstruct I/O Buffer according to MTU, which will reserve
|
||||
* the space for the L3 header
|
||||
*/
|
||||
|
||||
nfrags = ip_fragout_slice(dev->d_iob, PF_INET, mtu, hdrlen, &fragq);
|
||||
assert(nfrags > 1);
|
||||
netdev_iob_clear(dev);
|
||||
|
||||
/* Fill the L3 header into the reserved space */
|
||||
|
||||
for (iter = 0; iter < nfrags; iter++)
|
||||
{
|
||||
frag = iob_remove_queue(&fragq);
|
||||
|
||||
if (iter == 0)
|
||||
{
|
||||
ref = (FAR struct ipv4_hdr_s *)(frag->io_data + frag->io_offset);
|
||||
|
||||
/* Update the IPv4 header of the first fragment */
|
||||
|
||||
ipv4_fragout_buildipv4header(ref, ref, frag->io_pktlen,
|
||||
IP_FLAG_MOREFRAGS);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint16_t ipoff = (offset - iter * hdrlen) >> 3;
|
||||
|
||||
if (iter < nfrags - 1)
|
||||
{
|
||||
ipoff |= IP_FLAG_MOREFRAGS;
|
||||
}
|
||||
|
||||
/* Refer to the zero fragment ipv4 header to construct the ipv4
|
||||
* header of non-zero fragment
|
||||
*/
|
||||
|
||||
ipv4_fragout_buildipv4header(ref,
|
||||
(FAR struct ipv4_hdr_s *)(frag->io_data + frag->io_offset),
|
||||
frag->io_pktlen, ipoff);
|
||||
}
|
||||
|
||||
/* Enqueue this fragment to dev->d_fragout */
|
||||
|
||||
if (iob_tryadd_queue(frag, &dev->d_fragout) < 0)
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
|
||||
offset += frag->io_pktlen;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NET_STATISTICS
|
||||
g_netstats.ipv4.sent += nfrags - 1;
|
||||
#endif
|
||||
|
||||
netdev_txnotify_dev(dev);
|
||||
|
||||
return OK;
|
||||
|
||||
fail:
|
||||
netdev_iob_release(dev);
|
||||
iob_free_chain(frag);
|
||||
iob_free_queue(&fragq);
|
||||
iob_free_queue(&dev->d_fragout);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NET_IPv4 && CONFIG_NET_IPFRAG */
|
||||
Executable
+670
File diff suppressed because it is too large
Load Diff
@@ -35,6 +35,7 @@
|
||||
#include <net/ethernet.h>
|
||||
#include <nuttx/net/netdev.h>
|
||||
|
||||
#include "ipfrag/ipfrag.h"
|
||||
#include "netdev/netdev.h"
|
||||
#include "netlink/netlink.h"
|
||||
#include "arp/arp.h"
|
||||
@@ -92,6 +93,12 @@ int netdev_carrier_off(FAR struct net_driver_s *dev)
|
||||
dev->d_flags &= ~IFF_RUNNING;
|
||||
netlink_device_notify(dev);
|
||||
|
||||
#ifdef CONFIG_NET_IPFRAG
|
||||
/* Clean up fragment data for this NIC (if any) */
|
||||
|
||||
ip_frag_stop(dev);
|
||||
#endif
|
||||
|
||||
/* Notify clients that the network has been taken down */
|
||||
|
||||
devif_dev_event(dev, NETDEV_DOWN);
|
||||
|
||||
Reference in New Issue
Block a user