net: context: Add locking for concurrent access
If the net_context functions are accessed from preemptive priority, then we need to protect various internal resources. Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
This commit is contained in:
parent
a985e03349
commit
93e5181fbd
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user