| /** @file |
| @brief TCP data handler |
| |
| This is not to be included by the application. |
| */ |
| |
| /* |
| * Copyright (c) 2016 Intel Corporation |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #ifndef __TCP_H |
| #define __TCP_H |
| |
| #include <zephyr/types.h> |
| |
| #include <net/net_core.h> |
| #include <net/net_ip.h> |
| #include <net/net_pkt.h> |
| #include <net/net_context.h> |
| |
| #include "connection.h" |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| /** Is this TCP context/socket used or not */ |
| #define NET_TCP_IN_USE BIT(0) |
| |
| /** Is the final segment sent */ |
| #define NET_TCP_FINAL_SENT BIT(1) |
| |
| /** Is the final segment received */ |
| #define NET_TCP_FINAL_RECV BIT(2) |
| |
| /** Is the socket shutdown for read/write */ |
| #define NET_TCP_IS_SHUTDOWN BIT(3) |
| |
| /** A retransmitted packet has been sent and not yet ack'd */ |
| #define NET_TCP_RETRYING BIT(4) |
| |
| /** MSS option has been set already */ |
| #define NET_TCP_RECV_MSS_SET BIT(5) |
| |
| /* |
| * TCP connection states |
| */ |
| enum net_tcp_state { |
| NET_TCP_CLOSED = 0, |
| NET_TCP_LISTEN, |
| NET_TCP_SYN_SENT, |
| NET_TCP_SYN_RCVD, |
| NET_TCP_ESTABLISHED, |
| NET_TCP_CLOSE_WAIT, |
| NET_TCP_LAST_ACK, |
| NET_TCP_FIN_WAIT_1, |
| NET_TCP_FIN_WAIT_2, |
| NET_TCP_TIME_WAIT, |
| NET_TCP_CLOSING, |
| }; |
| |
| /* TCP packet types */ |
| #define NET_TCP_FIN 0x01 |
| #define NET_TCP_SYN 0x02 |
| #define NET_TCP_RST 0x04 |
| #define NET_TCP_PSH 0x08 |
| #define NET_TCP_ACK 0x10 |
| #define NET_TCP_URG 0x20 |
| #define NET_TCP_CTL 0x3f |
| |
| #define NET_TCP_FLAGS(hdr) (hdr->flags & NET_TCP_CTL) |
| |
| /* Length of TCP header, including options */ |
| /* "offset": 4-bit field in high nibble, units of dwords */ |
| #define NET_TCP_HDR_LEN(hdr) (4 * ((hdr)->offset >> 4)) |
| |
| /* RFC 1122 4.2.2.6 "If an MSS option is not received at connection |
| * setup, TCP MUST assume a default send MSS of 536" |
| */ |
| #define NET_TCP_DEFAULT_MSS 536 |
| |
| /* TCP max window size */ |
| #define NET_TCP_MAX_WIN (4 * 1024) |
| |
| /* Maximal value of the sequence number */ |
| #define NET_TCP_MAX_SEQ 0xffffffff |
| |
| #define NET_TCP_MAX_OPT_SIZE 8 |
| |
| /* TCP Option codes */ |
| #define NET_TCP_END_OPT 0 |
| #define NET_TCP_NOP_OPT 1 |
| #define NET_TCP_MSS_OPT 2 |
| #define NET_TCP_WINDOW_SCALE_OPT 3 |
| |
| /* TCP Option sizes */ |
| #define NET_TCP_END_SIZE 1 |
| #define NET_TCP_NOP_SIZE 1 |
| #define NET_TCP_MSS_SIZE 4 |
| #define NET_TCP_WINDOW_SCALE_SIZE 3 |
| |
| /** Parsed TCP option values for net_tcp_parse_opts() */ |
| struct net_tcp_options { |
| u16_t mss; |
| }; |
| |
| /* Max received bytes to buffer internally */ |
| #define NET_TCP_BUF_MAX_LEN 1280 |
| |
| /* Max segment lifetime, in seconds */ |
| #define NET_TCP_MAX_SEG_LIFETIME 60 |
| |
| struct net_context; |
| |
| struct net_tcp { |
| /** Network context back pointer. */ |
| struct net_context *context; |
| |
| /** Cookie pointer passed to net_context_recv() */ |
| void *recv_user_data; |
| |
| /** ACK message timer */ |
| struct k_delayed_work ack_timer; |
| |
| /** Timer for doing active close in case the peer FIN is lost. */ |
| struct k_delayed_work fin_timer; |
| |
| /** Retransmit timer */ |
| struct k_delayed_work retry_timer; |
| |
| /** List pointer used for TCP retransmit buffering */ |
| sys_slist_t sent_list; |
| |
| /** Max acknowledgment. */ |
| u32_t recv_max_ack; |
| |
| /** Current sequence number. */ |
| u32_t send_seq; |
| |
| /** Acknowledgment number to send in next packet. */ |
| u32_t send_ack; |
| |
| /** Last ACK value sent */ |
| u32_t sent_ack; |
| |
| /** Current retransmit period */ |
| u32_t retry_timeout_shift : 5; |
| /** Flags for the TCP */ |
| u32_t flags : 8; |
| /** Current TCP state */ |
| u32_t state : 4; |
| /* An outbound FIN packet has been sent */ |
| u32_t fin_sent : 1; |
| /* An inbound FIN packet has been received */ |
| u32_t fin_rcvd : 1; |
| /** Remaining bits in this u32_t */ |
| u32_t _padding : 13; |
| |
| /** Accept callback to be called when the connection has been |
| * established. |
| */ |
| net_tcp_accept_cb_t accept_cb; |
| |
| /** |
| * Semaphore to signal TCP connection completion |
| */ |
| struct k_sem connect_wait; |
| |
| /** |
| * Current TCP receive window for our side |
| */ |
| u16_t recv_wnd; |
| |
| /** |
| * Send MSS for the peer |
| */ |
| u16_t send_mss; |
| }; |
| |
| static inline bool net_tcp_is_used(struct net_tcp *tcp) |
| { |
| NET_ASSERT(tcp); |
| |
| return tcp->flags & NET_TCP_IN_USE; |
| } |
| |
| /** |
| * @brief Register a callback to be called when TCP packet |
| * is received corresponding to received packet. |
| * |
| * @param remote_addr Remote address of the connection end point. |
| * @param local_addr Local address of the connection end point. |
| * @param remote_port Remote port of the connection end point. |
| * @param local_port Local port of the connection end point. |
| * @param cb Callback to be called |
| * @param user_data User data supplied by caller. |
| * @param handle TCP handle that can be used when unregistering |
| * |
| * @return Return 0 if the registration succeed, <0 otherwise. |
| */ |
| static inline int net_tcp_register(const struct sockaddr *remote_addr, |
| const struct sockaddr *local_addr, |
| u16_t remote_port, |
| u16_t local_port, |
| net_conn_cb_t cb, |
| void *user_data, |
| struct net_conn_handle **handle) |
| { |
| return net_conn_register(IPPROTO_TCP, remote_addr, local_addr, |
| remote_port, local_port, cb, user_data, |
| handle); |
| } |
| |
| /** |
| * @brief Unregister TCP handler. |
| * |
| * @param handle Handle from registering. |
| * |
| * @return Return 0 if the unregistration succeed, <0 otherwise. |
| */ |
| static inline int net_tcp_unregister(struct net_conn_handle *handle) |
| { |
| return net_conn_unregister(handle); |
| } |
| |
| /* |
| * @brief Generate initial TCP sequence number |
| * |
| * @return Return a random TCP sequence number |
| */ |
| static inline u32_t tcp_init_isn(void) |
| { |
| /* Randomise initial seq number */ |
| return sys_rand32_get(); |
| } |
| |
| const char *net_tcp_state_str(enum net_tcp_state state); |
| |
| #if defined(CONFIG_NET_TCP) |
| void net_tcp_change_state(struct net_tcp *tcp, enum net_tcp_state new_state); |
| #else |
| #define net_tcp_change_state(...) |
| #endif |
| |
| /** |
| * @brief Allocate TCP connection context. |
| * |
| * @param context Pointer to net_context that is tied to this TCP |
| * context. |
| * |
| * @return Pointer TCP connection context. NULL if no available |
| * context can be found. |
| */ |
| struct net_tcp *net_tcp_alloc(struct net_context *context); |
| |
| /** |
| * @brief Release TCP connection context. |
| * |
| * @param tcp Pointer to net_tcp context. |
| * |
| * @return 0 if ok, < 0 if error |
| */ |
| int net_tcp_release(struct net_tcp *tcp); |
| |
| /** |
| * @brief Send a TCP segment without any data. The returned buffer |
| * is a ready made packet that can be sent via net_send_data() |
| * function. |
| * |
| * @param tcp TCP context |
| * @param flags TCP flags |
| * @param options Pointer TCP options, NULL if no options. |
| * @param optlen Length of the options. |
| * @param local Source address, or NULL to use the local address of |
| * the TCP context |
| * @param remote Peer address |
| * @param send_pkt Full IP + TCP header that is to be sent. |
| * |
| * @return 0 if ok, < 0 if error |
| */ |
| int net_tcp_prepare_segment(struct net_tcp *tcp, u8_t flags, |
| void *options, size_t optlen, |
| const struct sockaddr_ptr *local, |
| const struct sockaddr *remote, |
| struct net_pkt **send_pkt); |
| |
| /** |
| * @brief Prepare a TCP ACK message that can be send to peer. |
| * |
| * @param tcp TCP context |
| * @param remote Peer address |
| * @param pkt Network buffer |
| * |
| * @return 0 if ok, < 0 if error |
| */ |
| int net_tcp_prepare_ack(struct net_tcp *tcp, const struct sockaddr *remote, |
| struct net_pkt **pkt); |
| |
| /** |
| * @brief Prepare a TCP RST message that can be send to peer. |
| * |
| * @param tcp TCP context |
| * @param remote Peer address |
| * @param pkt Network buffer |
| * |
| * @return 0 if ok, < 0 if error |
| */ |
| int net_tcp_prepare_reset(struct net_tcp *tcp, const struct sockaddr *remote, |
| struct net_pkt **pkt); |
| |
| typedef void (*net_tcp_cb_t)(struct net_tcp *tcp, void *user_data); |
| |
| /** |
| * @brief Go through all the TCP connections and call callback |
| * for each of them. |
| * |
| * @param cb User supplied callback function to call. |
| * @param user_data User specified data. |
| */ |
| void net_tcp_foreach(net_tcp_cb_t cb, void *user_data); |
| |
| /** |
| * @brief Send available queued data over TCP connection |
| * |
| * @param context TCP context |
| * |
| * @return 0 if ok, < 0 if error |
| */ |
| int net_tcp_send_data(struct net_context *context); |
| |
| /** |
| * @brief Enqueue a single packet for transmission |
| * |
| * @param context TCP context |
| * @param pkt Packet |
| * |
| * @return 0 if ok, < 0 if error |
| */ |
| int net_tcp_queue_data(struct net_context *context, struct net_pkt *pkt); |
| |
| /** |
| * @brief Sends one TCP packet initialized with the _prepare_*() |
| * family of functions. |
| * |
| * @param pkt Packet |
| */ |
| int net_tcp_send_pkt(struct net_pkt *pkt); |
| |
| /** |
| * @brief Handle a received TCP ACK |
| * |
| * @param cts Context |
| * @param seq Received ACK sequence number |
| */ |
| void net_tcp_ack_received(struct net_context *ctx, u32_t ack); |
| |
| /** |
| * @brief Calculates and returns the MSS for a given TCP context |
| * |
| * @param tcp TCP context |
| * |
| * @return Maximum Segment Size |
| */ |
| u16_t net_tcp_get_recv_mss(const struct net_tcp *tcp); |
| |
| /** |
| * @brief Returns the receive window for a given TCP context |
| * |
| * @param tcp TCP context |
| * |
| * @return Current TCP receive window |
| */ |
| u32_t net_tcp_get_recv_wnd(const struct net_tcp *tcp); |
| |
| /** |
| * @brief Obtains the state for a TCP context |
| * |
| * @param tcp TCP context |
| */ |
| static inline enum net_tcp_state net_tcp_get_state(const struct net_tcp *tcp) |
| { |
| return (enum net_tcp_state)tcp->state; |
| } |
| |
| /** |
| * @brief Check if the sequence number is valid i.e., it is inside the window. |
| * |
| * @param tcp TCP context |
| * @param pkt Network packet |
| * |
| * @return true if network packet sequence number is valid, false otherwise |
| */ |
| bool net_tcp_validate_seq(struct net_tcp *tcp, struct net_pkt *pkt); |
| |
| #if defined(CONFIG_NET_TCP) |
| /** |
| * @brief Get TCP packet header data from net_pkt. The array values are in |
| * network byte order and other values are in host byte order. |
| * Note that you must access the TCP header values by the returned pointer, |
| * the hdr parameter is just a placeholder for the header data and it might |
| * not contain anything if the header fits properly in the first fragment of |
| * the network packet. |
| * |
| * @param pkt Network packet |
| * @param hdr Where to place the header if it does not fit in first fragment |
| * of the network packet. This might not be pupulated if TCP header fits in |
| * net_buf fragment. |
| * |
| * @return Return pointer to header or NULL if something went wrong. |
| * Always use the returned pointer to access the TCP header. |
| */ |
| struct net_tcp_hdr *net_tcp_get_hdr(struct net_pkt *pkt, |
| struct net_tcp_hdr *hdr); |
| |
| /** |
| * @brief Set TCP packet header data in net_pkt. |
| * |
| * @details The values in the header must be in network byte order. |
| * This function is normally called after a call to net_tcp_get_hdr(). |
| * The hdr parameter value should be the same that is returned by function |
| * net_tcp_get_hdr() call. Note that if the TCP header fits in first net_pkt |
| * fragment, then this function will not do anything as the returned value |
| * was pointing directly to net_pkt. |
| * |
| * @param pkt Network packet |
| * @param hdr Header data pointer that was returned by net_tcp_get_hdr(). |
| * |
| * @return Return hdr or NULL if error |
| */ |
| struct net_tcp_hdr *net_tcp_set_hdr(struct net_pkt *pkt, |
| struct net_tcp_hdr *hdr); |
| |
| /** |
| * @brief Set TCP checksum in network packet. |
| * |
| * @param pkt Network packet |
| * @param frag Fragment where to start calculating the offset. |
| * Typically this is set to pkt->frags by the caller. |
| * |
| * @return Return the actual fragment where the checksum was written. |
| */ |
| struct net_buf *net_tcp_set_chksum(struct net_pkt *pkt, struct net_buf *frag); |
| |
| /** |
| * @brief Get TCP checksum from network packet. |
| * |
| * @param pkt Network packet |
| * @param frag Fragment where to start calculating the offset. |
| * Typically this is set to pkt->frags by the caller. |
| * |
| * @return Return the checksum in host byte order. |
| */ |
| u16_t net_tcp_get_chksum(struct net_pkt *pkt, struct net_buf *frag); |
| |
| /** |
| * @brief Parse TCP options from network packet. |
| * |
| * Parse TCP options, returning MSS value (as that the only one we |
| * handle so far). |
| * |
| * @param pkt Network packet |
| * @param opt_totlen Total length of options to parse |
| * @param opts Pointer to TCP options structure. (Each option is updated |
| * only if present, so the structure must be initialized with the default |
| * values.) |
| * |
| * @return 0 if no error, <0 in case of error |
| */ |
| int net_tcp_parse_opts(struct net_pkt *pkt, int opt_totlen, |
| struct net_tcp_options *opts); |
| |
| #else |
| |
| static inline u16_t net_tcp_get_chksum(struct net_pkt *pkt, |
| struct net_buf *frag) |
| { |
| ARG_UNUSED(pkt); |
| ARG_UNUSED(frag); |
| return 0; |
| } |
| |
| static inline struct net_buf *net_tcp_set_chksum(struct net_pkt *pkt, |
| struct net_buf *frag) |
| { |
| ARG_UNUSED(pkt); |
| ARG_UNUSED(frag); |
| return NULL; |
| } |
| |
| static inline struct net_tcp_hdr *net_tcp_get_hdr(struct net_pkt *pkt, |
| struct net_tcp_hdr *hdr) |
| { |
| ARG_UNUSED(pkt); |
| ARG_UNUSED(hdr); |
| return NULL; |
| } |
| |
| static inline struct net_tcp_hdr *net_tcp_set_hdr(struct net_pkt *pkt, |
| struct net_tcp_hdr *hdr) |
| { |
| ARG_UNUSED(pkt); |
| ARG_UNUSED(hdr); |
| return NULL; |
| } |
| #endif |
| |
| #if defined(CONFIG_NET_TCP) |
| void net_tcp_init(void); |
| #else |
| #define net_tcp_init(...) |
| #endif |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| #endif /* __TCP_H */ |