From 6f0458dd75c6468f54c77fcd51831f396d056b6a Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 14 Feb 2018 18:43:34 +0200 Subject: [PATCH] net: Set net_buf alloc timeout for IPv4 ARP and IPv6 ND Instead of having K_FOREVER when allocating a packet in IPv4 ARP and IPv6 ND, set a timeout so that we do not have a case where we would wait net_buf forever. Fixes #5484 Signed-off-by: Jukka Rissanen --- subsys/net/ip/ipv6.c | 84 ++++++++++++++++++++++++++++-------------- subsys/net/ip/l2/arp.c | 21 ++++++++--- 2 files changed, 72 insertions(+), 33 deletions(-) diff --git a/subsys/net/ip/ipv6.c b/subsys/net/ip/ipv6.c index bfc47a4336c53..0e39a6e36b496 100644 --- a/subsys/net/ip/ipv6.c +++ b/subsys/net/ip/ipv6.c @@ -36,6 +36,11 @@ #include "rpl.h" #include "net_stats.h" +/* Timeout value to be used when allocating net buffer during various + * neighbor discovery procedures. + */ +#define ND_NET_BUF_TIMEOUT MSEC(100) + /* IPv6 wildcard and loopback address defined by RFC2553 */ const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; @@ -461,6 +466,7 @@ struct net_nbr *net_ipv6_nbr_add(struct net_if *iface, enum net_ipv6_nbr_state state) { struct net_nbr *nbr; + int ret; #if defined(CONFIG_NET_MGMT_EVENT_INFO) struct net_event_ipv6_nbr info; #endif @@ -500,7 +506,10 @@ struct net_nbr *net_ipv6_nbr_add(struct net_if *iface, /* Send NS so that we can verify that the neighbor is * reachable. */ - net_ipv6_send_ns(iface, NULL, NULL, NULL, addr, false); + ret = net_ipv6_send_ns(iface, NULL, NULL, NULL, addr, false); + if (ret < 0) { + NET_DBG("Cannot send NS (%d)", ret); + } } NET_DBG("[%d] nbr %p state %d router %d IPv6 %s ll %s iface %p", @@ -961,6 +970,7 @@ struct net_pkt *net_ipv6_prepare_for_send(struct net_pkt *pkt) struct in6_addr *nexthop = NULL; struct net_if *iface = NULL; struct net_nbr *nbr; + int ret; NET_ASSERT(pkt && pkt->frags); @@ -972,8 +982,6 @@ struct net_pkt *net_ipv6_prepare_for_send(struct net_pkt *pkt) size_t pkt_len = net_pkt_get_len(pkt); if (pkt_len > NET_IPV6_MTU) { - int ret; - ret = net_ipv6_send_fragmented_pkt(net_pkt_iface(pkt), pkt, pkt_len); if (ret < 0) { @@ -1125,20 +1133,21 @@ struct net_pkt *net_ipv6_prepare_for_send(struct net_pkt *pkt) #if defined(CONFIG_NET_IPV6_ND) /* We need to send NS and wait for NA before sending the packet. */ - if (net_ipv6_send_ns(net_pkt_iface(pkt), - pkt, - &NET_IPV6_HDR(pkt)->src, - NULL, - nexthop, - false) < 0) { + ret = net_ipv6_send_ns(net_pkt_iface(pkt), pkt, + &NET_IPV6_HDR(pkt)->src, NULL, + nexthop, false); + if (ret < 0) { /* In case of an error, the NS send function will unref * the pkt. */ + NET_DBG("Cannot send NS (%d)", ret); return NULL; } NET_DBG("pkt %p (frag %p) will be sent later", pkt, pkt->frags); #else + ARG_UNUSED(ret); + NET_DBG("pkt %p (frag %p) cannot be sent, dropping it.", pkt, pkt->frags); @@ -1270,13 +1279,16 @@ int net_ipv6_send_na(struct net_if *iface, const struct in6_addr *src, u8_t llao_len; pkt = net_pkt_get_reserve_tx(net_if_get_ll_reserve(iface, dst), - K_FOREVER); - - NET_ASSERT_INFO(pkt, "Out of TX packets"); - - frag = net_pkt_get_frag(pkt, K_FOREVER); + ND_NET_BUF_TIMEOUT); + if (!pkt) { + return -ENOMEM; + } - NET_ASSERT_INFO(frag, "Out of DATA buffers"); + frag = net_pkt_get_frag(pkt, ND_NET_BUF_TIMEOUT); + if (!frag) { + net_pkt_unref(pkt); + return -ENOMEM; + } net_pkt_frag_add(pkt, frag); @@ -1587,6 +1599,7 @@ static enum net_verdict handle_ns_input(struct net_pkt *pkt) tgt, flags); if (!ret) { + NET_DBG("Cannot send NA (%d)", ret); net_pkt_unref(pkt); return NET_OK; } @@ -1608,6 +1621,7 @@ static void nd_reachable_timeout(struct k_work *work) reachable); struct net_nbr *nbr = get_nbr_from_data(data); + int ret; if (!data || !nbr) { NET_DBG("ND reachable timeout but no nbr data " @@ -1638,8 +1652,11 @@ static void nd_reachable_timeout(struct k_work *work) NET_DBG("nbr %p incomplete count %u", nbr, data->ns_count); - net_ipv6_send_ns(nbr->iface, NULL, NULL, NULL, - &data->addr, false); + ret = net_ipv6_send_ns(nbr->iface, NULL, NULL, NULL, + &data->addr, false); + if (ret < 0) { + NET_DBG("Cannot send NS (%d)", ret); + } } break; @@ -1685,8 +1702,11 @@ static void nd_reachable_timeout(struct k_work *work) NET_DBG("nbr %p probe count %u", nbr, data->ns_count); - net_ipv6_send_ns(nbr->iface, NULL, NULL, NULL, - &data->addr, false); + ret = net_ipv6_send_ns(nbr->iface, NULL, NULL, NULL, + &data->addr, false); + if (ret < 0) { + NET_DBG("Cannot send NS (%d)", ret); + } k_delayed_work_submit( &net_ipv6_nbr_data(nbr)->reachable, @@ -2008,13 +2028,16 @@ int net_ipv6_send_ns(struct net_if *iface, u8_t llao_len; pkt = net_pkt_get_reserve_tx(net_if_get_ll_reserve(iface, dst), - K_FOREVER); - - NET_ASSERT_INFO(pkt, "Out of TX packets"); - - frag = net_pkt_get_frag(pkt, K_FOREVER); + ND_NET_BUF_TIMEOUT); + if (!pkt) { + return -ENOMEM; + } - NET_ASSERT_INFO(frag, "Out of DATA buffers"); + frag = net_pkt_get_frag(pkt, ND_NET_BUF_TIMEOUT); + if (!frag) { + net_pkt_unref(pkt); + return -ENOMEM; + } net_pkt_frag_add(pkt, frag); @@ -2143,9 +2166,16 @@ int net_ipv6_send_rs(struct net_if *iface) u8_t llao_len = 0; pkt = net_pkt_get_reserve_tx(net_if_get_ll_reserve(iface, NULL), - K_FOREVER); + ND_NET_BUF_TIMEOUT); + if (!pkt) { + return -ENOMEM; + } - frag = net_pkt_get_frag(pkt, K_FOREVER); + frag = net_pkt_get_frag(pkt, ND_NET_BUF_TIMEOUT); + if (!frag) { + net_pkt_unref(pkt); + return -ENOMEM; + } net_pkt_frag_add(pkt, frag); diff --git a/subsys/net/ip/l2/arp.c b/subsys/net/ip/l2/arp.c index e40e1faf1a1fa..b7cf018534baa 100644 --- a/subsys/net/ip/l2/arp.c +++ b/subsys/net/ip/l2/arp.c @@ -21,6 +21,8 @@ #include #include "net_private.h" +#define NET_BUF_TIMEOUT MSEC(100) + static struct arp_entry arp_table[CONFIG_NET_ARP_TABLE_SIZE]; static inline struct arp_entry *find_entry(struct net_if *iface, @@ -100,12 +102,13 @@ static inline struct net_pkt *prepare_arp(struct net_if *iface, struct net_eth_hdr *eth; struct in_addr *my_addr; - pkt = net_pkt_get_reserve_tx(sizeof(struct net_eth_hdr), K_FOREVER); + pkt = net_pkt_get_reserve_tx(sizeof(struct net_eth_hdr), + NET_BUF_TIMEOUT); if (!pkt) { return NULL; } - frag = net_pkt_get_frag(pkt, K_FOREVER); + frag = net_pkt_get_frag(pkt, NET_BUF_TIMEOUT); if (!frag) { net_pkt_unref(pkt); return NULL; @@ -187,9 +190,12 @@ struct net_pkt *net_arp_prepare(struct net_pkt *pkt) /* Add the ethernet header if it is missing. */ struct net_buf *header; - net_pkt_set_ll_reserve(pkt, sizeof(struct net_eth_hdr)); + header = net_pkt_get_frag(pkt, NET_BUF_TIMEOUT); + if (!header) { + return NULL; + } - header = net_pkt_get_frag(pkt, K_FOREVER); + net_pkt_set_ll_reserve(pkt, sizeof(struct net_eth_hdr)); hdr = (struct net_eth_hdr *)(header->data - net_pkt_ll_reserve(pkt)); @@ -358,12 +364,13 @@ static inline struct net_pkt *prepare_arp_reply(struct net_if *iface, struct net_arp_hdr *hdr, *query; struct net_eth_hdr *eth, *eth_query; - pkt = net_pkt_get_reserve_tx(sizeof(struct net_eth_hdr), K_FOREVER); + pkt = net_pkt_get_reserve_tx(sizeof(struct net_eth_hdr), + NET_BUF_TIMEOUT); if (!pkt) { goto fail; } - frag = net_pkt_get_frag(pkt, K_FOREVER); + frag = net_pkt_get_frag(pkt, NET_BUF_TIMEOUT); if (!frag) { goto fail; } @@ -455,6 +462,8 @@ enum net_verdict net_arp_input(struct net_pkt *pkt) reply = prepare_arp_reply(net_pkt_iface(pkt), pkt); if (reply) { net_if_queue_tx(net_pkt_iface(reply), reply); + } else { + NET_DBG("Cannot send ARP reply"); } break;