
On 2023/5/11 00:59, Dmitrii Merkurev wrote:
Changes:
- 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@google.com Cc: Ying-Chun Liu (PaulLiu) paul.liu@linaro.org Cc: Simon Glass sjg@chromium.org Сс: Joe Hershberger joe.hershberger@ni.com Сс: Ramon Fried rfried.dev@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;
break; #if defined(CONFIG_PROT_TCP) case IPPROTO_TCP:pkt_hdr_size += IP_UDP_HDR_SIZE;
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);
break; #endif default:pkt_hdr_size += ip_tcp_hdr_size;
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_try = 1; net_nd_timer_start = get_timer(0); ndisc_request(); return 1; /* waiting */ }net_nd_tx_packet_size = pkt_hdr_size + payload_len;
- 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 +
} else {tcp_lost.len));
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;
} else {options->sack_p.len = TCP_OPT_LEN_2;
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_activity_count = 0;"TCP Hdr:SYN (sq=%u, ak=%u)\n", *tcp_seq_num, *tcp_ack_num);
net_set_syn_options(b);
tcp_seq_num = 0;
tcp_ack_num = 0;
pkt_hdr_len = IP_TCP_O_SIZE;
*tcp_seq_num = 0;
if (current_tcp_state == TCP_SYN_SENT) { /* Too many SYNs */ action = TCP_FIN; current_tcp_state = TCP_FIN_WAIT_1;*tcp_ack_num = 0;
@@ -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);
debug_cond(DEBUG_DEV_PKT,b->ip.tcp_hdr.tcp_flags = action;
"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",
break; case TCP_FIN: debug_cond(DEBUG_DEV_PKT,*tcp_seq_num, *tcp_ack_num, action);
"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;
current_tcp_state = TCP_FIN_WAIT_1; break; case TCP_RST | TCP_ACK: case TCP_RST: debug_cond(DEBUG_DEV_PKT,"TCP Hdr:FIN (s=%u, a=%u)\n", *tcp_seq_num, *tcp_ack_num);
"TCP Hdr:RST (%pI4, %pI4, s=%u, a=%u)\n",
&net_server_ip, &net_ip, 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):"TCP Hdr:RST (s=%u, a=%u)\n", *tcp_seq_num, *tcp_ack_num);
debug_cond(DEBUG_DEV_PKT,
"TCP Hdr:FIN ACK PSH(s=%u, a=%u, A=%x)\n",
if (current_tcp_state == TCP_CLOSE_WAIT) current_tcp_state = TCP_CLOSING;*tcp_seq_num, *tcp_ack_num, action);
debug_cond(DEBUG_DEV_PKT,
"TCP Hdr:FIN ACK PSH(%pI4, %pI4, s=%u, a=%u, A=%x)\n",
&net_server_ip, &net_ip,
fallthrough; default:tcp_seq_num, tcp_ack_num, action);
pkt_hdr_len = IP_HDR_SIZE + net_set_ack_options(b);
b->ip.tcp_hdr.tcp_flags = action | TCP_PUSH | TCP_ACK;
debug_cond(DEBUG_DEV_PKT,action = action | TCP_PUSH | TCP_ACK;
"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,
{ u8 tcp_fin = tcp_flags & TCP_FIN; u8 tcp_syn = tcp_flags & TCP_SYN;u32 *tcp_ack_num_out, int payload_len)
@@ -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;
} else if (tcp_ack || tcp_fin) { action = TCP_DATA; } break; case TCP_SYN_RECEIVED:init_sack_options(tcp_seq_num, tcp_seq_num + 1); current_tcp_state = TCP_SYN_RECEIVED;
if (tcp_ack) {
action = TCP_DATA;
init_sack_options(tcp_seq_num, tcp_seq_num + 1);
current_tcp_state = TCP_ESTABLISHED;
}
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;break;
} 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)
} else { action = TCP_DATA; }action |= TCP_PUSH;
@@ -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@linaro.org