diff --git a/include/net/net_context.h b/include/net/net_context.h index 62a9ca2249d..6c809ee7df5 100644 --- a/include/net/net_context.h +++ b/include/net/net_context.h @@ -204,6 +204,10 @@ struct net_context { */ atomic_t refcount; + /** Internal lock for protecting this context from multiple access. + */ + struct k_mutex lock; + /** Local IP address. Note that the values are in network byte order. */ struct sockaddr_ptr local; diff --git a/subsys/net/ip/net_context.c b/subsys/net/ip/net_context.c index 7b29b72621a..353f9425238 100644 --- a/subsys/net/ip/net_context.c +++ b/subsys/net/ip/net_context.c @@ -248,6 +248,8 @@ int net_context_get(sa_family_t family, k_sem_init(&contexts[i].recv_data_wait, 1, UINT_MAX); #endif /* CONFIG_NET_CONTEXT_SYNC_RECV */ + k_mutex_init(&contexts[i].lock); + contexts[i].flags |= NET_CONTEXT_IN_USE; *context = &contexts[i]; @@ -294,7 +296,7 @@ int net_context_unref(struct net_context *context) return old_rc - 1; } - k_sem_take(&contexts_lock, K_FOREVER); + k_mutex_lock(&context->lock, K_FOREVER); net_tcp_unref(context); @@ -309,26 +311,29 @@ int net_context_unref(struct net_context *context) NET_DBG("Context %p released", context); - k_sem_give(&contexts_lock); + k_mutex_unlock(&context->lock); return 0; } int net_context_put(struct net_context *context) { + int ret = 0; + NET_ASSERT(context); if (!PART_OF_ARRAY(contexts, context)) { return -EINVAL; } + k_mutex_lock(&context->lock, K_FOREVER); + #if defined(CONFIG_NET_OFFLOAD) if (net_if_is_ip_offloaded(net_context_get_iface(context))) { - k_sem_take(&contexts_lock, K_FOREVER); context->flags &= ~NET_CONTEXT_IN_USE; - k_sem_give(&contexts_lock); - return net_offload_put( + ret = net_offload_put( net_context_get_iface(context), context); + goto unlock; } #endif /* CONFIG_NET_OFFLOAD */ @@ -337,11 +342,15 @@ int net_context_put(struct net_context *context) context->send_cb = NULL; if (net_tcp_put(context) >= 0) { - return 0; + goto unlock; } net_context_unref(context); - return 0; + +unlock: + k_mutex_unlock(&context->lock); + + return ret; } /* If local address is not bound, bind it to INADDR_ANY and random port. */ @@ -552,6 +561,10 @@ int net_context_bind(struct net_context *context, const struct sockaddr *addr, } #endif /* CONFIG_NET_OFFLOAD */ + k_mutex_lock(&context->lock, K_FOREVER); + + ret = 0; + net_context_set_iface(context, iface); net_sin_ptr(&context->local)->sin_family = AF_INET; @@ -565,7 +578,7 @@ int net_context_bind(struct net_context *context, const struct sockaddr *addr, } else { NET_ERR("Port %d is in use!", ntohs(addr4->sin_port)); - return ret; + goto unlock; } } else { addr4->sin_port = @@ -578,7 +591,10 @@ int net_context_bind(struct net_context *context, const struct sockaddr *addr, log_strdup(net_sprint_ipv4_addr(ptr)), ntohs(addr4->sin_port), iface); - return 0; + unlock: + k_mutex_unlock(&context->lock); + + return ret; } #endif @@ -619,10 +635,15 @@ int net_context_listen(struct net_context *context, int backlog) } #endif /* CONFIG_NET_OFFLOAD */ + k_mutex_lock(&context->lock, K_FOREVER); + if (net_tcp_listen(context) >= 0) { + k_mutex_unlock(&context->lock); return 0; } + k_mutex_unlock(&context->lock); + return -EOPNOTSUPP; } @@ -698,8 +719,11 @@ int net_context_connect(struct net_context *context, NET_ASSERT(addr); NET_ASSERT(PART_OF_ARRAY(contexts, context)); + k_mutex_lock(&context->lock, K_FOREVER); + if (!net_context_is_used(context)) { - return -EBADF; + ret = -EBADF; + goto unlock; } if (addr->sa_family != net_context_get_family(context)) { @@ -708,12 +732,13 @@ int net_context_connect(struct net_context *context, "Family mismatch %d should be %d", addr->sa_family, net_context_get_family(context)); - return -EINVAL; + ret = -EINVAL; + goto unlock; } #if defined(CONFIG_NET_OFFLOAD) if (net_if_is_ip_offloaded(net_context_get_iface(context))) { - return net_offload_connect( + ret = net_offload_connect( net_context_get_iface(context), context, addr, @@ -721,11 +746,13 @@ int net_context_connect(struct net_context *context, cb, timeout, user_data); + goto unlock; } #endif /* CONFIG_NET_OFFLOAD */ if (net_context_get_state(context) == NET_CONTEXT_LISTENING) { - return -EOPNOTSUPP; + ret = -EOPNOTSUPP; + goto unlock; } #if defined(CONFIG_NET_IPV6) @@ -734,12 +761,14 @@ int net_context_connect(struct net_context *context, &context->remote; if (addrlen < sizeof(struct sockaddr_in6)) { - return -EINVAL; + ret = -EINVAL; + goto unlock; } if (net_context_get_ip_proto(context) == IPPROTO_TCP && net_ipv6_is_addr_mcast(&addr6->sin6_addr)) { - return -EADDRNOTAVAIL; + ret = -EADDRNOTAVAIL; + goto unlock; } memcpy(&addr6->sin6_addr, &net_sin6(addr)->sin6_addr, @@ -764,7 +793,7 @@ int net_context_connect(struct net_context *context, */ ret = bind_default(context); if (ret) { - return ret; + goto unlock; } net_sin6_ptr(&context->local)->sin6_family = AF_INET6; @@ -787,7 +816,8 @@ int net_context_connect(struct net_context *context, &context->remote; if (addrlen < sizeof(struct sockaddr_in)) { - return -EINVAL; + ret = -EINVAL; + goto unlock; } /* FIXME - Add multicast and broadcast address check */ @@ -828,7 +858,8 @@ int net_context_connect(struct net_context *context, #endif /* CONFIG_NET_IPV4 */ { - return -EINVAL; /* Not IPv4 or IPv6 */ + ret = -EINVAL; /* Not IPv4 or IPv6 */ + goto unlock; } switch (net_context_get_type(context)) { @@ -838,19 +869,27 @@ int net_context_connect(struct net_context *context, cb(context, 0, user_data); } - return 0; + ret = 0; + goto unlock; #endif /* CONFIG_NET_UDP */ case SOCK_STREAM: - return net_tcp_connect(context, addr, laddr, rport, lport, - timeout, cb, user_data); + ret = net_tcp_connect(context, addr, laddr, rport, lport, + timeout, cb, user_data); + goto unlock; default: - return -ENOTSUP; + ret = -ENOTSUP; + goto unlock; } - return 0; + ret = 0; + +unlock: + k_mutex_unlock(&context->lock); + + return ret; } int net_context_accept(struct net_context *context, @@ -858,20 +897,25 @@ int net_context_accept(struct net_context *context, s32_t timeout, void *user_data) { + int ret = 0; + NET_ASSERT(PART_OF_ARRAY(contexts, context)); if (!net_context_is_used(context)) { return -EBADF; } + k_mutex_lock(&context->lock, K_FOREVER); + #if defined(CONFIG_NET_OFFLOAD) if (net_if_is_ip_offloaded(net_context_get_iface(context))) { - return net_offload_accept( + ret = net_offload_accept( net_context_get_iface(context), context, cb, timeout, user_data); + goto unlock; } #endif /* CONFIG_NET_OFFLOAD */ @@ -880,14 +924,19 @@ int net_context_accept(struct net_context *context, NET_DBG("Invalid socket, state %d type %d", net_context_get_state(context), net_context_get_type(context)); - return -EINVAL; + ret = -EINVAL; + goto unlock; } if (net_context_get_ip_proto(context) == IPPROTO_TCP) { - return net_tcp_accept(context, cb, user_data); + ret = net_tcp_accept(context, cb, user_data); + goto unlock; } - return 0; +unlock: + k_mutex_unlock(&context->lock); + + return ret; } #if defined(CONFIG_NET_UDP) @@ -1073,21 +1122,26 @@ int net_context_send(struct net_pkt *pkt, { struct net_context *context = net_pkt_context(pkt); socklen_t addrlen; + int ret = 0; NET_ASSERT(PART_OF_ARRAY(contexts, context)); + k_mutex_lock(&context->lock, K_FOREVER); + #if defined(CONFIG_NET_OFFLOAD) if (net_if_is_ip_offloaded(net_pkt_iface(pkt))) { - return net_offload_send( + ret = net_offload_send( net_pkt_iface(pkt), pkt, cb, timeout, token, user_data); + goto unlock; } #endif /* CONFIG_NET_OFFLOAD */ if (!(context->flags & NET_CONTEXT_REMOTE_ADDR_SET) || !net_sin(&context->remote)->sin_port) { - return -EDESTADDRREQ; + ret = -EDESTADDRREQ; + goto unlock; } #if defined(CONFIG_NET_IPV6) @@ -1105,8 +1159,13 @@ int net_context_send(struct net_pkt *pkt, addrlen = 0; } - return sendto(pkt, &context->remote, addrlen, cb, timeout, token, - user_data); + ret = sendto(pkt, &context->remote, addrlen, cb, timeout, token, + user_data); + +unlock: + k_mutex_unlock(&context->lock); + + return ret; } int net_context_sendto(struct net_pkt *pkt, @@ -1118,15 +1177,23 @@ int net_context_sendto(struct net_pkt *pkt, void *user_data) { struct net_context *context = net_pkt_context(pkt); + int ret; NET_ASSERT(PART_OF_ARRAY(contexts, context)); + k_mutex_lock(&context->lock, K_FOREVER); + if (net_context_get_ip_proto(context) == IPPROTO_TCP) { /* Match POSIX behavior and ignore dst_address and addrlen */ - return net_context_send(pkt, cb, timeout, token, user_data); + ret = net_context_send(pkt, cb, timeout, token, user_data); + } else { + ret = sendto(pkt, dst_addr, addrlen, cb, timeout, token, + user_data); } - return sendto(pkt, dst_addr, addrlen, cb, timeout, token, user_data); + k_mutex_unlock(&context->lock); + + return ret; } enum net_verdict net_context_packet_received(struct net_conn *conn, @@ -1134,10 +1201,13 @@ enum net_verdict net_context_packet_received(struct net_conn *conn, void *user_data) { struct net_context *context = find_context(conn); + enum net_verdict verdict = NET_DROP; NET_ASSERT(context); NET_ASSERT(net_pkt_iface(pkt)); + k_mutex_lock(&context->lock, K_FOREVER); + net_context_set_iface(context, net_pkt_iface(pkt)); net_pkt_set_context(pkt, context); @@ -1146,7 +1216,7 @@ enum net_verdict net_context_packet_received(struct net_conn *conn, */ if (!context->recv_cb) { - return NET_DROP; + goto unlock; } if (net_context_get_ip_proto(context) != IPPROTO_TCP) { @@ -1167,7 +1237,12 @@ enum net_verdict net_context_packet_received(struct net_conn *conn, k_sem_give(&context->recv_data_wait); #endif /* CONFIG_NET_CONTEXT_SYNC_RECV */ - return NET_OK; + verdict = NET_OK; + +unlock: + k_mutex_unlock(&context->lock); + + return verdict; } #if defined(CONFIG_NET_UDP) @@ -1251,11 +1326,14 @@ int net_context_recv(struct net_context *context, return -EBADF; } + k_mutex_lock(&context->lock, K_FOREVER); + #if defined(CONFIG_NET_OFFLOAD) if (net_if_is_ip_offloaded(net_context_get_iface(context))) { - return net_offload_recv( + ret = net_offload_recv( net_context_get_iface(context), context, cb, timeout, user_data); + goto unlock; } #endif /* CONFIG_NET_OFFLOAD */ @@ -1276,7 +1354,7 @@ int net_context_recv(struct net_context *context, } if (ret < 0) { - return ret; + goto unlock; } #if defined(CONFIG_NET_CONTEXT_SYNC_RECV) @@ -1289,19 +1367,37 @@ int net_context_recv(struct net_context *context, */ k_sem_reset(&context->recv_data_wait); + k_mutex_unlock(&context->lock); + ret = k_sem_take(&context->recv_data_wait, timeout); + + k_mutex_lock(&context->lock, K_FOREVER); + if (ret == -EAGAIN) { - return -ETIMEDOUT; + ret = -ETIMEDOUT; + goto unlock; } } #endif /* CONFIG_NET_CONTEXT_SYNC_RECV */ - return 0; +unlock: + k_mutex_unlock(&context->lock); + + return ret; } int net_context_update_recv_wnd(struct net_context *context, - s32_t delta) { - return net_tcp_update_recv_wnd(context, delta); + s32_t delta) +{ + int ret; + + k_mutex_lock(&context->lock, K_FOREVER); + + ret = net_tcp_update_recv_wnd(context, delta); + + k_mutex_unlock(&context->lock); + + return ret; } static int set_context_priority(struct net_context *context, @@ -1348,12 +1444,16 @@ int net_context_set_option(struct net_context *context, return -EINVAL; } + k_mutex_lock(&context->lock, K_FOREVER); + switch (option) { case NET_OPT_PRIORITY: ret = set_context_priority(context, value, len); break; } + k_mutex_unlock(&context->lock); + return ret; } @@ -1369,12 +1469,16 @@ int net_context_get_option(struct net_context *context, return -EINVAL; } + k_mutex_lock(&context->lock, K_FOREVER); + switch (option) { case NET_OPT_PRIORITY: ret = get_context_priority(context, value, len); break; } + k_mutex_unlock(&context->lock); + return ret; } @@ -1389,7 +1493,11 @@ void net_context_foreach(net_context_cb_t cb, void *user_data) continue; } + k_mutex_lock(&contexts[i].lock, K_FOREVER); + cb(&contexts[i], user_data); + + k_mutex_unlock(&contexts[i].lock); } k_sem_give(&contexts_lock); diff --git a/subsys/net/ip/tcp.c b/subsys/net/ip/tcp.c index 3c1cc997afc..62ce461d574 100644 --- a/subsys/net/ip/tcp.c +++ b/subsys/net/ip/tcp.c @@ -1989,17 +1989,21 @@ NET_CONN_CB(tcp_established) u8_t tcp_flags; u16_t data_len; + k_mutex_lock(&context->lock, K_FOREVER); + NET_ASSERT(context && context->tcp); tcp_hdr = net_tcp_get_hdr(pkt, &hdr); if (!tcp_hdr) { - return NET_DROP; + ret = NET_DROP; + goto unlock; } if (net_tcp_get_state(context->tcp) < NET_TCP_ESTABLISHED) { NET_ERR("Context %p in wrong state %d", context, net_tcp_get_state(context->tcp)); - return NET_DROP; + ret = NET_DROP; + goto unlock; } net_tcp_print_recv_info("DATA", pkt, tcp_hdr->src_port); @@ -2017,7 +2021,8 @@ NET_CONN_CB(tcp_established) */ resend_ack: send_ack(context, &conn->remote_addr, true); - return NET_DROP; + ret = NET_DROP; + goto unlock; } if (net_tcp_seq_cmp(sys_get_be32(tcp_hdr->seq), @@ -2026,7 +2031,8 @@ resend_ack: * match the next segment exactly, drop and wait for * retransmit */ - return NET_DROP; + ret = NET_DROP; + goto unlock; } /* @@ -2037,7 +2043,8 @@ resend_ack: /* We only accept RST packet that has valid seq field. */ if (!net_tcp_validate_seq(context->tcp, pkt)) { net_stats_update_tcp_seg_rsterr(net_pkt_iface(pkt)); - return NET_DROP; + ret = NET_DROP; + goto unlock; } net_stats_update_tcp_seg_rst(net_pkt_iface(pkt)); @@ -2051,7 +2058,8 @@ resend_ack: net_context_unref(context); - return NET_DROP; + ret = NET_DROP; + goto unlock; } /* Handle TCP state transition */ @@ -2121,7 +2129,8 @@ resend_ack: NET_ERR("Context %p: overflow of recv window (%d vs %d), " "pkt dropped", context, net_tcp_get_recv_wnd(context->tcp), data_len); - return NET_DROP; + ret = NET_DROP; + goto unlock; } /* If the pkt has appdata, notify the recv callback which should @@ -2157,6 +2166,9 @@ clean_up: net_context_unref(context); } +unlock: + k_mutex_unlock(&context->lock); + return ret; }