6LoWPAN: TCP logic was not obeying MTU packet size limitations. Other TCP-specific issues also fixed. There remains a major outstanding issue with ACK handling.

This commit is contained in:
Gregory Nutt
2017-06-24 09:48:41 -06:00
parent fa1d95dee2
commit 2fb938202c
4 changed files with 204 additions and 113 deletions
+7 -7
View File
@@ -694,8 +694,8 @@ CONFIG_MM_REGIONS=1
# Common I/O Buffer Support # Common I/O Buffer Support
# #
CONFIG_MM_IOB=y CONFIG_MM_IOB=y
CONFIG_IOB_NBUFFERS=36 CONFIG_IOB_NBUFFERS=48
CONFIG_IOB_BUFSIZE=196 CONFIG_IOB_BUFSIZE=128
CONFIG_IOB_NCHAINS=8 CONFIG_IOB_NCHAINS=8
CONFIG_IOB_THROTTLE=8 CONFIG_IOB_THROTTLE=8
@@ -910,15 +910,15 @@ CONFIG_EXAMPLES_NETTEST_IPv6=y
# #
# Server IPv6 address # Server IPv6 address
# #
CONFIG_EXAMPLES_NETTEST_SERVERIPv6ADDR_1=0xfc00 CONFIG_EXAMPLES_NETTEST_SERVERIPv6ADDR_1=0xfe80
CONFIG_EXAMPLES_NETTEST_SERVERIPv6ADDR_2=0x0000 CONFIG_EXAMPLES_NETTEST_SERVERIPv6ADDR_2=0x0000
CONFIG_EXAMPLES_NETTEST_SERVERIPv6ADDR_3=0x0000 CONFIG_EXAMPLES_NETTEST_SERVERIPv6ADDR_3=0x0000
CONFIG_EXAMPLES_NETTEST_SERVERIPv6ADDR_4=0x0000 CONFIG_EXAMPLES_NETTEST_SERVERIPv6ADDR_4=0x0000
CONFIG_EXAMPLES_NETTEST_SERVERIPv6ADDR_5=0x0000 CONFIG_EXAMPLES_NETTEST_SERVERIPv6ADDR_5=0x0000
CONFIG_EXAMPLES_NETTEST_SERVERIPv6ADDR_6=0x0000 CONFIG_EXAMPLES_NETTEST_SERVERIPv6ADDR_6=0x00ff
CONFIG_EXAMPLES_NETTEST_SERVERIPv6ADDR_7=0x0000 CONFIG_EXAMPLES_NETTEST_SERVERIPv6ADDR_7=0xfe00
CONFIG_EXAMPLES_NETTEST_SERVERIPv6ADDR_8=0x0001 CONFIG_EXAMPLES_NETTEST_SERVERIPv6ADDR_8=0xcda9
CONFIG_EXAMPLES_NETTEST_SERVER_PORTNO=5471 CONFIG_EXAMPLES_NETTEST_SERVER_PORTNO=61616
# CONFIG_EXAMPLES_NRF24L01TERM is not set # CONFIG_EXAMPLES_NRF24L01TERM is not set
CONFIG_EXAMPLES_NSH=y CONFIG_EXAMPLES_NSH=y
# CONFIG_EXAMPLES_NULL is not set # CONFIG_EXAMPLES_NULL is not set
+1 -1
View File
@@ -170,7 +170,7 @@
# define SIXLOWPAN_IPHC_TC_00 0x00 /* ECN+DSCP+4-bit Pad+Flow Label (4 bytes) */ # define SIXLOWPAN_IPHC_TC_00 0x00 /* ECN+DSCP+4-bit Pad+Flow Label (4 bytes) */
# define SIXLOWPAN_IPHC_TC_01 0x08 /* ECN+2-bit Pad+ Flow Label (3 bytes), DSCP is elided. */ # define SIXLOWPAN_IPHC_TC_01 0x08 /* ECN+2-bit Pad+ Flow Label (3 bytes), DSCP is elided. */
# define SIXLOWPAN_IPHC_TC_10 0x10 /* ECN+DSCP (1 byte), Flow Label is elided */ # define SIXLOWPAN_IPHC_TC_10 0x10 /* ECN+DSCP (1 byte), Flow Label is elided */
# define SIXLOWPAN_IPHC_TC_11 0x11 /* Traffic Class and Flow Label are elided */ # define SIXLOWPAN_IPHC_TC_11 0x18 /* Traffic Class and Flow Label are elided */
#define SIXLOWPAN_IPHC_NH 0x04 /* Bit 5: Next Header Compressed */ #define SIXLOWPAN_IPHC_NH 0x04 /* Bit 5: Next Header Compressed */
#define SIXLOWPAN_IPHC_HLIM_MASK 0x03 /* Bits 6-7: Hop Limit */ #define SIXLOWPAN_IPHC_HLIM_MASK 0x03 /* Bits 6-7: Hop Limit */
# define SIXLOWPAN_IPHC_HLIM_INLINE 0x00 /* Carried in-line */ # define SIXLOWPAN_IPHC_HLIM_INLINE 0x00 /* Carried in-line */
+15 -12
View File
@@ -289,7 +289,13 @@ static void sixlowpan_uncompress_ipv6hdr(FAR uint8_t *fptr, FAR uint8_t *bptr)
* iob - The IOB containing the frame. * iob - The IOB containing the frame.
* *
* Returned Value: * Returned Value:
* Ok is returned on success; Othewise a negated errno value is returned. * On success, a value greater than equal to zero is returned, either:
*
* INPUT_PARTIAL Frame processed successful, packet incomplete
* INPUT_COMPLETE Frame processed successful, packet complete
*
* Othewise a negated errno value is returned to indicate the nature of the
* failure.
* *
* Assumptions: * Assumptions:
* Network is locked * Network is locked
@@ -323,11 +329,8 @@ static int sixlowpan_frame_process(FAR struct ieee802154_driver_s *ieee,
fptr = iob->io_data; /* Frame data is in I/O buffer */ fptr = iob->io_data; /* Frame data is in I/O buffer */
hdrsize = iob->io_offset; /* Offset past the MAC header */ hdrsize = iob->io_offset; /* Offset past the MAC header */
if (hdrsize < 0)
{ DEBUGASSERT((unsigned)hdrsize < iob->io_len);
nwarn("Invalid IEEE802.15.2 header: %d\n", hdrsize);
return hdrsize;
}
/* Initialize global data. Locking the network guarantees that we have /* Initialize global data. Locking the network guarantees that we have
* exclusive use of the global values for intermediate calculations. * exclusive use of the global values for intermediate calculations.
@@ -462,7 +465,7 @@ static int sixlowpan_frame_process(FAR struct ieee802154_driver_s *ieee,
nwarn("WARNING: Dropping 6LoWPAN packet that is not a fragment of " nwarn("WARNING: Dropping 6LoWPAN packet that is not a fragment of "
"the packet currently being reassembled\n"); "the packet currently being reassembled\n");
return INPUT_PARTIAL; return -EPERM;
} }
else else
{ {
@@ -488,7 +491,7 @@ static int sixlowpan_frame_process(FAR struct ieee802154_driver_s *ieee,
if (!isfirstfrag) if (!isfirstfrag)
{ {
nwarn("WARNING: FRAGN 6LoWPAN fragment while not reassembling\n"); nwarn("WARNING: FRAGN 6LoWPAN fragment while not reassembling\n");
return OK; return -EPERM;
} }
/* Drop the packet if it cannot fit into the d_buf */ /* Drop the packet if it cannot fit into the d_buf */
@@ -496,7 +499,7 @@ static int sixlowpan_frame_process(FAR struct ieee802154_driver_s *ieee,
if (fragsize > CONFIG_NET_6LOWPAN_MTU) if (fragsize > CONFIG_NET_6LOWPAN_MTU)
{ {
nwarn("WARNING: Reassembled packet size exeeds CONFIG_NET_6LOWPAN_MTU\n"); nwarn("WARNING: Reassembled packet size exeeds CONFIG_NET_6LOWPAN_MTU\n");
return OK; return -ENOSPC;
} }
ieee->i_pktlen = fragsize; ieee->i_pktlen = fragsize;
@@ -556,7 +559,7 @@ static int sixlowpan_frame_process(FAR struct ieee802154_driver_s *ieee,
/* Unknown or unsupported header */ /* Unknown or unsupported header */
nwarn("WARNING: Unknown dispatch: %u\n", hc1[SIXLOWPAN_HC1_DISPATCH]); nwarn("WARNING: Unknown dispatch: %u\n", hc1[SIXLOWPAN_HC1_DISPATCH]);
return OK; return -ENOSYS;
} }
#ifdef CONFIG_NET_6LOWPAN_FRAG #ifdef CONFIG_NET_6LOWPAN_FRAG
@@ -594,7 +597,7 @@ static int sixlowpan_frame_process(FAR struct ieee802154_driver_s *ieee,
{ {
nwarn("WARNING: Packet dropped due to payload (%u) > packet buffer (%u)\n", nwarn("WARNING: Packet dropped due to payload (%u) > packet buffer (%u)\n",
paysize, CONFIG_NET_6LOWPAN_MTU); paysize, CONFIG_NET_6LOWPAN_MTU);
return OK; return -ENOSPC;
} }
/* Sanity-check size of incoming packet to avoid buffer overflow */ /* Sanity-check size of incoming packet to avoid buffer overflow */
@@ -795,7 +798,7 @@ int sixlowpan_input(FAR struct ieee802154_driver_s *ieee,
* reassembled? * reassembled?
*/ */
if (ret == INPUT_COMPLETE) if (ret >= 0 && ret == INPUT_COMPLETE)
{ {
/* Inject the uncompressed, reassembled packet into the network */ /* Inject the uncompressed, reassembled packet into the network */
+181 -93
View File
@@ -131,6 +131,149 @@ static uint16_t sixlowpan_tcp_chksum(FAR struct ipv6tcp_hdr_s *ipv6tcp,
return (sum == 0) ? 0xffff : htons(sum); return (sum == 0) ? 0xffff : htons(sum);
} }
/****************************************************************************
* Name: sixlowpan_send_packet
*
* Description:
* sixlowpan_send_packet() will send one TCP packet, respecting the
* configured 6LoWPAN MTU.
*
* Parameters:
* conn - An instance of the TCP connection structure.
* dev - The network device that will route the packet
* buf - Data to send
* bulen - Length of data to send
* timeout - Send timeout value
*
* Returned Value:
* On success, returns the number of characters sent. On error, a
* negated errnot value. Returned error numbers must be consistent with
* definition of errors reported by send() or sendto().
*
* Assumptions:
* Called with the network locked.
*
****************************************************************************/
static ssize_t sixlowpan_send_packet(FAR struct tcp_conn_s *conn,
FAR struct net_driver_s *dev,
FAR const void *buf, size_t buflen,
uint16_t timeout)
{
struct sixlowpan_tagaddr_s destmac;
struct ipv6tcp_hdr_s ipv6tcp;
ssize_t pktlen;
uint16_t iplen;
int ret;
/* How much of the data can send in this packet? */
pktlen = buflen;
if ((buflen + IPv6_HDRLEN + TCP_HDRLEN) > CONFIG_NET_6LOWPAN_MTU)
{
pktlen = (CONFIG_NET_6LOWPAN_MTU - IPv6_HDRLEN - TCP_HDRLEN);
}
else
{
pktlen = buflen;
}
/* Initialize the IPv6/TCP headers */
ipv6tcp.ipv6.vtc = 0x60;
ipv6tcp.ipv6.tcf = 0x00;
ipv6tcp.ipv6.flow = 0x00;
ipv6tcp.ipv6.proto = IP_PROTO_TCP;
ipv6tcp.ipv6.ttl = IP_TTL;
/* The IPv6 header length field does not include the size of IPv6 IP
* header.
*/
iplen = pktlen + TCP_HDRLEN;
ipv6tcp.ipv6.len[0] = (iplen >> 8);
ipv6tcp.ipv6.len[1] = (iplen & 0xff);
/* Copy the source and destination addresses */
#ifdef CONFIG_NETDEV_MULTINIC
net_ipv6addr_hdrcopy(ipv6tcp.ipv6.srcipaddr, conn->u.ipv6.laddr);
#endif
net_ipv6addr_hdrcopy(ipv6tcp.ipv6.destipaddr, conn->u.ipv6.raddr);
ninfo("IPv6 length: %d\n",
((int)ipv6tcp.ipv6.len[0] << 8) + ipv6tcp.ipv6.len[1]);
#ifdef CONFIG_NET_STATISTICS
g_netstats.ipv6.sent++;
#endif
/* Initialize the TCP header */
ipv6tcp.tcp.srcport = conn->lport; /* Local port */
ipv6tcp.tcp.destport = conn->rport; /* Connected remote port */
memcpy(ipv6tcp.tcp.ackno, conn->rcvseq, 4); /* ACK number */
memcpy(ipv6tcp.tcp.seqno, conn->sndseq, 4); /* Sequence number */
ipv6tcp.tcp.tcpoffset = (TCP_HDRLEN / 4) << 4; /* No optdata */
ipv6tcp.tcp.flags = 0; /* No urgent data */
ipv6tcp.tcp.urgp[0] = 0; /* No urgent data */
ipv6tcp.tcp.urgp[1] = 0;
/* Set the TCP window */
if (conn->tcpstateflags & TCP_STOPPED)
{
/* If the connection has issued TCP_STOPPED, we advertise a zero
* window so that the remote host will stop sending data.
*/
ipv6tcp.tcp.wnd[0] = 0;
ipv6tcp.tcp.wnd[1] = 0;
}
else
{
ipv6tcp.tcp.wnd[0] = ((NET_DEV_RCVWNDO(dev)) >> 8);
ipv6tcp.tcp.wnd[1] = ((NET_DEV_RCVWNDO(dev)) & 0xff);
}
/* Calculate TCP checksum. */
ipv6tcp.tcp.tcpchksum = 0;
ipv6tcp.tcp.tcpchksum = ~sixlowpan_tcp_chksum(&ipv6tcp, buf, pktlen);
ninfo("Outgoing TCP packet length: %d bytes\n", iplen + IPv6_HDRLEN);
#ifdef CONFIG_NET_STATISTICS
g_netstats.tcp.sent++;
#endif
/* Get the IEEE 802.15.4 MAC address of the destination. This assumes
* an encoding of the MAC address in the IPv6 address.
*/
sixlowpan_addrfromip(conn->u.ipv6.raddr, &destmac);
/* If routable, then call sixlowpan_send() to format and send the 6LoWPAN
* packet.
*/
ret = sixlowpan_send(dev, &conn->list,
(FAR const struct ipv6_hdr_s *)&ipv6tcp,
buf, pktlen, &destmac, timeout);
if (ret < 0)
{
nerr("ERROR: sixlowpan_send() failed: %d\n", ret);
}
/* Return the amount of data that was sent from the user buffer in this
* packet.
*/
return pktlen;
}
/**************************************************************************** /****************************************************************************
* Public Functions * Public Functions
****************************************************************************/ ****************************************************************************/
@@ -163,11 +306,11 @@ ssize_t psock_6lowpan_tcp_send(FAR struct socket *psock, FAR const void *buf,
{ {
FAR struct tcp_conn_s *conn; FAR struct tcp_conn_s *conn;
FAR struct net_driver_s *dev; FAR struct net_driver_s *dev;
struct ipv6tcp_hdr_s ipv6tcp; size_t remaining;
struct sixlowpan_tagaddr_s destmac;
uint16_t timeout; uint16_t timeout;
uint16_t iplen; #ifdef CONFIG_NET_ICMPv6_NEIGHBOR
int ret; int ret;
#endif
ninfo("buflen %lu\n", (unsigned long)buflen); ninfo("buflen %lu\n", (unsigned long)buflen);
sixlowpan_dumpbuffer("Outgoing TCP payload", buf, buflen); sixlowpan_dumpbuffer("Outgoing TCP payload", buf, buflen);
@@ -177,7 +320,7 @@ ssize_t psock_6lowpan_tcp_send(FAR struct socket *psock, FAR const void *buf,
/* Make sure that this is a valid socket */ /* Make sure that this is a valid socket */
if (psock != NULL || psock->s_crefs <= 0) if (psock == NULL || psock->s_crefs <= 0)
{ {
nerr("ERROR: Invalid socket\n"); nerr("ERROR: Invalid socket\n");
return (ssize_t)-EBADF; return (ssize_t)-EBADF;
@@ -243,110 +386,55 @@ ssize_t psock_6lowpan_tcp_send(FAR struct socket *psock, FAR const void *buf,
} }
#endif #endif
/* Initialize the IPv6/TCP headers */
/* Initialize the IPv6/UDP headers */
ipv6tcp.ipv6.vtc = 0x60;
ipv6tcp.ipv6.tcf = 0x00;
ipv6tcp.ipv6.flow = 0x00;
ipv6tcp.ipv6.proto = IP_PROTO_TCP;
ipv6tcp.ipv6.ttl = IP_TTL;
/* The IPv6 header length field does not include the size of IPv6 IP
* header.
*/
iplen = buflen + TCP_HDRLEN;
ipv6tcp.ipv6.len[0] = (iplen >> 8);
ipv6tcp.ipv6.len[1] = (iplen & 0xff);
/* Copy the source and destination addresses */
#ifdef CONFIG_NETDEV_MULTINIC
net_ipv6addr_hdrcopy(ipv6tcp.ipv6.srcipaddr, conn->u.ipv6.laddr);
#endif
net_ipv6addr_hdrcopy(ipv6tcp.ipv6.destipaddr, conn->u.ipv6.raddr);
ninfo("IPv6 length: %d\n",
((int)ipv6tcp.ipv6.len[0] << 8) + ipv6tcp.ipv6.len[1]);
#ifdef CONFIG_NET_STATISTICS
g_netstats.ipv6.sent++;
#endif
/* Initialize the TCP header */
ipv6tcp.tcp.srcport = conn->lport; /* Local port */
ipv6tcp.tcp.destport = conn->rport; /* Connected remote port */
memcpy(ipv6tcp.tcp.ackno, conn->rcvseq, 4); /* ACK number */
memcpy(ipv6tcp.tcp.seqno, conn->sndseq, 4); /* Sequence number */
ipv6tcp.tcp.tcpoffset = (TCP_HDRLEN / 4) << 4; /* No optdata */
ipv6tcp.tcp.urgp[0] = 0; /* No urgent data */
ipv6tcp.tcp.urgp[1] = 0;
/* Set the TCP window */
if (conn->tcpstateflags & TCP_STOPPED)
{
/* If the connection has issued TCP_STOPPED, we advertise a zero
* window so that the remote host will stop sending data.
*/
ipv6tcp.tcp.wnd[0] = 0;
ipv6tcp.tcp.wnd[1] = 0;
}
else
{
ipv6tcp.tcp.wnd[0] = ((NET_DEV_RCVWNDO(dev)) >> 8);
ipv6tcp.tcp.wnd[1] = ((NET_DEV_RCVWNDO(dev)) & 0xff);
}
/* Calculate TCP checksum. */
ipv6tcp.tcp.tcpchksum = 0;
ipv6tcp.tcp.tcpchksum = ~sixlowpan_tcp_chksum(&ipv6tcp, buf, buflen);
ninfo("Outgoing TCP packet length: %d bytes\n", iplen + IPv6_HDRLEN);
#ifdef CONFIG_NET_STATISTICS
g_netstats.tcp.sent++;
#endif
/* Set the socket state to sending */ /* Set the socket state to sending */
psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND); psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND);
/* Get the IEEE 802.15.4 MAC address of the destination. This assumes /* Send the TCP packets, breaking down the potential large user buffer
* an encoding of the MAC address in the IPv6 address. * into smaller packets that can be reassembled in the allocated MTU
*/ * packet buffer.
sixlowpan_addrfromip(conn->u.ipv6.raddr, &destmac);
/* If routable, then call sixlowpan_send() to format and send the 6LoWPAN
* packet.
*/ */
#ifdef CONFIG_NET_SOCKOPTS #ifdef CONFIG_NET_SOCKOPTS
timeout = psock->s_sndtimeo; timeout = psock->s_sndtimeo;
#else #else
timeout = 0; timeout = 0;
#endif #endif
remaining = buflen;
ret = sixlowpan_send(dev, &conn->list, for (; ; )
(FAR const struct ipv6_hdr_s *)&ipv6tcp,
buf, buflen, &destmac, timeout);
if (ret < 0)
{ {
nerr("ERROR: sixlowpan_send() failed: %d\n", ret); /* Send the next packet */
ssize_t pktlen = sixlowpan_send_packet(conn, dev, buf, remaining,
timeout);
if (pktlen < 0)
{
psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE);
return (ssize_t)pktlen;
}
/* Check if all data has been sent */
if (pktlen >= remaining)
{
/* Yes.. we are done */
break;
}
/* No.. Update the buffer pointer and bytes remaining and send the next
* packet.
*/
remaining -= pktlen;
buf += pktlen;
} }
/* Set the socket state to idle */ /* Set the socket state to idle */
psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE);
return ret; return (ssize_t)buflen;
} }
/**************************************************************************** /****************************************************************************
@@ -356,7 +444,7 @@ ssize_t psock_6lowpan_tcp_send(FAR struct socket *psock, FAR const void *buf,
* TCP output comes through three different mechansims. Either from: * TCP output comes through three different mechansims. Either from:
* *
* 1. TCP socket output. For the case of TCP output to an * 1. TCP socket output. For the case of TCP output to an
* IEEE802.15.4, the TCP output is caught in the socket * IEEE802.15.4 device, the TCP output is caught in the socket
* send()/sendto() logic and and redirected to psock_6lowpan_tcp_send(). * send()/sendto() logic and and redirected to psock_6lowpan_tcp_send().
* 2. TCP output from the TCP state machine. That will occur * 2. TCP output from the TCP state machine. That will occur
* during TCP packet processing by the TCP state meachine. * during TCP packet processing by the TCP state meachine.