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:
parent
fa1d95dee2
commit
2fb938202c
@ -694,8 +694,8 @@ CONFIG_MM_REGIONS=1
|
||||
# Common I/O Buffer Support
|
||||
#
|
||||
CONFIG_MM_IOB=y
|
||||
CONFIG_IOB_NBUFFERS=36
|
||||
CONFIG_IOB_BUFSIZE=196
|
||||
CONFIG_IOB_NBUFFERS=48
|
||||
CONFIG_IOB_BUFSIZE=128
|
||||
CONFIG_IOB_NCHAINS=8
|
||||
CONFIG_IOB_THROTTLE=8
|
||||
|
||||
@ -910,15 +910,15 @@ CONFIG_EXAMPLES_NETTEST_IPv6=y
|
||||
#
|
||||
# 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_3=0x0000
|
||||
CONFIG_EXAMPLES_NETTEST_SERVERIPv6ADDR_4=0x0000
|
||||
CONFIG_EXAMPLES_NETTEST_SERVERIPv6ADDR_5=0x0000
|
||||
CONFIG_EXAMPLES_NETTEST_SERVERIPv6ADDR_6=0x0000
|
||||
CONFIG_EXAMPLES_NETTEST_SERVERIPv6ADDR_7=0x0000
|
||||
CONFIG_EXAMPLES_NETTEST_SERVERIPv6ADDR_8=0x0001
|
||||
CONFIG_EXAMPLES_NETTEST_SERVER_PORTNO=5471
|
||||
CONFIG_EXAMPLES_NETTEST_SERVERIPv6ADDR_6=0x00ff
|
||||
CONFIG_EXAMPLES_NETTEST_SERVERIPv6ADDR_7=0xfe00
|
||||
CONFIG_EXAMPLES_NETTEST_SERVERIPv6ADDR_8=0xcda9
|
||||
CONFIG_EXAMPLES_NETTEST_SERVER_PORTNO=61616
|
||||
# CONFIG_EXAMPLES_NRF24L01TERM is not set
|
||||
CONFIG_EXAMPLES_NSH=y
|
||||
# CONFIG_EXAMPLES_NULL is not set
|
||||
|
@ -170,7 +170,7 @@
|
||||
# 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_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_HLIM_MASK 0x03 /* Bits 6-7: Hop Limit */
|
||||
# define SIXLOWPAN_IPHC_HLIM_INLINE 0x00 /* Carried in-line */
|
||||
|
@ -289,7 +289,13 @@ static void sixlowpan_uncompress_ipv6hdr(FAR uint8_t *fptr, FAR uint8_t *bptr)
|
||||
* iob - The IOB containing the frame.
|
||||
*
|
||||
* 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:
|
||||
* 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 */
|
||||
hdrsize = iob->io_offset; /* Offset past the MAC header */
|
||||
if (hdrsize < 0)
|
||||
{
|
||||
nwarn("Invalid IEEE802.15.2 header: %d\n", hdrsize);
|
||||
return hdrsize;
|
||||
}
|
||||
|
||||
DEBUGASSERT((unsigned)hdrsize < iob->io_len);
|
||||
|
||||
/* Initialize global data. Locking the network guarantees that we have
|
||||
* 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 "
|
||||
"the packet currently being reassembled\n");
|
||||
return INPUT_PARTIAL;
|
||||
return -EPERM;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -488,7 +491,7 @@ static int sixlowpan_frame_process(FAR struct ieee802154_driver_s *ieee,
|
||||
if (!isfirstfrag)
|
||||
{
|
||||
nwarn("WARNING: FRAGN 6LoWPAN fragment while not reassembling\n");
|
||||
return OK;
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
nwarn("WARNING: Reassembled packet size exeeds CONFIG_NET_6LOWPAN_MTU\n");
|
||||
return OK;
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
ieee->i_pktlen = fragsize;
|
||||
@ -556,7 +559,7 @@ static int sixlowpan_frame_process(FAR struct ieee802154_driver_s *ieee,
|
||||
/* Unknown or unsupported header */
|
||||
|
||||
nwarn("WARNING: Unknown dispatch: %u\n", hc1[SIXLOWPAN_HC1_DISPATCH]);
|
||||
return OK;
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
#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",
|
||||
paysize, CONFIG_NET_6LOWPAN_MTU);
|
||||
return OK;
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
/* Sanity-check size of incoming packet to avoid buffer overflow */
|
||||
@ -795,7 +798,7 @@ int sixlowpan_input(FAR struct ieee802154_driver_s *ieee,
|
||||
* reassembled?
|
||||
*/
|
||||
|
||||
if (ret == INPUT_COMPLETE)
|
||||
if (ret >= 0 && ret == INPUT_COMPLETE)
|
||||
{
|
||||
/* Inject the uncompressed, reassembled packet into the network */
|
||||
|
||||
|
@ -131,6 +131,149 @@ static uint16_t sixlowpan_tcp_chksum(FAR struct ipv6tcp_hdr_s *ipv6tcp,
|
||||
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
|
||||
****************************************************************************/
|
||||
@ -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 net_driver_s *dev;
|
||||
struct ipv6tcp_hdr_s ipv6tcp;
|
||||
struct sixlowpan_tagaddr_s destmac;
|
||||
size_t remaining;
|
||||
uint16_t timeout;
|
||||
uint16_t iplen;
|
||||
#ifdef CONFIG_NET_ICMPv6_NEIGHBOR
|
||||
int ret;
|
||||
#endif
|
||||
|
||||
ninfo("buflen %lu\n", (unsigned long)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 */
|
||||
|
||||
if (psock != NULL || psock->s_crefs <= 0)
|
||||
if (psock == NULL || psock->s_crefs <= 0)
|
||||
{
|
||||
nerr("ERROR: Invalid socket\n");
|
||||
return (ssize_t)-EBADF;
|
||||
@ -243,110 +386,55 @@ ssize_t psock_6lowpan_tcp_send(FAR struct socket *psock, FAR const void *buf,
|
||||
}
|
||||
#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 */
|
||||
|
||||
psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND);
|
||||
|
||||
/* 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.
|
||||
/* Send the TCP packets, breaking down the potential large user buffer
|
||||
* into smaller packets that can be reassembled in the allocated MTU
|
||||
* packet buffer.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_NET_SOCKOPTS
|
||||
timeout = psock->s_sndtimeo;
|
||||
timeout = psock->s_sndtimeo;
|
||||
#else
|
||||
timeout = 0;
|
||||
timeout = 0;
|
||||
#endif
|
||||
remaining = buflen;
|
||||
|
||||
ret = sixlowpan_send(dev, &conn->list,
|
||||
(FAR const struct ipv6_hdr_s *)&ipv6tcp,
|
||||
buf, buflen, &destmac, timeout);
|
||||
if (ret < 0)
|
||||
for (; ; )
|
||||
{
|
||||
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 */
|
||||
|
||||
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:
|
||||
*
|
||||
* 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().
|
||||
* 2. TCP output from the TCP state machine. That will occur
|
||||
* during TCP packet processing by the TCP state meachine.
|
||||
|
Loading…
Reference in New Issue
Block a user