u-boot/include/net/tcp.h
Andrew Goodbody 31a8d2d340 net: Add parens to macro PSEUDO_HDR_SIZE
Smatch reports a warning about possibly needing parens around the macro
PSEUDO_HDR_SIZE. This will not affect the one place the macro is used
but add the parens anyway as it is good practice to have them and if the
macro is used again in the future it could possibly matter then.

Signed-off-by: Andrew Goodbody <andrew.goodbody@linaro.org>
Reviewed-by: Jerome Forissier <jerome.forissier@linaro.org>
2025-08-01 09:30:47 +02:00

525 lines
14 KiB
C

/* SPDX-License-Identifier: GPL-2.0 */
/*
* TCP Support with SACK for file transfer.
*
* Copyright 2017 Duncan Hare, All rights reserved.
*/
#define TCP_ACTIVITY 127 /* Number of packets received */
/* before console progress mark */
/**
* struct ip_tcp_hdr - IP and TCP header
* @ip_hl_v: header length and version
* @ip_tos: type of service
* @ip_len: total length
* @ip_id: identification
* @ip_off: fragment offset field
* @ip_ttl: time to live
* @ip_p: protocol
* @ip_sum: checksum
* @ip_src: Source IP address
* @ip_dst: Destination IP address
* @tcp_src: TCP source port
* @tcp_dst: TCP destination port
* @tcp_seq: TCP sequence number
* @tcp_ack: TCP Acknowledgment number
* @tcp_hlen: 4 bits TCP header Length/4, 4 bits reserved, 2 more bits reserved
* @tcp_flag: flags of TCP
* @tcp_win: TCP windows size
* @tcp_xsum: Checksum
* @tcp_ugr: Pointer to urgent data
*/
struct ip_tcp_hdr {
u8 ip_hl_v;
u8 ip_tos;
u16 ip_len;
u16 ip_id;
u16 ip_off;
u8 ip_ttl;
u8 ip_p;
u16 ip_sum;
struct in_addr ip_src;
struct in_addr ip_dst;
u16 tcp_src;
u16 tcp_dst;
u32 tcp_seq;
u32 tcp_ack;
u8 tcp_hlen;
u8 tcp_flags;
u16 tcp_win;
u16 tcp_xsum;
u16 tcp_ugr;
} __packed;
#define IP_TCP_HDR_SIZE (sizeof(struct ip_tcp_hdr))
#define TCP_HDR_SIZE (IP_TCP_HDR_SIZE - IP_HDR_SIZE)
#define TCP_DATA 0x00 /* Data Packet - internal use only */
#define TCP_FIN 0x01 /* Finish flag */
#define TCP_SYN 0x02 /* Synch (start) flag */
#define TCP_RST 0x04 /* reset flag */
#define TCP_PUSH 0x08 /* Push - Notify app */
#define TCP_ACK 0x10 /* Acknowledgment of data received */
#define TCP_URG 0x20 /* Urgent */
#define TCP_ECE 0x40 /* Congestion control */
#define TCP_CWR 0x80 /* Congestion Control */
/*
* TCP header options, Seq, MSS, and SACK
*/
#define TCP_SACK 32 /* Number of packets analyzed */
/* on leading edge of stream */
#define TCP_O_END 0x00 /* End of option list */
#define TCP_1_NOP 0x01 /* Single padding NOP */
#define TCP_O_NOP 0x01010101 /* NOPs pad to 32 bit boundary */
#define TCP_O_MSS 0x02 /* MSS Size option */
#define TCP_O_SCL 0x03 /* Window Scale option */
#define TCP_P_SACK 0x04 /* SACK permitted */
#define TCP_V_SACK 0x05 /* SACK values */
#define TCP_O_TS 0x08 /* Timestamp option */
#define TCP_OPT_LEN_2 0x02
#define TCP_OPT_LEN_3 0x03
#define TCP_OPT_LEN_4 0x04
#define TCP_OPT_LEN_6 0x06
#define TCP_OPT_LEN_8 0x08
#define TCP_OPT_LEN_A 0x0a /* Timestamp Length */
#define TCP_MSS 1460 /* Max segment size */
#define TCP_SCALE 0x01 /* Scale */
/**
* struct tcp_mss - TCP option structure for MSS (Max segment size)
* @kind: Field ID
* @len: Field length
* @mss: Segment size value
*/
struct tcp_mss {
u8 kind;
u8 len;
u16 mss;
} __packed;
/**
* struct tcp_scale - TCP option structure for Windows scale
* @kind: Field ID
* @len: Field length
* @scale: windows shift value used for networks with many hops.
* Typically 4 or more hops
*/
struct tcp_scale {
u8 kind;
u8 len;
u8 scale;
} __packed;
/**
* struct tcp_sack_p - TCP option structure for SACK permitted
* @kind: Field ID
* @len: Field length
*/
struct tcp_sack_p {
u8 kind;
u8 len;
} __packed;
/**
* struct sack_edges - structure for SACK edges
* @l: Left edge of stream
* @r: right edge of stream
*/
struct sack_edges {
u32 l;
u32 r;
} __packed;
#define TCP_SACK_SIZE (sizeof(struct sack_edges))
/*
* A TCP stream has holes when packets are missing or disordered.
* A hill is the inverse of a hole, and is data received.
* TCP received hills (a sequence of data), and inferrs Holes
* from the "hills" or packets received.
*/
#define TCP_SACK_HILLS 4
/**
* struct tcp_sack_v - TCP option structure for SACK
* @kind: Field ID
* @len: Field length
* @hill: L & R window edges
*/
struct tcp_sack_v {
u8 kind;
u8 len;
struct sack_edges hill[TCP_SACK_HILLS];
} __packed;
/**
* struct tcp_t_opt - TCP option structure for time stamps
* @kind: Field ID
* @len: Field length
* @t_snd: Sender timestamp
* @t_rcv: Receiver timestamp
*/
struct tcp_t_opt {
u8 kind;
u8 len;
u32 t_snd;
u32 t_rcv;
} __packed;
#define TCP_TSOPT_SIZE (sizeof(struct tcp_t_opt))
/*
* ip tcp structure with options
*/
/**
* struct ip_tcp_hdr_o - IP + TCP header + TCP options
* @hdr: IP + TCP header
* @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_tcp_hdr hdr;
struct tcp_mss mss;
struct tcp_scale scale;
struct tcp_sack_p sack_p;
struct tcp_t_opt t_opt;
u8 end;
} __packed;
#define IP_TCP_O_SIZE (sizeof(struct ip_tcp_hdr_o))
/**
* struct ip_tcp_hdr_s - IP + TCP header + TCP options
* @hdr: IP + TCP header
* @t_opt: TCP Timestamp Option
* @sack_v: TCP SACK Option
* @end: end of options
*/
struct ip_tcp_hdr_s {
struct ip_tcp_hdr hdr;
struct tcp_t_opt t_opt;
struct tcp_sack_v sack_v;
u8 end;
} __packed;
#define IP_TCP_SACK_SIZE (sizeof(struct ip_tcp_hdr_s))
/*
* TCP pseudo header definitions
*/
#define PSEUDO_PAD_SIZE 8
/**
* struct pseudo_hdr - Pseudo Header
* @padding: pseudo hdr size = ip_tcp hdr size
* @p_src: Source IP address
* @p_dst: Destination IP address
* @rsvd: reserved
* @p: protocol
* @len: length of header
*/
struct pseudo_hdr {
u8 padding[PSEUDO_PAD_SIZE];
struct in_addr p_src;
struct in_addr p_dst;
u8 rsvd;
u8 p;
u16 len;
} __packed;
#define PSEUDO_HDR_SIZE ((sizeof(struct pseudo_hdr)) - PSEUDO_PAD_SIZE)
/**
* union tcp_build_pkt - union for building TCP/IP packet.
* @ph: pseudo header
* @ip: IP and TCP header plus TCP options
* @sack: IP and TCP header plus SACK options
* @raw: buffer
*
* 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;
struct ip_tcp_hdr_o ip;
struct ip_tcp_hdr_s sack;
uchar raw[1600];
} __packed;
/**
* enum tcp_state - TCP State machine states for connection
* @TCP_CLOSED: Need to send SYN to connect
* @TCP_SYN_SENT: Trying to connect, waiting for SYN ACK
* @TCP_SYN_RECEIVED: Initial SYN received, waiting for ACK
* @TCP_ESTABLISHED: both server & client have a connection
* @TCP_CLOSE_WAIT: Rec FIN, passed to app for FIN, ACK rsp
* @TCP_CLOSING: Rec FIN, sent FIN, ACK waiting for ACK
* @TCP_FIN_WAIT_1: Sent FIN waiting for response
* @TCP_FIN_WAIT_2: Rec ACK from FIN sent, waiting for FIN
* @TCP_LAST_ACK: Waiting for ACK of the connection termination
*/
enum tcp_state {
TCP_CLOSED,
TCP_SYN_SENT,
TCP_SYN_RECEIVED,
TCP_ESTABLISHED,
TCP_CLOSE_WAIT,
TCP_CLOSING,
TCP_FIN_WAIT_1,
TCP_FIN_WAIT_2,
TCP_LAST_ACK,
};
/**
* enum tcp_status - TCP stream status for connection
* @TCP_ERR_OK: no rx/tx errors
* @TCP_ERR_TOUT: rx/tx timeout happened
* @TCP_ERR_RST: connection was reset
* @TCP_ERR_IO: input/output error
*/
enum tcp_status {
TCP_ERR_OK = 0,
TCP_ERR_TOUT,
TCP_ERR_RST,
TCP_ERR_IO
};
/**
* struct tcp_stream - TCP data stream structure
* @rhost: Remote host, network byte order
* @rport: Remote port, host byte order
* @lport: Local port, host byte order
*
* @priv: User private data (not used by tcp module)
*
* @max_retry_count: Maximum retransmit attempts (default 3)
* @initial_timeout: Timeout from initial TX to reTX (default 2 sec)
* @rx_inactiv_timeout: Maximum time from last rx till connection drop
* (default 30 sec)
*
* @on_closed: User callback, called just before destroying TCP stream
* @on_established: User callback, called when TCP stream enters
* TCP_ESTABLISHED state
* @on_rcv_nxt_update: User callback, called when all data in the segment
* [0..rx_bytes - 1] was received
* @on_snd_una_update: User callback, called when all data in the segment
* [0..tx_bytes - 1] were transferred and acknowledged
* @rx: User callback, called on receive of segment
* [rx_offs..rx_offs+len-1]. If NULL -- all incoming data
* will be ignored. User SHOULD store the segment and
* return the number of accepted bytes or negative value
* on error.
* WARNING: Previous segmengs may not be received yet
* @tx: User callback, called on transmit/retransmit of segment
* [tx_offs..tx_offs+maxlen-1]. If NULL -- no data will
* be transmitted. User SHOULD fill provided buffer and
* return the number of bytes in the buffer or negative
* value on error.
* WARNING: do not use tcp_stream_close() from this
* callback (it will break stream). Better use
* on_snd_una_update() callback for such purposes.
*
* @time_last_rx: Arrival time of last valid incoming package (ticks)
* @time_start: Timeout start time (ticks)
* @time_delta: Timeout duration (ticks)
* @time_handler Timeout handler for a stream
*
* @state: TCP connection state
* @status: TCP stream status (OK or ERR)
* @rx_packets: total number of received packets
* @tx_packets: total number of transmitted packets
*
* @fin_rx: Non-zero if TCP_FIN was received
* @fin_rx_seq: TCP sequence of rx FIN bit
* @fin_tx: Non-zero if TCP_FIN was sent (or planned to send)
* @fin_tx_seq: TCP sequence of tx FIN bit
*
* @iss: Initial send sequence number
* @snd_una: Send unacknowledged
* @snd_nxt: Send next
* @snd_wnd: Send window (in bytes)
* @snd_wl1: Segment sequence number used for last window update
* @snd_wl2: Segment acknowledgment number used for last window update
*
* @irs: Initial receive sequence number
* @rcv_nxt: Receive next
* @rcv_wnd: Receive window (in bytes)
*
* @loc_timestamp: Local timestamp
* @rmt_timestamp: Remote timestamp
*
* @rmt_win_scale: Remote window scale factor
*
* @lost: Used for SACK
*
* @retry_cnt: Number of retry attempts remaining. Only SYN, FIN
* or DATA segments are tried to retransmit.
* @retry_timeout: Current retry timeout (ms)
* @retry_action: TCP flags used for sending
* @retry_seq_num: TCP sequence for retransmit
* retry_tx_len: Number of data to transmit
* @retry_tx_offs: Position in the TX stream
*/
struct tcp_stream {
struct in_addr rhost;
u16 rport;
u16 lport;
void *priv;
int max_retry_count;
int initial_timeout;
int rx_inactiv_timeout;
void (*on_closed)(struct tcp_stream *tcp);
void (*on_established)(struct tcp_stream *tcp);
void (*on_rcv_nxt_update)(struct tcp_stream *tcp, u32 rx_bytes);
void (*on_snd_una_update)(struct tcp_stream *tcp, u32 tx_bytes);
int (*rx)(struct tcp_stream *tcp, u32 rx_offs, void *buf, int len);
int (*tx)(struct tcp_stream *tcp, u32 tx_offs, void *buf, int maxlen);
ulong time_last_rx;
ulong time_start;
ulong time_delta;
void (*time_handler)(struct tcp_stream *tcp);
enum tcp_state state;
enum tcp_status status;
u32 rx_packets;
u32 tx_packets;
int fin_rx;
u32 fin_rx_seq;
int fin_tx;
u32 fin_tx_seq;
u32 iss;
u32 snd_una;
u32 snd_nxt;
u32 snd_wnd;
u32 snd_wl1;
u32 snd_wl2;
u32 irs;
u32 rcv_nxt;
u32 rcv_wnd;
/* TCP option timestamp */
u32 loc_timestamp;
u32 rmt_timestamp;
/* TCP window scale */
u8 rmt_win_scale;
/* TCP sliding window control used to request re-TX */
struct tcp_sack_v lost;
/* used for data retransmission */
int retry_cnt;
int retry_timeout;
u8 retry_action;
u32 retry_seq_num;
u32 retry_tx_len;
u32 retry_tx_offs;
};
void tcp_init(void);
/*
* This function sets user callback called on TCP stream creation.
* Callback should:
* + Check TCP stream endpoint and make connection verdict
* - return non-zero value to accept connection
* - return zero to drop connection
* + Setup TCP stream callbacks like: on_closed(), on_established(),
* n_rcv_nxt_update(), on_snd_una_update(), rx() and tx().
* + Setup other stream related data
*
* WARNING: User MUST setup TCP stream on_create handler. Without it
* no connection (including outgoung) will be created.
*/
void tcp_stream_set_on_create_handler(int (*on_create)(struct tcp_stream *));
/*
* tcp_stream_get -- Get or create TCP stream
* @is_new: if non-zero and no stream found, then create a new one
* @rhost: Remote host, network byte order
* @rport: Remote port, host byte order
* @lport: Local port, host byte order
*
* Returns: TCP stream structure or NULL (if not found/created)
*/
struct tcp_stream *tcp_stream_get(int is_new, struct in_addr rhost,
u16 rport, u16 lport);
/*
* tcp_stream_connect -- Create new TCP stream for remote connection.
* @rhost: Remote host, network byte order
* @rport: Remote port, host byte order
*
* Returns: TCP new stream structure or NULL (if not created).
* Random local port will be used.
*/
struct tcp_stream *tcp_stream_connect(struct in_addr rhost, u16 rport);
/*
* tcp_stream_put -- Return stream to a TCP subsystem. Subsystem will
* check stream and destroy it (if stream was already
* closed). Otherwize no stream change will happen.
* @tcp: TCP stream to put
*/
void tcp_stream_put(struct tcp_stream *tcp);
/*
* tcp_stream_restart_rx_timer -- Restart RX inactivity timer. Usually there
* is no needs to call this function. Timer
* will be restarted on receiving of any valid
* tcp packet belonging to a stream.
*
* This function may be used to prevent connection
* break in the following case:
* - u-boot is busy with very long data processing
* - remote side waits for u-boot reply
*
* @tcp: TCP stream to put
*/
void tcp_stream_restart_rx_timer(struct tcp_stream *tcp);
enum tcp_state tcp_stream_get_state(struct tcp_stream *tcp);
enum tcp_status tcp_stream_get_status(struct tcp_stream *tcp);
/*
* tcp_stream_rx_offs(),
* tcp_stream_tx_offs() -- Returns offset of first unacknowledged byte
* in receive/transmit stream correspondingly.
* The result is NOT affected by sin/fin flags.
* @tcp: TCP stream
*/
u32 tcp_stream_rx_offs(struct tcp_stream *tcp);
u32 tcp_stream_tx_offs(struct tcp_stream *tcp);
/* reset tcp stream */
void tcp_stream_reset(struct tcp_stream *tcp);
/* force TCP stream closing, do NOT use from tcp->tx callback */
void tcp_stream_close(struct tcp_stream *tcp);
void tcp_streams_poll(void);
int tcp_set_tcp_header(struct tcp_stream *tcp, uchar *pkt, int payload_len,
u8 action, u32 tcp_seq_num, u32 tcp_ack_num);
void rxhand_tcp_f(union tcp_build_pkt *b, unsigned int len);
u16 tcp_set_pseudo_header(uchar *pkt, struct in_addr src, struct in_addr dest,
int tcp_len, int pkt_len);