From 8f8259a0d60f127317aa60cce156b99d715c3750 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 16 Jan 2015 15:03:10 -0600 Subject: [PATCH] Networking: UDP and TCP MSS depends on the IP header size (as well as the link layer header size) and cannot be represented with a single value. --- fs/nfs/nfs_vfsops.c | 4 +- include/nuttx/net/ip.h | 2 +- include/nuttx/net/netconfig.h | 106 +++++++++++++++++++++++++++------- include/nuttx/net/tcp.h | 18 +++++- net/icmpv6/icmpv6_input.c | 6 +- net/socket/connect.c | 2 +- net/tcp/tcp_conn.c | 4 +- net/tcp/tcp_input.c | 36 ++++++++---- net/tcp/tcp_send.c | 5 +- net/udp/udp_input.c | 31 ++++++---- 10 files changed, 157 insertions(+), 57 deletions(-) diff --git a/fs/nfs/nfs_vfsops.c b/fs/nfs/nfs_vfsops.c index 7a26b530e8..bb42093de2 100644 --- a/fs/nfs/nfs_vfsops.c +++ b/fs/nfs/nfs_vfsops.c @@ -1722,9 +1722,9 @@ static int nfs_bind(FAR struct inode *blkdriver, FAR const void *data, * the minimum MSS for that case. */ - if (buflen > MIN_UDP_MSS) + if (buflen > MIN_IPv4_UDP_MSS) { - buflen = MIN_UDP_MSS; + buflen = MIN_IPv4_UDP_MSS; } /* Create an instance of the mountpt state structure */ diff --git a/include/nuttx/net/ip.h b/include/nuttx/net/ip.h index 3f01a22a57..e6a9f9c9d1 100644 --- a/include/nuttx/net/ip.h +++ b/include/nuttx/net/ip.h @@ -300,7 +300,7 @@ struct net_ipv6hdr_s net_ipv4addr_cmp(net_ip4addr_conv32(addr1), net_ip4addr_conv32(addr2)) #endif -#ifdef CONFIG_NET_IPv4 +#ifdef CONFIG_NET_IPv6 # define net_ipv6addr_cmp(addr1, addr2) \ (memcmp(&addr1, &addr2, sizeof(net_ipv6addr_t)) == 0) # define net_ipv6addr_hdrcmp(addr1, addr2) \ diff --git a/include/nuttx/net/netconfig.h b/include/nuttx/net/netconfig.h index 9df3a6f2cb..560bf5d92b 100644 --- a/include/nuttx/net/netconfig.h +++ b/include/nuttx/net/netconfig.h @@ -214,18 +214,52 @@ * than NET_DEV_MTU(d) - NET_LL_HDRLEN(dev) - IPv4UDP_HDRLEN. */ -#define UDP_MSS(d) (NET_DEV_MTU(d) - NET_LL_HDRLEN(d) - IPv4UDP_HDRLEN) +#define UDP_MSS(d,h) (NET_DEV_MTU(d) - NET_LL_HDRLEN(d) - (h)) -#ifdef CONFIG_NET_ETHERNET -# define MIN_UDP_MSS (CONFIG_NET_ETH_MTU - ETH_HDRLEN - IPv4UDP_HDRLEN) -#else /* if defined(CONFIG_NET_SLIP) */ -# define MIN_UDP_MSS (CONFIG_NET_SLIP_MTU - IPv4UDP_HDRLEN) -#endif +/* If Ethernet is supported, then it will have the smaller MSS */ #ifdef CONFIG_NET_SLIP -# define MAX_UDP_MSS (CONFIG_NET_SLIP_MTU - IPv4UDP_HDRLEN) -#else /* if defined(CONFIG_NET_ETHERNET) */ -# define MAX_UDP_MSS (CONFIG_NET_ETH_MTU - ETH_HDRLEN - IPv4UDP_HDRLEN) +# define SLIP_UDP_MSS(h) (CONFIG_NET_SLIP_MTU - (h)) +# define __MIN_UDP_MSS(h) SLIP_UDP_MSS(h) +#endif + +#ifdef CONFIG_NET_ETHERNET +# define ETH_UDP_MSS(h) (CONFIG_NET_ETH_MTU - ETH_HDRLEN - (h)) +# undef __MIN_UDP_MSS +# define __MIN_UDP_MSS(h) ETH_UDP_MSS(h) +# define __MAX_UDP_MSS(h) ETH_UDP_MSS(h) +#endif + +/* If SLIP is supported, then it will have the larger MSS */ + +#ifdef CONFIG_NET_SLIP +# undef __MAX_UDP_MSS +# define __MAX_UDP_MSS(h) SLIP_UDP_MSS(h) +#endif + +/* If IPv4 is supported, it will have the larger MSS */ + +#ifdef CONFIG_NET_IPv6 +# define UDP_IPv6_MSS(d) UDP_MSS(d,IPv6_HDRLEN) +# define ETH_IPv6_UDP_MSS ETH_UDP_MSS(IPv6_HDRLEN) +# define SLIP_IPv6_UDP_MSS SLIP_UDP_MSS(IPv6_HDRLEN) +# define MAX_UDP_MSS __MAX_UDP_MSS(IPv6_HDRLEN) +#endif + +#ifdef CONFIG_NET_IPv4 +# define UDP_IPv4_MSS(d) UDP_MSS(d,IPv4_HDRLEN) +# define ETH_IPv4_UDP_MSS ETH_UDP_MSS(IPv4_HDRLEN) +# define SLIP_IPv4_UDP_MSS SLIP_UDP_MSS(IPv4_HDRLEN) +# define MIN_UDP_MSS __MIN_UDP_MSS(IPv4_HDRLEN) +# undef MAX_UDP_MSS +# define MAX_UDP_MSS __MAX_UDP_MSS(IPv4_HDRLEN) +#endif + +/* If IPv6 is support, it will have the smaller MSS */ + +#ifdef CONFIG_NET_IPv6 +# undef MIN_UDP_MSS +# define MIN_UDP_MSS __MIN_UDP_MSS(IPv6_HDRLEN) #endif /* TCP configuration options */ @@ -296,20 +330,52 @@ * the minimum MSS for that case. */ -#define TCP_MSS(d) (NET_DEV_MTU(d) - NET_LL_HDRLEN(d) - IPv4TCP_HDRLEN) +#define TCP_MSS(d,h) (NET_DEV_MTU(d) - NET_LL_HDRLEN(d) - (h)) -#ifdef CONFIG_NET_ETHERNET -# define ETH_TCP_MSS (CONFIG_NET_ETH_MTU - ETH_HDRLEN - IPv4TCP_HDRLEN) -# define MIN_TCP_MSS ETH_TCP_MSS -#elif defined(CONFIG_NET_SLIP) -# define SLIP_TCP_MSS (CONFIG_NET_SLIP_MTU - IPv4TCP_HDRLEN) -# define MIN_TCP_MSS SLIP_TCP_MSS -#endif +/* If Ethernet is supported, then it will have the smaller MSS */ #ifdef CONFIG_NET_SLIP -# define MAX_TCP_MSS SLIP_TCP_MSS -#elif defined(CONFIG_NET_ETHERNET) -# define MAX_TCP_MSS ETH_TCP_MSS +# define SLIP_TCP_MSS(h) (CONFIG_NET_SLIP_MTU - (h)) +# define __MIN_TCP_MSS(h) SLIP_TCP_MSS(h) +#endif + +#ifdef CONFIG_NET_ETHERNET +# define ETH_TCP_MSS(h) (CONFIG_NET_ETH_MTU - ETH_HDRLEN - (h)) +# undef __MIN_TCP_MSS +# define __MIN_TCP_MSS(h) ETH_TCP_MSS(h) +# define __MAX_TCP_MSS(h) ETH_TCP_MSS(h) +#endif + +/* If SLIP is supported, then it will have the larger MSS */ + +#ifdef CONFIG_NET_SLIP +# undef __MAX_TCP_MSS +# define __MAX_TCP_MSS(h) SLIP_TCP_MSS(h) +#endif + +/* If IPv4 is support, it will have the larger MSS */ + +#ifdef CONFIG_NET_IPv6 +# define TCP_IPv6_MSS(d) TCP_MSS(d,IPv6_HDRLEN) +# define ETH_IPv6_TCP_MSS ETH_TCP_MSS(IPv6_HDRLEN) +# define SLIP_IPv6_TCP_MSS SLIP_TCP_MSS(IPv6_HDRLEN) +# define MAX_TCP_MSS __MAX_TCP_MSS(IPv6_HDRLEN) +#endif + +#ifdef CONFIG_NET_IPv4 +# define TCP_IPv4_MSS(d) TCP_MSS(d,IPv4_HDRLEN) +# define ETH_IPv4_TCP_MSS ETH_TCP_MSS(IPv4_HDRLEN) +# define SLIP_IPv4_TCP_MSS SLIP_TCP_MSS(IPv4_HDRLEN) +# define MIN_TCP_MSS __MIN_TCP_MSS(IPv4_HDRLEN) +# undef MAX_TCP_MSS +# define MAX_TCP_MSS __MAX_TCP_MSS(IPv4_HDRLEN) +#endif + +/* If IPv6 is supported, it will have the smaller MSS */ + +#ifdef CONFIG_NET_IPv6 +# undef MIN_TCP_MSS +# define MIN_TCP_MSS __MIN_TCP_MSS(IPv6_HDRLEN) #endif /* The size of the advertised receiver's window. diff --git a/include/nuttx/net/tcp.h b/include/nuttx/net/tcp.h index 8a33f81cd9..c6b9ddf17c 100644 --- a/include/nuttx/net/tcp.h +++ b/include/nuttx/net/tcp.h @@ -119,10 +119,22 @@ * This is a long established rule. */ -#define TCP_INITIAL_MSS(d) (TCP_MSS(d) > 576 ? 576 : TCP_MSS(d)) +#define TCP_INITIAL_MSS(d,h) (TCP_MSS(d,h) > 576 ? 576 : TCP_MSS(d,h)) -#define MIN_TCP_INITIAL_MSS (MIN_TCP_MSS > 576 ? 576 : MIN_TCP_MSS) -#define MAX_TCP_INITIAL_MSS (MAX_TCP_MSS > 576 ? 576 : MAX_TCP_MSS) +#define MIN_TCP_INITIAL_MSS(h) (__MIN_TCP_MSS(h) > 576 ? 576 : __MIN_TCP_MSS(h)) +#define MAX_TCP_INITIAL_MSS(h) (__MAX_TCP_MSS(h) > 576 ? 576 : __MAX_TCP_MSS(h)) + +#ifdef CONFIG_NET_IPv4 +# define TCP_IPv4_INITIAL_MSS(d) TCP_INITIAL_MSS(d,IPv4_HDRLEN) +# define MIN_IPv4_TCP_INITIAL_MSS MIN_TCP_INITIAL_MSS(IPv4_HDRLEN) +# define MAX_IPv4_TCP_INITIAL_MSS MAX_TCP_INITIAL_MSS(IPv4_HDRLEN) +#endif + +#ifdef CONFIG_NET_IPv6 +# define TCP_IPv6_INITIAL_MSS(d) TCP_INITIAL_MSS(d,IPv6_HDRLEN) +# define MIN_IPv6_TCP_INITIAL_MSS MIN_TCP_INITIAL_MSS(IPv6_HDRLEN) +# define MAX_IPv6_TCP_INITIAL_MSS MAX_TCP_INITIAL_MSS(IPv6_HDRLEN) +#endif /**************************************************************************** * Public Type Definitions diff --git a/net/icmpv6/icmpv6_input.c b/net/icmpv6/icmpv6_input.c index 6b53a13f19..da17c3c60f 100644 --- a/net/icmpv6/icmpv6_input.c +++ b/net/icmpv6/icmpv6_input.c @@ -122,7 +122,7 @@ void icmpv6_input(FAR struct net_driver_s *dev) if (picmp->type == ICMPv6_NEIGHBOR_SOLICITATION) { - if (net_ipv6addr_cmp(picmp->icmpv6data, dev->d_ipaddr)) + if (net_ipv6addr_cmp(picmp->icmpv6data, dev->d_ipv6addr)) { if (picmp->options[0] == ICMPv6_OPTION_SOURCE_LINK_ADDRESS) { @@ -142,7 +142,7 @@ void icmpv6_input(FAR struct net_driver_s *dev) picmp->reserved1 = picmp->reserved2 = picmp->reserved3 = 0; net_ipv6addr_copy(picmp->destipaddr, picmp->srcipaddr); - net_ipv6addr_copy(picmp->srcipaddr, dev->d_ipaddr); + net_ipv6addr_copy(picmp->srcipaddr, dev->d_ipv6addr); picmp->options[0] = ICMPv6_OPTION_TARGET_LINK_ADDRESS; picmp->options[1] = 1; /* Options length, 1 = 8 bytes. */ @@ -166,7 +166,7 @@ void icmpv6_input(FAR struct net_driver_s *dev) picmp->type = ICMPv6_ECHO_REPLY; net_ipv6addr_copy(picmp->destipaddr, picmp->srcipaddr); - net_ipv6addr_copy(picmp->srcipaddr, dev->d_ipaddr); + net_ipv6addr_copy(picmp->srcipaddr, dev->d_ipv6addr); picmp->icmpv6chksum = 0; picmp->icmpv6chksum = ~icmpv6_chksum(dev); diff --git a/net/socket/connect.c b/net/socket/connect.c index 51e4b8426a..838cec0ba0 100644 --- a/net/socket/connect.c +++ b/net/socket/connect.c @@ -259,7 +259,7 @@ static uint16_t psock_connect_interrupt(FAR struct net_driver_s *dev, */ DEBUGASSERT(pstate->tc_conn); - pstate->tc_conn->mss = TCP_INITIAL_MSS(dev); + pstate->tc_conn->mss = TCP_IPv4_INITIAL_MSS(dev); #endif /* Wake up the waiting thread */ diff --git a/net/tcp/tcp_conn.c b/net/tcp/tcp_conn.c index f2cc719146..6756fa6fb8 100644 --- a/net/tcp/tcp_conn.c +++ b/net/tcp/tcp_conn.c @@ -599,7 +599,7 @@ FAR struct tcp_conn_s *tcp_alloc_accept(FAR struct net_driver_s *dev, conn->nrtx = 0; conn->lport = tcp->destport; conn->rport = tcp->srcport; - conn->mss = TCP_INITIAL_MSS(dev); + conn->mss = TCP_IPv4_INITIAL_MSS(dev); net_ipv4addr_copy(conn->u.ipv4.raddr, net_ip4addr_conv32(ip->srcipaddr)); #ifdef CONFIG_NETDEV_MULTINIC net_ipv4addr_copy(conn->u.ipv4.laddr, net_ip4addr_conv32(ip->destipaddr)); @@ -780,7 +780,7 @@ int tcp_connect(FAR struct tcp_conn_s *conn, conn->tcpstateflags = TCP_SYN_SENT; tcp_initsequence(conn->sndseq); - conn->mss = MIN_TCP_INITIAL_MSS; + conn->mss = MIN_IPv4_TCP_INITIAL_MSS; conn->unacked = 1; /* TCP length of the SYN is one. */ conn->nrtx = 0; conn->timer = 1; /* Send the SYN next time around. */ diff --git a/net/tcp/tcp_input.c b/net/tcp/tcp_input.c index c7c808afdb..f851c67ead 100644 --- a/net/tcp/tcp_input.c +++ b/net/tcp/tcp_input.c @@ -95,10 +95,11 @@ * ****************************************************************************/ -static void tcp_input(FAR struct net_driver_s *dev, - FAR struct tcp_hdr_s *tcp, unsigned int tcpiplen) +static void tcp_input(FAR struct net_driver_s *dev, unsigned int iplen) { + FAR struct tcp_hdr_s *tcp; FAR struct tcp_conn_s *conn = NULL; + unsigned int tcpiplen; unsigned int hdrlen; uint16_t tmp16; uint16_t flags; @@ -113,6 +114,16 @@ static void tcp_input(FAR struct net_driver_s *dev, g_netstats.tcp.recv++; #endif + /* Get a pointer to the TCP header. The TCP header lies just after the + * the link layer header and the IP header. + */ + + tcp = (FAR struct tcp_hdr_s *)&dev->d_buf[iplen + NET_LL_HDRLEN(dev)]; + + /* Get the size of the IP header and the TCP header */ + + tcpiplen = iplen + TCP_HDRLEN; + /* Get the size of the link layer header, the IP header, and the TCP header */ hdrlen = tcpiplen + NET_LL_HDRLEN(dev); @@ -240,11 +251,13 @@ static void tcp_input(FAR struct net_driver_s *dev, else if (opt == TCP_OPT_MSS && dev->d_buf[hdrlen + 1 + i] == TCP_OPT_MSS_LEN) { + uint16_t tcp_mss = TCP_MSS(dev, iplen); + /* An MSS option with the right option length. */ tmp16 = ((uint16_t)dev->d_buf[hdrlen + 2 + i] << 8) | (uint16_t)dev->d_buf[hdrlen + 3 + i]; - conn->mss = tmp16 > TCP_MSS(dev) ? TCP_MSS(dev) : tmp16; + conn->mss = tmp16 > tcp_mss ? tcp_mss : tmp16; /* And we are done processing options. */ @@ -326,10 +339,10 @@ found: /* d_len will contain the length of the actual TCP data. This is * calculated by subtracting the length of the TCP header (in - * len) and the length of the IP header (20 bytes). + * len) and the length of the IP header. */ - dev->d_len -= (len + IPv4_HDRLEN); + dev->d_len -= (len + iplen); /* First, check if the sequence number of the incoming packet is * what we're expecting next. If not, we send out an ACK with the @@ -530,12 +543,14 @@ found: else if (opt == TCP_OPT_MSS && dev->d_buf[hdrlen + 1 + i] == TCP_OPT_MSS_LEN) { + uint16_t tcp_mss = TCP_MSS(dev, iplen); + /* An MSS option with the right option length. */ tmp16 = (dev->d_buf[hdrlen + 2 + i] << 8) | dev->d_buf[hdrlen + 3 + i]; - conn->mss = tmp16 > TCP_MSS(dev) ? TCP_MSS(dev) : tmp16; + conn->mss = tmp16 > tcp_mss ? tcp_mss : tmp16; /* And we are done processing options. */ @@ -697,7 +712,8 @@ found: * When the application is called, the d_len field * contains the length of the incoming data. The application can * access the incoming data through the global pointer - * d_appdata, which usually points hdrlen bytes into the d_buf array. + * d_appdata, which usually points hdrlen bytes into the d_buf + * array. * * If the application wishes to send any data, this data should be * put into the d_appdata and the length of the data should be @@ -871,8 +887,7 @@ drop: #ifdef CONFIG_NET_IPv4 void tcp_ipv4_input(FAR struct net_driver_s *dev) { - unsigned int offset = IPv4_HDRLEN + NET_LL_HDRLEN(dev); - tcp_input(dev, (FAR struct tcp_hdr_s *)&dev->d_buf[offset], IPv4TCP_HDRLEN); + tcp_input(dev, IPv4_HDRLEN); } #endif @@ -896,8 +911,7 @@ void tcp_ipv4_input(FAR struct net_driver_s *dev) #ifdef CONFIG_NET_IPv6 void tcp_ipv6_input(FAR struct net_driver_s *dev) { - unsigned int offset = IPv6_HDRLEN + NET_LL_HDRLEN(dev); - tcp_input(dev, (FAR struct tcp_hdr_s *)&dev->d_buf[offset], IPv6TCP_HDRLEN); + tcp_input(dev, IPv6_HDRLEN); } #endif diff --git a/net/tcp/tcp_send.c b/net/tcp/tcp_send.c index 1a70b6ab63..5c23b657fe 100644 --- a/net/tcp/tcp_send.c +++ b/net/tcp/tcp_send.c @@ -351,6 +351,7 @@ void tcp_ack(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn, uint8_t ack) { struct tcp_iphdr_s *pbuf = BUF; + uint16_t tcp_mss = TCP_IPv4_MSS(dev); /* Save the ACK bits */ @@ -360,8 +361,8 @@ void tcp_ack(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn, pbuf->optdata[0] = TCP_OPT_MSS; pbuf->optdata[1] = TCP_OPT_MSS_LEN; - pbuf->optdata[2] = TCP_MSS(dev) / 256; - pbuf->optdata[3] = TCP_MSS(dev) & 255; + pbuf->optdata[2] = tcp_mss >> 8; + pbuf->optdata[3] = tcp_mss & 0xff; dev->d_len = IPv4TCP_HDRLEN + TCP_OPT_MSS_LEN; pbuf->tcpoffset = ((TCP_HDRLEN + TCP_OPT_MSS_LEN) / 4) << 4; diff --git a/net/udp/udp_input.c b/net/udp/udp_input.c index d53b9185cb..9062b6dd52 100644 --- a/net/udp/udp_input.c +++ b/net/udp/udp_input.c @@ -93,10 +93,11 @@ * ****************************************************************************/ -static int udp_input(FAR struct net_driver_s *dev, FAR struct udp_hdr_s *udp, - unsigned int udpiplen) +static int udp_input(FAR struct net_driver_s *dev, unsigned int iplen) { + FAR struct udp_hdr_s *udp; FAR struct udp_conn_s *conn; + unsigned int udpiplen; unsigned int hdrlen; int ret = OK; @@ -106,6 +107,20 @@ static int udp_input(FAR struct net_driver_s *dev, FAR struct udp_hdr_s *udp, g_netstats.udp.recv++; #endif + /* Get a pointer to the UDP header. The UDP header lies just after the + * the link layer header and the IP header. + */ + + udp = (FAR struct udp_hdr_s *)&dev->d_buf[iplen + NET_LL_HDRLEN(dev)]; + + /* Get the size of the IP header and the UDP header */ + + udpiplen = iplen + UDP_HDRLEN; + + /* Get the size of the link layer header, the IP header, and the UDP header */ + + hdrlen = udpiplen + NET_LL_HDRLEN(dev); + /* UDP processing is really just a hack. We don't do anything to the UDP/IP * headers, but let the UDP application do all the hard work. If the * application sets d_sndlen, it has a packet to send. @@ -113,10 +128,6 @@ static int udp_input(FAR struct net_driver_s *dev, FAR struct udp_hdr_s *udp, dev->d_len -= udpiplen; - /* Get the size of the link layer header, the IP header, and the UDP header */ - - hdrlen = udpiplen + NET_LL_HDRLEN(dev); - #ifdef CONFIG_NET_UDP_CHECKSUMS dev->d_appdata = &dev->d_buf[hdrlen]; @@ -219,9 +230,7 @@ static int udp_input(FAR struct net_driver_s *dev, FAR struct udp_hdr_s *udp, #ifdef CONFIG_NET_IPv4 int udp_ipv4_input(FAR struct net_driver_s *dev) { - unsigned int offset = IPv4_HDRLEN + NET_LL_HDRLEN(dev); - return udp_input(dev, (FAR struct udp_hdr_s *)&dev->d_buf[offset], - IPv4UDP_HDRLEN); + return udp_input(dev, IPv4_HDRLEN); } #endif @@ -247,9 +256,7 @@ int udp_ipv4_input(FAR struct net_driver_s *dev) #ifdef CONFIG_NET_IPv6 int udp_ipv6_input(FAR struct net_driver_s *dev) { - unsigned int offset = IPv6_HDRLEN + NET_LL_HDRLEN(dev); - return udp_input(dev, (FAR struct udp_hdr_s *)&dev->d_buf[offset], - IPv6UDP_HDRLEN); + return udp_input(dev, IPv6_HDRLEN); } #endif