[PATCH v2 3/6] net: introduce TCP/IP6 support

Ying-Chun Liu (PaulLiu) paul.liu at linaro.org
Thu May 25 06:52:37 CEST 2023



On 2023/5/11 00:59, Dmitrii Merkurev wrote:
> Add TCP/IP6 related headers and reuse refactored TCP/IP
> implementation
> 
> 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/tcp6.h | 106 +++++++++++++++++++++++++++++++++++++++++++++
>   include/net6.h     |  14 ++++++
>   net/Makefile       |   1 +
>   net/net.c          |   6 +++
>   net/net6.c         |  72 +++++++++++++++++++++++++-----
>   net/tcp6.c         |  99 ++++++++++++++++++++++++++++++++++++++++++
>   6 files changed, 288 insertions(+), 10 deletions(-)
>   create mode 100644 include/net/tcp6.h
>   create mode 100644 net/tcp6.c
> 
> diff --git a/include/net/tcp6.h b/include/net/tcp6.h
> new file mode 100644
> index 0000000000..3db125ecc5
> --- /dev/null
> +++ b/include/net/tcp6.h
> @@ -0,0 +1,106 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Copyright (C) 2022 The Android Open Source Project
> + */
> +
> +#ifndef __TCP6_H__
> +#define __TCP6_H__
> +
> +#if defined(CONFIG_PROT_TCP)
> +
> +#include <net6.h>
> +#include <net/tcp.h>
> +
> +/**
> + * typedef rxhand_tcp6_f() - An incoming TCP IPv6 packet handler.
> + * @pkt: pointer to the application packet
> + * @dport: destination TCP port
> + * @sip: source IP6 address
> + * @sport: source TCP port
> + * @tcp_seq_num: TCP sequential number
> + * @tcp_ack_num: TCP acknowledgment number
> + * @action: TCP packet type (SYN, ACK, FIN, etc)
> + */
> +typedef void rxhand_tcp6_f(uchar *pkt, u16 dport,
> +			   struct in6_addr sip, u16 sport,
> +			   u32 tcp_seq_num, u32 tcp_ack_num,
> +			   u8 action, unsigned int len);
> +
> +/**
> + * struct ip6_tcp_hdr_o - IP6 + TCP header + TCP options
> + * @ip_hdr: IP6 + TCP header
> + * @tcp_hdr: TCP header
> + * @tcp_o: TCP options
> + * @end: end of IP6/TCP header
> + */
> +struct ip6_tcp_hdr_o {
> +	struct  ip6_hdr    ip_hdr;
> +	struct  tcp_hdr    tcp_hdr;
> +	struct  tcp_hdr_o  tcp_o;
> +	u8	end;
> +} __packed;
> +
> +#define IP6_TCP_O_SIZE (sizeof(struct ip6_tcp_hdr_o))
> +
> +/**
> + * struct ip6_tcp_hdr_s - IP6 + TCP header + TCP options
> + * @ip_hdr: IP6 + TCP header
> + * @tcp_hdr: TCP header
> + * @t_opt: TCP Timestamp Option
> + * @sack_v: TCP SACK Option
> + * @end: end of options
> + */
> +struct ip6_tcp_hdr_s {
> +	struct  ip6_hdr    ip_hdr;
> +	struct  tcp_hdr    tcp_hdr;
> +	struct  tcp_t_opt  t_opt;
> +	struct  tcp_sack_v sack_v;
> +	u8	end;
> +} __packed;
> +
> +#define IP6_TCP_SACK_SIZE (sizeof(struct ip6_tcp_hdr_s))
> +
> +/**
> + * union tcp6_build_pkt - union for building TCP/IP6 packet.
> + * @ip: IP6 and TCP header plus TCP options
> + * @sack: IP6 and TCP header plus SACK options
> + * @raw: buffer
> + */
> +union tcp6_build_pkt {
> +	struct ip6_tcp_hdr_o ip;
> +	struct ip6_tcp_hdr_s sack;
> +	uchar  raw[1600];
> +} __packed;
> +
> +/**
> + * net_set_tcp6_handler6() - set application TCP6 packet handler
> + * @param f pointer to callback function
> + */
> +void net_set_tcp_handler6(rxhand_tcp6_f *f);
> +
> +/**
> + * net_set_tcp_header6() - set
> + * @pkt: pointer to IP6/TCP headers
> + * @dport: destination TCP port
> + * @sport: source TCP port
> + * @payload_len: payload length
> + * @action: TCP packet type (SYN, ACK, FIN, etc)
> + * @tcp_seq_num: TCP sequential number
> + * @tcp_ack_num: TCP acknowledgment number
> + *
> + * returns TCP header size
> + */
> +int net_set_tcp_header6(uchar *pkt, u16 dport, u16 sport, int payload_len,
> +			u8 action, u32 tcp_seq_num, u32 tcp_ack_num);
> +
> +void net_set_tcp_handler6(rxhand_tcp6_f *f);
> +
> +/**
> + * rxhand_tcp6() - handle incoming IP6 TCP packet
> + * @param b pointer to IP6/TCP packet builder struct
> + * @param len full packet length
> + */
> +void rxhand_tcp6(union tcp6_build_pkt *b, unsigned int len);
> +
> +#endif // CONFIG_PROT_TCP
> +#endif // __TCP6_H__
> diff --git a/include/net6.h b/include/net6.h
> index beafc05338..fa926f07ac 100644
> --- a/include/net6.h
> +++ b/include/net6.h
> @@ -344,6 +344,20 @@ int ip6_add_hdr(uchar *xip, struct in6_addr *src, struct in6_addr *dest,
>   int net_send_udp_packet6(uchar *ether, struct in6_addr *dest, int dport,
>   			 int sport, int len);
>   
> +/**
> + * net_send_tcp_packet6() - Make up TCP packet and send it
> + *
> + * @payload_len: TCP payload length
> + * @dport:	 destination port
> + * @sport:	 source port
> + * @action:	 TCP flag (SYN, ACL, PUSH, etc)
> + * @tcp_seq_num: TCP sequence number
> + * @tcp_ack_num: TCP ackno
> + * Return: 0 if send successfully, -1 otherwise
> + */
> +int net_send_tcp_packet6(int payload_len, int dport, int sport, u8 action,
> +			 u32 tcp_seq_num, u32 tcp_ack_num);
> +
>   /**
>    * net_ip6_handler() - Handle IPv6 packet
>    *
> diff --git a/net/Makefile b/net/Makefile
> index 3e2d061338..002b0f68a2 100644
> --- a/net/Makefile
> +++ b/net/Makefile
> @@ -32,6 +32,7 @@ obj-$(CONFIG_TCP_FUNCTION_FASTBOOT)  += fastboot_tcp.o
>   obj-$(CONFIG_CMD_WOL)  += wol.o
>   obj-$(CONFIG_PROT_UDP) += udp.o
>   obj-$(CONFIG_PROT_TCP) += tcp.o
> +obj-$(CONFIG_IPV6) += tcp6.o
>   obj-$(CONFIG_CMD_WGET) += wget.o
>   
>   # Disable this warning as it is triggered by:
> diff --git a/net/net.c b/net/net.c
> index 0b68bf7b13..9ef290dc41 100644
> --- a/net/net.c
> +++ b/net/net.c
> @@ -92,6 +92,7 @@
>   #include <log.h>
>   #include <net.h>
>   #include <net6.h>
> +#include <net/tcp6.h>
>   #include <ndisc.h>
>   #include <net/fastboot_udp.h>
>   #include <net/fastboot_tcp.h>
> @@ -386,6 +387,9 @@ static void net_clear_handlers(void)
>   	net_set_udp_handler(NULL);
>   	net_set_arp_handler(NULL);
>   	net_set_timeout_handler(0, NULL);
> +#if defined(CONFIG_IPV6) && defined(CONFIG_PROT_TCP)
> +	net_set_tcp_handler6(NULL);
> +#endif
>   }
>   
>   static void net_cleanup_loop(void)
> @@ -916,7 +920,9 @@ int net_send_ip_packet(uchar *ether, struct in_addr dest, int dport, int sport,
>   {
>   	uchar *pkt;
>   	int eth_hdr_size;
> +#if defined(CONFIG_PROT_TCP)
>   	int ip_tcp_hdr_size;
> +#endif
>   	int pkt_hdr_size;
>   
>   	/* make sure the net_tx_packet is initialized (net_init() was called) */
> diff --git a/net/net6.c b/net/net6.c
> index e395b930b0..575726766e 100644
> --- a/net/net6.c
> +++ b/net/net6.c
> @@ -14,6 +14,7 @@
>   #include <malloc.h>
>   #include <net.h>
>   #include <net6.h>
> +#include <net/tcp6.h>
>   #include <ndisc.h>
>   
>   /* NULL IPv6 address */
> @@ -350,11 +351,17 @@ int net_send_ip_packet6(uchar *ether, struct in6_addr *dest, int dport, int spor
>   			u32 tcp_ack_num)
>   {
>   	uchar *pkt;
> +	int pkt_hdr_size;
>   	int eth_hdr_size;
> +#if defined(CONFIG_PROT_UDP) || defined(CONFIG_PROT_TCP)
>   	int ip_hdr_size;
> +#endif
> +#if defined(CONFIG_PROT_UDP)
>   	int udp_hdr_size;
> +#endif
> +#if defined(CONFIG_PROT_TCP)
>   	int tcp_hdr_size;
> -	int pkt_hdr_size;
> +#endif
>   
>   	if (!net_tx_packet)
>   		return -1;
> @@ -362,8 +369,8 @@ int net_send_ip_packet6(uchar *ether, struct in6_addr *dest, int dport, int spor
>   	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;
> +	pkt_hdr_size = eth_hdr_size;
> +	pkt += eth_hdr_size;
>   
>   	switch (proto) {
>   #if defined(CONFIG_PROT_UDP)
> @@ -377,6 +384,18 @@ int net_send_ip_packet6(uchar *ether, struct in6_addr *dest, int dport, int spor
>   		pkt_hdr_size += udp_hdr_size;
>   		pkt += udp_hdr_size;
>   		break;
> +#endif
> +#if defined(CONFIG_PROT_TCP)
> +	case IPPROTO_TCP:
> +		tcp_hdr_size = net_set_tcp_header6(pkt, dport, sport,
> +						   payload_len, action, tcp_seq_num,
> +						   tcp_ack_num);
> +		ip_hdr_size = ip6_add_hdr(pkt, &net_ip6, dest, IPPROTO_TCP, 64,
> +					  tcp_hdr_size + payload_len);
> +
> +		pkt_hdr_size += ip_hdr_size + tcp_hdr_size;
> +		pkt += ip_hdr_size + tcp_hdr_size;
> +		break;
>   #endif
>   	default:
>   		return -EINVAL;
> @@ -411,11 +430,25 @@ int net_send_udp_packet6(uchar *ether, struct in6_addr *dest, int dport,
>   	return net_send_ip_packet6(ether, dest, dport, sport, len, IPPROTO_UDP, 0, 0, 0);
>   }
>   
> +int net_send_tcp_packet6(int payload_len, int dport, int sport, u8 action,
> +			 u32 tcp_seq_num, u32 tcp_ack_num)
> +{
> +	return net_send_ip_packet6(net_server_ethaddr, &net_server_ip6, dport,
> +				   sport, payload_len, IPPROTO_TCP, action,
> +				   tcp_seq_num, tcp_ack_num);
> +}
> +
>   int net_ip6_handler(struct ethernet_hdr *et, struct ip6_hdr *ip6, int len)
>   {
> -	struct in_addr zero_ip = {.s_addr = 0 };
>   	struct icmp6hdr *icmp;
> +#if defined(CONFIG_PROT_UDP)
> +	struct in_addr zero_ip = {.s_addr = 0 };
>   	struct udp_hdr *udp;
> +#endif
> +#if defined(CONFIG_PROT_TCP)
> +	union tcp6_build_pkt *tcp_headers;
> +	struct tcp_hdr *tcp;
> +#endif
>   	u16 csum;
>   	u16 csum_p;
>   	u16 hlen;
> @@ -454,6 +487,7 @@ int net_ip6_handler(struct ethernet_hdr *et, struct ip6_hdr *ip6, int len)
>   			break;
>   		}
>   		break;
> +#if defined(CONFIG_PROT_UDP)
>   	case IPPROTO_UDP:
>   		udp = (struct udp_hdr *)(((uchar *)ip6) + IP6_HDR_SIZE);
>   		csum = udp->udp_xsum;
> @@ -468,13 +502,31 @@ int net_ip6_handler(struct ethernet_hdr *et, struct ip6_hdr *ip6, int len)
>   			return -EINVAL;
>   
>   		/* IP header OK. Pass the packet to the current handler. */
> -		net_get_udp_handler()((uchar *)ip6 + IP6_HDR_SIZE +
> -					UDP_HDR_SIZE,
> -				ntohs(udp->udp_dst),
> -				zero_ip,
> -				ntohs(udp->udp_src),
> -				ntohs(udp->udp_len) - 8);
> +		net_get_udp_handler()((uchar *)ip6 + IP6_HDR_SIZE + UDP_HDR_SIZE,
> +				      ntohs(udp->udp_dst),
> +				      zero_ip,
> +				      ntohs(udp->udp_src),
> +				      ntohs(udp->udp_len) - 8);
> +		break;
> +#endif
> +#if defined(CONFIG_PROT_TCP)
> +	case IPPROTO_TCP:
> +		tcp = (struct tcp_hdr *)(((uchar *)ip6) + IP6_HDR_SIZE);
> +		csum = tcp->tcp_xsum;
> +		hlen = ntohs(ip6->payload_len);
> +		tcp->tcp_xsum = 0;
> +		/* checksum */
> +		csum_p = csum_partial((u8 *)tcp, hlen, 0);
> +		tcp->tcp_xsum = csum_ipv6_magic(&ip6->saddr, &ip6->daddr,
> +						hlen, IPPROTO_TCP, csum_p);
> +
> +		if (csum != tcp->tcp_xsum)
> +			return -EINVAL;
> +
> +		tcp_headers = (union tcp6_build_pkt *)ip6;
> +		rxhand_tcp6(tcp_headers, len);
>   		break;
> +#endif
>   	default:
>   		return -EINVAL;
>   	}
> diff --git a/net/tcp6.c b/net/tcp6.c
> new file mode 100644
> index 0000000000..09b2190db7
> --- /dev/null
> +++ b/net/tcp6.c
> @@ -0,0 +1,99 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (C) 2022 The Android Open Source Project
> + */
> +
> +#if defined(CONFIG_PROT_TCP)
> +
> +#include <common.h>
> +#include <net/tcp.h>
> +#include <net/tcp6.h>
> +#include <net6.h>
> +
> +static rxhand_tcp6_f *tcp6_packet_handler;
> +
> +static void dummy_handler(uchar *pkt, u16 dport,
> +			  struct in6_addr sip, u16 sport,
> +			  u32 tcp_seq_num, u32 tcp_ack_num,
> +			  u8 action, unsigned int len)
> +{
> +}
> +
> +void net_set_tcp_handler6(rxhand_tcp6_f *f)
> +{
> +	if (!f)
> +		tcp6_packet_handler = dummy_handler;
> +	else
> +		tcp6_packet_handler = f;
> +}
> +
> +int net_set_tcp_header6(uchar *pkt, u16 dport, u16 sport, int payload_len,
> +			u8 action, u32 tcp_seq_num, u32 tcp_ack_num)
> +{
> +	union tcp6_build_pkt *b = (union tcp6_build_pkt *)pkt;
> +	int tcp_hdr_len;
> +	int pkt_len;
> +	u16 csum;
> +
> +	pkt_len = IP6_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;
> +
> +	csum = csum_partial((u8 *)&b->ip.tcp_hdr, tcp_hdr_len + payload_len, 0);
> +	b->ip.tcp_hdr.tcp_xsum = csum_ipv6_magic(&net_ip6, &net_server_ip6,
> +						 tcp_hdr_len + payload_len,
> +						 IPPROTO_TCP, csum);
> +
> +	return tcp_hdr_len;
> +}
> +
> +void rxhand_tcp6(union tcp6_build_pkt *b, unsigned int len)
> +{
> +	int tcp_len = len - IP6_HDR_SIZE;
> +	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;
> +
> +	net_copy_ip6(&net_server_ip6, &b->ip.ip_hdr.saddr);
> +
> +	tcp_hdr_len = GET_TCP_HDR_LEN_IN_BYTES(b->ip.tcp_hdr.tcp_hlen);
> +	payload_len = tcp_len - tcp_hdr_len;
> +
> +	if (tcp_hdr_len > TCP_HDR_SIZE)
> +		tcp_parse_options((uchar *)b + IP6_HDR_SIZE + TCP_HDR_SIZE,
> +				  tcp_hdr_len - TCP_HDR_SIZE);
> +
> +	tcp_seq_num = ntohl(b->ip.tcp_hdr.tcp_seq);
> +	tcp_ack_num = ntohl(b->ip.tcp_hdr.tcp_ack);
> +
> +	tcp_action = tcp_state_machine(b->ip.tcp_hdr.tcp_flags,
> +				       tcp_seq_num, &res_tcp_seq_num, &res_tcp_ack_num,
> +				       payload_len);
> +
> +	if ((tcp_action & TCP_PUSH) || payload_len > 0) {
> +		debug_cond(DEBUG_DEV_PKT,
> +			   "TCP Notify (action=%x, Seq=%u,Ack=%u,Pay%d)\n",
> +			   tcp_action, tcp_seq_num, tcp_ack_num, payload_len);
> +
> +		(*tcp6_packet_handler) ((uchar *)b + len - payload_len, b->ip.tcp_hdr.tcp_dst,
> +					b->ip.ip_hdr.saddr, b->ip.tcp_hdr.tcp_src, tcp_seq_num,
> +					tcp_ack_num, tcp_action, payload_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, res_tcp_seq_num, res_tcp_ack_num, payload_len);
> +
> +		net_send_tcp_packet6(0, ntohs(b->ip.tcp_hdr.tcp_src),
> +				     ntohs(b->ip.tcp_hdr.tcp_dst),
> +				     (tcp_action & (~TCP_PUSH)),
> +				     res_tcp_seq_num, res_tcp_ack_num);
> +	}
> +}
> +
> +#endif // CONFIG_PROT_TCP

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


More information about the U-Boot mailing list