[PATCH v2 3/6] net: introduce TCP/IP6 support
Dmitrii Merkurev
dimorinny at google.com
Wed May 10 18:59:56 CEST 2023
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
--
2.40.1.606.ga4b1b128d6-goog
More information about the U-Boot
mailing list