[PATCH v2 2/6] net: prepare existing TCP stack to be reused by IP6

Ying-Chun Liu (PaulLiu) paul.liu at linaro.org
Wed May 24 23:38:15 CEST 2023



On 2023/5/11 00:59, Dmitrii Merkurev wrote:
> Changes:
> 1. Separate reusable part from net_set_tcp_header to
> net_set_tcp_header_common
> 2. Make TCP signatures reusable by receiving particular
> IP agnostic TCP headers
> 3. Extract net_send_ip_packet6 from net_send_udp_packet6
> to reuse the code
> 4. Expose TCP state machine related functions
> 
> This allows us to reuse TCP logic between IP and IP6 stack.
> 
> Signed-off-by: Dmitrii Merkurev <dimorinny at google.com>
> Cc: Ying-Chun Liu (PaulLiu) <paul.liu at linaro.org>
> Cc: Simon Glass <sjg at chromium.org>
> Сс: Joe Hershberger <joe.hershberger at ni.com>
> Сс: Ramon Fried <rfried.dev at gmail.com>
> ---
>   include/net/tcp.h | 109 +++++++++++++--
>   net/net.c         |  18 ++-
>   net/net6.c        |  78 ++++++++---
>   net/tcp.c         | 337 ++++++++++++++++++++++++++++------------------
>   4 files changed, 372 insertions(+), 170 deletions(-)
> 
> diff --git a/include/net/tcp.h b/include/net/tcp.h
> index 93ed728dfe..344b4be2a4 100644
> --- a/include/net/tcp.h
> +++ b/include/net/tcp.h
> @@ -8,10 +8,20 @@
>   #ifndef __TCP_H__
>   #define __TCP_H__
>   
> +#include <net.h>
> +
>   #define TCP_ACTIVITY 127		/* Number of packets received   */
>   					/* before console progress mark */
>   
> +/*
> + * TCP lengths are stored as a rounded up number of 32 bit words.
> + * Add 3 to length round up, rounded, then divided into the
> + * length in 32 bit words.
> + */
> +#define LEN_B_TO_DW(x) ((x) >> 2)
> +#define ROUND_TCPHDR_LEN(x) (LEN_B_TO_DW((x) + 3))
>   #define GET_TCP_HDR_LEN_IN_BYTES(x) ((x) >> 2)
> +#define SHIFT_TO_TCPHDRLEN_FIELD(x) ((x) << 4)
>   
>   /**
>    * struct tcp_hdr - TCP header
> @@ -24,7 +34,7 @@
>    * @tcp_win: TCP windows size
>    * @tcp_xsum: Checksum
>    * @tcp_ugr: Pointer to urgent data
> -*/
> + */
>   struct tcp_hdr {
>   	u16		tcp_src;
>   	u16		tcp_dst;
> @@ -163,18 +173,14 @@ struct tcp_t_opt {
>    */
>   
>   /**
> - * struct ip_tcp_hdr_o - IP + TCP header + TCP options
> - * @ip_hdr: IP + TCP header
> - * @tcp_hdr: TCP header
> + * struct tcp_hdr_o - TCP options
>    * @mss: TCP MSS Option
>    * @scale: TCP Windows Scale Option
>    * @sack_p: TCP Sack-Permitted Option
>    * @t_opt: TCP Timestamp Option
>    * @end: end of options
>    */
> -struct ip_tcp_hdr_o {
> -	struct	ip_hdr     ip_hdr;
> -	struct	tcp_hdr    tcp_hdr;
> +struct tcp_hdr_o {
>   	struct	tcp_mss	   mss;
>   	struct	tcp_scale  scale;
>   	struct	tcp_sack_p sack_p;
> @@ -182,6 +188,22 @@ struct ip_tcp_hdr_o {
>   	u8	end;
>   } __packed;
>   
> +#define TCP_O_SIZE (sizeof(struct tcp_hdr_o))
> +
> +/**
> + * struct ip_tcp_hdr_o - IP + TCP header + TCP options
> + * @ip_hdr: IP + TCP header
> + * @tcp_hdr: TCP header
> + * @tcp_o: TCP options
> + * @end: end of IP/TCP header
> + */
> +struct ip_tcp_hdr_o {
> +	struct  ip_hdr     ip_hdr;
> +	struct	tcp_hdr    tcp_hdr;
> +	struct  tcp_hdr_o  tcp_o;
> +	u8	end;
> +} __packed;
> +
>   #define IP_TCP_O_SIZE (sizeof(struct ip_tcp_hdr_o))
>   
>   /**
> @@ -209,7 +231,7 @@ struct ip_tcp_hdr_s {
>   
>   /**
>    * struct pseudo_hdr - Pseudo Header
> - * @padding: pseudo hdr size = ip_tcp hdr size
> + * @padding: pseudo hdr size = ip hdr size
>    * @p_src: Source IP address
>    * @p_dst: Destination IP address
>    * @rsvd: reserved
> @@ -236,7 +258,6 @@ struct pseudo_hdr {
>    *
>    * Build Pseudo header in packed buffer
>    * first, calculate TCP checksum, then build IP header in packed buffer.
> - *
>    */
>   union tcp_build_pkt {
>   	struct pseudo_hdr ph;
> @@ -269,9 +290,77 @@ enum tcp_state {
>   
>   enum tcp_state tcp_get_tcp_state(void);
>   void tcp_set_tcp_state(enum tcp_state new_state);
> -int tcp_set_tcp_header(uchar *pkt, int dport, int sport, int payload_len,
> +
> +/**
> + * net_set_tcp_header_common() - IP version agnostic TCP header building implementation
> + *
> + * @tcp_hdr: pointer to TCP header struct
> + * @tcp_o: pointer to TCP options header struct
> + * @sack_t_opt: pointer to TCP sack options header struct
> + * @sack_v: pointer to TCP sack header struct
> + * @dport: destination TCP port
> + * @sport: source TCP port
> + * @payload_len: TCP payload len
> + * @action: TCP action (SYN, ACK, FIN, etc)
> + * @tcp_seq_num: TCP sequential number
> + * @tcp_ack_num: TCP acknowledgment number
> + *
> + * returns TCP header
> + */
> +int net_set_tcp_header_common(struct tcp_hdr *tcp_hdr, struct tcp_hdr_o *tcp_o,
> +			      struct tcp_t_opt *sack_t_opt, struct tcp_sack_v *sack_v,
> +			      u16 dport, u16 sport, int payload_len, u8 action,
> +			      u32 tcp_seq_num, u32 tcp_ack_num);
> +
> +/**
> + * net_set_tcp_header() - IPv4 TCP header bulding implementation
> + *
> + * @pkt: pointer to the IP header
> + * @dport: destination TCP port
> + * @sport: source TCP port
> + * @payload_len: TCP payload len
> + * @action: TCP action (SYN, ACK, FIN, etc)
> + * @tcp_seq_num: TCP sequential number
> + * @tcp_ack_num: TCP acknowledgment number
> + *
> + * returns TCP header
> + */
> +int net_set_tcp_header(uchar *pkt, u16 dport, u16 sport, int payload_len,
>   		       u8 action, u32 tcp_seq_num, u32 tcp_ack_num);
>   
> +/**
> + * tcp_parse_options() - parsing TCP options
> + *
> + * @o: pointer to the option field.
> + * @o_len: length of the option field.
> + */
> +void tcp_parse_options(uchar *o, int o_len);
> +
> +/**
> + * tcp_state_machine() - update TCP state in a reaction to incoming packet
> + *
> + * @tcp_flags: TCP action (SYN, ACK, FIN, etc)
> + * @tcp_seq_num: TCP sequential number
> + * @tcp_seq_num_out: TCP sequential number we expect to answer with
> + * @tcp_ack_num_out: TCP acknowledgment number we expect to answer with
> + * @payload_len: TCP payload len
> + *
> + * returns TCP action we expect to answer with
> + */
> +u8 tcp_state_machine(u8 tcp_flags, u32 tcp_seq_num, u32 *tcp_seq_num_out,
> +		     u32 *tcp_ack_num_out, int payload_len);
> +
> +/**
> + * tcp_sent_state_machine() - update TCP state in a reaction to outcoming packet
> + *
> + * @action: TCP action (SYN, ACK, FIN, etc)
> + * @tcp_seq_num: TCP sequential number
> + * @tcp_ack_num: TCP acknowledgment number
> + *
> + * returns TCP action we expect to answer with
> + */
> +u8 tcp_sent_state_machine(u8 action, u32 *tcp_seq_num, u32 *tcp_ack_num);
> +
>   /**
>    * rxhand_tcp() - An incoming packet handler.
>    * @pkt: pointer to the application packet
> diff --git a/net/net.c b/net/net.c
> index 43abbac7c3..0b68bf7b13 100644
> --- a/net/net.c
> +++ b/net/net.c
> @@ -916,6 +916,7 @@ int net_send_ip_packet(uchar *ether, struct in_addr dest, int dport, int sport,
>   {
>   	uchar *pkt;
>   	int eth_hdr_size;
> +	int ip_tcp_hdr_size;
>   	int pkt_hdr_size;
>   
>   	/* make sure the net_tx_packet is initialized (net_init() was called) */
> @@ -934,19 +935,24 @@ int net_send_ip_packet(uchar *ether, struct in_addr dest, int dport, int sport,
>   	pkt = (uchar *)net_tx_packet;
>   
>   	eth_hdr_size = net_set_ether(pkt, ether, PROT_IP);
> +	pkt_hdr_size = eth_hdr_size;
> +	pkt += eth_hdr_size;
>   
>   	switch (proto) {
>   	case IPPROTO_UDP:
> -		net_set_udp_header(pkt + eth_hdr_size, dest, dport, sport,
> +		net_set_udp_header(pkt, dest, dport, sport,
>   				   payload_len);
> -		pkt_hdr_size = eth_hdr_size + IP_UDP_HDR_SIZE;
> +		pkt_hdr_size += IP_UDP_HDR_SIZE;
>   		break;
>   #if defined(CONFIG_PROT_TCP)
>   	case IPPROTO_TCP:
> -		pkt_hdr_size = eth_hdr_size
> -			+ tcp_set_tcp_header(pkt + eth_hdr_size, dport, sport,
> -					     payload_len, action, tcp_seq_num,
> -					     tcp_ack_num);
> +		ip_tcp_hdr_size = IP_HDR_SIZE;
> +		ip_tcp_hdr_size += net_set_tcp_header(pkt, dport, sport,
> +						      payload_len, action, tcp_seq_num,
> +						      tcp_ack_num);
> +		net_set_ip_header(pkt, net_server_ip, net_ip,
> +				  ip_tcp_hdr_size + payload_len, IPPROTO_TCP);
> +		pkt_hdr_size += ip_tcp_hdr_size;
>   		break;
>   #endif
>   	default:
> diff --git a/net/net6.c b/net/net6.c
> index 2dd64c0e16..e395b930b0 100644
> --- a/net/net6.c
> +++ b/net/net6.c
> @@ -324,15 +324,13 @@ int ip6_add_hdr(uchar *xip, struct in6_addr *src, struct in6_addr *dest,
>   	return sizeof(struct ip6_hdr);
>   }
>   
> -int net_send_udp_packet6(uchar *ether, struct in6_addr *dest, int dport,
> -			 int sport, int len)
> +int udp6_add_hdr(uchar *xip, struct in6_addr *dest, int dport, int sport,
> +		 int len)
>   {
> -	uchar *pkt;
>   	struct udp_hdr *udp;
>   	u16 csum_p;
>   
> -	udp = (struct udp_hdr *)((uchar *)net_tx_packet + net_eth_hdr_size() +
> -			IP6_HDR_SIZE);
> +	udp = (struct udp_hdr *)xip;
>   
>   	udp->udp_dst = htons(dport);
>   	udp->udp_src = htons(sport);
> @@ -344,39 +342,75 @@ int net_send_udp_packet6(uchar *ether, struct in6_addr *dest, int dport,
>   	udp->udp_xsum = csum_ipv6_magic(&net_ip6, dest, len + UDP_HDR_SIZE,
>   					IPPROTO_UDP, csum_p);
>   
> +	return sizeof(struct udp_hdr);
> +}
> +
> +int net_send_ip_packet6(uchar *ether, struct in6_addr *dest, int dport, int sport,
> +			int payload_len, int proto, u8 action, u32 tcp_seq_num,
> +			u32 tcp_ack_num)
> +{
> +	uchar *pkt;
> +	int eth_hdr_size;
> +	int ip_hdr_size;
> +	int udp_hdr_size;
> +	int tcp_hdr_size;
> +	int pkt_hdr_size;
> +
> +	if (!net_tx_packet)
> +		return -1;
> +
> +	pkt = (uchar *)net_tx_packet;
> +
> +	eth_hdr_size = net_set_ether(pkt, ether, PROT_IP6);
> +	pkt_hdr_size += eth_hdr_size;
> +	pkt = eth_hdr_size;
> +
> +	switch (proto) {
> +#if defined(CONFIG_PROT_UDP)
> +	case IPPROTO_UDP:
> +		ip_hdr_size = ip6_add_hdr(pkt, &net_ip6, dest, IPPROTO_UDP, 64,
> +					  payload_len + UDP_HDR_SIZE);
> +		pkt_hdr_size += ip_hdr_size;
> +		pkt += ip_hdr_size;
> +
> +		udp_hdr_size = udp6_add_hdr(pkt, dest, dport, sport, payload_len);
> +		pkt_hdr_size += udp_hdr_size;
> +		pkt += udp_hdr_size;
> +		break;
> +#endif
> +	default:
> +		return -EINVAL;
> +	}
> +
>   	/* if MAC address was not discovered yet, save the packet and do
>   	 * neighbour discovery
>   	 */
> -	if (!memcmp(ether, net_null_ethaddr, 6)) {
> +	if (memcmp(ether, net_null_ethaddr, 6) == 0) {
> +		memcpy((uchar *)net_nd_tx_packet,
> +		       (uchar *)net_tx_packet, pkt_hdr_size + payload_len);
> +		memset((uchar *)net_tx_packet, 0, pkt_hdr_size + payload_len);
> +
>   		net_copy_ip6(&net_nd_sol_packet_ip6, dest);
>   		net_nd_packet_mac = ether;
> -
> -		pkt = net_nd_tx_packet;
> -		pkt += net_set_ether(pkt, net_nd_packet_mac, PROT_IP6);
> -		pkt += ip6_add_hdr(pkt, &net_ip6, dest, IPPROTO_UDP, 64,
> -				len + UDP_HDR_SIZE);
> -		memcpy(pkt, (uchar *)udp, len + UDP_HDR_SIZE);
> -
>   		/* size of the waiting packet */
> -		net_nd_tx_packet_size = (pkt - net_nd_tx_packet) +
> -			UDP_HDR_SIZE + len;
> -
> -		/* and do the neighbor solicitation */
> +		net_nd_tx_packet_size = pkt_hdr_size + payload_len;
>   		net_nd_try = 1;
>   		net_nd_timer_start = get_timer(0);
>   		ndisc_request();
>   		return 1;	/* waiting */
>   	}
>   
> -	pkt = (uchar *)net_tx_packet;
> -	pkt += net_set_ether(pkt, ether, PROT_IP6);
> -	pkt += ip6_add_hdr(pkt, &net_ip6, dest, IPPROTO_UDP, 64,
> -			len + UDP_HDR_SIZE);
> -	(void)eth_send(net_tx_packet, pkt - net_tx_packet + UDP_HDR_SIZE + len);
> +	(void)eth_send(net_tx_packet, pkt_hdr_size + payload_len);
>   
>   	return 0;	/* transmitted */
>   }
>   
> +int net_send_udp_packet6(uchar *ether, struct in6_addr *dest, int dport,
> +			 int sport, int len)
> +{
> +	return net_send_ip_packet6(ether, dest, dport, sport, len, IPPROTO_UDP, 0, 0, 0);
> +}
> +
>   int net_ip6_handler(struct ethernet_hdr *et, struct ip6_hdr *ip6, int len)
>   {
>   	struct in_addr zero_ip = {.s_addr = 0 };
> diff --git a/net/tcp.c b/net/tcp.c
> index 10ce799814..483c03a595 100644
> --- a/net/tcp.c
> +++ b/net/tcp.c
> @@ -54,16 +54,6 @@ static struct sack_r edge_a[TCP_SACK];
>   static unsigned int sack_idx;
>   static unsigned int prev_len;
>   
> -/*
> - * TCP lengths are stored as a rounded up number of 32 bit words.
> - * Add 3 to length round up, rounded, then divided into the
> - * length in 32 bit words.
> - */
> -#define LEN_B_TO_DW(x) ((x) >> 2)
> -#define ROUND_TCPHDR_LEN(x) (LEN_B_TO_DW((x) + 3))
> -#define SHIFT_TO_TCPHDRLEN_FIELD(x) ((x) << 4)
> -#define GET_TCP_HDR_LEN_IN_BYTES(x) ((x) >> 2)
> -
>   /* TCP connection state */
>   static enum tcp_state current_tcp_state;
>   
> @@ -149,29 +139,32 @@ u16 tcp_set_pseudo_header(uchar *pkt, struct in_addr src, struct in_addr dest,
>   
>   /**
>    * net_set_ack_options() - set TCP options in acknowledge packets
> - * @b: the packet
> + * @tcp_hdr: pointer to TCP header struct
> + * @t_opt: pointer to TCP t opt header struct
> + * @sack_v: pointer to TCP sack header struct
>    *
>    * Return: TCP header length
>    */
> -int net_set_ack_options(union tcp_build_pkt *b)
> +int net_set_ack_options(struct tcp_hdr *tcp_hdr, struct tcp_t_opt *t_opt,
> +			struct tcp_sack_v *sack_v)
>   {
> -	b->sack.tcp_hdr.tcp_hlen = SHIFT_TO_TCPHDRLEN_FIELD(LEN_B_TO_DW(TCP_HDR_SIZE));
> +	tcp_hdr->tcp_hlen = SHIFT_TO_TCPHDRLEN_FIELD(LEN_B_TO_DW(TCP_HDR_SIZE));
>   
> -	b->sack.t_opt.kind = TCP_O_TS;
> -	b->sack.t_opt.len = TCP_OPT_LEN_A;
> -	b->sack.t_opt.t_snd = htons(loc_timestamp);
> -	b->sack.t_opt.t_rcv = rmt_timestamp;
> -	b->sack.sack_v.kind = TCP_1_NOP;
> -	b->sack.sack_v.len = 0;
> +	t_opt->kind = TCP_O_TS;
> +	t_opt->len = TCP_OPT_LEN_A;
> +	t_opt->t_snd = htons(loc_timestamp);
> +	t_opt->t_rcv = rmt_timestamp;
> +	sack_v->kind = TCP_1_NOP;
> +	sack_v->len = 0;
>   
>   	if (IS_ENABLED(CONFIG_PROT_TCP_SACK)) {
>   		if (tcp_lost.len > TCP_OPT_LEN_2) {
>   			debug_cond(DEBUG_DEV_PKT, "TCP ack opt lost.len %x\n",
>   				   tcp_lost.len);
> -			b->sack.sack_v.len = tcp_lost.len;
> -			b->sack.sack_v.kind = TCP_V_SACK;
> -			b->sack.sack_v.hill[0].l = htonl(tcp_lost.hill[0].l);
> -			b->sack.sack_v.hill[0].r = htonl(tcp_lost.hill[0].r);
> +			sack_v->len = tcp_lost.len;
> +			sack_v->kind = TCP_V_SACK;
> +			sack_v->hill[0].l = htonl(tcp_lost.hill[0].l);
> +			sack_v->hill[0].r = htonl(tcp_lost.hill[0].r);
>   
>   			/*
>   			 * These SACK structures are initialized with NOPs to
> @@ -179,21 +172,21 @@ int net_set_ack_options(union tcp_build_pkt *b)
>   			 * SACK structures used for both header padding and
>   			 * internally.
>   			 */
> -			b->sack.sack_v.hill[1].l = htonl(tcp_lost.hill[1].l);
> -			b->sack.sack_v.hill[1].r = htonl(tcp_lost.hill[1].r);
> -			b->sack.sack_v.hill[2].l = htonl(tcp_lost.hill[2].l);
> -			b->sack.sack_v.hill[2].r = htonl(tcp_lost.hill[2].r);
> -			b->sack.sack_v.hill[3].l = TCP_O_NOP;
> -			b->sack.sack_v.hill[3].r = TCP_O_NOP;
> +			sack_v->hill[1].l = htonl(tcp_lost.hill[1].l);
> +			sack_v->hill[1].r = htonl(tcp_lost.hill[1].r);
> +			sack_v->hill[2].l = htonl(tcp_lost.hill[2].l);
> +			sack_v->hill[2].r = htonl(tcp_lost.hill[2].r);
> +			sack_v->hill[3].l = TCP_O_NOP;
> +			sack_v->hill[3].r = TCP_O_NOP;
>   		}
>   
> -		b->sack.tcp_hdr.tcp_hlen = SHIFT_TO_TCPHDRLEN_FIELD(ROUND_TCPHDR_LEN(TCP_HDR_SIZE +
> -										 TCP_TSOPT_SIZE +
> -										 tcp_lost.len));
> +		tcp_hdr->tcp_hlen = SHIFT_TO_TCPHDRLEN_FIELD(ROUND_TCPHDR_LEN(TCP_HDR_SIZE +
> +									      TCP_TSOPT_SIZE +
> +									      tcp_lost.len));
>   	} else {
> -		b->sack.sack_v.kind = 0;
> -		b->sack.tcp_hdr.tcp_hlen = SHIFT_TO_TCPHDRLEN_FIELD(ROUND_TCPHDR_LEN(TCP_HDR_SIZE +
> -										 TCP_TSOPT_SIZE));
> +		sack_v->kind = 0;
> +		tcp_hdr->tcp_hlen = SHIFT_TO_TCPHDRLEN_FIELD(ROUND_TCPHDR_LEN(TCP_HDR_SIZE +
> +									      TCP_TSOPT_SIZE));
>   	}
>   
>   	/*
> @@ -201,69 +194,61 @@ int net_set_ack_options(union tcp_build_pkt *b)
>   	 * TCP header to add to the total packet length
>   	 */
>   
> -	return GET_TCP_HDR_LEN_IN_BYTES(b->sack.tcp_hdr.tcp_hlen);
> +	return GET_TCP_HDR_LEN_IN_BYTES(tcp_hdr->tcp_hlen);
>   }
>   
>   /**
>    * net_set_ack_options() - set TCP options in SYN packets
> - * @b: the packet
> + * @tcp_hdr: pointer to TCP header struct
> + * @options: pointer to TCP header options struct
>    */
> -void net_set_syn_options(union tcp_build_pkt *b)
> +void net_set_syn_options(struct tcp_hdr *tcp_hdr, struct tcp_hdr_o *options)
>   {
>   	if (IS_ENABLED(CONFIG_PROT_TCP_SACK))
>   		tcp_lost.len = 0;
>   
> -	b->ip.tcp_hdr.tcp_hlen = 0xa0;
> +	tcp_hdr->tcp_hlen = 0xa0;
>   
> -	b->ip.mss.kind = TCP_O_MSS;
> -	b->ip.mss.len = TCP_OPT_LEN_4;
> -	b->ip.mss.mss = htons(TCP_MSS);
> -	b->ip.scale.kind = TCP_O_SCL;
> -	b->ip.scale.scale = TCP_SCALE;
> -	b->ip.scale.len = TCP_OPT_LEN_3;
> +	options->mss.kind = TCP_O_MSS;
> +	options->mss.len = TCP_OPT_LEN_4;
> +	options->mss.mss = htons(TCP_MSS);
> +	options->scale.kind = TCP_O_SCL;
> +	options->scale.scale = TCP_SCALE;
> +	options->scale.len = TCP_OPT_LEN_3;
>   	if (IS_ENABLED(CONFIG_PROT_TCP_SACK)) {
> -		b->ip.sack_p.kind = TCP_P_SACK;
> -		b->ip.sack_p.len = TCP_OPT_LEN_2;
> +		options->sack_p.kind = TCP_P_SACK;
> +		options->sack_p.len = TCP_OPT_LEN_2;
>   	} else {
> -		b->ip.sack_p.kind = TCP_1_NOP;
> -		b->ip.sack_p.len = TCP_1_NOP;
> +		options->sack_p.kind = TCP_1_NOP;
> +		options->sack_p.len = TCP_1_NOP;
>   	}
> -	b->ip.t_opt.kind = TCP_O_TS;
> -	b->ip.t_opt.len = TCP_OPT_LEN_A;
> +	options->t_opt.kind = TCP_O_TS;
> +	options->t_opt.len = TCP_OPT_LEN_A;
>   	loc_timestamp = get_ticks();
>   	rmt_timestamp = 0;
> -	b->ip.t_opt.t_snd = 0;
> -	b->ip.t_opt.t_rcv = 0;
> -	b->ip.end = TCP_O_END;
> +
> +	options->t_opt.t_snd = 0;
> +	options->t_opt.t_rcv = 0;
>   }
>   
> -int tcp_set_tcp_header(uchar *pkt, int dport, int sport, int payload_len,
> -		       u8 action, u32 tcp_seq_num, u32 tcp_ack_num)
> +/**
> + * tcp_sent_state_machine() - update TCP state in a reaction to outcoming packet
> + *
> + * @action: TCP action (SYN, ACK, FIN, etc)
> + * @tcp_seq_num: TCP sequential number
> + * @tcp_ack_num: TCP acknowledgment number
> + *
> + * returns TCP action we expect to answer with
> + */
> +u8 tcp_sent_state_machine(u8 action, u32 *tcp_seq_num, u32 *tcp_ack_num)
>   {
> -	union tcp_build_pkt *b = (union tcp_build_pkt *)pkt;
> -	int pkt_hdr_len;
> -	int pkt_len;
> -	int tcp_len;
> -
> -	/*
> -	 * Header: 5 32 bit words. 4 bits TCP header Length,
> -	 *         4 bits reserved options
> -	 */
> -	b->ip.tcp_hdr.tcp_flags = action;
> -	pkt_hdr_len = IP_TCP_HDR_SIZE;
> -	b->ip.tcp_hdr.tcp_hlen = SHIFT_TO_TCPHDRLEN_FIELD(LEN_B_TO_DW(TCP_HDR_SIZE));
> -
>   	switch (action) {
>   	case TCP_SYN:
>   		debug_cond(DEBUG_DEV_PKT,
> -			   "TCP Hdr:SYN (%pI4, %pI4, sq=%u, ak=%u)\n",
> -			   &net_server_ip, &net_ip,
> -			   tcp_seq_num, tcp_ack_num);
> +			   "TCP Hdr:SYN (sq=%u, ak=%u)\n", *tcp_seq_num, *tcp_ack_num);
>   		tcp_activity_count = 0;
> -		net_set_syn_options(b);
> -		tcp_seq_num = 0;
> -		tcp_ack_num = 0;
> -		pkt_hdr_len = IP_TCP_O_SIZE;
> +		*tcp_seq_num = 0;
> +		*tcp_ack_num = 0;
>   		if (current_tcp_state == TCP_SYN_SENT) {  /* Too many SYNs */
>   			action = TCP_FIN;
>   			current_tcp_state = TCP_FIN_WAIT_1;
> @@ -273,57 +258,93 @@ int tcp_set_tcp_header(uchar *pkt, int dport, int sport, int payload_len,
>   		break;
>   	case TCP_SYN | TCP_ACK:
>   	case TCP_ACK:
> -		pkt_hdr_len = IP_HDR_SIZE + net_set_ack_options(b);
> -		b->ip.tcp_hdr.tcp_flags = action;
>   		debug_cond(DEBUG_DEV_PKT,
> -			   "TCP Hdr:ACK (%pI4, %pI4, s=%u, a=%u, A=%x)\n",
> -			   &net_server_ip, &net_ip, tcp_seq_num, tcp_ack_num,
> -			   action);
> +			   "TCP Hdr:ACK (s=%u, a=%u, A=%x)\n",
> +			   *tcp_seq_num, *tcp_ack_num, action);
>   		break;
>   	case TCP_FIN:
>   		debug_cond(DEBUG_DEV_PKT,
> -			   "TCP Hdr:FIN  (%pI4, %pI4, s=%u, a=%u)\n",
> -			   &net_server_ip, &net_ip, tcp_seq_num, tcp_ack_num);
> -		payload_len = 0;
> -		pkt_hdr_len = IP_TCP_HDR_SIZE;
> +			   "TCP Hdr:FIN  (s=%u, a=%u)\n", *tcp_seq_num, *tcp_ack_num);
>   		current_tcp_state = TCP_FIN_WAIT_1;
>   		break;
>   	case TCP_RST | TCP_ACK:
>   	case TCP_RST:
>   		debug_cond(DEBUG_DEV_PKT,
> -			   "TCP Hdr:RST  (%pI4, %pI4, s=%u, a=%u)\n",
> -			   &net_server_ip, &net_ip, tcp_seq_num, tcp_ack_num);
> +			   "TCP Hdr:RST  (s=%u, a=%u)\n", *tcp_seq_num, *tcp_ack_num);
>   		current_tcp_state = TCP_CLOSED;
>   		break;
>   	/* Notify connection closing */
>   	case (TCP_FIN | TCP_ACK):
>   	case (TCP_FIN | TCP_ACK | TCP_PUSH):
> +		debug_cond(DEBUG_DEV_PKT,
> +			   "TCP Hdr:FIN ACK PSH(s=%u, a=%u, A=%x)\n",
> +			   *tcp_seq_num, *tcp_ack_num, action);
>   		if (current_tcp_state == TCP_CLOSE_WAIT)
>   			current_tcp_state = TCP_CLOSING;
> -
> -		debug_cond(DEBUG_DEV_PKT,
> -			   "TCP Hdr:FIN ACK PSH(%pI4, %pI4, s=%u, a=%u, A=%x)\n",
> -			   &net_server_ip, &net_ip,
> -			   tcp_seq_num, tcp_ack_num, action);
>   		fallthrough;
>   	default:
> -		pkt_hdr_len = IP_HDR_SIZE + net_set_ack_options(b);
> -		b->ip.tcp_hdr.tcp_flags = action | TCP_PUSH | TCP_ACK;
> +		action = action | TCP_PUSH | TCP_ACK;
>   		debug_cond(DEBUG_DEV_PKT,
> -			   "TCP Hdr:dft  (%pI4, %pI4, s=%u, a=%u, A=%x)\n",
> -			   &net_server_ip, &net_ip,
> -			   tcp_seq_num, tcp_ack_num, action);
> +			   "TCP Hdr:dft  (s=%u, a=%u, A=%x)\n",
> +			   *tcp_seq_num, *tcp_ack_num, action);
>   	}
>   
> -	pkt_len	= pkt_hdr_len + payload_len;
> -	tcp_len	= pkt_len - IP_HDR_SIZE;
> +	return action;
> +}
> +
> +/**
> + * net_set_tcp_header_common() - IP version agnostic TCP header building implementation
> + *
> + * @tcp_hdr: pointer to TCP header struct
> + * @tcp_o: pointer to TCP options header struct
> + * @sack_t_opt: pointer to TCP sack options header struct
> + * @sack_v: pointer to TCP sack header struct
> + * @dport: destination TCP port
> + * @sport: source TCP port
> + * @payload_len: TCP payload len
> + * @action: TCP action (SYN, ACK, FIN, etc)
> + * @tcp_seq_num: TCP sequential number
> + * @tcp_ack_num: TCP acknowledgment number
> + *
> + * returns TCP header size
> + */
> +int net_set_tcp_header_common(struct tcp_hdr *tcp_hdr, struct tcp_hdr_o *tcp_o,
> +			      struct tcp_t_opt *sack_t_opt, struct tcp_sack_v *sack_v,
> +			      u16 dport, u16 sport, int payload_len, u8 action,
> +			      u32 tcp_seq_num, u32 tcp_ack_num)
> +{
> +	u8  tcp_action = TCP_DATA;
> +	int tcp_hdr_len;
> +
> +	/*
> +	 * Header: 5 32 bit words. 4 bits TCP header Length,
> +	 *         4 bits reserved options
> +	 */
> +	tcp_hdr_len = TCP_HDR_SIZE;
> +	tcp_hdr->tcp_hlen = SHIFT_TO_TCPHDRLEN_FIELD(LEN_B_TO_DW(TCP_HDR_SIZE));
> +
> +	switch (action) {
> +	case TCP_SYN:
> +		net_set_syn_options(tcp_hdr, tcp_o);
> +		tcp_hdr_len = TCP_HDR_SIZE + TCP_O_SIZE;
> +		break;
> +	case TCP_RST | TCP_ACK:
> +	case TCP_RST:
> +	case TCP_FIN:
> +		payload_len = 0;
> +		break;
> +	default:
> +		tcp_hdr_len = net_set_ack_options(tcp_hdr, sack_t_opt, sack_v);
> +	}
> +
> +	tcp_action = tcp_sent_state_machine(action, &tcp_seq_num, &tcp_ack_num);
> +	tcp_hdr->tcp_flags = tcp_action;
>   
>   	tcp_ack_edge = tcp_ack_num;
> -	/* TCP Header */
> -	b->ip.tcp_hdr.tcp_ack = htonl(tcp_ack_edge);
> -	b->ip.tcp_hdr.tcp_src = htons(sport);
> -	b->ip.tcp_hdr.tcp_dst = htons(dport);
> -	b->ip.tcp_hdr.tcp_seq = htonl(tcp_seq_num);
> +	tcp_hdr->tcp_ack = htonl(tcp_ack_edge);
> +	tcp_hdr->tcp_seq = htonl(tcp_seq_num);
> +	tcp_hdr->tcp_src = htons(sport);
> +	tcp_hdr->tcp_dst = htons(dport);
>   
>   	/*
>   	 * TCP window size - TCP header variable tcp_win.
> @@ -340,18 +361,46 @@ int tcp_set_tcp_header(uchar *pkt, int dport, int sport, int payload_len,
>   	 * it is, then the u-boot tftp or nfs kernel netboot should be
>   	 * considered.
>   	 */
> -	b->ip.tcp_hdr.tcp_win = htons(PKTBUFSRX * TCP_MSS >> TCP_SCALE);
> +	tcp_hdr->tcp_win = htons(PKTBUFSRX * TCP_MSS >> TCP_SCALE);
>   
> -	b->ip.tcp_hdr.tcp_xsum = 0;
> -	b->ip.tcp_hdr.tcp_ugr = 0;
> +	tcp_hdr->tcp_xsum = 0;
> +	tcp_hdr->tcp_ugr = 0;
>   
> -	b->ip.tcp_hdr.tcp_xsum = tcp_set_pseudo_header(pkt, net_ip, net_server_ip,
> -						       tcp_len, pkt_len);
> +	return tcp_hdr_len;
> +}
>   
> -	net_set_ip_header((uchar *)&b->ip, net_server_ip, net_ip,
> -			  pkt_len, IPPROTO_TCP);
> +/**
> + * net_set_tcp_header() - IPv4 TCP header bulding implementation
> + *
> + * @pkt: pointer to the IP header
> + * @dport: destination TCP port
> + * @sport: source TCP port
> + * @payload_len: TCP payload len
> + * @action: TCP action (SYN, ACK, FIN, etc)
> + * @tcp_seq_num: TCP sequential number
> + * @tcp_ack_num: TCP acknowledgment number
> + *
> + * returns TCP header + payload size
> + */
> +int net_set_tcp_header(uchar *pkt, u16 dport, u16 sport, int payload_len,
> +		       u8 action, u32 tcp_seq_num, u32 tcp_ack_num)
> +{
> +	union tcp_build_pkt *b = (union tcp_build_pkt *)pkt;
> +	int tcp_hdr_len;
> +	int pkt_len;
>   
> -	return pkt_hdr_len;
> +	pkt_len = IP_HDR_SIZE;
> +	tcp_hdr_len = net_set_tcp_header_common(&b->ip.tcp_hdr, &b->ip.tcp_o,
> +						&b->sack.t_opt, &b->sack.sack_v,
> +						dport, sport, payload_len, action,
> +						tcp_seq_num, tcp_ack_num);
> +	pkt_len += tcp_hdr_len;
> +	pkt_len += payload_len;
> +
> +	b->ip.tcp_hdr.tcp_xsum = tcp_set_pseudo_header(pkt, net_ip, net_server_ip,
> +						       tcp_hdr_len + payload_len, pkt_len);
> +
> +	return tcp_hdr_len;
>   }
>   
>   /**
> @@ -500,7 +549,31 @@ void tcp_parse_options(uchar *o, int o_len)
>   	}
>   }
>   
> -static u8 tcp_state_machine(u8 tcp_flags, u32 tcp_seq_num, int payload_len)
> +static void init_sack_options(u32 tcp_seq_num, u32 tcp_ack_num)
> +{
> +	tcp_seq_init = tcp_seq_num;
> +	tcp_ack_edge = tcp_ack_num;
> +	sack_idx = 0;
> +	edge_a[sack_idx].se.l = tcp_ack_edge;
> +	edge_a[sack_idx].se.r = tcp_ack_edge;
> +	prev_len = 0;
> +	for (int i = 0; i < TCP_SACK; i++)
> +		edge_a[i].st = NOPKT;
> +}
> +
> +/**
> + * tcp_state_machine() - update TCP state in a reaction to incoming request
> + *
> + * @tcp_flags: TCP action (SYN, ACK, FIN, etc)
> + * @tcp_seq_num: TCP sequential number
> + * @tcp_seq_num_out: TCP sequential number we expect to answer with
> + * @tcp_ack_num_out: TCP acknowledgment number we expect to answer with
> + * @payload_len: TCP payload len
> + *
> + * returns TCP action we expect to answer with
> + */
> +u8 tcp_state_machine(u8 tcp_flags, u32 tcp_seq_num, u32 *tcp_seq_num_out,
> +		     u32 *tcp_ack_num_out, int payload_len)
>   {
>   	u8 tcp_fin = tcp_flags & TCP_FIN;
>   	u8 tcp_syn = tcp_flags & TCP_SYN;
> @@ -508,7 +581,6 @@ static u8 tcp_state_machine(u8 tcp_flags, u32 tcp_seq_num, int payload_len)
>   	u8 tcp_push = tcp_flags & TCP_PUSH;
>   	u8 tcp_ack = tcp_flags & TCP_ACK;
>   	u8 action = TCP_DATA;
> -	int i;
>   
>   	/*
>   	 * tcp_flags are examined to determine TX action in a given state
> @@ -533,34 +605,29 @@ static u8 tcp_state_machine(u8 tcp_flags, u32 tcp_seq_num, int payload_len)
>   		debug_cond(DEBUG_INT_STATE, "TCP CLOSED %x\n", tcp_flags);
>   		if (tcp_syn) {
>   			action = TCP_SYN | TCP_ACK;
> -			tcp_seq_init = tcp_seq_num;
> -			tcp_ack_edge = tcp_seq_num + 1;
> +			init_sack_options(tcp_seq_num, tcp_seq_num + 1);
>   			current_tcp_state = TCP_SYN_RECEIVED;
>   		} else if (tcp_ack || tcp_fin) {
>   			action = TCP_DATA;
>   		}
>   		break;
>   	case TCP_SYN_RECEIVED:
> +		if (tcp_ack) {
> +			action = TCP_DATA;
> +			init_sack_options(tcp_seq_num, tcp_seq_num + 1);
> +			current_tcp_state = TCP_ESTABLISHED;
> +		}
> +		break;
>   	case TCP_SYN_SENT:
>   		debug_cond(DEBUG_INT_STATE, "TCP_SYN_SENT | TCP_SYN_RECEIVED %x, %u\n",
>   			   tcp_flags, tcp_seq_num);
>   		if (tcp_fin) {
>   			action = action | TCP_PUSH;
>   			current_tcp_state = TCP_CLOSE_WAIT;
> -		} else if (tcp_ack || (tcp_syn && tcp_ack)) {
> -			action |= TCP_ACK;
> -			tcp_seq_init = tcp_seq_num;
> -			tcp_ack_edge = tcp_seq_num + 1;
> -			sack_idx = 0;
> -			edge_a[sack_idx].se.l = tcp_ack_edge;
> -			edge_a[sack_idx].se.r = tcp_ack_edge;
> -			prev_len = 0;
> +		} else if (tcp_syn && tcp_ack) {
> +			action |= TCP_ACK | TCP_PUSH;
> +			init_sack_options(tcp_seq_num, tcp_seq_num + 1);
>   			current_tcp_state = TCP_ESTABLISHED;
> -			for (i = 0; i < TCP_SACK; i++)
> -				edge_a[i].st = NOPKT;
> -
> -			if (tcp_syn && tcp_ack)
> -				action |= TCP_PUSH;
>   		} else {
>   			action = TCP_DATA;
>   		}
> @@ -627,6 +694,10 @@ static u8 tcp_state_machine(u8 tcp_flags, u32 tcp_seq_num, int payload_len)
>   		}
>   		break;
>   	}
> +
> +	*tcp_seq_num_out = tcp_seq_num;
> +	*tcp_ack_num_out = tcp_ack_edge;
> +
>   	return action;
>   }
>   
> @@ -641,6 +712,7 @@ void rxhand_tcp_f(union tcp_build_pkt *b, unsigned int pkt_len)
>   	u16 tcp_rx_xsum = b->ip.ip_hdr.ip_sum;
>   	u8  tcp_action = TCP_DATA;
>   	u32 tcp_seq_num, tcp_ack_num;
> +	u32 res_tcp_seq_num, res_tcp_ack_num;
>   	int tcp_hdr_len, payload_len;
>   
>   	/* Verify IP header */
> @@ -685,7 +757,8 @@ void rxhand_tcp_f(union tcp_build_pkt *b, unsigned int pkt_len)
>   
>   	/* Packets are not ordered. Send to app as received. */
>   	tcp_action = tcp_state_machine(b->ip.tcp_hdr.tcp_flags,
> -				       tcp_seq_num, payload_len);
> +				       tcp_seq_num, &res_tcp_seq_num,
> +				       &res_tcp_ack_num, payload_len);
>   
>   	tcp_activity_count++;
>   	if (tcp_activity_count > TCP_ACTIVITY) {
> @@ -705,7 +778,7 @@ void rxhand_tcp_f(union tcp_build_pkt *b, unsigned int pkt_len)
>   	} else if (tcp_action != TCP_DATA) {
>   		debug_cond(DEBUG_DEV_PKT,
>   			   "TCP Action (action=%x,Seq=%u,Ack=%u,Pay=%d)\n",
> -			   tcp_action, tcp_ack_num, tcp_ack_edge, payload_len);
> +			   tcp_action, res_tcp_seq_num, res_tcp_ack_num, payload_len);
>   
>   		/*
>   		 * Warning: Incoming Ack & Seq sequence numbers are transposed
> @@ -714,6 +787,6 @@ void rxhand_tcp_f(union tcp_build_pkt *b, unsigned int pkt_len)
>   		net_send_tcp_packet(0, ntohs(b->ip.tcp_hdr.tcp_src),
>   				    ntohs(b->ip.tcp_hdr.tcp_dst),
>   				    (tcp_action & (~TCP_PUSH)),
> -				    tcp_ack_num, tcp_ack_edge);
> +				    res_tcp_seq_num, res_tcp_ack_num);
>   	}
>   }

Reviewed-by: Ying-Chun Liu (PaulLiu) <paul.liu at linaro.org>


More information about the U-Boot mailing list