net: tcp2: No dynamic allocation for TCP connection endpoint
Avoid dynamic allocations and all the issues if we run out of memory, by placing the connection endpoint directly to TCP connection struct. Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
This commit is contained in:
parent
bf0add1a34
commit
76a7fdd213
2 changed files with 96 additions and 126 deletions
|
@ -58,87 +58,56 @@ static size_t tcp_endpoint_len(sa_family_t af)
|
||||||
sizeof(struct sockaddr_in6);
|
sizeof(struct sockaddr_in6);
|
||||||
}
|
}
|
||||||
|
|
||||||
static union tcp_endpoint *tcp_endpoint_new(struct net_pkt *pkt)
|
static int tcp_endpoint_set(union tcp_endpoint *ep, struct net_pkt *pkt,
|
||||||
|
enum pkt_addr src)
|
||||||
{
|
{
|
||||||
sa_family_t af = net_pkt_family(pkt);
|
int ret = 0;
|
||||||
union tcp_endpoint *ep = tcp_calloc(1, tcp_endpoint_len(af));
|
|
||||||
|
|
||||||
if (ep) {
|
switch (net_pkt_family(pkt)) {
|
||||||
ep->sa.sa_family = af;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ep;
|
|
||||||
}
|
|
||||||
|
|
||||||
static union tcp_endpoint *tcp_endpoint_set(union tcp_endpoint *ep,
|
|
||||||
struct net_pkt *pkt,
|
|
||||||
enum pkt_addr src)
|
|
||||||
{
|
|
||||||
if (!ep) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (ep->sa.sa_family) {
|
|
||||||
case AF_INET:
|
case AF_INET:
|
||||||
if (IS_ENABLED(CONFIG_NET_IPV4)) {
|
if (IS_ENABLED(CONFIG_NET_IPV4)) {
|
||||||
struct net_ipv4_hdr *ip = (struct net_ipv4_hdr *)
|
struct net_ipv4_hdr *ip = NET_IPV4_HDR(pkt);
|
||||||
net_pkt_ip_data(pkt);
|
|
||||||
struct tcphdr *th = th_get(pkt);
|
struct tcphdr *th = th_get(pkt);
|
||||||
|
|
||||||
|
memset(ep, 0, sizeof(*ep));
|
||||||
|
|
||||||
ep->sin.sin_port = src == TCP_EP_SRC ? th->th_sport :
|
ep->sin.sin_port = src == TCP_EP_SRC ? th->th_sport :
|
||||||
th->th_dport;
|
th->th_dport;
|
||||||
ep->sin.sin_addr = src == TCP_EP_SRC ? ip->src :
|
net_ipaddr_copy(&ep->sin.sin_addr,
|
||||||
ip->dst;
|
src == TCP_EP_SRC ?
|
||||||
|
&ip->src : &ip->dst);
|
||||||
|
ep->sa.sa_family = AF_INET;
|
||||||
|
} else {
|
||||||
|
ret = -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AF_INET6:
|
case AF_INET6:
|
||||||
if (IS_ENABLED(CONFIG_NET_IPV6)) {
|
if (IS_ENABLED(CONFIG_NET_IPV6)) {
|
||||||
struct net_ipv6_hdr *ip = (struct net_ipv6_hdr *)
|
struct net_ipv6_hdr *ip = NET_IPV6_HDR(pkt);
|
||||||
net_pkt_ip_data(pkt);
|
|
||||||
struct tcphdr *th = th_get(pkt);
|
struct tcphdr *th = th_get(pkt);
|
||||||
|
|
||||||
|
memset(ep, 0, sizeof(*ep));
|
||||||
|
|
||||||
ep->sin6.sin6_port = src == TCP_EP_SRC ? th->th_sport :
|
ep->sin6.sin6_port = src == TCP_EP_SRC ? th->th_sport :
|
||||||
th->th_dport;
|
th->th_dport;
|
||||||
ep->sin6.sin6_addr = src == TCP_EP_SRC ? ip->src :
|
net_ipaddr_copy(&ep->sin6.sin6_addr,
|
||||||
ip->dst;
|
src == TCP_EP_SRC ?
|
||||||
|
&ip->src : &ip->dst);
|
||||||
|
ep->sa.sa_family = AF_INET6;
|
||||||
|
} else {
|
||||||
|
ret = -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
NET_ERR("Unknown address family: %hu", ep->sa.sa_family);
|
NET_ERR("Unknown address family: %hu", net_pkt_family(pkt));
|
||||||
|
ret = -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ep;
|
return ret;
|
||||||
}
|
|
||||||
|
|
||||||
static char *tcp_endpoint_to_string(union tcp_endpoint *ep)
|
|
||||||
{
|
|
||||||
#define NBUFS 2
|
|
||||||
#define BUF_SIZE 80
|
|
||||||
sa_family_t af = ep->sa.sa_family;
|
|
||||||
static char buf[NBUFS][BUF_SIZE];
|
|
||||||
char addr[INET6_ADDRSTRLEN];
|
|
||||||
static int i;
|
|
||||||
char *s = buf[++i % NBUFS];
|
|
||||||
|
|
||||||
switch (af) {
|
|
||||||
case 0:
|
|
||||||
snprintk(s, BUF_SIZE, ":%hu", ntohs(ep->sin.sin_port));
|
|
||||||
break;
|
|
||||||
case AF_INET: case AF_INET6:
|
|
||||||
net_addr_ntop(af, &ep->sin.sin_addr, addr, sizeof(addr));
|
|
||||||
snprintk(s, BUF_SIZE, "%s:%hu", addr, ntohs(ep->sin.sin_port));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
s = NULL;
|
|
||||||
NET_ERR("Unknown address family: %hu", af);
|
|
||||||
}
|
|
||||||
#undef BUF_SIZE
|
|
||||||
#undef NBUFS
|
|
||||||
return s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *tcp_flags(u8_t flags)
|
static const char *tcp_flags(u8_t flags)
|
||||||
|
@ -274,9 +243,6 @@ static int tcp_conn_unref(struct tcp *conn)
|
||||||
|
|
||||||
k_delayed_work_cancel(&conn->timewait_timer);
|
k_delayed_work_cancel(&conn->timewait_timer);
|
||||||
|
|
||||||
tcp_free(conn->src);
|
|
||||||
tcp_free(conn->dst);
|
|
||||||
|
|
||||||
memset(conn, 0, sizeof(*conn));
|
memset(conn, 0, sizeof(*conn));
|
||||||
|
|
||||||
sys_slist_find_and_remove(&tcp_conns, (sys_snode_t *)conn);
|
sys_slist_find_and_remove(&tcp_conns, (sys_snode_t *)conn);
|
||||||
|
@ -520,8 +486,8 @@ static int tcp_header_add(struct tcp *conn, struct net_pkt *pkt, u8_t flags)
|
||||||
|
|
||||||
memset(th, 0, sizeof(struct tcphdr));
|
memset(th, 0, sizeof(struct tcphdr));
|
||||||
|
|
||||||
th->th_sport = conn->src->sin.sin_port;
|
th->th_sport = conn->src.sin.sin_port;
|
||||||
th->th_dport = conn->dst->sin.sin_port;
|
th->th_dport = conn->dst.sin.sin_port;
|
||||||
|
|
||||||
th->th_off = 5;
|
th->th_off = 5;
|
||||||
th->th_flags = flags;
|
th->th_flags = flags;
|
||||||
|
@ -539,14 +505,14 @@ static int ip_header_add(struct tcp *conn, struct net_pkt *pkt)
|
||||||
{
|
{
|
||||||
if (IS_ENABLED(CONFIG_NET_IPV4) && net_pkt_family(pkt) == AF_INET) {
|
if (IS_ENABLED(CONFIG_NET_IPV4) && net_pkt_family(pkt) == AF_INET) {
|
||||||
return net_context_create_ipv4_new(conn->context, pkt,
|
return net_context_create_ipv4_new(conn->context, pkt,
|
||||||
&conn->src->sin.sin_addr,
|
&conn->src.sin.sin_addr,
|
||||||
&conn->dst->sin.sin_addr);
|
&conn->dst.sin.sin_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_NET_IPV6) && net_pkt_family(pkt) == AF_INET6) {
|
if (IS_ENABLED(CONFIG_NET_IPV6) && net_pkt_family(pkt) == AF_INET6) {
|
||||||
return net_context_create_ipv6_new(conn->context, pkt,
|
return net_context_create_ipv6_new(conn->context, pkt,
|
||||||
&conn->src->sin6.sin6_addr,
|
&conn->src.sin6.sin6_addr,
|
||||||
&conn->dst->sin6.sin6_addr);
|
&conn->dst.sin6.sin6_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -710,19 +676,19 @@ out:
|
||||||
static bool tcp_endpoint_cmp(union tcp_endpoint *ep, struct net_pkt *pkt,
|
static bool tcp_endpoint_cmp(union tcp_endpoint *ep, struct net_pkt *pkt,
|
||||||
enum pkt_addr which)
|
enum pkt_addr which)
|
||||||
{
|
{
|
||||||
union tcp_endpoint ep_tmp = { 0 }, *ep_ptr;
|
union tcp_endpoint ep_tmp;
|
||||||
|
|
||||||
ep_tmp.sa.sa_family = net_pkt_family(pkt);
|
if (tcp_endpoint_set(&ep_tmp, pkt, which) < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
ep_ptr = tcp_endpoint_set(&ep_tmp, pkt, which);
|
return !memcmp(ep, &ep_tmp, tcp_endpoint_len(ep->sa.sa_family));
|
||||||
|
|
||||||
return !memcmp(ep, ep_ptr, tcp_endpoint_len(ep->sa.sa_family));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool tcp_conn_cmp(struct tcp *conn, struct net_pkt *pkt)
|
static bool tcp_conn_cmp(struct tcp *conn, struct net_pkt *pkt)
|
||||||
{
|
{
|
||||||
return tcp_endpoint_cmp(conn->src, pkt, TCP_EP_DST) &&
|
return tcp_endpoint_cmp(&conn->src, pkt, TCP_EP_DST) &&
|
||||||
tcp_endpoint_cmp(conn->dst, pkt, TCP_EP_SRC);
|
tcp_endpoint_cmp(&conn->dst, pkt, TCP_EP_SRC);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct tcp *tcp_conn_search(struct net_pkt *pkt)
|
static struct tcp *tcp_conn_search(struct net_pkt *pkt)
|
||||||
|
@ -732,12 +698,7 @@ static struct tcp *tcp_conn_search(struct net_pkt *pkt)
|
||||||
|
|
||||||
SYS_SLIST_FOR_EACH_CONTAINER(&tcp_conns, conn, next) {
|
SYS_SLIST_FOR_EACH_CONTAINER(&tcp_conns, conn, next) {
|
||||||
|
|
||||||
if (NULL == conn->src || NULL == conn->dst) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
found = tcp_conn_cmp(conn, pkt);
|
found = tcp_conn_cmp(conn, pkt);
|
||||||
|
|
||||||
if (found) {
|
if (found) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -772,7 +733,7 @@ static enum net_verdict tcp_recv(struct net_conn *net_conn,
|
||||||
|
|
||||||
conn = tcp_conn_new(pkt);
|
conn = tcp_conn_new(pkt);
|
||||||
|
|
||||||
conn_old->context->remote = conn->dst->sa;
|
net_ipaddr_copy(&conn_old->context->remote, &conn->dst.sa);
|
||||||
|
|
||||||
conn_old->accept_cb(conn->context,
|
conn_old->accept_cb(conn->context,
|
||||||
&conn_old->context->remote,
|
&conn_old->context->remote,
|
||||||
|
@ -806,16 +767,27 @@ static struct tcp *tcp_conn_new(struct net_pkt *pkt)
|
||||||
conn = context->tcp;
|
conn = context->tcp;
|
||||||
conn->iface = pkt->iface;
|
conn->iface = pkt->iface;
|
||||||
|
|
||||||
net_context_set_family(conn->context, pkt->family);
|
net_context_set_family(conn->context, net_pkt_family(pkt));
|
||||||
|
|
||||||
conn->dst = tcp_endpoint_set(tcp_endpoint_new(pkt), pkt, TCP_EP_SRC);
|
if (tcp_endpoint_set(&conn->dst, pkt, TCP_EP_SRC) < 0) {
|
||||||
conn->src = tcp_endpoint_set(tcp_endpoint_new(pkt), pkt, TCP_EP_DST);
|
net_context_unref(context);
|
||||||
|
conn = NULL;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tcp_endpoint_set(&conn->src, pkt, TCP_EP_DST) < 0) {
|
||||||
|
net_context_unref(context);
|
||||||
|
conn = NULL;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
NET_DBG("conn: src: %s, dst: %s",
|
NET_DBG("conn: src: %s, dst: %s",
|
||||||
log_strdup(tcp_endpoint_to_string(conn->src)),
|
log_strdup(net_sprint_addr(conn->src.sa.sa_family,
|
||||||
log_strdup(tcp_endpoint_to_string(conn->dst)));
|
(const void *)&conn->src.sin.sin_addr)),
|
||||||
|
log_strdup(net_sprint_addr(conn->dst.sa.sa_family,
|
||||||
|
(const void *)&conn->dst.sin.sin_addr)));
|
||||||
|
|
||||||
memcpy(&context->remote, conn->dst, sizeof(context->remote));
|
memcpy(&context->remote, &conn->dst, sizeof(context->remote));
|
||||||
context->flags |= NET_CONTEXT_REMOTE_ADDR_SET;
|
context->flags |= NET_CONTEXT_REMOTE_ADDR_SET;
|
||||||
|
|
||||||
((struct sockaddr_in *)&context->local)->sin_family = af;
|
((struct sockaddr_in *)&context->local)->sin_family = af;
|
||||||
|
@ -826,8 +798,8 @@ static struct tcp *tcp_conn_new(struct net_pkt *pkt)
|
||||||
|
|
||||||
ret = net_conn_register(IPPROTO_TCP, af,
|
ret = net_conn_register(IPPROTO_TCP, af,
|
||||||
&context->remote, (void *)&context->local,
|
&context->remote, (void *)&context->local,
|
||||||
ntohs(conn->dst->sin.sin_port),/* local port */
|
ntohs(conn->dst.sin.sin_port),/* local port */
|
||||||
ntohs(conn->src->sin.sin_port),/* remote port */
|
ntohs(conn->src.sin.sin_port),/* remote port */
|
||||||
tcp_recv, context,
|
tcp_recv, context,
|
||||||
&context->conn_handler);
|
&context->conn_handler);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
@ -1067,51 +1039,54 @@ int net_tcp_connect(struct net_context *context,
|
||||||
const struct in6_addr *ip6;
|
const struct in6_addr *ip6;
|
||||||
|
|
||||||
case AF_INET:
|
case AF_INET:
|
||||||
conn->src = tcp_calloc(1, tcp_endpoint_len(AF_INET));
|
memset(&conn->src, 0, sizeof(struct sockaddr_in));
|
||||||
conn->dst = tcp_calloc(1, tcp_endpoint_len(AF_INET));
|
memset(&conn->dst, 0, sizeof(struct sockaddr_in));
|
||||||
|
|
||||||
conn->src->sa.sa_family = AF_INET;
|
conn->src.sa.sa_family = AF_INET;
|
||||||
conn->dst->sa.sa_family = AF_INET;
|
conn->dst.sa.sa_family = AF_INET;
|
||||||
|
|
||||||
conn->dst->sin.sin_port = remote_port;
|
conn->dst.sin.sin_port = remote_port;
|
||||||
conn->src->sin.sin_port = local_port;
|
conn->src.sin.sin_port = local_port;
|
||||||
|
|
||||||
/* we have to select the source address here as
|
/* we have to select the source address here as
|
||||||
* net_context_create_ipv4_new() is not called in the packet
|
* net_context_create_ipv4_new() is not called in the packet
|
||||||
* output chain
|
* output chain
|
||||||
*/
|
*/
|
||||||
ip4 = net_if_ipv4_select_src_addr(net_context_get_iface(context),
|
ip4 = net_if_ipv4_select_src_addr(
|
||||||
(struct in_addr *)remote_addr);
|
net_context_get_iface(context),
|
||||||
conn->src->sin.sin_addr = *ip4;
|
&net_sin(remote_addr)->sin_addr);
|
||||||
conn->dst->sin.sin_addr = ((struct sockaddr_in *)remote_addr)->sin_addr;
|
conn->src.sin.sin_addr = *ip4;
|
||||||
|
net_ipaddr_copy(&conn->dst.sin.sin_addr,
|
||||||
|
&net_sin(remote_addr)->sin_addr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AF_INET6:
|
case AF_INET6:
|
||||||
conn->src = tcp_calloc(1, tcp_endpoint_len(AF_INET6));
|
memset(&conn->src, 0, sizeof(struct sockaddr_in6));
|
||||||
conn->dst = tcp_calloc(1, tcp_endpoint_len(AF_INET6));
|
memset(&conn->dst, 0, sizeof(struct sockaddr_in6));
|
||||||
|
|
||||||
memset(conn->src, 0, tcp_endpoint_len(AF_INET6));
|
conn->src.sin6.sin6_family = AF_INET6;
|
||||||
memset(conn->dst, 0, tcp_endpoint_len(AF_INET6));
|
conn->dst.sin6.sin6_family = AF_INET6;
|
||||||
|
|
||||||
conn->src->sin6.sin6_family = AF_INET6;
|
conn->dst.sin6.sin6_port = remote_port;
|
||||||
conn->dst->sin6.sin6_family = AF_INET6;
|
conn->src.sin6.sin6_port = local_port;
|
||||||
|
|
||||||
conn->dst->sin6.sin6_port = remote_port;
|
ip6 = net_if_ipv6_select_src_addr(
|
||||||
conn->src->sin6.sin6_port = local_port;
|
net_context_get_iface(context),
|
||||||
|
&net_sin6(remote_addr)->sin6_addr);
|
||||||
ip6 = net_if_ipv6_select_src_addr(net_context_get_iface(context),
|
conn->src.sin6.sin6_addr = *ip6;
|
||||||
(struct in6_addr *)remote_addr);
|
net_ipaddr_copy(&conn->dst.sin6.sin6_addr,
|
||||||
conn->src->sin6.sin6_addr = *ip6;
|
&net_sin6(remote_addr)->sin6_addr);
|
||||||
conn->dst->sin6.sin6_addr = ((struct sockaddr_in6 *)remote_addr)->sin6_addr;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return -EPROTONOSUPPORT;
|
return -EPROTONOSUPPORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
NET_DBG("conn: %p, local: %s, remote: %s", conn,
|
NET_DBG("conn: %p src: %s, dst: %s", conn,
|
||||||
log_strdup(tcp_endpoint_to_string(conn->src)),
|
log_strdup(net_sprint_addr(conn->src.sa.sa_family,
|
||||||
log_strdup(tcp_endpoint_to_string(conn->dst)));
|
(const void *)&conn->src.sin.sin_addr)),
|
||||||
|
log_strdup(net_sprint_addr(conn->dst.sa.sa_family,
|
||||||
|
(const void *)&conn->dst.sin.sin_addr)));
|
||||||
|
|
||||||
net_context_set_state(context, NET_CONTEXT_CONNECTING);
|
net_context_set_state(context, NET_CONTEXT_CONNECTING);
|
||||||
|
|
||||||
|
@ -1276,12 +1251,10 @@ static enum net_verdict tcp_input(struct net_conn *net_conn,
|
||||||
struct net_context *context =
|
struct net_context *context =
|
||||||
tcp_calloc(1, sizeof(struct net_context));
|
tcp_calloc(1, sizeof(struct net_context));
|
||||||
net_tcp_get(context);
|
net_tcp_get(context);
|
||||||
net_context_set_family(context, pkt->family);
|
net_context_set_family(context, net_pkt_family(pkt));
|
||||||
conn = context->tcp;
|
conn = context->tcp;
|
||||||
conn->dst = tcp_endpoint_set(tcp_endpoint_new(pkt),
|
tcp_endpoint_set(&conn->dst, pkt, TCP_EP_SRC);
|
||||||
pkt, TCP_EP_SRC);
|
tcp_endpoint_set(&conn->src, pkt, TCP_EP_DST);
|
||||||
conn->src = tcp_endpoint_set(tcp_endpoint_new(pkt),
|
|
||||||
pkt, TCP_EP_DST);
|
|
||||||
/* Make an extra reference, the sanity check suite
|
/* Make an extra reference, the sanity check suite
|
||||||
* will delete the connection explicitly
|
* will delete the connection explicitly
|
||||||
*/
|
*/
|
||||||
|
@ -1398,14 +1371,11 @@ enum net_verdict tp_input(struct net_conn *net_conn,
|
||||||
struct net_context *context = tcp_calloc(1,
|
struct net_context *context = tcp_calloc(1,
|
||||||
sizeof(struct net_context));
|
sizeof(struct net_context));
|
||||||
net_tcp_get(context);
|
net_tcp_get(context);
|
||||||
net_context_set_family(context, pkt->family);
|
net_context_set_family(context,
|
||||||
|
net_pkt_family(pkt));
|
||||||
conn = context->tcp;
|
conn = context->tcp;
|
||||||
conn->dst =
|
tcp_endpoint_set(&conn->dst, pkt, TCP_EP_SRC);
|
||||||
tcp_endpoint_set(tcp_endpoint_new(pkt),
|
tcp_endpoint_set(&conn->src, pkt, TCP_EP_DST);
|
||||||
pkt, TCP_EP_SRC);
|
|
||||||
conn->src =
|
|
||||||
tcp_endpoint_set(tcp_endpoint_new(pkt),
|
|
||||||
pkt, TCP_EP_DST);
|
|
||||||
conn->iface = pkt->iface;
|
conn->iface = pkt->iface;
|
||||||
tcp_conn_ref(conn);
|
tcp_conn_ref(conn);
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,8 +128,8 @@ struct tcp { /* TCP connection */
|
||||||
enum tcp_state state;
|
enum tcp_state state;
|
||||||
u32_t seq;
|
u32_t seq;
|
||||||
u32_t ack;
|
u32_t ack;
|
||||||
union tcp_endpoint *src;
|
union tcp_endpoint src;
|
||||||
union tcp_endpoint *dst;
|
union tcp_endpoint dst;
|
||||||
u16_t win;
|
u16_t win;
|
||||||
struct k_delayed_work send_timer;
|
struct k_delayed_work send_timer;
|
||||||
sys_slist_t send_queue;
|
sys_slist_t send_queue;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue