From 33030721c4aaf23e93b06ee5a690281506338f85 Mon Sep 17 00:00:00 2001 From: Robert Chou Date: Fri, 8 Dec 2017 11:55:01 +0800 Subject: [PATCH] net: lwm2m: increase packet reference to avoid packet being freed CoAP packet w/ confirmation flag set is required to be retransmitted before it got the ACK message from the peer. However, the packet is usally unreference once it's sent to the network. Although we set the timeout as no wait when calling function net_app_send_pkt(), it's still possible that the packet is unreferenced before we got a chance to increase the packet reference by calling coap_pending_cycle(). Usually, the IP stack will generate an ARP packet first and then send out the packet. However, this is not the case when the remote is a loopback address. As issue #5101 described, when asking client to perform a firmware pull on URL "coap://127.0.0.1:7783/large". The packet will be unreferenced immediately after calling net_app_send_pkt(). Which then result in client hang. The solution to the issue is to increase the reference count on the sending packet and decrease it after the process is finished. Signed-off-by: Robert Chou --- subsys/net/lib/lwm2m/lwm2m_engine.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index f318a0acbc5..b4e860b9dd4 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -886,34 +886,42 @@ cleanup: int lwm2m_send_message(struct lwm2m_message *msg) { int ret; + struct net_pkt *pkt; if (!msg || !msg->ctx) { SYS_LOG_ERR("LwM2M message is invalid."); return -EINVAL; } + /* protect the packet from being released inbetween net_app_send_pkt() + * to coap_pending_cycle() + */ + pkt = msg->cpkt.pkt; + net_pkt_ref(pkt); + msg->send_attempts++; ret = net_app_send_pkt(&msg->ctx->net_app_ctx, msg->cpkt.pkt, &msg->ctx->net_app_ctx.default_ctx->remote, NET_SOCKADDR_MAX_SIZE, K_NO_WAIT, NULL); if (ret < 0) { - return ret; + goto out; } if (msg->type == COAP_TYPE_CON) { if (msg->send_attempts > 1) { - return 0; + goto out; } coap_pending_cycle(msg->pending); k_delayed_work_submit(&msg->ctx->retransmit_work, msg->pending->timeout); } else { - /* if we're not expecting an ACK, free up the msg data */ lwm2m_reset_message(msg, true); } - return 0; +out: + net_pkt_unref(pkt); + return ret; } u16_t lwm2m_get_rd_data(u8_t *client_data, u16_t size)