blob: 8fa8e81c1318f07c2442af87deb4db6005061c46 [file] [log] [blame]
/*
* Copyright (c) 2018-2019 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "tp.h"
#define is(_a, _b) (strcmp((_a), (_b)) == 0)
#define is_timer_subscribed(_t) (k_timer_remaining_get(_t))
#define th_seq(_x) ntohl((_x)->th_seq)
#define th_ack(_x) ntohl((_x)->th_ack)
#define ip_get(_x) ((struct net_ipv4_hdr *) net_pkt_ip_data((_x)))
#define ip6_get(_x) ((struct net_ipv6_hdr *) net_pkt_ip_data((_x)))
#define tcp_slist(_slist, _op, _type, _link) \
({ \
sys_snode_t *_node = sys_slist_##_op(_slist); \
\
_type * _x = _node ? CONTAINER_OF(_node, _type, _link) : NULL; \
\
_x; \
})
#if IS_ENABLED(CONFIG_NET_TEST_PROTOCOL)
#define tcp_malloc(_size) \
tp_malloc(_size, tp_basename(__FILE__), __LINE__, __func__)
#define tcp_calloc(_nmemb, _size) \
tp_calloc(_nmemb, _size, tp_basename(__FILE__), __LINE__, __func__)
#define tcp_free(_ptr) tp_free(_ptr, tp_basename(__FILE__), __LINE__, __func__)
#else
#define tcp_malloc(_size) k_malloc(_size)
#define tcp_calloc(_nmemb, _size) k_calloc(_nmemb, _size)
#define tcp_free(_ptr) k_free(_ptr)
#endif
#if IS_ENABLED(CONFIG_NET_TEST_PROTOCOL)
#define tcp_pkt_alloc(_len) tp_pkt_alloc(_len, tp_basename(__FILE__), __LINE__)
#define tcp_pkt_clone(_pkt) tp_pkt_clone(_pkt, tp_basename(__FILE__), __LINE__)
#define tcp_pkt_unref(_pkt) tp_pkt_unref(_pkt, tp_basename(__FILE__), __LINE__)
#else
static struct net_pkt *tcp_pkt_alloc(size_t len)
{
struct net_pkt *pkt = net_pkt_alloc(K_NO_WAIT);
pkt->family = AF_INET;
NET_ASSERT(pkt);
if (len) {
struct net_buf *buf = net_pkt_get_frag(pkt, K_NO_WAIT);
net_buf_add(buf, len);
net_pkt_frag_insert(pkt, buf);
NET_ASSERT(buf);
}
return pkt;
}
#define tcp_pkt_clone(_pkt) net_pkt_clone(_pkt, K_NO_WAIT)
#define tcp_pkt_unref(_pkt) net_pkt_unref(_pkt)
#endif
#define tcp_pkt_ref(_pkt) net_pkt_ref(_pkt)
#if IS_ENABLED(CONFIG_NET_TEST_PROTOCOL)
#define conn_seq(_conn, _req) \
tp_seq_track(TP_SEQ, &(_conn)->seq, (_req), tp_basename(__FILE__), \
__LINE__, __func__)
#define conn_ack(_conn, _req) \
tp_seq_track(TP_ACK, &(_conn)->ack, (_req), tp_basename(__FILE__), \
__LINE__, __func__)
#else
#define conn_seq(_conn, _req) (_conn)->seq += (_req)
#define conn_ack(_conn, _req) (_conn)->ack += (_req)
#endif
#define conn_state(_conn, _s) \
({ \
NET_DBG("%s->%s", \
tcp_state_to_str((_conn)->state, false), \
tcp_state_to_str((_s), false)); \
(_conn)->state = _s; \
})
#define TCPOPT_PAD 0
#define TCPOPT_NOP 1
#define TCPOPT_MAXSEG 2
#define TCPOPT_WINDOW 3
enum pkt_addr {
SRC = 1,
DST = 0
};
struct tcphdr {
u16_t th_sport;
u16_t th_dport;
u32_t th_seq;
u32_t th_ack;
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
u8_t th_x2:4; /* unused */
u8_t th_off:4; /* data offset */
#endif
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
u8_t th_off:4;
u8_t th_x2:4;
#endif
u8_t th_flags;
u16_t th_win;
u16_t th_sum;
u16_t th_urp;
};
enum th_flags {
FIN = 1,
SYN = 1 << 1,
RST = 1 << 2,
PSH = 1 << 3,
ACK = 1 << 4,
URG = 1 << 5,
};
enum tcp_state {
TCP_LISTEN = 1,
TCP_SYN_SENT,
TCP_SYN_RECEIVED,
TCP_ESTABLISHED,
TCP_FIN_WAIT1,
TCP_FIN_WAIT2,
TCP_CLOSE_WAIT,
TCP_CLOSING,
TCP_LAST_ACK,
TCP_TIME_WAIT,
TCP_CLOSED
};
struct tcp_win { /* TCP window */
size_t len;
sys_slist_t bufs;
};
union tcp_endpoint {
struct sockaddr sa;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
};
struct tcp { /* TCP connection */
sys_snode_t next;
struct net_context *context;
void *recv_user_data;
enum tcp_state state;
u32_t seq;
u32_t ack;
union tcp_endpoint *src;
union tcp_endpoint *dst;
u16_t win;
struct tcp_win *rcv;
struct tcp_win *snd;
struct k_timer send_timer;
sys_slist_t send_queue;
bool in_retransmission;
size_t send_retries;
struct net_if *iface;
net_tcp_accept_cb_t accept_cb;
atomic_t ref_count;
sys_slist_t rsv_bufs;
size_t rsv_bytes;
};
#define _flags(_fl, _op, _mask, _cond) \
({ \
bool result = false; \
\
if (*(_fl) && (_cond) && (*(_fl) _op (_mask))) { \
*(_fl) &= ~(_mask); \
result = true; \
} \
\
result; \
})
#define FL(_fl, _op, _mask, _args...) \
_flags(_fl, _op, _mask, strlen("" #_args) ? _args : true)
extern struct net_buf_pool tcp_nbufs;
#if IS_ENABLED(CONFIG_NET_TEST_PROTOCOL)
#define tcp_nbuf_alloc(_conn, _len) \
tp_nbuf_alloc(&tcp_nbufs, _len, tp_basename(__FILE__), \
__LINE__, __func__)
#define tcp_nbuf_clone(_buf) \
tp_nbuf_clone((_buf), tp_basename(__FILE__), __LINE__, __func__)
#define tcp_nbuf_unref(_nbuf) \
tp_nbuf_unref(_nbuf, tp_basename(__FILE__), __LINE__, __func__)
#else
static struct net_buf *tcp_nbuf_alloc(struct tcp *conn, size_t len)
{
struct net_buf *buf;
if (conn->rsv_bytes >= len) {
buf = tcp_slist(&conn->rsv_bufs, get, struct net_buf, node);
conn->rsv_bytes -= buf->size;
} else {
buf = net_buf_alloc_len(&tcp_nbufs, len, K_NO_WAIT);
}
NET_ASSERT(buf && buf->size >= len);
NET_DBG("len: %zu, buf->size: %hu", len, buf->size);
return buf;
}
#define tcp_nbuf_clone(_buf) net_buf_clone(_buf, K_NO_WAIT)
#define tcp_nbuf_unref(_nbuf) net_buf_unref(_nbuf)
#endif