summaryrefslogtreecommitdiff
path: root/net/tcp.c
diff options
context:
space:
mode:
authorMikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>2024-12-28 13:46:30 +0300
committerTom Rini <trini@konsulko.com>2024-12-28 11:59:42 -0600
commit2b1774987031d6f30fb773bd84e91884f35fbc8d (patch)
tree40e6436e42f7afdbd7c7ebe11673928b69a29e8d /net/tcp.c
parentddedfe1cb8b6c262990b629494165082320cc884 (diff)
net/tcp: add connection info to tcp_stream structure
Changes: * Avoid use net_server_ip in tcp code, use tcp_stream data instead * Ignore packets from other connections if connection already created. This prevents us from connection break caused by other tcp stream. Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu> Reviewed-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'net/tcp.c')
-rw-r--r--net/tcp.c129
1 files changed, 99 insertions, 30 deletions
diff --git a/net/tcp.c b/net/tcp.c
index 8eeb43b8796..db708f0a2a5 100644
--- a/net/tcp.c
+++ b/net/tcp.c
@@ -26,6 +26,7 @@
static int tcp_activity_count;
static struct tcp_stream tcp_stream;
+static tcp_incoming_filter *incoming_filter;
/*
* TCP lengths are stored as a rounded up number of 32 bit words.
@@ -40,40 +41,95 @@ static struct tcp_stream tcp_stream;
/* Current TCP RX packet handler */
static rxhand_tcp *tcp_packet_handler;
+#define RANDOM_PORT_START 1024
+#define RANDOM_PORT_RANGE 0x4000
+
+/**
+ * random_port() - make port a little random (1024-17407)
+ *
+ * Return: random port number from 1024 to 17407
+ *
+ * This keeps the math somewhat trivial to compute, and seems to work with
+ * all supported protocols/clients/servers
+ */
+static uint random_port(void)
+{
+ return RANDOM_PORT_START + (get_timer(0) % RANDOM_PORT_RANGE);
+}
+
static inline s32 tcp_seq_cmp(u32 a, u32 b)
{
return (s32)(a - b);
}
/**
- * tcp_get_tcp_state() - get TCP stream state
+ * tcp_stream_get_state() - get TCP stream state
* @tcp: tcp stream
*
* Return: TCP stream state
*/
-enum tcp_state tcp_get_tcp_state(struct tcp_stream *tcp)
+enum tcp_state tcp_stream_get_state(struct tcp_stream *tcp)
{
return tcp->state;
}
/**
- * tcp_set_tcp_state() - set TCP stream state
+ * tcp_stream_set_state() - set TCP stream state
* @tcp: tcp stream
* @new_state: new TCP state
*/
-void tcp_set_tcp_state(struct tcp_stream *tcp,
- enum tcp_state new_state)
+static void tcp_stream_set_state(struct tcp_stream *tcp,
+ enum tcp_state new_state)
{
tcp->state = new_state;
}
-struct tcp_stream *tcp_stream_get(void)
+void tcp_init(void)
+{
+ incoming_filter = NULL;
+ tcp_stream.state = TCP_CLOSED;
+}
+
+void tcp_set_incoming_filter(tcp_incoming_filter *filter)
+{
+ incoming_filter = filter;
+}
+
+static struct tcp_stream *tcp_stream_add(struct in_addr rhost,
+ u16 rport, u16 lport)
+{
+ struct tcp_stream *tcp = &tcp_stream;
+
+ if (tcp->state != TCP_CLOSED)
+ return NULL;
+
+ memset(tcp, 0, sizeof(struct tcp_stream));
+ tcp->rhost.s_addr = rhost.s_addr;
+ tcp->rport = rport;
+ tcp->lport = lport;
+ tcp->state = TCP_CLOSED;
+ tcp->lost.len = TCP_OPT_LEN_2;
+ return tcp;
+}
+
+struct tcp_stream *tcp_stream_get(int is_new, struct in_addr rhost,
+ u16 rport, u16 lport)
{
- return &tcp_stream;
+ struct tcp_stream *tcp = &tcp_stream;
+
+ if (tcp->rhost.s_addr == rhost.s_addr &&
+ tcp->rport == rport &&
+ tcp->lport == lport)
+ return tcp;
+
+ if (!is_new || !incoming_filter ||
+ !incoming_filter(rhost, rport, lport))
+ return NULL;
+
+ return tcp_stream_add(rhost, rport, lport);
}
-static void dummy_handler(uchar *pkt, u16 dport,
- struct in_addr sip, u16 sport,
+static void dummy_handler(struct tcp_stream *tcp, uchar *pkt,
u32 tcp_seq_num, u32 tcp_ack_num,
u8 action, unsigned int len)
{
@@ -222,8 +278,7 @@ void net_set_syn_options(struct tcp_stream *tcp, union tcp_build_pkt *b)
b->ip.end = TCP_O_END;
}
-int tcp_set_tcp_header(struct tcp_stream *tcp, uchar *pkt, int dport,
- int sport, int payload_len,
+int tcp_set_tcp_header(struct tcp_stream *tcp, uchar *pkt, int payload_len,
u8 action, u32 tcp_seq_num, u32 tcp_ack_num)
{
union tcp_build_pkt *b = (union tcp_build_pkt *)pkt;
@@ -243,7 +298,7 @@ int tcp_set_tcp_header(struct tcp_stream *tcp, uchar *pkt, int dport,
case TCP_SYN:
debug_cond(DEBUG_DEV_PKT,
"TCP Hdr:SYN (%pI4, %pI4, sq=%u, ak=%u)\n",
- &net_server_ip, &net_ip,
+ &tcp->rhost, &net_ip,
tcp_seq_num, tcp_ack_num);
tcp_activity_count = 0;
net_set_syn_options(tcp, b);
@@ -264,13 +319,13 @@ int tcp_set_tcp_header(struct tcp_stream *tcp, uchar *pkt, int dport,
b->ip.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,
+ &tcp->rhost, &net_ip, 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);
+ &tcp->rhost, &net_ip, tcp_seq_num, tcp_ack_num);
payload_len = 0;
pkt_hdr_len = IP_TCP_HDR_SIZE;
tcp->state = TCP_FIN_WAIT_1;
@@ -279,7 +334,7 @@ int tcp_set_tcp_header(struct tcp_stream *tcp, uchar *pkt, int dport,
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->rhost, &net_ip, tcp_seq_num, tcp_ack_num);
tcp->state = TCP_CLOSED;
break;
/* Notify connection closing */
@@ -290,7 +345,7 @@ int tcp_set_tcp_header(struct tcp_stream *tcp, uchar *pkt, int dport,
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->rhost, &net_ip,
tcp_seq_num, tcp_ack_num, action);
fallthrough;
default:
@@ -298,7 +353,7 @@ int tcp_set_tcp_header(struct tcp_stream *tcp, uchar *pkt, int dport,
b->ip.hdr.tcp_flags = 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->rhost, &net_ip,
tcp_seq_num, tcp_ack_num, action);
}
@@ -308,8 +363,8 @@ int tcp_set_tcp_header(struct tcp_stream *tcp, uchar *pkt, int dport,
tcp->ack_edge = tcp_ack_num;
/* TCP Header */
b->ip.hdr.tcp_ack = htonl(tcp->ack_edge);
- b->ip.hdr.tcp_src = htons(sport);
- b->ip.hdr.tcp_dst = htons(dport);
+ b->ip.hdr.tcp_src = htons(tcp->lport);
+ b->ip.hdr.tcp_dst = htons(tcp->rport);
b->ip.hdr.tcp_seq = htonl(tcp_seq_num);
/*
@@ -332,10 +387,10 @@ int tcp_set_tcp_header(struct tcp_stream *tcp, uchar *pkt, int dport,
b->ip.hdr.tcp_xsum = 0;
b->ip.hdr.tcp_ugr = 0;
- b->ip.hdr.tcp_xsum = tcp_set_pseudo_header(pkt, net_ip, net_server_ip,
+ b->ip.hdr.tcp_xsum = tcp_set_pseudo_header(pkt, net_ip, tcp->rhost,
tcp_len, pkt_len);
- net_set_ip_header((uchar *)&b->ip, net_server_ip, net_ip,
+ net_set_ip_header((uchar *)&b->ip, tcp->rhost, net_ip,
pkt_len, IPPROTO_TCP);
return pkt_hdr_len;
@@ -616,19 +671,26 @@ void rxhand_tcp_f(union tcp_build_pkt *b, unsigned int pkt_len)
u32 tcp_seq_num, tcp_ack_num;
int tcp_hdr_len, payload_len;
struct tcp_stream *tcp;
+ struct in_addr src;
/* Verify IP header */
debug_cond(DEBUG_DEV_PKT,
"TCP RX in RX Sum (to=%pI4, from=%pI4, len=%d)\n",
&b->ip.hdr.ip_src, &b->ip.hdr.ip_dst, pkt_len);
- b->ip.hdr.ip_src = net_server_ip;
+ /*
+ * src IP address will be destroyed by TCP checksum verification
+ * algorithm (see tcp_set_pseudo_header()), so remember it before
+ * it was garbaged.
+ */
+ src.s_addr = b->ip.hdr.ip_src.s_addr;
+
b->ip.hdr.ip_dst = net_ip;
b->ip.hdr.ip_sum = 0;
if (tcp_rx_xsum != compute_ip_checksum(b, IP_HDR_SIZE)) {
debug_cond(DEBUG_DEV_PKT,
"TCP RX IP xSum Error (%pI4, =%pI4, len=%d)\n",
- &net_ip, &net_server_ip, pkt_len);
+ &net_ip, &src, pkt_len);
return;
}
@@ -640,11 +702,14 @@ void rxhand_tcp_f(union tcp_build_pkt *b, unsigned int pkt_len)
pkt_len)) {
debug_cond(DEBUG_DEV_PKT,
"TCP RX TCP xSum Error (%pI4, %pI4, len=%d)\n",
- &net_ip, &net_server_ip, tcp_len);
+ &net_ip, &src, tcp_len);
return;
}
- tcp = tcp_stream_get();
+ tcp = tcp_stream_get(b->ip.hdr.tcp_flags & TCP_SYN,
+ src,
+ ntohs(b->ip.hdr.tcp_src),
+ ntohs(b->ip.hdr.tcp_dst));
if (!tcp)
return;
@@ -676,9 +741,9 @@ void rxhand_tcp_f(union tcp_build_pkt *b, unsigned int pkt_len)
"TCP Notify (action=%x, Seq=%u,Ack=%u,Pay%d)\n",
tcp_action, tcp_seq_num, tcp_ack_num, payload_len);
- (*tcp_packet_handler) ((uchar *)b + pkt_len - payload_len, b->ip.hdr.tcp_dst,
- b->ip.hdr.ip_src, b->ip.hdr.tcp_src, tcp_seq_num,
- tcp_ack_num, tcp_action, payload_len);
+ (*tcp_packet_handler) (tcp, (uchar *)b + pkt_len - payload_len,
+ tcp_seq_num, tcp_ack_num, tcp_action,
+ payload_len);
} else if (tcp_action != TCP_DATA) {
debug_cond(DEBUG_DEV_PKT,
@@ -689,9 +754,13 @@ void rxhand_tcp_f(union tcp_build_pkt *b, unsigned int pkt_len)
* Warning: Incoming Ack & Seq sequence numbers are transposed
* here to outgoing Seq & Ack sequence numbers
*/
- net_send_tcp_packet(0, ntohs(b->ip.hdr.tcp_src),
- ntohs(b->ip.hdr.tcp_dst),
+ net_send_tcp_packet(0, tcp->rhost, tcp->rport, tcp->lport,
(tcp_action & (~TCP_PUSH)),
tcp_ack_num, tcp->ack_edge);
}
}
+
+struct tcp_stream *tcp_stream_connect(struct in_addr rhost, u16 rport)
+{
+ return tcp_stream_add(rhost, rport, random_port());
+}