/* 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 */ 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 }; /** * 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 * * @state: TCP connection state * * @seq_init: Initial receive sequence number * @ack_edge: Receive next * * @loc_timestamp: Local timestamp * @rmt_timestamp: Remote timestamp * * @lost: Used for SACK */ struct tcp_stream { struct in_addr rhost; u16 rport; u16 lport; /* TCP connection state */ enum tcp_state state; u32 seq_init; u32 ack_edge; /* TCP option timestamp */ u32 loc_timestamp; u32 rmt_timestamp; /* TCP sliding window control used to request re-TX */ struct tcp_sack_v lost; }; void tcp_init(void); typedef int tcp_incoming_filter(struct in_addr rhost, u16 rport, u16 sport); /* * This function sets user callback used to accept/drop incoming * connections. Callback should: * + Check TCP stream endpoint and make connection verdict * - return non-zero value to accept connection * - return zero to drop connection * * WARNING: If callback is NOT defined, all incoming connections * will be dropped. */ void tcp_set_incoming_filter(tcp_incoming_filter *filter); /* * 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); enum tcp_state tcp_stream_get_state(struct tcp_stream *tcp); int tcp_set_tcp_header(struct tcp_stream *tcp, uchar *pkt, int payload_len, u8 action, u32 tcp_seq_num, u32 tcp_ack_num); /** * rxhand_tcp() - An incoming packet handler. * @tcp: TCP stream * @pkt: pointer to the application packet * @dport: destination TCP port * @sip: source IP address * @sport: source TCP port * @tcp_seq_num: TCP sequential number * @tcp_ack_num: TCP acknowledgment number * @action: TCP action (SYN, ACK, FIN, etc) * @len: packet length */ typedef void rxhand_tcp(struct tcp_stream *tcp, uchar *pkt, u32 tcp_seq_num, u32 tcp_ack_num, u8 action, unsigned int len); void tcp_set_tcp_handler(rxhand_tcp *f); 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);