net/tcp: parse tcp options in common function

Signed-off-by: chao an <anchao@xiaomi.com>
This commit is contained in:
chao an 2023-01-09 19:44:23 +08:00 committed by Xiang Xiao
parent d175f50f01
commit c581cc5f9b

View File

@ -564,6 +564,100 @@ clear:
}
#endif /* CONFIG_NET_TCP_OUT_OF_ORDER */
/****************************************************************************
* Name: tcp_parse_option
*
* Description:
* Parse incoming TCP options
*
* Input Parameters:
* dev - The device driver structure containing the received TCP packet.
* conn - The TCP connection of interest
* iplen - Length of the IP header (IPv4_HDRLEN or IPv6_HDRLEN).
*
* Returned Value:
* None
*
* Assumptions:
* The network is locked.
*
****************************************************************************/
static void tcp_parse_option(FAR struct net_driver_s *dev,
FAR struct tcp_conn_s *conn,
unsigned int iplen)
{
FAR struct tcp_hdr_s *tcp;
unsigned int tcpiplen;
uint16_t tmp16;
uint8_t opt;
int i;
tcp = IPBUF(iplen);
if ((tcp->tcpoffset & 0xf0) <= 0x50)
{
return;
}
tcpiplen = iplen + TCP_HDRLEN;
for (i = 0; i < ((tcp->tcpoffset >> 4) - 5) << 2 ; )
{
opt = IPDATA(tcpiplen + i);
if (opt == TCP_OPT_END)
{
/* End of options. */
break;
}
else if (opt == TCP_OPT_NOOP)
{
/* NOP option. */
++i;
continue;
}
else if (opt == TCP_OPT_MSS &&
IPDATA(tcpiplen + 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)IPDATA(tcpiplen + 2 + i) << 8) |
(uint16_t)IPDATA(tcpiplen + 3 + i);
conn->mss = tmp16 > tcp_mss ? tcp_mss : tmp16;
}
#ifdef CONFIG_NET_TCP_WINDOW_SCALE
else if (opt == TCP_OPT_WS &&
IPDATA(tcpiplen + 1 + i) == TCP_OPT_WS_LEN)
{
conn->snd_scale = IPDATA(tcpiplen + 2 + i);
conn->rcv_scale = CONFIG_NET_TCP_WINDOW_SCALE_FACTOR;
conn->flags |= TCP_WSCALE;
}
#endif
else
{
/* All other options have a length field, so that we
* easily can skip past them.
*/
if (IPDATA(tcpiplen + 1 + i) == 0)
{
/* If the length field is zero, the options are
* malformed and we don't process them further.
*/
break;
}
}
i += IPDATA(tcpiplen + 1 + i);
}
}
/****************************************************************************
* Name: tcp_input
*
@ -593,9 +687,7 @@ static void tcp_input(FAR struct net_driver_s *dev, uint8_t domain,
uint16_t tmp16;
uint16_t flags;
uint16_t result;
uint8_t opt;
int len;
int i;
#ifdef CONFIG_NET_STATISTICS
/* Bump up the count of TCP packets received */
@ -748,63 +840,7 @@ static void tcp_input(FAR struct net_driver_s *dev, uint8_t domain,
/* Parse the TCP MSS option, if present. */
if ((tcp->tcpoffset & 0xf0) > 0x50)
{
for (i = 0; i < ((tcp->tcpoffset >> 4) - 5) << 2 ; )
{
opt = IPDATA(tcpiplen + i);
if (opt == TCP_OPT_END)
{
/* End of options. */
break;
}
else if (opt == TCP_OPT_NOOP)
{
/* NOP option. */
++i;
continue;
}
else if (opt == TCP_OPT_MSS &&
IPDATA(tcpiplen + 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)IPDATA(tcpiplen + 2 + i) << 8) |
(uint16_t)IPDATA(tcpiplen + 3 + i);
conn->mss = tmp16 > tcp_mss ? tcp_mss : tmp16;
}
#ifdef CONFIG_NET_TCP_WINDOW_SCALE
else if (opt == TCP_OPT_WS &&
IPDATA(tcpiplen + 1 + i) == TCP_OPT_WS_LEN)
{
conn->snd_scale = IPDATA(tcpiplen + 2 + i);
conn->rcv_scale = CONFIG_NET_TCP_WINDOW_SCALE_FACTOR;
conn->flags |= TCP_WSCALE;
}
#endif
else
{
/* All other options have a length field, so that we
* easily can skip past them.
*/
if (IPDATA(tcpiplen + 1 + i) == 0)
{
/* If the length field is zero, the options are
* malformed and we don't process them further.
*/
break;
}
}
i += IPDATA(tcpiplen + 1 + i);
}
}
tcp_parse_option(dev, conn, iplen);
/* Our response will be a SYNACK. */
@ -1245,63 +1281,7 @@ found:
{
/* Parse the TCP MSS option, if present. */
if ((tcp->tcpoffset & 0xf0) > 0x50)
{
for (i = 0; i < ((tcp->tcpoffset >> 4) - 5) << 2 ; )
{
opt = IPDATA(tcpiplen + i);
if (opt == TCP_OPT_END)
{
/* End of options. */
break;
}
else if (opt == TCP_OPT_NOOP)
{
/* NOP option. */
++i;
continue;
}
else if (opt == TCP_OPT_MSS &&
IPDATA(tcpiplen + 1 + i) == TCP_OPT_MSS_LEN)
{
uint16_t tcp_mss = TCP_MSS(dev, iplen);
/* An MSS option with the right option length. */
tmp16 = (IPDATA(tcpiplen + 2 + i) << 8) |
IPDATA(tcpiplen + 3 + i);
conn->mss = tmp16 > tcp_mss ? tcp_mss : tmp16;
}
#ifdef CONFIG_NET_TCP_WINDOW_SCALE
else if (opt == TCP_OPT_WS &&
IPDATA(tcpiplen + 1 + i) == TCP_OPT_WS_LEN)
{
conn->snd_scale = IPDATA(tcpiplen + 2 + i);
conn->rcv_scale = CONFIG_NET_TCP_WINDOW_SCALE_FACTOR;
conn->flags |= TCP_WSCALE;
}
#endif
else
{
/* All other options have a length field, so that we
* easily can skip past them.
*/
if (IPDATA(tcpiplen + 1 + i) == 0)
{
/* If the length field is zero, the options are
* malformed and we don't process them further.
*/
break;
}
}
i += IPDATA(tcpiplen + 1 + i);
}
}
tcp_parse_option(dev, conn, iplen);
conn->tcpstateflags = TCP_ESTABLISHED;
memcpy(conn->rcvseq, tcp->seqno, 4);