Merge "Merge net branch into master"
diff --git a/.known-issues/doc/networking.conf b/.known-issues/doc/networking.conf
index b198341..2ed5799 100644
--- a/.known-issues/doc/networking.conf
+++ b/.known-issues/doc/networking.conf
@@ -47,3 +47,15 @@
 ^(?P=filename):(?P=lineno): WARNING: Invalid definition: Expected end of definition. \[error at [0-9]+]
 ^.*dns_context.address
 ^[- \t]*\^
+#
+# include/net/net_mgmt.h
+#
+^(?P<filename>[-._/\w]+/doc/api/networking.rst):(?P<lineno>[0-9]+): WARNING: Invalid definition: Expected identifier in nested name. \[error at [0-9]+]
+^[ \t]*
+^[ \t]*\^
+^(?P=filename):(?P=lineno): WARNING: Invalid definition: Expected identifier in nested name. \[error at [0-9]+]
+^[ \t]*
+^[ \t]*\^
+^(?P=filename):(?P=lineno): WARNING: Invalid definition: Expected end of definition. \[error at [0-9]+]
+^.*net_mgmt_event_callback.__unnamed__
+^[- \t]*\^
diff --git a/drivers/ethernet/Kconfig.sam_gmac b/drivers/ethernet/Kconfig.sam_gmac
index 8b99a81..fcb8f5e 100644
--- a/drivers/ethernet/Kconfig.sam_gmac
+++ b/drivers/ethernet/Kconfig.sam_gmac
@@ -20,20 +20,20 @@
 	  Device name allows user to obtain a handle to the device object
 	  required by all driver API functions. Device name has to be unique.
 
-config ETH_SAM_GMAC_NBUF_DATA_COUNT
-	int "Network data buffers pre-allocated by the SAM ETH driver"
-	default 12
+config ETH_SAM_GMAC_NBUF_RX_DATA_COUNT
+	int "Network RX data buffers pre-allocated by the SAM ETH driver"
+	default 18
 	help
 	  Number of network data buffers that will be permanently allocated by the
 	  Ethernet driver. These data buffers are used in receive path. They are
 	  pre-alocated by the driver and made available to the GMAC module to be
 	  filled in with incoming data. Their number has to be large enough to fit
 	  at least one complete Ethernet frame. SAM ETH driver will always allocate
-	  that amount of buffers for itself thus reducing the NET_NBUF_DATA_COUNT
-	  which is a total amount of data buffers used by the whole networking
-	  stack. One has to ensure that NET_NBUF_DATA_COUNT is large enough to fit
-	  at least two ethernet frames: one being received by the GMAC module and
-	  the other being processed by the higer layer networking stack.
+	  that amount of buffers for itself thus reducing the NET_NBUF_RX_DATA_COUNT
+	  which is a total amount of RX data buffers used by the whole networking
+	  stack. One has to ensure that NET_NBUF_RX_DATA_COUNT is large enough to
+	  fit at least two ethernet frames: one being received by the GMAC module
+	  and the other being processed by the higer layer networking stack.
 
 config ETH_SAM_GMAC_IRQ_PRI
 	int "Interrupt priority"
diff --git a/drivers/ethernet/eth_sam_gmac.c b/drivers/ethernet/eth_sam_gmac.c
index b6ab561..c1146fd 100644
--- a/drivers/ethernet/eth_sam_gmac.c
+++ b/drivers/ethernet/eth_sam_gmac.c
@@ -38,21 +38,24 @@
  * Verify Kconfig configuration
  */
 
-#if CONFIG_NET_NBUF_RX_DATA_COUNT <= CONFIG_ETH_SAM_GMAC_NBUF_DATA_COUNT
-#error CONFIG_NET_NBUF_RX_DATA_COUNT has to be larger than \
-	CONFIG_ETH_SAM_GMAC_NBUF_DATA_COUNT
-#endif
-
-#if CONFIG_NET_NBUF_DATA_SIZE * CONFIG_ETH_SAM_GMAC_NBUF_DATA_COUNT \
+#if CONFIG_NET_NBUF_DATA_SIZE * CONFIG_ETH_SAM_GMAC_NBUF_RX_DATA_COUNT \
 	< GMAC_FRAME_SIZE_MAX
-#error CONFIG_NET_NBUF_DATA_SIZE * CONFIG_ETH_SAM_GMAC_NBUF_DATA_COUNT is not \
-	large enough to hold a full frame
+#error CONFIG_NET_NBUF_DATA_SIZE * CONFIG_ETH_SAM_GMAC_NBUF_RX_DATA_COUNT is \
+	not large enough to hold a full frame
 #endif
 
-#if CONFIG_NET_NBUF_DATA_SIZE * CONFIG_NET_NBUF_RX_DATA_COUNT \
-	< 2 * GMAC_FRAME_SIZE_MAX
-#error CONFIG_NET_NBUF_DATA_SIZE * CONFIG_NET_NBUF_RX_DATA_COUNT is not large\
-	enough to hold two full frames
+#if CONFIG_NET_NBUF_DATA_SIZE * (CONFIG_NET_NBUF_RX_DATA_COUNT - \
+	CONFIG_ETH_SAM_GMAC_NBUF_RX_DATA_COUNT) < GMAC_FRAME_SIZE_MAX
+#error Remaining free RX data buffers (CONFIG_NET_NBUF_RX_DATA_COUNT -
+	CONFIG_ETH_SAM_GMAC_NBUF_RX_DATA_COUNT) * CONFIG_NET_NBUF_DATA_SIZE
+	are not large enough to hold a full frame
+#endif
+
+#if CONFIG_NET_NBUF_DATA_SIZE * CONFIG_NET_NBUF_TX_DATA_COUNT \
+	< GMAC_FRAME_SIZE_MAX
+#pragma message "Maximum frame size GMAC driver is able to transmit " \
+	"CONFIG_NET_NBUF_DATA_SIZE * CONFIG_NET_NBUF_TX_DATA_COUNT is smaller" \
+	"than a full Ethernet frame"
 #endif
 
 #if CONFIG_NET_NBUF_DATA_SIZE & 0x3F
@@ -225,6 +228,7 @@
 
 		tx_desc = &tx_desc_list->buf[tx_desc_list->tail];
 		MODULO_INC(tx_desc_list->tail, tx_desc_list->len);
+		k_sem_give(&queue->tx_desc_sem);
 
 		if (tx_desc->w1 & GMAC_TXW1_LASTBUFFER) {
 			/* Release net buffer to the buffer pool */
@@ -242,19 +246,36 @@
  */
 static void tx_error_handler(Gmac *gmac, struct gmac_queue *queue)
 {
+	struct net_buf *buf;
+	struct ring_buf *tx_frames = &queue->tx_frames;
+
 	queue->err_tx_flushed_count++;
 
 	/* Stop transmission, clean transmit pipeline and control registers */
 	gmac->GMAC_NCR &= ~GMAC_NCR_TXEN;
 
+	/* Free all nbuf resources in the TX path */
+	while (tx_frames->tail != tx_frames->head) {
+		/* Release net buffer to the buffer pool */
+		buf = UINT_TO_POINTER(tx_frames->buf[tx_frames->tail]);
+		net_buf_unref(buf);
+		SYS_LOG_DBG("Dropping buf %p", buf);
+		MODULO_INC(tx_frames->tail, tx_frames->len);
+	}
+
+	/* Reinitialize TX descriptor list */
+	k_sem_reset(&queue->tx_desc_sem);
 	tx_descriptors_init(gmac, queue);
+	for (int i = 0; i < queue->tx_desc_list.len - 1; i++) {
+		k_sem_give(&queue->tx_desc_sem);
+	}
 
 	/* Restart transmission */
 	gmac->GMAC_NCR |=  GMAC_NCR_TXEN;
 }
 
 /*
- * Clean RX queue, any received data stored still in the buffers is abandoned.
+ * Clean RX queue, any received data still stored in the buffers is abandoned.
  */
 static void rx_error_handler(Gmac *gmac, struct gmac_queue *queue)
 {
@@ -379,6 +400,13 @@
 
 	tx_descriptors_init(gmac, queue);
 
+	/* Initialize TX descriptors semaphore. The semaphore is required as the
+	 * size of the TX descriptor list is limited while the number of TX data
+	 * buffers is not.
+	 */
+	k_sem_init(&queue->tx_desc_sem, queue->tx_desc_list.len - 1,
+		   queue->tx_desc_list.len - 1);
+
 	/* Set Receive Buffer Queue Pointer Register */
 	gmac->GMAC_RBQB = (uint32_t)queue->rx_desc_list.buf;
 	/* Set Transmit Buffer Queue Pointer Register */
@@ -509,7 +537,7 @@
 			DCACHE_INVALIDATE(frag_data, frag_len);
 
 			/* Get a new data net buffer from the buffer pool */
-			new_frag = net_nbuf_get_frag(buf, K_NO_WAIT);
+			new_frag = net_nbuf_get_frag(rx_frame, K_NO_WAIT);
 			if (new_frag == NULL) {
 				queue->err_rx_frames_dropped++;
 				net_buf_unref(rx_frame);
@@ -576,6 +604,8 @@
 	struct net_buf *frag;
 	uint8_t *frag_data;
 	uint16_t frag_len;
+	uint32_t err_tx_flushed_count_at_entry = queue->err_tx_flushed_count;
+	unsigned int key;
 
 	__ASSERT(buf, "buf pointer is NULL");
 	__ASSERT(buf->frags, "Frame data missing");
@@ -605,6 +635,20 @@
 		/* Assure cache coherency before DMA read operation */
 		DCACHE_CLEAN(frag_data, frag_len);
 
+		k_sem_take(&queue->tx_desc_sem, K_FOREVER);
+
+		/* The following section becomes critical and requires IRQ lock
+		 * / unlock protection only due to the possibility of executing
+		 * tx_error_handler() function.
+		 */
+		key = irq_lock();
+
+		/* Check if tx_error_handler() function was executed */
+		if (queue->err_tx_flushed_count != err_tx_flushed_count_at_entry) {
+			irq_unlock(key);
+			return -EIO;
+		}
+
 		tx_desc = &tx_desc_list->buf[tx_desc_list->head];
 
 		/* Update buffer descriptor address word */
@@ -626,12 +670,22 @@
 		__ASSERT(tx_desc_list->head != tx_desc_list->tail,
 			 "tx_desc_list overflow");
 
+		irq_unlock(key);
+
 		/* Continue with the rest of fragments (only data) */
 		frag = frag->frags;
 		frag_data = frag->data;
 		frag_len = frag->len;
 	}
 
+	key = irq_lock();
+
+	/* Check if tx_error_handler() function was executed */
+	if (queue->err_tx_flushed_count != err_tx_flushed_count_at_entry) {
+		irq_unlock(key);
+		return -EIO;
+	}
+
 	/* Ensure the descriptor following the last one is marked as used */
 	tx_desc = &tx_desc_list->buf[tx_desc_list->head];
 	tx_desc->w1 |= GMAC_TXW1_USED;
@@ -639,6 +693,8 @@
 	/* Account for a sent frame */
 	ring_buf_put(&queue->tx_frames, POINTER_TO_UINT(buf));
 
+	irq_unlock(key);
+
 	/* Start transmission */
 	gmac->GMAC_NCR |= GMAC_NCR_TSTART;
 
diff --git a/drivers/ethernet/eth_sam_gmac_priv.h b/drivers/ethernet/eth_sam_gmac_priv.h
index 9664053..78ef9fe 100644
--- a/drivers/ethernet/eth_sam_gmac_priv.h
+++ b/drivers/ethernet/eth_sam_gmac_priv.h
@@ -20,10 +20,9 @@
 /** Total number of queues supported by GMAC hardware module */
 #define GMAC_QUEUE_NO                     3
 /** RX descriptors count for main queue */
-#define MAIN_QUEUE_RX_DESC_COUNT CONFIG_ETH_SAM_GMAC_NBUF_DATA_COUNT
+#define MAIN_QUEUE_RX_DESC_COUNT CONFIG_ETH_SAM_GMAC_NBUF_RX_DATA_COUNT
 /** TX descriptors count for main queue */
-#define MAIN_QUEUE_TX_DESC_COUNT (CONFIG_NET_NBUF_RX_DATA_COUNT - \
-		CONFIG_ETH_SAM_GMAC_NBUF_DATA_COUNT + 1)
+#define MAIN_QUEUE_TX_DESC_COUNT (CONFIG_NET_NBUF_TX_DATA_COUNT + 1)
 /** RX/TX descriptors count for priority queues */
 #define PRIORITY_QUEUE_DESC_COUNT         1
 
@@ -151,6 +150,7 @@
 struct gmac_queue {
 	struct gmac_desc_list rx_desc_list;
 	struct gmac_desc_list tx_desc_list;
+	struct k_sem tx_desc_sem;
 
 	struct ring_buf rx_nbuf_list;
 	struct ring_buf tx_frames;
diff --git a/drivers/ieee802154/Kconfig.cc2520 b/drivers/ieee802154/Kconfig.cc2520
index 472e7c9..0d538e9 100644
--- a/drivers/ieee802154/Kconfig.cc2520
+++ b/drivers/ieee802154/Kconfig.cc2520
@@ -64,4 +64,41 @@
 	be ready first (and sometime gpio should be the very first as spi
 	might need it too). And of course it has to start before the net stack.
 
+config IEEE802154_CC2520_RANDOM_MAC
+	bool "Random MAC address"
+	default y
+	help
+	  Generate a random MAC address dynamically.
+
+if ! IEEE802154_CC2520_RANDOM_MAC
+
+config IEEE802154_CC2520_MAC4
+	hex "MAC Address Byte 4"
+	default 0
+	range 0 ff
+	help
+	  This is the byte 4 of the MAC address.
+
+config IEEE802154_CC2520_MAC5
+	hex "MAC Address Byte 5"
+	default 0
+	range 0 ff
+	help
+	  This is the byte 5 of the MAC address.
+
+config IEEE802154_CC2520_MAC6
+	hex "MAC Address Byte 6"
+	default 0
+	range 0 ff
+	help
+	  This is the byte 6 of the MAC address.
+
+config IEEE802154_CC2520_MAC7
+	hex "MAC Address Byte 7"
+	default 0
+	range 0 ff
+	help
+	  This is the byte 7 of the MAC address.
+endif
+
 endif
diff --git a/drivers/ieee802154/ieee802154_cc2520.c b/drivers/ieee802154/ieee802154_cc2520.c
index 8b19d04..6193bd7 100644
--- a/drivers/ieee802154/ieee802154_cc2520.c
+++ b/drivers/ieee802154/ieee802154_cc2520.c
@@ -274,15 +274,24 @@
 static inline uint8_t *get_mac(struct device *dev)
 {
 	struct cc2520_context *cc2520 = dev->driver_data;
+
+#if defined(CONFIG_IEEE802154_CC2520_RANDOM_MAC)
 	uint32_t *ptr = (uint32_t *)(cc2520->mac_addr + 4);
 
+	UNALIGNED_PUT(sys_rand32_get(), ptr);
+
+	cc2520->mac_addr[7] = (cc2520->mac_addr[7] & ~0x01) | 0x02;
+#else
+	cc2520->mac_addr[4] = CONFIG_IEEE802154_CC2520_MAC4;
+	cc2520->mac_addr[5] = CONFIG_IEEE802154_CC2520_MAC5;
+	cc2520->mac_addr[6] = CONFIG_IEEE802154_CC2520_MAC6;
+	cc2520->mac_addr[7] = CONFIG_IEEE802154_CC2520_MAC7;
+#endif
+
 	cc2520->mac_addr[0] = 0x00;
 	cc2520->mac_addr[1] = 0x12;
 	cc2520->mac_addr[2] = 0x4b;
 	cc2520->mac_addr[3] = 0x00;
-	UNALIGNED_PUT(sys_rand32_get(), ptr);
-
-	cc2520->mac_addr[7] = (cc2520->mac_addr[7] & ~0x01) | 0x02;
 
 	return cc2520->mac_addr;
 }
diff --git a/drivers/slip/Kconfig b/drivers/slip/Kconfig
index 1170efd..d3cfd4a 100644
--- a/drivers/slip/Kconfig
+++ b/drivers/slip/Kconfig
@@ -77,4 +77,15 @@
 	  By default TUN is used. In TAP the Ethernet frames
 	  are transferred over SLIP.
 
+
+config	SLIP_MAC_ADDR
+	string "MAC address for the interface"
+	default ""
+	help
+	  Specify a MAC address for the SLIP interface in the form of
+	  six hex 8-bit chars separaed by colons (eg:
+	  aa:33:cc:22:e2:c0).  The default is an empty string, which
+	  means the code will make 00:00:5E:00:53:XX, where XX will be
+	  random.
+
 endif
diff --git a/drivers/slip/slip.c b/drivers/slip/slip.c
index c4e70ee..b932182 100644
--- a/drivers/slip/slip.c
+++ b/drivers/slip/slip.c
@@ -48,6 +48,7 @@
 	struct net_buf *rx;	/* and then placed into this net_buf */
 	struct net_buf *last;	/* Pointer to last fragment in the list */
 	uint8_t *ptr;		/* Where in net_buf to add data */
+	struct net_if *iface;
 	uint8_t state;
 
 	uint8_t mac_addr[6];
@@ -237,7 +238,7 @@
 		return;
 	}
 
-	if (net_recv_data(net_if_get_by_link_addr(&slip->ll_addr), buf) < 0) {
+	if (net_recv_data(slip->iface, buf) < 0) {
 		net_nbuf_unref(buf);
 	}
 
@@ -312,6 +313,14 @@
 		break;
 	}
 
+	/* It is possible that slip->last is not set during the startup
+	 * of the device. If this happens do not continue and overwrite
+	 * some random memory.
+	 */
+	if (!slip->last) {
+		return 0;
+	}
+
 	if (!net_buf_tailroom(slip->last)) {
 		/* We need to allocate a new fragment */
 		struct net_buf *frag;
@@ -387,6 +396,33 @@
 	return buf;
 }
 
+static inline int _slip_mac_addr_from_str(struct slip_context *slip,
+					  const char *src)
+{
+	unsigned int len, i;
+	char *endptr;
+
+	len = strlen(src);
+	for (i = 0; i < len; i++) {
+		if (!(src[i] >= '0' && src[i] <= '9') &&
+		    !(src[i] >= 'A' && src[i] <= 'F') &&
+		    !(src[i] >= 'a' && src[i] <= 'f') &&
+		    src[i] != ':') {
+			return -EINVAL;
+		}
+	}
+
+	memset(slip->mac_addr, 0, sizeof(slip->mac_addr));
+
+	for (i = 0; i < sizeof(slip->mac_addr); i++) {
+		slip->mac_addr[i] = strtol(src, &endptr, 16);
+		src = ++endptr;
+	}
+
+	return 0;
+}
+
+
 static int slip_init(struct device *dev)
 {
 	struct slip_context *slip = dev->driver_data;
@@ -408,17 +444,6 @@
 
 static inline struct net_linkaddr *slip_get_mac(struct slip_context *slip)
 {
-	if (slip->mac_addr[0] == 0x00) {
-		/* 10-00-00-00-00 to 10-00-00-00-FF Documentation RFC7042 */
-		slip->mac_addr[0] = 0x10;
-		slip->mac_addr[1] = 0x00;
-		slip->mac_addr[2] = 0x00;
-
-		slip->mac_addr[3] = 0x00;
-		slip->mac_addr[4] = 0x00;
-		slip->mac_addr[5] = sys_rand32_get();
-	}
-
 	slip->ll_addr.addr = slip->mac_addr;
 	slip->ll_addr.len = sizeof(slip->mac_addr);
 
@@ -431,7 +456,22 @@
 	struct net_linkaddr *ll_addr = slip_get_mac(slip);
 
 	slip->init_done = true;
+	slip->iface = iface;
 
+	if (CONFIG_SLIP_MAC_ADDR[0] != 0) {
+		if (_slip_mac_addr_from_str(slip, CONFIG_SLIP_MAC_ADDR) < 0) {
+			goto use_random_mac;
+		}
+	} else {
+use_random_mac:
+		/* 00-00-5E-00-53-xx Documentation RFC 7042 */
+		slip->mac_addr[0] = 0x00;
+		slip->mac_addr[1] = 0x00;
+		slip->mac_addr[2] = 0x5E;
+		slip->mac_addr[3] = 0x00;
+		slip->mac_addr[4] = 0x53;
+		slip->mac_addr[5] = sys_rand32_get();
+	}
 	net_if_set_link_addr(iface, ll_addr->addr, ll_addr->len,
 			     NET_LINK_ETHERNET);
 }
diff --git a/include/net/net_mgmt.h b/include/net/net_mgmt.h
index 78788ec..ebfbed7 100644
--- a/include/net/net_mgmt.h
+++ b/include/net/net_mgmt.h
@@ -29,11 +29,13 @@
 #define NET_MGMT_EVENT_MASK		0x80000000
 #define NET_MGMT_ON_IFACE_MASK		0x40000000
 #define NET_MGMT_LAYER_MASK		0x30000000
-#define NET_MGMT_LAYER_CODE_MASK	0x0FFF0000
+#define NET_MGMT_SYNC_EVENT_MASK	0x08000000
+#define NET_MGMT_LAYER_CODE_MASK	0x07FF0000
 #define NET_MGMT_COMMAND_MASK		0x0000FFFF
 
 #define NET_MGMT_EVENT_BIT		BIT(31)
 #define NET_MGMT_IFACE_BIT		BIT(30)
+#define NET_MGMT_SYNC_EVENT_BIT		BIT(27)
 
 #define NET_MGMT_LAYER(_layer)		(_layer << 28)
 #define NET_MGMT_LAYER_CODE(_code)	(_code << 16)
@@ -44,6 +46,9 @@
 #define NET_MGMT_ON_IFACE(mgmt_request)		\
 	(mgmt_request & NET_MGMT_ON_IFACE_MASK)
 
+#define NET_MGMT_EVENT_SYNCHRONOUS(mgmt_request)	\
+	(mgmt_request & NET_MGMT_SYNC_EVENT_MASK)
+
 #define NET_MGMT_GET_LAYER(mgmt_request)	\
 	((mgmt_request & NET_MGMT_LAYER_MASK) >> 28)
 
@@ -115,16 +120,33 @@
 	 */
 	sys_snode_t node;
 
-	/** Actual callback function being used to notify the owner
-	 */
-	net_mgmt_event_handler_t handler;
+	union {
+		/** Actual callback function being used to notify the owner
+		 */
+		net_mgmt_event_handler_t handler;
+		/** Semaphore meant to be used internaly for the synchronous
+		 * net_mgmt_event_wait() function.
+		 */
+		struct k_sem *sync_call;
+	};
 
 	/** A mask of network events on which the above handler should be
 	 * called in case those events come. Such mask can be modified
 	 * whenever necessary by the owner, and thus will affect the handler
 	 * being called or not.
 	 */
-	uint32_t event_mask;
+	union {
+		/** A mask of network events on which the above handler should
+		 * be called in case those events come. Such mask can be
+		 * modified whenever necessary by the owner, and thus will
+		 * affect the handler being called or not.
+		 */
+		uint32_t event_mask;
+		/** Internal place holder when a synchronous event wait is
+		 * successfully unlocked on a event.
+		 */
+		uint32_t raised_event;
+	};
 };
 
 #ifdef CONFIG_NET_MGMT_EVENT
@@ -167,6 +189,49 @@
 void net_mgmt_event_notify(uint32_t mgmt_event, struct net_if *iface);
 
 /**
+ * @brief Used to wait synchronously on an event mask
+ * @param mgmt_event_mask A mask of relevant events to wait on.
+ * @param raised_event a pointer on a uint32_t to get which event from
+ *        the mask generated the event. Can be NULL if the caller is not
+ *        interested in that information.
+ * @param iface a pointer on a place holder for the iface on which the
+ *        event has originated from. This is valid if only the event mask
+ *        has bit NET_MGMT_IFACE_BIT set relevantly, depending on events
+ *        the caller wants to listen to.
+ * @param timeout a delay in milliseconds. K_FOREVER can be used to wait
+ *        undefinitely.
+ *
+ * @return 0 on success, a negative error code otherwise. -ETIMEDOUT will
+ *         be specifically returned if the timeout kick-in instead of an
+ *         actual event.
+ */
+int net_mgmt_event_wait(uint32_t mgmt_event_mask,
+			uint32_t *raised_event,
+			struct net_if **iface,
+			int timeout);
+
+/**
+ * @brief Used to wait synchronously on an event mask for a specific iface
+ * @param iface a pointer on a valid network interface to listen event to
+ * @param mgmt_event_mask A mask of relevant events to wait on. Listened
+ *        to events should be relevant to iface events and thus have the bit
+ *        NET_MGMT_IFACE_BIT set.
+ * @param raised_event a pointer on a uint32_t to get which event from
+ *        the mask generated the event. Can be NULL if the caller is not
+ *        interested in that information.
+ * @param timeout a delay in milliseconds. K_FOREVER can be used to wait
+ *        undefinitely.
+ *
+ * @return 0 on success, a negative error code otherwise. -ETIMEDOUT will
+ *         be specifically returned if the timeout kick-in instead of an
+ *         actual event.
+ */
+int net_mgmt_event_wait_on_iface(struct net_if *iface,
+				 uint32_t mgmt_event_mask,
+				 uint32_t *raised_event,
+				 int timeout);
+
+/**
  * @brief Used by the core of the network stack to initialize the network
  *        event processing.
  */
@@ -176,6 +241,23 @@
 #define net_mgmt_add_event_callback(...)
 #define net_mgmt_event_notify(...)
 #define net_mgmt_event_init(...)
+
+static inline int net_mgmt_event_wait(uint32_t mgmt_event_mask,
+				      uint32_t *raised_event,
+				      struct net_if **iface,
+				      int timeout)
+{
+	return 0;
+}
+
+static inline int net_mgmt_event_wait_on_iface(struct net_if *iface,
+					       uint32_t mgmt_event_mask,
+					       uint32_t *raised_event,
+					       int timeout)
+{
+	return 0;
+}
+
 #endif /* CONFIG_NET_MGMT_EVENT */
 
 /**
diff --git a/samples/net/coaps_client/src/coaps_client.c b/samples/net/coaps_client/src/coaps_client.c
index 84f875f..893f8c4 100644
--- a/samples/net/coaps_client/src/coaps_client.c
+++ b/samples/net/coaps_client/src/coaps_client.c
@@ -163,22 +163,19 @@
 			  size_t *olen)
 {
 	uint32_t seed;
-	char *ptr = data;
+
+	ARG_UNUSED(data);
 
 	seed = sys_rand32_get();
 
-	if (!seed) {
-		seed = 7;
+	if (len > sizeof(seed)) {
+		len = sizeof(seed);
 	}
 
-	for (int i = 0; i < len; i++) {
-		seed ^= seed << 13;
-		seed ^= seed >> 17;
-		seed ^= seed << 5;
-		*ptr++ = (char)seed;
-	}
+	memcpy(output, &seed, len);
 
 	*olen = len;
+
 	return 0;
 }
 
@@ -269,7 +266,7 @@
 	mbedtls_ssl_set_timer_cb(&ssl, &timer, dtls_timing_set_delay,
 				 dtls_timing_get_delay);
 
-	mbedtls_ssl_set_bio(&ssl, &ctx, udp_tx, NULL, udp_rx);
+	mbedtls_ssl_set_bio(&ssl, &ctx, udp_tx, udp_rx, NULL);
 
 	do {
 		ret = mbedtls_ssl_handshake(&ssl);
diff --git a/samples/net/coaps_server/prj_qemu_x86.conf b/samples/net/coaps_server/prj_qemu_x86.conf
index 535dea8..68886f7 100644
--- a/samples/net/coaps_server/prj_qemu_x86.conf
+++ b/samples/net/coaps_server/prj_qemu_x86.conf
@@ -1,8 +1,7 @@
 CONFIG_NETWORKING=y
 CONFIG_NET_IPV6=y
-CONFIG_NET_IPV4=y
+CONFIG_NET_IPV4=n
 CONFIG_NET_UDP=y
-CONFIG_NET_TCP=y
 CONFIG_TEST_RANDOM_GENERATOR=y
 CONFIG_NET_LOG=y
 CONFIG_NET_SLIP_TAP=y
@@ -26,6 +25,4 @@
 
 CONFIG_NET_SAMPLES_IP_ADDRESSES=y
 CONFIG_NET_SAMPLES_MY_IPV6_ADDR="2001:db8::1"
-CONFIG_NET_SAMPLES_PEER_IPV6_ADDR="2001:db8::2"
 CONFIG_NET_SAMPLES_MY_IPV4_ADDR="192.0.2.1"
-CONFIG_NET_SAMPLES_PEER_IPV4_ADDR="192.0.2.2"
diff --git a/samples/net/coaps_server/src/coaps_server.c b/samples/net/coaps_server/src/coaps_server.c
index 23c0f53..569603c 100644
--- a/samples/net/coaps_server/src/coaps_server.c
+++ b/samples/net/coaps_server/src/coaps_server.c
@@ -395,24 +395,19 @@
 			  size_t *olen)
 {
 	uint32_t seed;
-	char *ptr = data;
 
 	ARG_UNUSED(data);
 
 	seed = sys_rand32_get();
 
-	if (!seed) {
-		seed = 7;
+	if (len > sizeof(seed)) {
+		len = sizeof(seed);
 	}
 
-	for (size_t i = 0; i < len; i++) {
-		seed ^= seed << 13;
-		seed ^= seed >> 17;
-		seed ^= seed << 5;
-		*ptr++ = (char)seed;
-	}
+	memcpy(output, &seed, len);
 
 	*olen = len;
+
 	return 0;
 }
 
diff --git a/samples/net/echo_server/prj_sam_e70_xplained.conf b/samples/net/echo_server/prj_sam_e70_xplained.conf
index fee2764..78fa597 100644
--- a/samples/net/echo_server/prj_sam_e70_xplained.conf
+++ b/samples/net/echo_server/prj_sam_e70_xplained.conf
@@ -24,7 +24,6 @@
 
 CONFIG_ETH_INIT_PRIORITY=95
 CONFIG_ETH_SAM_GMAC=y
-CONFIG_ETH_SAM_GMAC_NBUF_DATA_COUNT=24
 CONFIG_ETH_SAM_GMAC_MAC0=10
 CONFIG_ETH_SAM_GMAC_MAC1=22
 CONFIG_ETH_SAM_GMAC_MAC2=33
@@ -34,6 +33,4 @@
 
 CONFIG_NET_SAMPLES_IP_ADDRESSES=y
 CONFIG_NET_SAMPLES_MY_IPV6_ADDR="2001:db8::1"
-CONFIG_NET_SAMPLES_PEER_IPV6_ADDR="2001:db8::2"
 CONFIG_NET_SAMPLES_MY_IPV4_ADDR="192.0.2.1"
-CONFIG_NET_SAMPLES_PEER_IPV4_ADDR="192.0.2.2"
diff --git a/samples/net/http_client/prj_frdm_k64f.conf b/samples/net/http_client/prj_frdm_k64f.conf
index 9251293..196c2ec 100644
--- a/samples/net/http_client/prj_frdm_k64f.conf
+++ b/samples/net/http_client/prj_frdm_k64f.conf
@@ -16,7 +16,6 @@
 CONFIG_NET_IPV4=n
 CONFIG_NET_IPV6=y
 
-CONFIG_HTTP=y
 CONFIG_HTTP_CLIENT=y
 CONFIG_HTTP_PARSER=y
 
diff --git a/samples/net/http_client/prj_qemu_x86.conf b/samples/net/http_client/prj_qemu_x86.conf
index f694f12..b20f2bc 100644
--- a/samples/net/http_client/prj_qemu_x86.conf
+++ b/samples/net/http_client/prj_qemu_x86.conf
@@ -20,7 +20,6 @@
 # Enable IPv4 support
 CONFIG_NET_IPV4=y
 
-CONFIG_HTTP=y
 CONFIG_HTTP_CLIENT=y
 CONFIG_HTTP_PARSER=y
 CONFIG_STDOUT_CONSOLE=y
diff --git a/samples/net/http_server/README.rst b/samples/net/http_server/README.rst
index 792bbda..409c05a 100644
--- a/samples/net/http_server/README.rst
+++ b/samples/net/http_server/README.rst
@@ -222,6 +222,27 @@
 	<body><h1><center>404 Not Found</center></h1></body>
 	</html>
 
+To test the HTTP Basic Authentication functionality, use the
+following command:
+
+.. code-block:: console
+
+	wget 192.168.1.101/auth -O index.html --user=zephyr --password=0123456789
+
+the :file:`index.html` file will contain the following information:
+
+.. code-block:: html
+
+	<html>
+	<head>
+	<title>Zephyr HTTP Server</title>
+	</head>
+	<body>
+	<h1><center>Zephyr HTTP server</center></h1>
+	<h2><center>user: zephyr, password: 0123456789</center></h2>
+	</body>
+	</html>
+
 HTTPS Server
 ============
 
diff --git a/samples/net/http_server/prj_frdm_k64f.conf b/samples/net/http_server/prj_frdm_k64f.conf
index ebd9f67..7dca08a 100644
--- a/samples/net/http_server/prj_frdm_k64f.conf
+++ b/samples/net/http_server/prj_frdm_k64f.conf
@@ -16,7 +16,6 @@
 
 CONFIG_STDOUT_CONSOLE=y
 
-CONFIG_HTTP=y
 CONFIG_HTTP_SERVER=y
 CONFIG_HTTP_PARSER=y
 
diff --git a/samples/net/http_server/prj_qemu_x86.conf b/samples/net/http_server/prj_qemu_x86.conf
index d3447ef..49fd22b 100644
--- a/samples/net/http_server/prj_qemu_x86.conf
+++ b/samples/net/http_server/prj_qemu_x86.conf
@@ -17,7 +17,6 @@
 
 CONFIG_STDOUT_CONSOLE=y
 
-CONFIG_HTTP=y
 CONFIG_HTTP_SERVER=y
 CONFIG_HTTP_PARSER=y
 
diff --git a/samples/net/http_server/src/config.h b/samples/net/http_server/src/config.h
index 054a4c4..874c20b 100644
--- a/samples/net/http_server/src/config.h
+++ b/samples/net/http_server/src/config.h
@@ -23,6 +23,15 @@
 
 #define ZEPHYR_PORT		80
 
+#define HTTP_AUTH_URL		"/auth"
+#define HTTP_AUTH_TYPE		"Basic"
+
+/* HTTP Basic Auth, see https://tools.ietf.org/html/rfc7617 */
+#define HTTP_AUTH_REALM		"Zephyr"
+#define HTTP_AUTH_USERNAME	"zephyr"
+#define HTTP_AUTH_PASSWORD	"0123456789"
+#define HTTP_AUTH_CREDENTIALS	"emVwaHlyOjAxMjM0NTY3ODk="
+
 #define APP_SLEEP_MSECS		500
 
 #ifdef CONFIG_MBEDTLS
diff --git a/samples/net/http_server/src/http_server.c b/samples/net/http_server/src/http_server.c
index 9b75aae..2ab4e51 100644
--- a/samples/net/http_server/src/http_server.c
+++ b/samples/net/http_server/src/http_server.c
@@ -113,7 +113,6 @@
 	if (!rx) {
 		printf("[%s:%d] Connection closed by peer\n",
 		       __func__, __LINE__);
-		http_ctx_release(http_ctx);
 		goto lb_exit;
 	}
 
@@ -136,6 +135,8 @@
 		goto lb_exit;
 	}
 
+	data->data[min(data->size - 1, rcv_len)] = 0;
+
 	parser_init(http_ctx);
 	parsed_len = parser_parse_request(http_ctx, data);
 	if (parsed_len <= 0) {
@@ -152,6 +153,8 @@
 lb_exit:
 	net_buf_unref(data);
 	net_buf_unref(rx);
+
+	http_ctx_release(http_ctx);
 }
 
 /**
@@ -314,8 +317,7 @@
 	return 0;
 }
 
-static
-int http_ctx_release(struct http_server_ctx *http_ctx)
+static int http_ctx_release(struct http_server_ctx *http_ctx)
 {
 	if (http_ctx == NULL) {
 		return 0;
@@ -432,3 +434,14 @@
 		       http_ctx->url_len, http_ctx->url);
 	}
 }
+
+int http_auth(struct http_server_ctx *ctx)
+{
+	const char *auth_str = "Authorization: Basic "HTTP_AUTH_CREDENTIALS;
+
+	if (strstr(ctx->field_values[0].key, auth_str)) {
+		return http_response_auth(ctx);
+	}
+
+	return http_response_401(ctx);
+}
diff --git a/samples/net/http_server/src/http_server.h b/samples/net/http_server/src/http_server.h
index 5e00279..437d025 100644
--- a/samples/net/http_server/src/http_server.h
+++ b/samples/net/http_server/src/http_server.h
@@ -52,4 +52,6 @@
 int http_url_add(const char *url, uint8_t flags,
 		 int (*write_cb)(struct http_server_ctx *http_ctx));
 
+int http_auth(struct http_server_ctx *ctx);
+
 #endif
diff --git a/samples/net/http_server/src/http_types.h b/samples/net/http_server/src/http_types.h
index 8fbee79..2bcc81a 100644
--- a/samples/net/http_server/src/http_types.h
+++ b/samples/net/http_server/src/http_types.h
@@ -11,10 +11,10 @@
 #include <net/http.h>
 
 /* Max number of HTTP header field-value pairs */
-#define HTTP_PARSER_MAX_FIELD_VALUES	10
+#define HTTP_PARSER_MAX_FIELD_VALUES	CONFIG_HTTP_HEADER_FIELD_ITEMS
 
 /* Max number of HTTP server context available to this app */
-#define HTTP_MAX_NUMBER_SERVER_CTX	16
+#define HTTP_MAX_NUMBER_SERVER_CTX	CONFIG_NET_MAX_CONTEXTS
 
 /* Max number of URLs this server will handle */
 #define HTTP_MAX_NUMBER_URL		16
diff --git a/samples/net/http_server/src/http_write_utils.c b/samples/net/http_server/src/http_write_utils.c
index 61381d2..2855c28 100644
--- a/samples/net/http_server/src/http_write_utils.c
+++ b/samples/net/http_server/src/http_write_utils.c
@@ -7,6 +7,7 @@
 #include "http_write_utils.h"
 #include "http_types.h"
 #include "http_utils.h"
+#include "config.h"
 
 #include <net/nbuf.h>
 #include <stdio.h>
@@ -16,6 +17,10 @@
 				"Transfer-Encoding: chunked\r\n" \
 				"\r\n"
 
+#define HTTP_401_STATUS_US	"HTTP/1.1 401 Unauthorized status\r\n" \
+				"WWW-Authenticate: Basic realm=" \
+				"\""HTTP_AUTH_REALM"\"\r\n\r\n"
+
 #define HTML_HEADER		"<html><head>" \
 				"<title>Zephyr HTTP Server</title>" \
 				"</head><body><h1>" \
@@ -89,9 +94,22 @@
 			     HTML_FOOTER);
 }
 
+int http_response_401(struct http_server_ctx *ctx)
+{
+	return http_response(ctx, HTTP_401_STATUS_US, NULL);
+}
+
 int http_response_soft_404(struct http_server_ctx *ctx)
 {
 	return http_response(ctx, HTTP_STATUS_200_OK, HTML_HEADER
 			     "<h2><center>404 Not Found</center></h2>"
 			     HTML_FOOTER);
 }
+
+int http_response_auth(struct http_server_ctx *ctx)
+{
+	return http_response(ctx, HTTP_STATUS_200_OK,
+			     HTML_HEADER"<h2><center>user: "HTTP_AUTH_USERNAME
+			     ", password: "HTTP_AUTH_PASSWORD"</center></h2>"
+			     HTML_FOOTER);
+}
diff --git a/samples/net/http_server/src/http_write_utils.h b/samples/net/http_server/src/http_write_utils.h
index 3935560..3679850 100644
--- a/samples/net/http_server/src/http_write_utils.h
+++ b/samples/net/http_server/src/http_write_utils.h
@@ -16,7 +16,11 @@
 /* Writes an elementary It Works! HTML web page to the client */
 int http_response_it_works(struct http_server_ctx *ctx);
 
+int http_response_401(struct http_server_ctx *ctx);
+
 /* Writes a 200 OK HTTP status code with a 404 Not Found HTML msg */
 int http_response_soft_404(struct http_server_ctx *ctx);
 
+int http_response_auth(struct http_server_ctx *ctx);
+
 #endif
diff --git a/samples/net/http_server/src/main.c b/samples/net/http_server/src/main.c
index 9e244ca..28e1e06 100644
--- a/samples/net/http_server/src/main.c
+++ b/samples/net/http_server/src/main.c
@@ -31,6 +31,7 @@
 	http_ctx_init();
 
 	http_url_default_handler(http_response_soft_404);
+	http_url_add(HTTP_AUTH_URL, HTTP_URL_STANDARD, http_auth);
 	http_url_add("/headers", HTTP_URL_STANDARD,
 		     http_response_header_fields);
 	http_url_add("/index.html", HTTP_URL_STANDARD, http_response_it_works);
diff --git a/samples/net/leds_demo/src/leds-demo.c b/samples/net/leds_demo/src/leds-demo.c
index 4c941a2..0a57d5c 100644
--- a/samples/net/leds_demo/src/leds-demo.c
+++ b/samples/net/leds_demo/src/leds-demo.c
@@ -143,8 +143,13 @@
 		return -EINVAL;
 	}
 
-	return net_context_sendto(buf, from, sizeof(struct sockaddr_in6),
-				  NULL, 0, NULL, NULL);
+	r = net_context_sendto(buf, from, sizeof(struct sockaddr_in6),
+			       NULL, 0, NULL, NULL);
+	if (r < 0) {
+		net_nbuf_unref(buf);
+	}
+
+	return r;
 }
 
 static int led_post(struct zoap_resource *resource,
@@ -216,8 +221,13 @@
 		return -EINVAL;
 	}
 
-	return net_context_sendto(buf, from, sizeof(struct sockaddr_in6),
-				  NULL, 0, NULL, NULL);
+	r = net_context_sendto(buf, from, sizeof(struct sockaddr_in6),
+			       NULL, 0, NULL, NULL);
+	if (r < 0) {
+		net_nbuf_unref(buf);
+	}
+
+	return r;
 }
 
 static int led_put(struct zoap_resource *resource,
@@ -290,8 +300,13 @@
 		return -EINVAL;
 	}
 
-	return net_context_sendto(buf, from, sizeof(struct sockaddr_in6),
-				  NULL, 0, NULL, NULL);
+	r = net_context_sendto(buf, from, sizeof(struct sockaddr_in6),
+			       NULL, 0, NULL, NULL);
+	if (r < 0) {
+		net_nbuf_unref(buf);
+	}
+
+	return r;
 }
 
 static int dummy_get(struct zoap_resource *resource,
@@ -342,8 +357,13 @@
 		return -EINVAL;
 	}
 
-	return net_context_sendto(buf, from, sizeof(struct sockaddr_in6),
-				  NULL, 0, NULL, NULL);
+	r = net_context_sendto(buf, from, sizeof(struct sockaddr_in6),
+			       NULL, 0, NULL, NULL);
+	if (r < 0) {
+		net_nbuf_unref(buf);
+	}
+
+	return r;
 }
 
 static const char * const led_default_path[] = { "led", NULL };
diff --git a/samples/net/zperf/src/zperf_udp_receiver.c b/samples/net/zperf/src/zperf_udp_receiver.c
index efcdd7c..c88b4f3 100644
--- a/samples/net/zperf/src/zperf_udp_receiver.c
+++ b/samples/net/zperf/src/zperf_udp_receiver.c
@@ -151,7 +151,7 @@
 
 	offset = net_nbuf_appdata(buf) - net_nbuf_ip_data(buf);
 
-	frag = net_nbuf_read_be32(frag, offset, &pos, &hdr.id);
+	frag = net_nbuf_read_be32(frag, offset, &pos, (uint32_t *)&hdr.id);
 	frag = net_nbuf_read_be32(frag, pos, &pos, &hdr.tv_sec);
 	frag = net_nbuf_read_be32(frag, pos, &pos, &hdr.tv_usec);
 
diff --git a/samples/net/zperf/src/zperf_udp_uploader.c b/samples/net/zperf/src/zperf_udp_uploader.c
index 794dfb3..f25e635 100644
--- a/samples/net/zperf/src/zperf_udp_uploader.c
+++ b/samples/net/zperf/src/zperf_udp_uploader.c
@@ -42,16 +42,17 @@
 		return;
 	}
 
-	frag = net_nbuf_read_be32(frag, offset, &pos, &hdr.flags);
-	frag = net_nbuf_read_be32(frag, pos, &pos, &hdr.total_len1);
-	frag = net_nbuf_read_be32(frag, pos, &pos, &hdr.total_len2);
-	frag = net_nbuf_read_be32(frag, pos, &pos, &hdr.stop_sec);
-	frag = net_nbuf_read_be32(frag, pos, &pos, &hdr.stop_usec);
-	frag = net_nbuf_read_be32(frag, pos, &pos, &hdr.error_cnt);
-	frag = net_nbuf_read_be32(frag, pos, &pos, &hdr.outorder_cnt);
-	frag = net_nbuf_read_be32(frag, pos, &pos, &hdr.datagrams);
-	frag = net_nbuf_read_be32(frag, pos, &pos, &hdr.jitter1);
-	frag = net_nbuf_read_be32(frag, pos, &pos, &hdr.jitter2);
+	frag = net_nbuf_read_be32(frag, offset, &pos, (uint32_t *)&hdr.flags);
+	frag = net_nbuf_read_be32(frag, pos, &pos, (uint32_t *)&hdr.total_len1);
+	frag = net_nbuf_read_be32(frag, pos, &pos, (uint32_t *)&hdr.total_len2);
+	frag = net_nbuf_read_be32(frag, pos, &pos, (uint32_t *)&hdr.stop_sec);
+	frag = net_nbuf_read_be32(frag, pos, &pos, (uint32_t *)&hdr.stop_usec);
+	frag = net_nbuf_read_be32(frag, pos, &pos, (uint32_t *)&hdr.error_cnt);
+	frag = net_nbuf_read_be32(frag, pos, &pos,
+				  (uint32_t *)&hdr.outorder_cnt);
+	frag = net_nbuf_read_be32(frag, pos, &pos, (uint32_t *)&hdr.datagrams);
+	frag = net_nbuf_read_be32(frag, pos, &pos, (uint32_t *)&hdr.jitter1);
+	frag = net_nbuf_read_be32(frag, pos, &pos, (uint32_t *)&hdr.jitter2);
 
 	results->nb_packets_rcvd = hdr.datagrams;
 	results->nb_packets_lost = hdr.error_cnt;
@@ -121,7 +122,8 @@
 
 			frag = net_nbuf_write(buf, net_buf_frag_last(buf),
 					     sizeof(struct zperf_udp_datagram),
-					      &pos, size, sample_packet,
+					      &pos, size,
+					      (uint8_t *)sample_packet,
 					      K_FOREVER);
 		}
 
diff --git a/subsys/net/ip/6lo.c b/subsys/net/ip/6lo.c
index 0f34a74..f33c299 100644
--- a/subsys/net/ip/6lo.c
+++ b/subsys/net/ip/6lo.c
@@ -36,7 +36,7 @@
 
 static inline uint8_t get_6co_compress(struct net_icmpv6_nd_opt_6co *opt)
 {
-	return (opt->flag & 0x10) > 4;
+	return (opt->flag & 0x10) >> 4;
 }
 
 static inline uint8_t get_6co_cid(struct net_icmpv6_nd_opt_6co *opt)
diff --git a/subsys/net/ip/Kconfig.ipv6 b/subsys/net/ip/Kconfig.ipv6
index 7ce0a7f..99141cf 100644
--- a/subsys/net/ip/Kconfig.ipv6
+++ b/subsys/net/ip/Kconfig.ipv6
@@ -48,8 +48,16 @@
 	be active. Currently we support only MLDv2. See RFC 3810 for
 	details.
 
+config NET_IPV6_NBR_CACHE
+	bool "Neighbor cache"
+	default y
+	help
+	The value depends on your network needs. Neighbor cache should
+	normally be active.
+
 config NET_IPV6_ND
 	bool "Activate neighbor discovery"
+	depends on NET_IPV6_NBR_CACHE
 	default y
 	help
 	The value depends on your network needs. ND should normally
@@ -57,7 +65,7 @@
 
 config NET_IPV6_DAD
 	bool "Activate duplicate address detection"
-	depends on NET_IPV6_ND
+	depends on NET_IPV6_NBR_CACHE
 	default y
 	help
 	The value depends on your network needs. DAD should normally
diff --git a/subsys/net/ip/connection.c b/subsys/net/ip/connection.c
index cf46157..7e1b43f 100644
--- a/subsys/net/ip/connection.c
+++ b/subsys/net/ip/connection.c
@@ -50,26 +50,6 @@
  */
 #define NET_CONN_BUF(buf) ((struct net_udp_hdr *)(net_nbuf_udp_data(buf)))
 
-#if defined(CONFIG_NET_DEBUG_CONN)
-static inline const char *proto2str(enum net_ip_protocol proto)
-{
-	switch (proto) {
-	case IPPROTO_ICMP:
-		return "ICMPv4";
-	case IPPROTO_TCP:
-		return "TCP";
-	case IPPROTO_UDP:
-		return "UDP";
-	case IPPROTO_ICMPV6:
-		return "ICMPv6";
-	default:
-		break;
-	}
-
-	return "<unknown>";
-}
-#endif /* CONFIG_NET_DEBUG_CONN */
-
 #if defined(CONFIG_NET_CONN_CACHE)
 
 /* Cache the connection so that we do not have to go
@@ -314,7 +294,7 @@
 
 			NET_DBG("Cache %s listener for buf %p src port %u "
 				"dst port %u family %d cache[%d] 0x%x",
-				proto2str(proto), buf,
+				net_proto2str(proto), buf,
 				ntohs(NET_CONN_BUF(buf)->src_port),
 				ntohs(NET_CONN_BUF(buf)->dst_port),
 				net_nbuf_family(buf), *pos,
@@ -672,7 +652,7 @@
 		}
 
 		NET_DBG("Check %s listener for buf %p src port %u dst port %u "
-			"family %d chksum 0x%04x", proto2str(proto), buf,
+			"family %d chksum 0x%04x", net_proto2str(proto), buf,
 			ntohs(NET_CONN_BUF(buf)->src_port),
 			ntohs(NET_CONN_BUF(buf)->dst_port),
 			net_nbuf_family(buf), ntohs(chksum));
diff --git a/subsys/net/ip/icmpv4.c b/subsys/net/ip/icmpv4.c
index 22859d4..079f864 100644
--- a/subsys/net/ip/icmpv4.c
+++ b/subsys/net/ip/icmpv4.c
@@ -22,6 +22,8 @@
 #include "icmpv4.h"
 #include "net_stats.h"
 
+#define BUF_WAIT_TIME K_SECONDS(1)
+
 static inline enum net_verdict handle_echo_request(struct net_buf *buf)
 {
 	/* Note that we send the same data buffers back and just swap
@@ -165,11 +167,15 @@
 	ARG_UNUSED(code);
 	ARG_UNUSED(len);
 
+	net_stats_update_icmp_recv();
+
 	switch (type) {
 	case NET_ICMPV4_ECHO_REQUEST:
 		return handle_echo_request(buf);
 	}
 
+	net_stats_update_icmp_drop();
+
 	return NET_DROP;
 }
 
@@ -179,17 +185,23 @@
 	struct net_if *iface = net_nbuf_iface(orig);
 	size_t extra_len, reserve;
 	struct in_addr addr, *src, *dst;
+	int err = -EIO;
 
 	if (NET_IPV4_BUF(orig)->proto == IPPROTO_ICMP) {
 		if (NET_ICMP_BUF(orig)->code < 8) {
 			/* We must not send ICMP errors back */
-			return -EINVAL;
+			err = -EINVAL;
+			goto drop_no_buf;
 		}
 	}
 
 	iface = net_nbuf_iface(orig);
 
-	buf = net_nbuf_get_reserve_tx(0, K_FOREVER);
+	buf = net_nbuf_get_reserve_tx(0, BUF_WAIT_TIME);
+	if (!buf) {
+		err = -ENOMEM;
+		goto drop_no_buf;
+	}
 
 	reserve = sizeof(struct net_ipv4_hdr) + sizeof(struct net_icmp_hdr) +
 		NET_ICMPV4_UNUSED_LEN;
@@ -220,8 +232,9 @@
 	/* We only copy minimal IPv4 + next header from original message.
 	 * This is so that the memory pressure is minimized.
 	 */
-	frag = net_nbuf_copy(orig, extra_len, reserve, K_FOREVER);
+	frag = net_nbuf_copy(orig, extra_len, reserve, BUF_WAIT_TIME);
 	if (!frag) {
+		err = -ENOMEM;
 		goto drop;
 	}
 
@@ -259,15 +272,14 @@
 
 	if (net_send_data(buf) >= 0) {
 		net_stats_update_icmp_sent();
-		return -EIO;
+		return 0;
 	}
 
 drop:
 	net_nbuf_unref(buf);
+
+drop_no_buf:
 	net_stats_update_icmp_drop();
 
-	/* Note that we always return < 0 so that the caller knows to
-	 * discard the original buffer.
-	 */
-	return -EIO;
+	return err;
 }
diff --git a/subsys/net/ip/icmpv6.c b/subsys/net/ip/icmpv6.c
index dfa174e..b0461de 100644
--- a/subsys/net/ip/icmpv6.c
+++ b/subsys/net/ip/icmpv6.c
@@ -24,6 +24,12 @@
 #include "ipv6.h"
 #include "net_stats.h"
 
+#if defined(CONFIG_NET_RPL)
+#include "rpl.h"
+#endif
+
+#define BUF_WAIT_TIME K_SECONDS(1)
+
 static sys_slist_t handlers;
 
 void net_icmpv6_register_handler(struct net_icmpv6_handler *handler)
@@ -97,12 +103,15 @@
 
 	iface = net_nbuf_iface(orig);
 
-	buf = net_nbuf_get_reserve_tx(0, K_FOREVER);
+	buf = net_nbuf_get_reserve_tx(0, BUF_WAIT_TIME);
+	if (!buf) {
+		goto drop_no_buf;
+	}
 
 	payload_len = sys_get_be16(NET_IPV6_BUF(orig)->len) -
 		sizeof(NET_ICMPH_LEN) - NET_ICMPV6_UNUSED_LEN;
 
-	frag = net_nbuf_copy_all(orig, 0, K_FOREVER);
+	frag = net_nbuf_copy_all(orig, 0, BUF_WAIT_TIME);
 	if (!frag) {
 		goto drop;
 	}
@@ -111,10 +120,24 @@
 	net_nbuf_set_family(buf, AF_INET6);
 	net_nbuf_set_iface(buf, iface);
 	net_nbuf_set_ll_reserve(buf, net_buf_headroom(frag));
-	net_nbuf_set_ext_len(buf, 0);
+	net_nbuf_set_ip_hdr_len(buf, sizeof(struct net_ipv6_hdr));
 
-	setup_ipv6_header(buf, payload_len, net_if_ipv6_get_hop_limit(iface),
-			  NET_ICMPV6_ECHO_REPLY, 0);
+	if (net_nbuf_ext_len(orig)) {
+		net_nbuf_set_ext_len(buf, net_nbuf_ext_len(orig));
+	} else {
+		net_nbuf_set_ext_len(buf, 0);
+	}
+
+	/* Set up IPv6 Header fields */
+	NET_IPV6_BUF(buf)->vtc = 0x60;
+	NET_IPV6_BUF(buf)->tcflow = 0;
+	NET_IPV6_BUF(buf)->flow = 0;
+	NET_IPV6_BUF(buf)->hop_limit = net_if_ipv6_get_hop_limit(iface);
+
+	/* ICMPv6 fields */
+	NET_ICMP_BUF(buf)->type = NET_ICMPV6_ECHO_REPLY;
+	NET_ICMP_BUF(buf)->code = 0;
+	NET_ICMP_BUF(buf)->chksum = 0;
 
 	if (net_is_ipv6_addr_mcast(&NET_IPV6_BUF(buf)->dst)) {
 		net_ipaddr_copy(&NET_IPV6_BUF(buf)->dst,
@@ -132,6 +155,17 @@
 		net_ipaddr_copy(&NET_IPV6_BUF(buf)->dst, &addr);
 	}
 
+	if (NET_IPV6_BUF(buf)->nexthdr == NET_IPV6_NEXTHDR_HBHO) {
+#if defined(CONFIG_NET_RPL)
+		uint16_t offset = NET_IPV6H_LEN;
+
+		if (net_rpl_revert_header(buf, offset, &offset) < 0) {
+			/* TODO: Handle error cases */
+			goto drop;
+		}
+#endif
+	}
+
 	net_nbuf_ll_src(buf)->addr = net_nbuf_ll_dst(orig)->addr;
 	net_nbuf_ll_src(buf)->len = net_nbuf_ll_dst(orig)->len;
 
@@ -156,6 +190,8 @@
 
 drop:
 	net_nbuf_unref(buf);
+
+drop_no_buf:
 	net_stats_update_icmp_drop();
 
 	return NET_DROP;
@@ -168,17 +204,23 @@
 	struct net_if *iface;
 	struct in6_addr *src, *dst;
 	size_t extra_len, reserve;
+	int err = -EIO;
 
 	if (NET_IPV6_BUF(orig)->nexthdr == IPPROTO_ICMPV6) {
 		if (NET_ICMP_BUF(orig)->code < 128) {
 			/* We must not send ICMP errors back */
-			return -EINVAL;
+			err = -EINVAL;
+			goto drop_no_buf;
 		}
 	}
 
 	iface = net_nbuf_iface(orig);
 
-	buf = net_nbuf_get_reserve_tx(0, K_FOREVER);
+	buf = net_nbuf_get_reserve_tx(0, BUF_WAIT_TIME);
+	if (!buf) {
+		err = -ENOMEM;
+		goto drop_no_buf;
+	}
 
 	/* We need to remember the original location of source and destination
 	 * addresses as the net_nbuf_copy() will mangle the original buffer.
@@ -212,8 +254,9 @@
 	/* We only copy minimal IPv6 + next header from original message.
 	 * This is so that the memory pressure is minimized.
 	 */
-	frag = net_nbuf_copy(orig, extra_len, reserve, K_FOREVER);
+	frag = net_nbuf_copy(orig, extra_len, reserve, BUF_WAIT_TIME);
 	if (!frag) {
+		err = -ENOMEM;
 		goto drop;
 	}
 
@@ -267,17 +310,16 @@
 
 	if (net_send_data(buf) >= 0) {
 		net_stats_update_icmp_sent();
-		return -EIO;
+		return 0;
 	}
 
 drop:
 	net_nbuf_unref(buf);
+
+drop_no_buf:
 	net_stats_update_icmp_drop();
 
-	/* Note that we always return < 0 so that the caller knows to
-	 * discard the original buffer.
-	 */
-	return -EIO;
+	return err;
 }
 
 int net_icmpv6_send_echo_request(struct net_if *iface,
@@ -310,7 +352,9 @@
 	NET_ICMP_BUF(buf)->chksum = 0;
 	NET_ICMP_BUF(buf)->chksum = ~net_calc_chksum_icmpv6(buf);
 
-	buf = net_ipv6_finalize_raw(buf, IPPROTO_ICMPV6);
+	if (net_ipv6_finalize_raw(buf, IPPROTO_ICMPV6) < 0) {
+		goto drop;
+	}
 
 #if defined(CONFIG_NET_DEBUG_ICMPV6)
 	do {
@@ -329,6 +373,7 @@
 		return 0;
 	}
 
+drop:
 	net_nbuf_unref(buf);
 	net_stats_update_icmp_drop();
 
@@ -340,13 +385,16 @@
 {
 	struct net_icmpv6_handler *cb;
 
+	net_stats_update_icmp_recv();
+
 	SYS_SLIST_FOR_EACH_CONTAINER(&handlers, cb, node) {
 		if (cb->type == type && (cb->code == code || cb->code == 0)) {
-			net_stats_update_icmp_recv();
 			return cb->handler(buf);
 		}
 	}
 
+	net_stats_update_icmp_drop();
+
 	return NET_DROP;
 }
 
diff --git a/subsys/net/ip/ipv4.c b/subsys/net/ip/ipv4.c
index e94a5b7..5720182 100644
--- a/subsys/net/ip/ipv4.c
+++ b/subsys/net/ip/ipv4.c
@@ -77,8 +77,7 @@
 				   net_context_get_ip_proto(context));
 }
 
-struct net_buf *net_ipv4_finalize_raw(struct net_buf *buf,
-				      uint8_t next_header)
+int net_ipv4_finalize_raw(struct net_buf *buf, uint8_t next_header)
 {
 	/* Set the length of the IPv4 header */
 	size_t total_len;
@@ -106,11 +105,10 @@
 	}
 #endif
 
-	return buf;
+	return 0;
 }
 
-struct net_buf *net_ipv4_finalize(struct net_context *context,
-				  struct net_buf *buf)
+int net_ipv4_finalize(struct net_context *context, struct net_buf *buf)
 {
 	return net_ipv4_finalize_raw(buf,
 				     net_context_get_ip_proto(context));
diff --git a/subsys/net/ip/ipv4.h b/subsys/net/ip/ipv4.h
index f04cfb3..b33dbb5 100644
--- a/subsys/net/ip/ipv4.h
+++ b/subsys/net/ip/ipv4.h
@@ -63,10 +63,9 @@
  * @param buf Network buffer
  * @param next_header Protocol type of the next header after IPv4 header.
  *
- * @return Return network buffer that contains the IPv4 packet.
+ * @return Return 0 on Success, < 0 on Failure.
  */
-struct net_buf *net_ipv4_finalize_raw(struct net_buf *buf,
-				      uint8_t next_header);
+int net_ipv4_finalize_raw(struct net_buf *buf, uint8_t next_header);
 
 /**
  * @brief Finalize IPv4 packet. It should be called right before
@@ -77,9 +76,8 @@
  * @param context Network context for a connection
  * @param buf Network buffer
  *
- * @return Return network buffer that contains the IPv4 packet.
+ * @return Return 0 on Success, < 0 on Failure.
  */
-struct net_buf *net_ipv4_finalize(struct net_context *context,
-				  struct net_buf *buf);
+int net_ipv4_finalize(struct net_context *context, struct net_buf *buf);
 
 #endif /* __IPV4_H */
diff --git a/subsys/net/ip/ipv6.c b/subsys/net/ip/ipv6.c
index a975ebd..579a74b 100644
--- a/subsys/net/ip/ipv6.c
+++ b/subsys/net/ip/ipv6.c
@@ -34,9 +34,15 @@
 #include "net_stats.h"
 
 #if defined(CONFIG_NET_IPV6_ND)
+static void nd_reachable_timeout(struct k_work *work);
+#endif
+
+#if defined(CONFIG_NET_IPV6_NBR_CACHE)
 
 #define MAX_MULTICAST_SOLICIT 3
 #define MAX_UNICAST_SOLICIT   3
+#define DELAY_FIRST_PROBE_TIME (5 * MSEC_PER_SEC) /* RFC 4861 ch 10 */
+#define RETRANS_TIMER 1000 /* in ms, RFC 4861 ch 10 */
 
 extern void net_neighbor_data_remove(struct net_nbr *nbr);
 extern void net_neighbor_table_clear(struct net_nbr_table *table);
@@ -52,6 +58,37 @@
 		   net_neighbor_pool,
 		   net_neighbor_table_clear);
 
+const char *net_nbr_state2str(enum net_nbr_state state)
+{
+	switch (state) {
+	case NET_NBR_INCOMPLETE:
+		return "incomplete";
+	case NET_NBR_REACHABLE:
+		return "reachable";
+	case NET_NBR_STALE:
+		return "stale";
+	case NET_NBR_DELAY:
+		return "delay";
+	case NET_NBR_PROBE:
+		return "probe";
+	}
+
+	return "<invalid state>";
+}
+
+static void nbr_set_state(struct net_nbr *nbr, enum net_nbr_state new_state)
+{
+	if (new_state == net_ipv6_nbr_data(nbr)->state) {
+		return;
+	}
+
+	NET_DBG("nbr %p %s -> %s", nbr,
+		net_nbr_state2str(net_ipv6_nbr_data(nbr)->state),
+		net_nbr_state2str(new_state));
+
+	net_ipv6_nbr_data(nbr)->state = new_state;
+}
+
 static inline bool net_is_solicited(struct net_buf *buf)
 {
 	return NET_ICMPV6_NA_BUF(buf)->flags & NET_ICMPV6_NA_FLAG_SOLICITED;
@@ -222,7 +259,7 @@
 	}
 
 	net_ipaddr_copy(&net_ipv6_nbr_data(nbr)->addr, addr);
-	net_ipv6_nbr_data(nbr)->state = state;
+	nbr_set_state(nbr, state);
 	net_ipv6_nbr_data(nbr)->is_router = is_router;
 
 	NET_DBG("[%d] nbr %p state %d router %d IPv6 %s ll %s",
@@ -243,6 +280,43 @@
 				is_router, state);
 }
 
+#define NS_REPLY_TIMEOUT MSEC_PER_SEC
+
+static void ns_reply_timeout(struct k_work *work)
+{
+	/* We did not receive reply to a sent NS */
+	struct net_ipv6_nbr_data *data = CONTAINER_OF(work,
+						      struct net_ipv6_nbr_data,
+						      send_ns);
+
+	struct net_nbr *nbr = get_nbr_from_data(data);
+
+	if (!nbr) {
+		NET_DBG("NS timeout but no nbr data");
+		return;
+	}
+
+	if (!data->pending) {
+		/* Silently return, this is not an error as the work
+		 * cannot be cancelled in certain cases.
+		 */
+		return;
+	}
+
+	NET_DBG("NS nbr %p pending %p timeout to %s", nbr, data->pending,
+		net_sprint_ipv6_addr(&NET_IPV6_BUF(data->pending)->dst));
+
+	/* To unref when pending variable was set */
+	net_nbuf_unref(data->pending);
+
+	/* To unref the original buf allocation */
+	net_nbuf_unref(data->pending);
+
+	data->pending = NULL;
+
+	net_nbr_unref(nbr);
+}
+
 static struct net_nbr *nbr_new(struct net_if *iface,
 			       struct in6_addr *addr,
 			       enum net_nbr_state state)
@@ -257,9 +331,16 @@
 	nbr->iface = iface;
 
 	net_ipaddr_copy(&net_ipv6_nbr_data(nbr)->addr, addr);
-	net_ipv6_nbr_data(nbr)->state = state;
+	nbr_set_state(nbr, state);
 	net_ipv6_nbr_data(nbr)->pending = NULL;
 
+#if defined(CONFIG_NET_IPV6_ND)
+	k_delayed_work_init(&net_ipv6_nbr_data(nbr)->reachable,
+			    nd_reachable_timeout);
+#endif
+	k_delayed_work_init(&net_ipv6_nbr_data(nbr)->send_ns,
+			    ns_reply_timeout);
+
 	NET_DBG("nbr %p iface %p state %d IPv6 %s",
 		nbr, iface, state, net_sprint_ipv6_addr(addr));
 
@@ -305,7 +386,7 @@
 
 	return NULL;
 }
-#endif /* CONFIG_NET_IPV6_ND */
+#endif /* CONFIG_NET_IPV6_NBR_CACHE */
 
 const struct in6_addr *net_ipv6_unspecified_address(void)
 {
@@ -370,8 +451,7 @@
 				   net_context_get_ip_proto(context));
 }
 
-struct net_buf *net_ipv6_finalize_raw(struct net_buf *buf,
-				      uint8_t next_header)
+int net_ipv6_finalize_raw(struct net_buf *buf, uint8_t next_header)
 {
 	/* Set the length of the IPv6 header */
 	size_t total_len;
@@ -381,6 +461,7 @@
 		/* Check if we need to add RPL header to sent UDP packet. */
 		if (net_rpl_insert_header(buf) < 0) {
 			NET_DBG("RPL HBHO insert failed");
+			return -EINVAL;
 		}
 	}
 #endif
@@ -414,14 +495,12 @@
 							     IPPROTO_ICMPV6);
 	}
 
-	return buf;
+	return 0;
 }
 
-struct net_buf *net_ipv6_finalize(struct net_context *context,
-				  struct net_buf *buf)
+int net_ipv6_finalize(struct net_context *context, struct net_buf *buf)
 {
-	return net_ipv6_finalize_raw(buf,
-				     net_context_get_ip_proto(context));
+	return net_ipv6_finalize_raw(buf, net_context_get_ip_proto(context));
 }
 
 #if defined(CONFIG_NET_IPV6_DAD)
@@ -525,43 +604,7 @@
 #define dbg_addr_sent_tgt(...)
 #endif /* CONFIG_NET_DEBUG_IPV6 */
 
-#if defined(CONFIG_NET_IPV6_ND)
-#define NS_REPLY_TIMEOUT MSEC_PER_SEC
-
-static void ns_reply_timeout(struct k_work *work)
-{
-	/* We did not receive reply to a sent NS */
-	struct net_ipv6_nbr_data *data = CONTAINER_OF(work,
-						      struct net_ipv6_nbr_data,
-						      send_ns);
-
-	struct net_nbr *nbr = get_nbr_from_data(data);
-
-	if (!nbr) {
-		NET_DBG("NS timeout but no nbr data");
-		return;
-	}
-
-	if (!data->pending) {
-		/* Silently return, this is not an error as the work
-		 * cannot be cancelled in certain cases.
-		 */
-		return;
-	}
-
-	NET_DBG("NS nbr %p pending %p timeout to %s", nbr, data->pending,
-		net_sprint_ipv6_addr(&NET_IPV6_BUF(data->pending)->dst));
-
-	/* To unref when pending variable was set */
-	net_nbuf_unref(data->pending);
-
-	/* To unref the original buf allocation */
-	net_nbuf_unref(data->pending);
-
-	data->pending = NULL;
-
-	net_nbr_unref(nbr);
-}
+#if defined(CONFIG_NET_IPV6_NBR_CACHE)
 
 /* If the reserve has changed, we need to adjust it accordingly in the
  * fragment chain. This can only happen in IEEE 802.15.4 where the link
@@ -621,7 +664,13 @@
 		}
 
 		if (!copy_len) {
-			orig_frag = net_nbuf_frag_del(NULL, orig_frag);
+			struct net_buf *tmp = orig_frag;
+
+			orig_frag = orig_frag->frags;
+
+			tmp->frags = NULL;
+			net_nbuf_unref(tmp);
+
 			if (!orig_frag) {
 				break;
 			}
@@ -640,6 +689,8 @@
 	struct net_if *iface = NULL;
 	struct net_nbr *nbr;
 
+	NET_ASSERT(buf && buf->frags);
+
 	/* Workaround Linux bug, see:
 	 * https://jira.zephyrproject.org/browse/ZEP-1656
 	 */
@@ -719,10 +770,11 @@
 try_send:
 	nbr = nbr_lookup(&net_neighbor.table, net_nbuf_iface(buf), nexthop);
 
-	NET_DBG("Neighbor lookup %p (%d) iface %p addr %s", nbr,
+	NET_DBG("Neighbor lookup %p (%d) iface %p addr %s state %s", nbr,
 		nbr ? nbr->idx : NET_NBR_LLADDR_UNKNOWN,
 		net_nbuf_iface(buf),
-		net_sprint_ipv6_addr(nexthop));
+		net_sprint_ipv6_addr(nexthop),
+		net_nbr_state2str(net_ipv6_nbr_data(nbr)->state));
 
 	if (nbr && nbr->idx != NET_NBR_LLADDR_UNKNOWN) {
 		struct net_linkaddr_storage *lladdr;
@@ -735,9 +787,23 @@
 		NET_DBG("Neighbor %p addr %s", nbr,
 			net_sprint_ll_addr(lladdr->addr, lladdr->len));
 
+		/* Start the NUD if we are in STALE state.
+		 * See RFC 4861 ch 7.3.3 for details.
+		 */
+#if defined(CONFIG_NET_IPV6_ND)
+		if (net_ipv6_nbr_data(nbr)->state == NET_NBR_STALE) {
+			nbr_set_state(nbr, NET_NBR_DELAY);
+
+			k_delayed_work_submit(
+				&net_ipv6_nbr_data(nbr)->reachable,
+				DELAY_FIRST_PROBE_TIME);
+		}
+#endif
+
 		return update_ll_reserve(buf, nexthop);
 	}
 
+#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_nbuf_iface(buf),
 			     buf,
@@ -751,7 +817,13 @@
 		return NULL;
 	}
 
-	NET_DBG("Buf %p will be sent later", buf);
+	NET_DBG("Buf %p (frag %p) will be sent later", buf, buf->frags);
+#else
+	NET_DBG("Buf %p (frag %p) cannot be sent, dropping it.", buf,
+		buf->frags);
+
+	net_nbuf_unref(buf);
+#endif /* CONFIG_NET_IPV6_ND */
 
 	return NULL;
 }
@@ -869,6 +941,12 @@
 
 			return;
 		}
+
+		/* Send NS so that we can verify that the neighbor is
+		 * reachable.
+		 */
+		net_ipv6_send_ns(net_nbuf_iface(buf), NULL, NULL, NULL,
+				 &net_ipv6_nbr_data(nbr)->addr, false);
 	}
 
 	if (net_nbr_link(nbr, net_nbuf_iface(buf), &lladdr) == -EALREADY) {
@@ -886,11 +964,11 @@
 			net_linkaddr_set(cached_lladdr, lladdr.addr,
 					 lladdr.len);
 
-			net_ipv6_nbr_data(nbr)->state = NET_NBR_STALE;
+			nbr_set_state(nbr, NET_NBR_STALE);
 		} else {
 			if (net_ipv6_nbr_data(nbr)->state ==
 							NET_NBR_INCOMPLETE) {
-				net_ipv6_nbr_data(nbr)->state = NET_NBR_STALE;
+				nbr_set_state(nbr, NET_NBR_STALE);
 			}
 		}
 	}
@@ -1138,17 +1216,20 @@
 
 	return NET_DROP;
 }
+#endif /* CONFIG_NET_IPV6_NBR_CACHE */
 
+#if defined(CONFIG_NET_IPV6_ND)
 static void nd_reachable_timeout(struct k_work *work)
 {
 	struct net_ipv6_nbr_data *data = CONTAINER_OF(work,
 						      struct net_ipv6_nbr_data,
-						      send_ns);
+						      reachable);
 
 	struct net_nbr *nbr = get_nbr_from_data(data);
 
 	if (!data || !nbr) {
-		NET_DBG("ND reachable timeout but no nbr data");
+		NET_DBG("ND reachable timeout but no nbr data "
+			"(nbr %p data %p)", nbr, data);
 		return;
 	}
 
@@ -1187,7 +1268,8 @@
 
 		NET_DBG("nbr %p moving %s state to PROBE (%d)",
 			nbr, net_sprint_ipv6_addr(&data->addr), data->state);
-		break;
+
+		/* Intentionally continuing to probe state */
 
 	case NET_NBR_PROBE:
 		if (data->ns_count >= MAX_UNICAST_SOLICIT) {
@@ -1211,6 +1293,10 @@
 
 			net_ipv6_send_ns(nbr->iface, NULL, NULL, NULL,
 					 &data->addr, false);
+
+			k_delayed_work_submit(
+				&net_ipv6_nbr_data(nbr)->reachable,
+				RETRANS_TIMER);
 		}
 		break;
 	}
@@ -1224,12 +1310,14 @@
 
 	NET_ASSERT_INFO(time, "Zero reachable timeout!");
 
-	k_delayed_work_init(&net_ipv6_nbr_data(nbr)->reachable,
-			    nd_reachable_timeout);
+	NET_DBG("Starting reachable timer nbr %p data %p time %d ms",
+		nbr, net_ipv6_nbr_data(nbr), time);
 
 	k_delayed_work_submit(&net_ipv6_nbr_data(nbr)->reachable, time);
 }
+#endif /* CONFIG_NET_IPV6_ND */
 
+#if defined(CONFIG_NET_IPV6_NBR_CACHE)
 static inline bool handle_na_neighbor(struct net_buf *buf,
 				      struct net_icmpv6_nd_opt_hdr *hdr,
 				      uint8_t *tllao)
@@ -1307,13 +1395,17 @@
 		}
 
 		if (net_is_solicited(buf)) {
-			net_ipv6_nbr_data(nbr)->state = NET_NBR_REACHABLE;
+			nbr_set_state(nbr, NET_NBR_REACHABLE);
 			net_ipv6_nbr_data(nbr)->ns_count = 0;
 
+			/* We might have active timer from PROBE */
+			k_delayed_work_cancel(
+				&net_ipv6_nbr_data(nbr)->reachable);
+
 			net_ipv6_nbr_set_reachable_timer(net_nbuf_iface(buf),
 							 nbr);
 		} else {
-			net_ipv6_nbr_data(nbr)->state = NET_NBR_STALE;
+			nbr_set_state(nbr, NET_NBR_STALE);
 		}
 
 		net_ipv6_nbr_data(nbr)->is_router = net_is_router(buf);
@@ -1326,7 +1418,7 @@
 	 */
 	if (!net_is_override(buf) && lladdr_changed) {
 		if (net_ipv6_nbr_data(nbr)->state == NET_NBR_REACHABLE) {
-			net_ipv6_nbr_data(nbr)->state = NET_NBR_STALE;
+			nbr_set_state(nbr, NET_NBR_STALE);
 		}
 
 		return false;
@@ -1347,13 +1439,17 @@
 		}
 
 		if (net_is_solicited(buf)) {
-			net_ipv6_nbr_data(nbr)->state = NET_NBR_REACHABLE;
+			nbr_set_state(nbr, NET_NBR_REACHABLE);
+
+			/* We might have active timer from PROBE */
+			k_delayed_work_cancel(
+				&net_ipv6_nbr_data(nbr)->reachable);
 
 			net_ipv6_nbr_set_reachable_timer(net_nbuf_iface(buf),
 							 nbr);
 		} else {
 			if (lladdr_changed) {
-				net_ipv6_nbr_data(nbr)->state = NET_NBR_STALE;
+				nbr_set_state(nbr, NET_NBR_STALE);
 			}
 		}
 	}
@@ -1608,8 +1704,6 @@
 
 		NET_DBG("Setting timeout %d for NS", NS_REPLY_TIMEOUT);
 
-		k_delayed_work_init(&net_ipv6_nbr_data(nbr)->send_ns,
-				    ns_reply_timeout);
 		k_delayed_work_submit(&net_ipv6_nbr_data(nbr)->send_ns,
 				      NS_REPLY_TIMEOUT);
 	}
@@ -1620,6 +1714,12 @@
 			  &NET_ICMPV6_NS_BUF(buf)->tgt);
 
 	if (net_send_data(buf) < 0) {
+		NET_DBG("Cannot send NS %p (pending %p)", buf, pending);
+
+		if (pending) {
+			nbr_clear_ns_pending(net_ipv6_nbr_data(nbr));
+		}
+
 		goto drop;
 	}
 
@@ -1633,7 +1733,9 @@
 
 	return -EINVAL;
 }
+#endif /* CONFIG_NET_IPV6_NBR_CACHE */
 
+#if defined(CONFIG_NET_IPV6_ND)
 int net_ipv6_send_rs(struct net_if *iface)
 {
 	struct net_buf *buf, *frag;
@@ -1781,11 +1883,11 @@
 			net_linkaddr_set(cached_lladdr, lladdr.addr,
 					 lladdr.len);
 
-			net_ipv6_nbr_data(*nbr)->state = NET_NBR_STALE;
+			nbr_set_state(*nbr, NET_NBR_STALE);
 		} else {
 			if (net_ipv6_nbr_data(*nbr)->state ==
 							NET_NBR_INCOMPLETE) {
-				net_ipv6_nbr_data(*nbr)->state = NET_NBR_STALE;
+				nbr_set_state(*nbr, NET_NBR_STALE);
 			}
 		}
 	}
@@ -1802,16 +1904,16 @@
 
 	prefix = net_if_ipv6_prefix_lookup(net_nbuf_iface(buf),
 					   &prefix_info->prefix,
-					   prefix_info->len);
+					   prefix_info->prefix_len);
 	if (!prefix) {
 		if (!prefix_info->valid_lifetime) {
 			return;
 		}
 
 		prefix = net_if_ipv6_prefix_add(net_nbuf_iface(buf),
-					&prefix_info->prefix,
-					prefix_info->len,
-					prefix_info->valid_lifetime);
+						&prefix_info->prefix,
+						prefix_info->prefix_len,
+						prefix_info->valid_lifetime);
 		if (prefix) {
 			NET_DBG("Interface %p add prefix %s/%d lifetime %u",
 				net_nbuf_iface(buf),
@@ -1821,7 +1923,7 @@
 		} else {
 			NET_ERR("Prefix %s/%d could not be added to iface %p",
 				net_sprint_ipv6_addr(&prefix_info->prefix),
-				prefix_info->len,
+				prefix_info->prefix_len,
 				net_nbuf_iface(buf));
 
 			return;
@@ -1833,7 +1935,7 @@
 		NET_DBG("Interface %p delete prefix %s/%d",
 			net_nbuf_iface(buf),
 			net_sprint_ipv6_addr(&prefix_info->prefix),
-			prefix_info->len);
+			prefix_info->prefix_len);
 
 		net_if_ipv6_prefix_rm(net_nbuf_iface(buf),
 				      &prefix->prefix,
@@ -1867,12 +1969,7 @@
 
 static inline uint32_t remaining(struct k_delayed_work *work)
 {
-	if (work->timeout.delta_ticks_from_prev < 0) {
-		return NET_IPV6_ND_INFINITE_LIFETIME;
-	}
-
-	return (uint32_t)work->timeout.delta_ticks_from_prev /
-		sys_clock_ticks_per_sec;
+	return k_delayed_work_remaining_get(work) / MSEC_PER_SEC;
 }
 
 static inline void handle_prefix_autonomous(struct net_buf *buf,
@@ -1983,6 +2080,21 @@
 	context.len = len * 8 - 2;
 
 	frag = net_nbuf_read_u8(frag, offset, pos, &context.context_len);
+
+	/* RFC 6775, 4.2
+	 * Context Length: 8-bit unsigned integer.  The number of leading
+	 * bits in the Context Prefix field that are valid.  The value ranges
+	 * from 0 to 128.  If it is more than 64, then the Length MUST be 3.
+	 */
+	if (context.context_len > 64 && len != 3) {
+		return NULL;
+	}
+
+	if (context.context_len <= 64 && len != 2) {
+		return NULL;
+	}
+
+	context.context_len = context.context_len / 8;
 	frag = net_nbuf_read_u8(frag, *pos, pos, &context.flag);
 
 	/* Skip reserved bytes */
@@ -2001,13 +2113,20 @@
 		 */
 		frag = net_nbuf_read(frag, *pos, pos, 8,
 				     context.prefix.s6_addr);
-		memset(context.prefix.s6_addr + 8, 0, 8);
 	}
 
 	if (!frag && *pos) {
 		return NULL;
 	}
 
+	/* context_len: The number of leading bits in the Context Prefix
+	 * field that are valid. So set remaining data to zero.
+	 */
+	if (context.context_len != sizeof(struct in6_addr)) {
+		memset(context.prefix.s6_addr + context.context_len, 0,
+		       sizeof(struct in6_addr) - context.context_len);
+	}
+
 	net_6lo_set_context(net_nbuf_iface(buf), &context);
 
 	return frag;
@@ -2285,7 +2404,10 @@
 	/* Insert the actual multicast record(s) here */
 	net_buf_frag_add(buf, frags);
 
-	buf = net_ipv6_finalize_raw(buf, NET_IPV6_NEXTHDR_HBHO);
+	ret = net_ipv6_finalize_raw(buf, NET_IPV6_NEXTHDR_HBHO);
+	if (ret < 0) {
+		goto drop;
+	}
 
 	net_nbuf_set_ext_len(buf, ROUTER_ALERT_LEN);
 
@@ -2295,17 +2417,20 @@
 
 	ret = net_send_data(buf);
 	if (ret < 0) {
-		net_nbuf_unref(buf);
-		net_stats_update_icmp_drop();
-		net_stats_update_ipv6_mld_drop();
-
-		return ret;
+		goto drop;
 	}
 
 	net_stats_update_icmp_sent();
 	net_stats_update_ipv6_mld_sent();
 
 	return 0;
+
+drop:
+	net_nbuf_unref(buf);
+	net_stats_update_icmp_drop();
+	net_stats_update_ipv6_mld_drop();
+
+	return ret;
 }
 
 static int send_mldv2(struct net_if *iface, const struct in6_addr *addr,
@@ -2474,7 +2599,7 @@
 };
 #endif /* CONFIG_NET_IPV6_MLD */
 
-#if defined(CONFIG_NET_IPV6_ND)
+#if defined(CONFIG_NET_IPV6_NBR_CACHE)
 static struct net_icmpv6_handler ns_input_handler = {
 	.type = NET_ICMPV6_NS,
 	.code = 0,
@@ -2486,7 +2611,9 @@
 	.code = 0,
 	.handler = handle_na_input,
 };
+#endif /* CONFIG_NET_IPV6_NBR_CACHE */
 
+#if defined(CONFIG_NET_IPV6_ND)
 static struct net_icmpv6_handler ra_input_handler = {
 	.type = NET_ICMPV6_RA,
 	.code = 0,
@@ -2496,9 +2623,11 @@
 
 void net_ipv6_init(void)
 {
-#if defined(CONFIG_NET_IPV6_ND)
+#if defined(CONFIG_NET_IPV6_NBR_CACHE)
 	net_icmpv6_register_handler(&ns_input_handler);
 	net_icmpv6_register_handler(&na_input_handler);
+#endif
+#if defined(CONFIG_NET_IPV6_ND)
 	net_icmpv6_register_handler(&ra_input_handler);
 #endif
 #if defined(CONFIG_NET_IPV6_MLD)
diff --git a/subsys/net/ip/ipv6.h b/subsys/net/ip/ipv6.h
index 4ac87e6..471bb48 100644
--- a/subsys/net/ip/ipv6.h
+++ b/subsys/net/ip/ipv6.h
@@ -72,6 +72,8 @@
 	NET_NBR_PROBE,
 };
 
+const char *net_nbr_state2str(enum net_nbr_state state);
+
 /**
  * @brief IPv6 neighbor information.
  */
@@ -171,10 +173,9 @@
  * @param buf Network buffer
  * @param next_header Protocol type of the next header after IPv6 header.
  *
- * @return Return network buffer that contains the IPv6 packet.
+ * @return Return 0 on Success, < 0 on Failure.
  */
-struct net_buf *net_ipv6_finalize_raw(struct net_buf *buf,
-				      uint8_t next_header);
+int net_ipv6_finalize_raw(struct net_buf *buf, uint8_t next_header);
 
 /**
  * @brief Finalize IPv6 packet. It should be called right before
@@ -185,10 +186,9 @@
  * @param context Network context for a connection
  * @param buf Network buffer
  *
- * @return Return network buffer that contains the IPv6 packet.
+ * @return Return 0 on Success, < 0 on Failure.
  */
-struct net_buf *net_ipv6_finalize(struct net_context *context,
-				  struct net_buf *buf);
+int net_ipv6_finalize(struct net_context *context, struct net_buf *buf);
 
 #if defined(CONFIG_NET_IPV6_MLD)
 /**
@@ -215,7 +215,16 @@
 #define net_ipv6_mld_leave(...)
 #endif /* CONFIG_NET_IPV6_MLD */
 
-#if defined(CONFIG_NET_IPV6_ND)
+/**
+ * @typedef net_nbr_cb_t
+ * @brief Callback used while iterating over neighbors.
+ *
+ * @param nbr A valid pointer on current neighbor.
+ * @param user_data A valid pointer on some user data or NULL
+ */
+typedef void (*net_nbr_cb_t)(struct net_nbr *nbr, void *user_data);
+
+#if defined(CONFIG_NET_IPV6_NBR_CACHE)
 /**
  * @brief Make sure the link layer address is set according to
  * destination address. If the ll address is not yet known, then
@@ -293,24 +302,6 @@
 bool net_ipv6_nbr_rm(struct net_if *iface, struct in6_addr *addr);
 
 /**
- * @brief Set the neighbor reachable timer.
- *
- * @param iface A valid pointer on a network interface
- * @param nbr Neighbor struct pointer
- */
-void net_ipv6_nbr_set_reachable_timer(struct net_if *iface,
-				      struct net_nbr *nbr);
-
-/**
- * @typedef net_nbr_cb_t
- * @brief Callback used while iterating over neighbors.
- *
- * @param nbr A valid pointer on current neighbor.
- * @param user_data A valid pointer on some user data or NULL
- */
-typedef void (*net_nbr_cb_t)(struct net_nbr *nbr, void *user_data);
-
-/**
  * @brief Go through all the neighbors and call callback for each of them.
  *
  * @param cb User supplied callback function to call.
@@ -318,7 +309,7 @@
  */
 void net_ipv6_nbr_foreach(net_nbr_cb_t cb, void *user_data);
 
-#else /* CONFIG_NET_IPV6_ND */
+#else /* CONFIG_NET_IPV6_NBR_CACHE */
 static inline struct net_buf *net_ipv6_prepare_for_send(struct net_buf *buf)
 {
 	return buf;
@@ -346,6 +337,28 @@
 	return NULL;
 }
 
+static inline bool net_ipv6_nbr_rm(struct net_if *iface, struct in6_addr *addr)
+{
+	return true;
+}
+
+static inline void net_ipv6_nbr_foreach(net_nbr_cb_t cb, void *user_data)
+{
+	return;
+}
+#endif /* CONFIG_NET_IPV6_NBR_CACHE */
+
+#if defined(CONFIG_NET_IPV6_ND)
+/**
+ * @brief Set the neighbor reachable timer.
+ *
+ * @param iface A valid pointer on a network interface
+ * @param nbr Neighbor struct pointer
+ */
+void net_ipv6_nbr_set_reachable_timer(struct net_if *iface,
+				      struct net_nbr *nbr);
+
+#else /* CONFIG_NET_IPV6_ND */
 static inline void net_ipv6_nbr_set_reachable_timer(struct net_if *iface,
 						    struct net_nbr *nbr)
 {
diff --git a/subsys/net/ip/l2/bluetooth.c b/subsys/net/ip/l2/bluetooth.c
index 8d3fc6e..c055a20 100644
--- a/subsys/net/ip/l2/bluetooth.c
+++ b/subsys/net/ip/l2/bluetooth.c
@@ -52,7 +52,7 @@
 
 static enum net_verdict net_bt_recv(struct net_if *iface, struct net_buf *buf)
 {
-	NET_DBG("iface %p buf %p len %u", iface, buf, net_buf_frags_len(buf));
+	NET_DBG("iface %p buf %p len %zu", iface, buf, net_buf_frags_len(buf));
 
 	if (!net_6lo_uncompress(buf)) {
 		NET_DBG("Packet decompression failed");
@@ -66,7 +66,7 @@
 {
 	struct bt_context *ctxt = net_if_get_device(iface)->driver_data;
 
-	NET_DBG("iface %p buf %p len %u", iface, buf, net_buf_frags_len(buf));
+	NET_DBG("iface %p buf %p len %zu", iface, buf, net_buf_frags_len(buf));
 
 	/* Only accept IPv6 packets */
 	if (net_nbuf_family(buf) != AF_INET6) {
@@ -174,7 +174,7 @@
 	struct bt_context *ctxt = CHAN_CTXT(chan);
 	struct net_buf *nbuf;
 
-	NET_DBG("Incoming data channel %p len %u", chan,
+	NET_DBG("Incoming data channel %p len %zu", chan,
 		net_buf_frags_len(buf));
 
 	/* Get buffer for bearer / protocol related data */
@@ -226,7 +226,7 @@
 	struct bt_context *ctxt = net_if_get_device(iface)->driver_data;
 	int ret;
 
-	NET_DBG("iface %p buf %p len %u", iface, buf, net_buf_frags_len(buf));
+	NET_DBG("iface %p buf %p len %zu", iface, buf, net_buf_frags_len(buf));
 
 	ret = bt_l2cap_chan_send(&ctxt->ipsp_chan.chan, buf);
 	if (ret < 0) {
diff --git a/subsys/net/ip/l2/ieee802154/ieee802154_mgmt.c b/subsys/net/ip/l2/ieee802154/ieee802154_mgmt.c
index ce7229a..03b05f8 100644
--- a/subsys/net/ip/l2/ieee802154/ieee802154_mgmt.c
+++ b/subsys/net/ip/l2/ieee802154/ieee802154_mgmt.c
@@ -442,7 +442,7 @@
 	struct ieee802154_context *ctx = net_if_l2_data(iface);
 	uint16_t *value;
 
-	if (mgmt_request != NET_REQUEST_IEEE802154_SET_EXT_ADDR &&
+	if (mgmt_request != NET_REQUEST_IEEE802154_GET_EXT_ADDR &&
 	    (len != sizeof(uint16_t) || !data)) {
 		return -EINVAL;
 	}
diff --git a/subsys/net/ip/l2/ieee802154/ieee802154_shell.c b/subsys/net/ip/l2/ieee802154/ieee802154_shell.c
index f6e78ea..e96d5a3 100644
--- a/subsys/net/ip/l2/ieee802154/ieee802154_shell.c
+++ b/subsys/net/ip/l2/ieee802154/ieee802154_shell.c
@@ -80,10 +80,10 @@
 
 	if (net_mgmt(NET_REQUEST_IEEE802154_ASSOCIATE, iface,
 		     &params, sizeof(struct ieee802154_req_params))) {
-		printk("Could not associate to %s on PAN ID %u",
+		printk("Could not associate to %s on PAN ID %u\n",
 		       argv[2], params.pan_id);
 	} else {
-		printk("Associated to PAN ID %u", params.pan_id);
+		printk("Associated to PAN ID %u\n", params.pan_id);
 	}
 
 	return 0;
@@ -275,7 +275,7 @@
 	uint8_t addr[IEEE802154_EXT_ADDR_LENGTH];
 
 	if (strlen(argv[2]) != 23) {
-		printk("23 characters needed");
+		printk("23 characters needed\n");
 		return 0;
 	}
 
@@ -310,6 +310,8 @@
 				printk(":");
 			}
 		}
+
+		printk("\n");
 	}
 
 	return 0;
diff --git a/subsys/net/ip/net_context.c b/subsys/net/ip/net_context.c
index a2f2a7b..b72fb4f7 100644
--- a/subsys/net/ip/net_context.c
+++ b/subsys/net/ip/net_context.c
@@ -72,9 +72,7 @@
 				 struct net_buf *buf,
 				 void *user_data);
 
-static void set_appdata_values(struct net_buf *buf,
-			       enum net_ip_protocol proto,
-			       size_t total_len);
+static void set_appdata_values(struct net_buf *buf, enum net_ip_protocol proto);
 
 #if defined(CONFIG_NET_TCP)
 static struct sockaddr *create_sockaddr(struct net_buf *buf,
@@ -526,7 +524,9 @@
 			}
 		}
 
-		NET_DBG("Context %p binding to [%s]:%d iface %p", context,
+		NET_DBG("Context %p binding to %s [%s]:%d iface %p",
+			context,
+			net_proto2str(net_context_get_ip_proto(context)),
 			net_sprint_ipv6_addr(ptr), ntohs(addr6->sin6_port),
 			iface);
 
@@ -595,7 +595,9 @@
 			}
 		}
 
-		NET_DBG("Context %p binding to %s:%d iface %p", context,
+		NET_DBG("Context %p binding to %s %s:%d iface %p",
+			context,
+			net_proto2str(net_context_get_ip_proto(context)),
 			net_sprint_ipv4_addr(ptr),
 			ntohs(addr4->sin_port), iface);
 
@@ -815,7 +817,7 @@
 		return NET_DROP;
 	}
 
-	set_appdata_values(buf, IPPROTO_TCP, net_buf_frags_len(buf));
+	set_appdata_values(buf, IPPROTO_TCP);
 	context->tcp->send_ack += net_nbuf_appdatalen(buf);
 
 	ret = packet_received(conn, buf, context->tcp->recv_user_data);
@@ -1591,13 +1593,15 @@
 			     const struct sockaddr *dst_addr,
 			     struct net_buf **out_buf)
 {
+	int r = 0;
+
 #if defined(CONFIG_NET_IPV6)
 	if (net_nbuf_family(buf) == AF_INET6) {
 		struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)dst_addr;
 
 		buf = net_ipv6_create(context, buf, NULL, &addr6->sin6_addr);
 		buf = net_udp_append(context, buf, ntohs(addr6->sin6_port));
-		buf = net_ipv6_finalize(context, buf);
+		r = net_ipv6_finalize(context, buf);
 	} else
 #endif /* CONFIG_NET_IPV6 */
 
@@ -1607,7 +1611,7 @@
 
 		buf = net_ipv4_create(context, buf, NULL, &addr4->sin_addr);
 		buf = net_udp_append(context, buf, ntohs(addr4->sin_port));
-		buf = net_ipv4_finalize(context, buf);
+		r = net_ipv4_finalize(context, buf);
 	} else
 #endif /* CONFIG_NET_IPV4 */
 	{
@@ -1616,7 +1620,7 @@
 
 	*out_buf = buf;
 
-	return 0;
+	return r;
 }
 #endif /* CONFIG_NET_UDP */
 
@@ -1784,17 +1788,14 @@
 	return sendto(buf, dst_addr, addrlen, cb, timeout, token, user_data);
 }
 
-static void set_appdata_values(struct net_buf *buf,
-			       enum net_ip_protocol proto,
-			       size_t total_len)
+static void set_appdata_values(struct net_buf *buf, enum net_ip_protocol proto)
 {
+	size_t total_len = net_buf_frags_len(buf);
+
 #if defined(CONFIG_NET_UDP)
 	if (proto == IPPROTO_UDP) {
 		net_nbuf_set_appdata(buf, net_nbuf_udp_data(buf) +
 				     sizeof(struct net_udp_hdr));
-		net_nbuf_set_appdatalen(buf, total_len -
-					net_nbuf_ip_hdr_len(buf) -
-					sizeof(struct net_udp_hdr));
 	} else
 #endif /* CONFIG_NET_UDP */
 
@@ -1802,18 +1803,17 @@
 	if (proto == IPPROTO_TCP) {
 		net_nbuf_set_appdata(buf, net_nbuf_udp_data(buf) +
 				     tcp_hdr_len(buf));
-		net_nbuf_set_appdatalen(buf, total_len -
-					net_nbuf_ip_hdr_len(buf) -
-					tcp_hdr_len(buf));
 	} else
 #endif /* CONFIG_NET_TCP */
 	{
 		net_nbuf_set_appdata(buf, net_nbuf_ip_data(buf) +
 				     net_nbuf_ip_hdr_len(buf));
-		net_nbuf_set_appdatalen(buf, total_len -
-					net_nbuf_ip_hdr_len(buf));
 	}
 
+	net_nbuf_set_appdatalen(buf, total_len -
+				(net_nbuf_appdata(buf) -
+				 net_nbuf_ip_data(buf)));
+
 	NET_ASSERT_INFO(net_nbuf_appdatalen(buf) < total_len,
 			"Wrong appdatalen %u, total %zu",
 			net_nbuf_appdatalen(buf), total_len);
@@ -1831,49 +1831,37 @@
 	net_context_set_iface(context, net_nbuf_iface(buf));
 	net_nbuf_set_context(buf, context);
 
-	if (context->recv_cb) {
-		size_t total_len = net_buf_frags_len(buf);
-
-		if (net_context_get_ip_proto(context) != IPPROTO_TCP) {
-			/* TCP packets get appdata earlier in
-			 * tcp_established().
-			 */
-			if (net_nbuf_family(buf) == AF_INET6) {
-				set_appdata_values(buf,
-						   NET_IPV6_BUF(buf)->nexthdr,
-						   total_len);
-			} else {
-				set_appdata_values(buf,
-						   NET_IPV4_BUF(buf)->proto,
-						   total_len);
-			}
-		}
-#if defined(CONFIG_NET_TCP)
-		else if (net_context_get_type(context) == SOCK_STREAM) {
-			if (net_nbuf_appdatalen(buf) == 0) {
-				net_nbuf_unref(buf);
-				return NET_OK;
-			}
-		}
-#endif /* CONFIG_NET_TCP */
-
-		NET_DBG("Set appdata %p to len %u (total %zu)",
-			net_nbuf_appdata(buf), net_nbuf_appdatalen(buf),
-			total_len);
-
-		context->recv_cb(context, buf, 0, user_data);
-
-#if defined(CONFIG_NET_CONTEXT_SYNC_RECV)
-		k_sem_give(&context->recv_data_wait);
-#endif /* CONFIG_NET_CONTEXT_SYNC_RECV */
-
-		return NET_OK;
-	}
-
 	/* If there is no callback registered, then we can only drop
 	 * the packet.
 	 */
-	return NET_DROP;
+
+	if (!context->recv_cb) {
+		return NET_DROP;
+	}
+
+	if (net_context_get_ip_proto(context) != IPPROTO_TCP) {
+		/* TCP packets get appdata earlier in tcp_established(). */
+		set_appdata_values(buf, IPPROTO_UDP);
+	}
+#if defined(CONFIG_NET_TCP)
+	else if (net_context_get_type(context) == SOCK_STREAM) {
+		if (net_nbuf_appdatalen(buf) == 0) {
+			net_nbuf_unref(buf);
+			return NET_OK;
+		}
+	}
+#endif /* CONFIG_NET_TCP */
+	NET_DBG("Set appdata %p to len %u (total %zu)",
+		net_nbuf_appdata(buf), net_nbuf_appdatalen(buf),
+		net_buf_frags_len(buf));
+
+	context->recv_cb(context, buf, 0, user_data);
+
+#if defined(CONFIG_NET_CONTEXT_SYNC_RECV)
+	k_sem_give(&context->recv_data_wait);
+#endif /* CONFIG_NET_CONTEXT_SYNC_RECV */
+
+	return NET_OK;
 }
 
 #if defined(CONFIG_NET_UDP)
diff --git a/subsys/net/ip/net_core.c b/subsys/net/ip/net_core.c
index 8bb489b..6fa3abd 100644
--- a/subsys/net/ip/net_core.c
+++ b/subsys/net/ip/net_core.c
@@ -63,6 +63,7 @@
 
 static struct k_fifo rx_queue;
 static k_tid_t rx_tid;
+static K_SEM_DEFINE(startup_sync, 0, UINT_MAX);
 
 #if defined(CONFIG_NET_IPV6)
 static inline enum net_verdict process_icmpv6_pkt(struct net_buf *buf,
@@ -126,6 +127,9 @@
 {
 	uint8_t opt_type, opt_len;
 	uint16_t length = 0, loc;
+#if defined(CONFIG_NET_RPL)
+	bool result;
+#endif
 
 	if (len > total_len) {
 		NET_DBG("Corrupted packet, extension header %d too long "
@@ -158,10 +162,17 @@
 #if defined(CONFIG_NET_RPL)
 		case NET_IPV6_EXT_HDR_OPT_RPL:
 			NET_DBG("Processing RPL option");
-			if (!net_rpl_verify_header(buf, loc, &loc)) {
+			frag = net_rpl_verify_header(buf, frag, loc, &loc,
+						     &result);
+			if (!result) {
 				NET_DBG("RPL option error, packet dropped");
 				goto drop;
 			}
+
+			if (!frag && *pos == 0xffff) {
+				goto drop;
+			}
+
 			*verdict = NET_CONTINUE;
 			return frag;
 #endif
@@ -530,8 +541,16 @@
 
 	/* Starting TX side. The ordering is important here and the TX
 	 * can only be started when RX side is ready to receive packets.
+	 * We synchronize the startup of the device so that both RX and TX
+	 * are only started fully when both are ready to receive or send
+	 * data.
 	 */
-	net_if_init();
+	net_if_init(&startup_sync);
+
+	k_sem_take(&startup_sync, K_FOREVER);
+
+	/* This will take the interface up and start everything. */
+	net_if_post_init();
 
 	while (1) {
 #if defined(CONFIG_NET_STATISTICS) || defined(CONFIG_NET_DEBUG_CORE)
@@ -693,10 +712,17 @@
 /* Called by driver when an IP packet has been received */
 int net_recv_data(struct net_if *iface, struct net_buf *buf)
 {
+	NET_ASSERT(buf && buf->frags);
+	NET_ASSERT(iface);
+
 	if (!buf->frags) {
 		return -ENODATA;
 	}
 
+	if (!atomic_test_bit(iface->flags, NET_IF_UP)) {
+		return -ENETDOWN;
+	}
+
 	NET_DBG("fifo %p iface %p buf %p len %zu", &rx_queue, iface, buf,
 		net_buf_frags_len(buf));
 
diff --git a/subsys/net/ip/net_if.c b/subsys/net/ip/net_if.c
index 10ab03d..eab8514 100644
--- a/subsys/net/ip/net_if.c
+++ b/subsys/net/ip/net_if.c
@@ -176,10 +176,6 @@
 	int ev_count = 0;
 
 	for (iface = __net_if_start; iface != __net_if_end; iface++) {
-		if (!atomic_test_bit(iface->flags, NET_IF_UP)) {
-			continue;
-		}
-
 		k_poll_event_init(&__net_if_event_start[ev_count],
 				  K_POLL_TYPE_FIFO_DATA_AVAILABLE,
 				  K_POLL_MODE_NOTIFY_ONLY,
@@ -190,11 +186,14 @@
 	return ev_count;
 }
 
-static void net_if_tx_thread(void)
+static void net_if_tx_thread(struct k_sem *startup_sync)
 {
 	NET_DBG("Starting TX thread (stack %d bytes)",
 		CONFIG_NET_TX_STACK_SIZE);
 
+	/* This will allow RX thread to start to receive data. */
+	k_sem_give(startup_sync);
+
 	while (1) {
 		int ev_count;
 
@@ -219,9 +218,6 @@
 	k_fifo_init(&iface->tx_queue);
 
 	api->init(iface);
-
-	/* Attempt to bring the interface up */
-	net_if_up(iface);
 }
 
 enum net_verdict net_if_send_data(struct net_if *iface, struct net_buf *buf)
@@ -429,7 +425,6 @@
 		net_sprint_ipv6_addr(&ifaddr->address.in6_addr));
 
 	if (!net_ipv6_start_dad(iface, ifaddr)) {
-		k_delayed_work_init(&ifaddr->dad_timer, dad_timeout);
 		k_delayed_work_submit(&ifaddr->dad_timer, DAD_TIMEOUT);
 	}
 }
@@ -474,7 +469,6 @@
 	NET_DBG("Interface %p", iface);
 
 	if (!net_ipv6_start_rs(iface)) {
-		k_delayed_work_init(&iface->rs_timer, rs_timeout);
 		k_delayed_work_submit(&iface->rs_timer, RS_TIMEOUT);
 	}
 }
@@ -552,6 +546,36 @@
 	return NULL;
 }
 
+static inline void net_if_addr_init(struct net_if_addr *ifaddr,
+				    struct in6_addr *addr,
+				    enum net_addr_type addr_type,
+				    uint32_t vlifetime)
+{
+	ifaddr->is_used = true;
+	ifaddr->address.family = AF_INET6;
+	ifaddr->addr_type = addr_type;
+	net_ipaddr_copy(&ifaddr->address.in6_addr, addr);
+
+#if defined(CONFIG_NET_IPV6_DAD)
+	k_delayed_work_init(&ifaddr->dad_timer, dad_timeout);
+#endif
+
+	/* FIXME - set the mcast addr for this node */
+
+	if (vlifetime) {
+		ifaddr->is_infinite = false;
+
+		k_delayed_work_init(&ifaddr->lifetime, ipv6_addr_expired);
+
+		NET_DBG("Expiring %s in %u secs", net_sprint_ipv6_addr(addr),
+			vlifetime);
+
+		net_if_ipv6_addr_update_lifetime(ifaddr, vlifetime);
+	} else {
+		ifaddr->is_infinite = true;
+	}
+}
+
 struct net_if_addr *net_if_ipv6_addr_add(struct net_if *iface,
 					 struct in6_addr *addr,
 					 enum net_addr_type addr_type,
@@ -570,28 +594,8 @@
 			continue;
 		}
 
-		iface->ipv6.unicast[i].is_used = true;
-		iface->ipv6.unicast[i].address.family = AF_INET6;
-		iface->ipv6.unicast[i].addr_type = addr_type;
-		memcpy(&iface->ipv6.unicast[i].address.in6_addr, addr, 16);
-
-		/* FIXME - set the mcast addr for this node */
-
-		if (vlifetime) {
-			iface->ipv6.unicast[i].is_infinite = false;
-
-			k_delayed_work_init(
-				&iface->ipv6.unicast[i].lifetime,
-				ipv6_addr_expired);
-
-			NET_DBG("Expiring %s in %u secs",
-				net_sprint_ipv6_addr(addr), vlifetime);
-
-			net_if_ipv6_addr_update_lifetime(
-				&iface->ipv6.unicast[i], vlifetime);
-		} else {
-			iface->ipv6.unicast[i].is_infinite = true;
-		}
+		net_if_addr_init(&iface->ipv6.unicast[i], addr, addr_type,
+				 vlifetime);
 
 		NET_DBG("[%d] interface %p address %s type %s added", i, iface,
 			net_sprint_ipv6_addr(addr),
@@ -758,6 +762,33 @@
 	return NULL;
 }
 
+static inline void prefix_lf_timeout(struct k_work *work)
+{
+	struct net_if_ipv6_prefix *prefix =
+		CONTAINER_OF(work, struct net_if_ipv6_prefix, lifetime);
+
+	NET_DBG("Prefix %s/%d expired",
+		net_sprint_ipv6_addr(&prefix->prefix), prefix->len);
+
+	prefix->is_used = false;
+}
+
+static void net_if_ipv6_prefix_init(struct net_if_ipv6_prefix *prefix,
+				    struct in6_addr *addr, uint8_t len,
+				    uint32_t lifetime)
+{
+	prefix->is_used = true;
+	prefix->len = len;
+	net_ipaddr_copy(&prefix->prefix, addr);
+	k_delayed_work_init(&prefix->lifetime, prefix_lf_timeout);
+
+	if (lifetime == NET_IPV6_ND_INFINITE_LIFETIME) {
+		prefix->is_infinite = true;
+	} else {
+		prefix->is_infinite = false;
+	}
+}
+
 struct net_if_ipv6_prefix *net_if_ipv6_prefix_add(struct net_if *iface,
 						  struct in6_addr *prefix,
 						  uint8_t len,
@@ -776,17 +807,8 @@
 			continue;
 		}
 
-		iface->ipv6.prefix[i].is_used = true;
-		iface->ipv6.prefix[i].len = len;
-
-		if (lifetime == NET_IPV6_ND_INFINITE_LIFETIME) {
-			iface->ipv6.prefix[i].is_infinite = true;
-		} else {
-			iface->ipv6.prefix[i].is_infinite = false;
-		}
-
-		memcpy(&iface->ipv6.prefix[i].prefix, prefix,
-		       sizeof(struct in6_addr));
+		net_if_ipv6_prefix_init(&iface->ipv6.prefix[i], prefix, len,
+					lifetime);
 
 		NET_DBG("[%d] interface %p prefix %s/%d added", i, iface,
 			net_sprint_ipv6_addr(prefix), len);
@@ -875,17 +897,6 @@
 	return false;
 }
 
-static inline void prefix_lf_timeout(struct k_work *work)
-{
-	struct net_if_ipv6_prefix *prefix =
-		CONTAINER_OF(work, struct net_if_ipv6_prefix, lifetime);
-
-	NET_DBG("Prefix %s/%d expired",
-		net_sprint_ipv6_addr(&prefix->prefix), prefix->len);
-
-	prefix->is_used = false;
-}
-
 void net_if_ipv6_prefix_set_timer(struct net_if_ipv6_prefix *prefix,
 				  uint32_t lifetime)
 {
@@ -911,7 +922,6 @@
 
 	NET_DBG("Prefix lifetime %u ms", timeout);
 
-	k_delayed_work_init(&prefix->lifetime, prefix_lf_timeout);
 	k_delayed_work_submit(&prefix->lifetime, timeout);
 }
 
@@ -989,6 +999,32 @@
 			      lifetime * MSEC_PER_SEC);
 }
 
+static inline void net_if_router_init(struct net_if_router *router,
+				      struct net_if *iface,
+				      struct in6_addr *addr, uint16_t lifetime)
+{
+	router->is_used = true;
+	router->iface = iface;
+	router->address.family = AF_INET6;
+	net_ipaddr_copy(&router->address.in6_addr, addr);
+
+	if (lifetime) {
+		/* This is a default router. RFC 4861 page 43
+		 * AdvDefaultLifetime variable
+		 */
+		router->is_default = true;
+		router->is_infinite = false;
+
+		k_delayed_work_init(&router->lifetime, ipv6_router_expired);
+
+		NET_DBG("Expiring %s in %u secs", net_sprint_ipv6_addr(addr),
+			lifetime);
+	} else {
+		router->is_default = false;
+		router->is_infinite = true;
+	}
+}
+
 struct net_if_router *net_if_ipv6_router_add(struct net_if *iface,
 					     struct in6_addr *addr,
 					     uint16_t lifetime)
@@ -1000,28 +1036,7 @@
 			continue;
 		}
 
-		routers[i].is_used = true;
-		routers[i].iface = iface;
-		routers[i].address.family = AF_INET6;
-
-		if (lifetime) {
-			/* This is a default router. RFC 4861 page 43
-			 * AdvDefaultLifetime variable
-			 */
-			routers[i].is_default = true;
-			routers[i].is_infinite = false;
-
-			k_delayed_work_init(&routers[i].lifetime,
-					    ipv6_router_expired);
-
-			NET_DBG("Expiring %s in %u secs",
-				net_sprint_ipv6_addr(addr), lifetime);
-		} else {
-			routers[i].is_default = false;
-			routers[i].is_infinite = true;
-		}
-
-		net_ipaddr_copy(&routers[i].address.in6_addr, addr);
+		net_if_router_init(&routers[i], iface, addr, lifetime);
 
 		NET_DBG("[%d] interface %p router %s lifetime %u default %d "
 			"added",
@@ -1600,7 +1615,7 @@
 	return 0;
 }
 
-void net_if_init(void)
+void net_if_init(struct k_sem *startup_sync)
 {
 	struct net_if *iface;
 
@@ -1618,13 +1633,29 @@
 		iface->base_reachable_time = REACHABLE_TIME;
 
 		net_if_ipv6_set_reachable_time(iface);
+
+#if defined(CONFIG_NET_IPV6_ND)
+		k_delayed_work_init(&iface->rs_timer, rs_timeout);
+#endif
 #endif
 	}
 
 	k_thread_spawn(tx_stack, sizeof(tx_stack),
 		       (k_thread_entry_t)net_if_tx_thread,
-		       NULL, NULL, NULL, K_PRIO_COOP(7),
+		       startup_sync, NULL, NULL, K_PRIO_COOP(7),
 		       K_ESSENTIAL, K_NO_WAIT);
+}
+
+void net_if_post_init(void)
+{
+	struct net_if *iface;
+
+	NET_DBG("");
+
+	/* After TX is running, attempt to bring the interface up */
+	for (iface = __net_if_start; iface != __net_if_end; iface++) {
+		net_if_up(iface);
+	}
 
 	/* RPL init must be done after the network interface is up
 	 * as the RPL code wants to add multicast address to interface.
diff --git a/subsys/net/ip/net_mgmt.c b/subsys/net/ip/net_mgmt.c
index 8962f25..59f735e 100644
--- a/subsys/net/ip/net_mgmt.c
+++ b/subsys/net/ip/net_mgmt.c
@@ -22,7 +22,13 @@
 	struct net_if *iface;
 };
 
-static struct k_sem network_event;
+struct mgmt_event_wait {
+	struct k_sem sync_call;
+	struct net_if *iface;
+};
+
+static K_SEM_DEFINE(network_event, 0, UINT_MAX);
+
 NET_STACK_DEFINE(MGMT, mgmt_stack, CONFIG_NET_MGMT_EVENT_STACK_SIZE,
 		 CONFIG_NET_MGMT_EVENT_STACK_SIZE);
 static struct mgmt_event_entry events[CONFIG_NET_MGMT_EVENT_QUEUE_SIZE];
@@ -102,6 +108,7 @@
 
 static inline void mgmt_run_callbacks(struct mgmt_event_entry *mgmt_event)
 {
+	sys_snode_t *prev = NULL;
 	struct net_mgmt_event_callback *cb, *tmp;
 
 	NET_DBG("Event layer %u code %u type %u",
@@ -110,18 +117,41 @@
 		NET_MGMT_GET_COMMAND(mgmt_event->event));
 
 	SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&event_callbacks, cb, tmp, node) {
-		NET_DBG("Running callback %p : %p", cb, cb->handler);
-
-		if ((mgmt_event->event & cb->event_mask) == mgmt_event->event) {
-			cb->handler(cb, mgmt_event->event, mgmt_event->iface);
+		if ((mgmt_event->event & cb->event_mask) != mgmt_event->event) {
+			continue;
 		}
 
-#ifdef CONFIG_NET_DEBUG_MGMT_EVENT_STACK
-			net_analyze_stack("Net MGMT event stack",
-					  mgmt_stack,
-					  CONFIG_NET_MGMT_EVENT_STACK_SIZE);
-#endif
+		if (NET_MGMT_EVENT_SYNCHRONOUS(cb->event_mask)) {
+			struct mgmt_event_wait *sync_data =
+				CONTAINER_OF(cb->sync_call,
+					     struct mgmt_event_wait, sync_call);
+
+			if (sync_data->iface &&
+			    sync_data->iface != mgmt_event->iface) {
+				continue;
+			}
+
+			NET_DBG("Unlocking %p synchronous call", cb);
+
+			cb->raised_event = mgmt_event->event;
+			sync_data->iface = mgmt_event->iface;
+
+			sys_slist_remove(&event_callbacks, prev, &cb->node);
+
+			k_sem_give(cb->sync_call);
+		} else {
+			NET_DBG("Running callback %p : %p",
+				cb, cb->handler);
+
+			cb->handler(cb, mgmt_event->event, mgmt_event->iface);
+			prev = &cb->node;
+		}
 	}
+
+#ifdef CONFIG_NET_DEBUG_MGMT_EVENT_STACK
+	net_analyze_stack("Net MGMT event stack", mgmt_stack,
+			  CONFIG_NET_MGMT_EVENT_STACK_SIZE);
+#endif
 }
 
 static void mgmt_thread(void)
@@ -155,6 +185,47 @@
 	}
 }
 
+static int mgmt_event_wait_call(struct net_if *iface,
+				uint32_t mgmt_event_mask,
+				uint32_t *raised_event,
+				struct net_if **event_iface,
+				int timeout)
+{
+	struct mgmt_event_wait sync_data = {
+		.sync_call = K_SEM_INITIALIZER(sync_data.sync_call, 0, 1),
+	};
+	struct net_mgmt_event_callback sync = {
+		.sync_call = &sync_data.sync_call,
+		.event_mask = mgmt_event_mask | NET_MGMT_SYNC_EVENT_BIT,
+	};
+	int ret;
+
+	if (iface) {
+		sync_data.iface = iface;
+	}
+
+	NET_DBG("Synchronous event 0x%08x wait %p", sync.event_mask, &sync);
+
+	net_mgmt_add_event_callback(&sync);
+
+	ret = k_sem_take(sync.sync_call, timeout);
+	if (ret == -EAGAIN) {
+		ret = -ETIMEDOUT;
+	} else {
+		if (!ret) {
+			if (raised_event) {
+				*raised_event = sync.raised_event;
+			}
+
+			if (event_iface) {
+				*event_iface = sync_data.iface;
+			}
+		}
+	}
+
+	return ret;
+}
+
 void net_mgmt_add_event_callback(struct net_mgmt_event_callback *cb)
 {
 	NET_DBG("Adding event callback %p", cb);
@@ -186,6 +257,27 @@
 	}
 }
 
+int net_mgmt_event_wait(uint32_t mgmt_event_mask,
+			uint32_t *raised_event,
+			struct net_if **iface,
+			int timeout)
+{
+	return mgmt_event_wait_call(NULL, mgmt_event_mask,
+				    raised_event, iface, timeout);
+}
+
+int net_mgmt_event_wait_on_iface(struct net_if *iface,
+				 uint32_t mgmt_event_mask,
+				 uint32_t *raised_event,
+				 int timeout)
+{
+	NET_ASSERT(NET_MGMT_ON_IFACE(mgmt_event_mask));
+	NET_ASSERT(iface);
+
+	return mgmt_event_wait_call(iface, mgmt_event_mask,
+				    raised_event, NULL, timeout);
+}
+
 void net_mgmt_event_init(void)
 {
 	sys_slist_init(&event_callbacks);
@@ -194,8 +286,6 @@
 	in_event = 0;
 	out_event = 0;
 
-	k_sem_init(&network_event, 0, UINT_MAX);
-
 	memset(events, 0,
 	       CONFIG_NET_MGMT_EVENT_QUEUE_SIZE *
 	       sizeof(struct mgmt_event_entry));
diff --git a/subsys/net/ip/net_private.h b/subsys/net/ip/net_private.h
index 704ca82..bc53c0e 100644
--- a/subsys/net/ip/net_private.h
+++ b/subsys/net/ip/net_private.h
@@ -16,11 +16,13 @@
 #include <net/nbuf.h>
 
 extern void net_nbuf_init(void);
-extern void net_if_init(void);
+extern void net_if_init(struct k_sem *startup_sync);
+extern void net_if_post_init(void);
 extern void net_context_init(void);
 extern void net_ipv6_init(void);
 
-extern char *net_byte_to_hex(uint8_t *ptr, uint8_t byte, char base, bool pad);
+extern const char *net_proto2str(enum net_ip_protocol proto);
+extern char *net_byte_to_hex(char *ptr, uint8_t byte, char base, bool pad);
 extern char *net_sprint_ll_addr_buf(const uint8_t *ll, uint8_t ll_len,
 				    char *buf, int buflen);
 extern uint16_t net_calc_chksum(struct net_buf *buf, uint8_t proto);
diff --git a/subsys/net/ip/net_shell.c b/subsys/net/ip/net_shell.c
index b5c5696..ad4c515 100644
--- a/subsys/net/ip/net_shell.c
+++ b/subsys/net/ip/net_shell.c
@@ -11,6 +11,7 @@
  */
 
 #include <zephyr.h>
+#include <stdlib.h>
 #include <shell/shell.h>
 
 #include <net/net_if.h>
@@ -704,36 +705,25 @@
 }
 
 #if defined(CONFIG_NET_IPV6)
-static inline const char *nbrstate2str(enum net_nbr_state state)
-{
-	switch (state) {
-	case NET_NBR_INCOMPLETE:
-		return "incomplete";
-	case NET_NBR_REACHABLE:
-		return "reachable";
-	case NET_NBR_STALE:
-		return "stale";
-	case NET_NBR_DELAY:
-		return "delay";
-	case NET_NBR_PROBE:
-		return "probe";
-	}
-
-	return "<invalid state>";
-}
-
 static void nbr_cb(struct net_nbr *nbr, void *user_data)
 {
 	int *count = user_data;
 
+	if (*count == 0) {
+		printk("     Neighbor   Flags   Interface  State\t"
+		       "Remain\tLink              Address\n");
+	}
+
 	(*count)++;
 
-	printk("[%d] %d/%d/%d/%d %10s iface %p ll %s addr %s\n",
-	       *count, nbr->ref, net_ipv6_nbr_data(nbr)->ns_count,
+	printk("[%2d] %p %d/%d/%d/%d %p %9s\t%6d\t%17s %s\n",
+	       *count, nbr, nbr->ref, net_ipv6_nbr_data(nbr)->ns_count,
 	       net_ipv6_nbr_data(nbr)->is_router,
 	       net_ipv6_nbr_data(nbr)->link_metric,
-	       nbrstate2str(net_ipv6_nbr_data(nbr)->state),
 	       nbr->iface,
+	       net_nbr_state2str(net_ipv6_nbr_data(nbr)->state),
+	       k_delayed_work_remaining_get(
+		       &net_ipv6_nbr_data(nbr)->reachable),
 	       nbr->idx == NET_NBR_LLADDR_UNKNOWN ? "?" :
 	       net_sprint_ll_addr(
 		       net_nbr_get_lladdr(nbr->idx)->addr,
@@ -746,9 +736,40 @@
 {
 #if defined(CONFIG_NET_IPV6)
 	int count = 0;
+	int arg = 1;
 
-	ARG_UNUSED(argc);
-	ARG_UNUSED(argv);
+	if (strcmp(argv[0], "nbr")) {
+		arg++;
+	}
+
+	if (argv[arg]) {
+		struct in6_addr addr;
+		int ret;
+
+		if (strcmp(argv[arg], "rm")) {
+			printk("Unknown command '%s'\n", argv[arg]);
+			return 0;
+		}
+
+		if (!argv[++arg]) {
+			printk("Neighbor IPv6 address missing.\n");
+			return 0;
+		}
+
+		ret = net_addr_pton(AF_INET6, argv[arg], &addr);
+		if (ret < 0) {
+			printk("Cannot parse '%s'\n", argv[arg]);
+			return 0;
+		}
+
+		if (!net_ipv6_nbr_rm(net_if_get_default(), &addr)) {
+			printk("Cannot remove neighbor %s\n",
+			       net_sprint_ipv6_addr(&addr));
+		} else {
+			printk("Neighbor %s removed.\n",
+			       net_sprint_ipv6_addr(&addr));
+		}
+	}
 
 	net_ipv6_nbr_foreach(nbr_cb, &count);
 
@@ -940,6 +961,7 @@
 	printk("net iface\n\tPrint information about network interfaces\n");
 	printk("net mem\n\tPrint network buffer information\n");
 	printk("net nbr\n\tPrint neighbor information\n");
+	printk("net nbr rm <IPv6 address>\n\tRemove neighbor from cache\n");
 	printk("net ping <host>\n\tPing a network host\n");
 	printk("net route\n\tShow network routes\n");
 	printk("net stacks\n\tShow network stacks information\n");
diff --git a/subsys/net/ip/rpl.c b/subsys/net/ip/rpl.c
index 1702496..ad3e6e1 100644
--- a/subsys/net/ip/rpl.c
+++ b/subsys/net/ip/rpl.c
@@ -552,7 +552,11 @@
 			dag->prefix_info.length);
 	}
 
-	buf = net_ipv6_finalize_raw(buf, IPPROTO_ICMPV6);
+	ret = net_ipv6_finalize_raw(buf, IPPROTO_ICMPV6);
+	if (ret < 0) {
+		net_nbuf_unref(buf);
+		return ret;
+	}
 
 	ret = net_send_data(buf);
 	if (ret >= 0) {
@@ -622,7 +626,7 @@
 		}
 		instance->dio_send = false;
 
-		NET_DBG("Next DIO send after %lu ms",
+		NET_DBG("Next DIO send after %d ms",
 			instance->dio_next_delay);
 
 		k_delayed_work_submit(&instance->dio_timer,
@@ -682,8 +686,6 @@
 
 	NET_DBG("DIO Timer interval set to %d", time);
 
-	k_delayed_work_cancel(&instance->dio_timer);
-	k_delayed_work_init(&instance->dio_timer, dio_timer);
 	k_delayed_work_submit(&instance->dio_timer, time);
 }
 
@@ -748,7 +750,11 @@
 			  &pos, 0);
 	net_nbuf_write_u8(buf, buf->frags, pos, &pos, 0);
 
-	buf = net_ipv6_finalize_raw(buf, IPPROTO_ICMPV6);
+	ret = net_ipv6_finalize_raw(buf, IPPROTO_ICMPV6);
+	if (ret < 0) {
+		net_nbuf_unref(buf);
+		return ret;
+	}
 
 	ret = net_send_data(buf);
 	if (ret >= 0) {
@@ -940,14 +946,64 @@
 		      sys_rand32_get() % NET_RPL_PROBING_INTERVAL) *
 		MSEC_PER_SEC;
 
-	NET_DBG("Send probe in %lu ms, instance %p (%d)",
+	NET_DBG("Send probe in %d ms, instance %p (%d)",
 		expiration, instance, instance->instance_id);
 
-	k_delayed_work_init(&instance->probing_timer, rpl_probing_timer);
 	k_delayed_work_submit(&instance->probing_timer, expiration);
 }
 #endif /* CONFIG_NET_RPL_PROBING */
 
+static void dao_timer(struct net_rpl_instance *instance)
+{
+	/* Send the DAO to the preferred parent. */
+	if (instance->current_dag->preferred_parent) {
+		NET_DBG("Sending DAO iface %p", instance->iface);
+
+		dao_send(instance->current_dag->preferred_parent,
+			 instance->default_lifetime,
+			 instance->iface);
+
+#if NET_RPL_MULTICAST
+		/* Send DAOs for multicast prefixes only if the instance is
+		 * in MOP 3.
+		 */
+		if (instance->mop == NET_RPL_MOP_STORING_MULTICAST) {
+			send_mcast_dao(instance);
+		}
+#endif
+	} else {
+		NET_DBG("No suitable DAO parent found.");
+	}
+}
+
+static void dao_lifetime_timer(struct k_work *work)
+{
+	struct net_rpl_instance *instance =
+		CONTAINER_OF(work, struct net_rpl_instance,
+			     dao_lifetime_timer);
+
+	dao_timer(instance);
+
+	instance->dao_lifetime_timer_active = false;
+
+	set_dao_lifetime_timer(instance);
+}
+
+static inline void net_rpl_instance_init(struct net_rpl_instance *instance,
+					 uint8_t id)
+{
+	memset(instance, 0, sizeof(struct net_rpl_instance));
+
+	instance->instance_id = id;
+	instance->default_route = NULL;
+	instance->is_used = true;
+
+	k_delayed_work_init(&instance->dio_timer, dio_timer);
+	k_delayed_work_init(&instance->probing_timer, rpl_probing_timer);
+	k_delayed_work_init(&instance->dao_lifetime_timer, dao_lifetime_timer);
+	k_delayed_work_init(&instance->dao_timer, dao_send_timer);
+}
+
 static struct net_rpl_instance *net_rpl_alloc_instance(uint8_t instance_id)
 {
 	int i;
@@ -957,11 +1013,7 @@
 			continue;
 		}
 
-		memset(&rpl_instances[i], 0, sizeof(struct net_rpl_instance));
-
-		rpl_instances[i].instance_id = instance_id;
-		rpl_instances[i].default_route = NULL;
-		rpl_instances[i].is_used = true;
+		net_rpl_instance_init(&rpl_instances[i], instance_id);
 
 #if defined(CONFIG_NET_RPL_PROBING)
 		net_rpl_schedule_probing(&rpl_instances[i]);
@@ -1503,42 +1555,6 @@
 	return NULL;
 }
 
-static void dao_timer(struct net_rpl_instance *instance)
-{
-	/* Send the DAO to the preferred parent. */
-	if (instance->current_dag->preferred_parent) {
-		NET_DBG("Sending DAO iface %p", instance->iface);
-
-		dao_send(instance->current_dag->preferred_parent,
-			 instance->default_lifetime,
-			 instance->iface);
-
-#if NET_RPL_MULTICAST
-		/* Send DAOs for multicast prefixes only if the instance is
-		 * in MOP 3.
-		 */
-		if (instance->mop == NET_RPL_MOP_STORING_MULTICAST) {
-			send_mcast_dao(instance);
-		}
-#endif
-	} else {
-		NET_DBG("No suitable DAO parent found.");
-	}
-}
-
-static void dao_lifetime_timer(struct k_work *work)
-{
-	struct net_rpl_instance *instance =
-		CONTAINER_OF(work, struct net_rpl_instance,
-			     dao_lifetime_timer);
-
-	dao_timer(instance);
-
-	instance->dao_lifetime_timer_active = false;
-
-	set_dao_lifetime_timer(instance);
-}
-
 static void set_dao_lifetime_timer(struct net_rpl_instance *instance)
 {
 	if (net_rpl_get_mode() == NET_RPL_MODE_FEATHER) {
@@ -1561,8 +1577,6 @@
 		NET_DBG("Scheduling DAO lifetime timer %d ms in the future",
 			expiration_time);
 
-		k_delayed_work_init(&instance->dao_lifetime_timer,
-				    dao_lifetime_timer);
 		k_delayed_work_submit(&instance->dao_lifetime_timer,
 				      expiration_time);
 	}
@@ -1613,7 +1627,6 @@
 
 	instance->dao_timer_active = true;
 
-	k_delayed_work_init(&instance->dao_timer, dao_send_timer);
 	k_delayed_work_submit(&instance->dao_timer, expiration);
 
 	if (!instance->dao_lifetime_timer_active) {
@@ -3012,7 +3025,11 @@
 	net_nbuf_append_u8(buf, 0); /* path seq */
 	net_nbuf_append_u8(buf, lifetime);
 
-	buf = net_ipv6_finalize_raw(buf, IPPROTO_ICMPV6);
+	ret = net_ipv6_finalize_raw(buf, IPPROTO_ICMPV6);
+	if (ret < 0) {
+		net_nbuf_unref(buf);
+		return ret;
+	}
 
 	ret = net_send_data(buf);
 	if (ret >= 0) {
@@ -3106,7 +3123,11 @@
 	net_nbuf_append_u8(buf, sequence);
 	net_nbuf_append_u8(buf, 0); /* status */
 
-	buf = net_ipv6_finalize_raw(buf, IPPROTO_ICMPV6);
+	ret = net_ipv6_finalize_raw(buf, IPPROTO_ICMPV6);
+	if (ret < 0) {
+		net_nbuf_unref(buf);
+		return ret;
+	}
 
 	ret = net_send_data(buf);
 	if (ret >= 0) {
@@ -3535,27 +3556,29 @@
 	return 0;
 }
 
-bool net_rpl_verify_header(struct net_buf *buf,
-			   uint16_t offset, uint16_t *pos)
+struct net_buf *net_rpl_verify_header(struct net_buf *buf, struct net_buf *frag,
+				      uint16_t offset, uint16_t *pos,
+				      bool *result)
 {
 	struct net_rpl_instance *instance;
-	struct net_buf *frag;
 	uint16_t sender_rank;
 	uint8_t instance_id, flags;
 	bool down, sender_closer;
 
-	frag = net_nbuf_read_u8(buf, offset, pos, &flags);
+	frag = net_nbuf_read_u8(frag, offset, pos, &flags);
 	frag = net_nbuf_read_u8(frag, *pos, pos, &instance_id);
 	frag = net_nbuf_read_be16(frag, *pos, pos, &sender_rank);
 
 	if (!frag && *pos == 0xffff) {
-		return false;
+		*result = false;
+		return frag;
 	}
 
 	instance = net_rpl_get_instance(instance_id);
 	if (!instance) {
 		NET_DBG("Unknown instance %u", instance_id);
-		return false;
+		*result = false;
+		return frag;
 	}
 
 	if (flags & NET_RPL_HDR_OPT_FWD_ERR) {
@@ -3580,12 +3603,14 @@
 		net_rpl_reset_dio_timer(instance);
 
 		/* drop the packet as it is not routable */
-		return false;
+		*result = false;
+		return frag;
 	}
 
 	if (!net_rpl_dag_is_joined(instance->current_dag)) {
 		NET_DBG("No DAG in the instance");
-		return false;
+		*result = false;
+		return frag;
 	}
 
 	if (flags & NET_RPL_HDR_OPT_DOWN) {
@@ -3617,20 +3642,22 @@
 			 */
 			net_rpl_reset_dio_timer(instance);
 
-			return false;
+			*result = false;
+			return frag;
 		}
 
 		NET_DBG("Single error tolerated.");
 		net_stats_update_rpl_loop_warnings();
 
-		net_nbuf_write_u8(buf, buf->frags, offset, pos,
-				  flags | NET_RPL_HDR_OPT_RANK_ERR);
-
-		return true;
+		/* FIXME: Handle (NET_RPL_HDR_OPT_RANK_ERR) errors properly */
+		*result = true;
+		return frag;
 	}
 
 	NET_DBG("Rank OK");
-	return true;
+
+	*result = true;
+	return frag;
 }
 
 static inline int add_rpl_opt(struct net_buf *buf, uint16_t offset)
@@ -3847,6 +3874,63 @@
 	return 0;
 }
 
+int net_rpl_revert_header(struct net_buf *buf, uint16_t offset, uint16_t *pos)
+{
+	struct net_rpl_instance *instance;
+	struct net_buf *frag;
+	uint16_t sender_rank;
+	uint16_t revert_pos;
+	uint8_t instance_id;
+	uint8_t opt_len;
+	uint8_t flags;
+	uint8_t opt;
+
+	/* Skip HBHO next header and length */
+	frag = net_nbuf_skip(buf->frags, offset, pos, 2);
+	frag = net_nbuf_read_u8(frag, *pos, pos, &opt);
+	frag = net_nbuf_read_u8(frag, *pos, pos, &opt_len);
+
+	if (opt != NET_IPV6_EXT_HDR_OPT_RPL) {
+		return -EINVAL;
+	}
+
+	revert_pos = *pos;
+	frag = net_nbuf_read_u8(frag, *pos, pos, &flags);
+	frag = net_nbuf_read_u8(frag, *pos, pos, &instance_id);
+	if (!frag && *pos == 0xffff) {
+		return -EINVAL;
+	}
+
+	instance = net_rpl_get_instance(instance_id);
+	if (!instance) {
+		NET_DBG("Unknown instance %u", instance_id);
+		return -EINVAL;
+	}
+
+	if (!instance->current_dag) {
+		NET_DBG("Current DAG not available");
+		return -EINVAL;
+	}
+
+	flags &= NET_RPL_HDR_OPT_DOWN;
+	flags ^= NET_RPL_HDR_OPT_DOWN;
+
+	sender_rank = instance->current_dag->rank;
+
+	/* Reverting RPL options from 'revert_pos' */
+	*pos = revert_pos;
+
+	/* Update flags, instance id, sender rank */
+	frag = net_nbuf_write_u8(buf, frag, *pos, pos, flags);
+	frag = net_nbuf_write_u8(buf, frag, *pos, pos, instance_id);
+	frag = net_nbuf_write_be16(buf, frag, *pos, pos, sender_rank);
+	if (!frag && *pos == 0xffff) {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 int net_rpl_insert_header(struct net_buf *buf)
 {
 #if defined(CONFIG_NET_RPL_INSERT_HBH_OPTION)
@@ -3895,6 +3979,11 @@
 #endif
 }
 
+struct net_rpl_instance *net_rpl_get_default_instance(void)
+{
+	return rpl_default_instance;
+}
+
 void net_rpl_init(void)
 {
 	/* Note that link_cb needs to be static as it is added
diff --git a/subsys/net/ip/rpl.h b/subsys/net/ip/rpl.h
index 7555e18..126c0d1 100644
--- a/subsys/net/ip/rpl.h
+++ b/subsys/net/ip/rpl.h
@@ -911,14 +911,17 @@
 /**
  * @brief Verify RPL header in IPv6 packet.
  *
- * @param buf Network buffer.
+ * @param buf Network buffer fragment list.
+ * @param frag Current network buffer fragment.
  * @param offset Where the RPL header starts in the packet
  * @param pos How long the RPL header was, this is returned to the caller.
+ * @param out result True if ok, false if error
  *
- * @return True if ok, false if error
+ * @return frag Returns the fragment where this call finished reading.
  */
-bool net_rpl_verify_header(struct net_buf *buf, uint16_t offset,
-			   uint16_t *pos);
+struct net_buf *net_rpl_verify_header(struct net_buf *buf, struct net_buf *frag,
+				      uint16_t offset, uint16_t *pos,
+				      bool *result);
 
 /**
  * @brief Insert RPL extension header to IPv6 packet.
@@ -930,6 +933,18 @@
 int net_rpl_insert_header(struct net_buf *buf);
 
 /**
+ * @brief Revert RPL extension header to IPv6 packet.
+ *        Revert flags, instance ID and sender rank in the packet.
+ *
+ * @param buf Network buffer.
+ * @param offset Where the HBH header starts in the packet
+ * @param pos How long the RPL header was, this is returned to the caller.
+ *
+ * @return 0 if ok, <0 if error.
+ */
+int net_rpl_revert_header(struct net_buf *buf, uint16_t offset, uint16_t *pos);
+
+/**
  * @brief Get parent IPv6 address.
  *
  * @param iface Network interface
@@ -956,6 +971,13 @@
  */
 enum net_rpl_mode net_rpl_get_mode(void);
 
+/**
+ * @brief Get the default RPL instance.
+ *
+ * @return Current default RPL instance.
+ */
+struct net_rpl_instance *net_rpl_get_default_instance(void);
+
 void net_rpl_init(void);
 #else
 #define net_rpl_init(...)
diff --git a/subsys/net/ip/tcp.c b/subsys/net/ip/tcp.c
index 8c6b5e8..045715a 100644
--- a/subsys/net/ip/tcp.c
+++ b/subsys/net/ip/tcp.c
@@ -68,30 +68,35 @@
 	return chr | 0x20;
 }
 
-static void net_tcp_trace(char *str, struct net_buf *buf)
+static void net_tcp_trace(struct net_buf *buf, struct net_tcp *tcp)
 {
 	uint8_t flags = NET_TCP_FLAGS(buf);
+	uint32_t rel_ack;
 
-	NET_INFO("%s[TCP header]", str);
-	NET_INFO("|(SrcPort)         %5u |(DestPort)      %5u |",
-		 ntohs(NET_TCP_BUF(buf)->src_port),
-		 ntohs(NET_TCP_BUF(buf)->dst_port));
-	NET_INFO("|(Sequence number)                 0x%010x |",
-		 sys_get_be32(NET_TCP_BUF(buf)->seq));
-	NET_INFO("|(ACK number)                      0x%010x |",
-		 sys_get_be32(NET_TCP_BUF(buf)->ack));
-	NET_INFO("|(HL) %2u |(F)  %c%c%c%c%c%c |(Window)           %5u |",
-		 (NET_TCP_BUF(buf)->offset >> 4) * 4,
-		 upper_if_set('u', flags & NET_TCP_URG),
-		 upper_if_set('a', flags & NET_TCP_ACK),
-		 upper_if_set('p', flags & NET_TCP_PSH),
-		 upper_if_set('r', flags & NET_TCP_RST),
-		 upper_if_set('s', flags & NET_TCP_SYN),
-		 upper_if_set('f', flags & NET_TCP_FIN),
-		 sys_get_be16(NET_TCP_BUF(buf)->wnd));
-	NET_INFO("|(Checksum)    0x%04x |(Urgent)           %5u |",
-		 ntohs(NET_TCP_BUF(buf)->chksum),
-		 sys_get_be16(NET_TCP_BUF(buf)->urg));
+	if (!tcp->sent_ack) {
+		rel_ack = 0;
+	} else {
+		rel_ack = sys_get_be32(NET_TCP_BUF(buf)->ack) ?
+		       sys_get_be32(NET_TCP_BUF(buf)->ack) - tcp->sent_ack : 0;
+	}
+
+	NET_DBG("buf %p src %u dst %u seq 0x%04x ack 0x%04x (%u) "
+		"flags %c%c%c%c%c%c win %u chk 0x%04x",
+		buf,
+		ntohs(NET_TCP_BUF(buf)->src_port),
+		ntohs(NET_TCP_BUF(buf)->dst_port),
+		sys_get_be32(NET_TCP_BUF(buf)->seq),
+		sys_get_be32(NET_TCP_BUF(buf)->ack),
+		/* This tells how many bytes we are acking now */
+		rel_ack,
+		upper_if_set('u', flags & NET_TCP_URG),
+		upper_if_set('a', flags & NET_TCP_ACK),
+		upper_if_set('p', flags & NET_TCP_PSH),
+		upper_if_set('r', flags & NET_TCP_RST),
+		upper_if_set('s', flags & NET_TCP_SYN),
+		upper_if_set('f', flags & NET_TCP_FIN),
+		sys_get_be16(NET_TCP_BUF(buf)->wnd),
+		ntohs(NET_TCP_BUF(buf)->chksum));
 }
 #else
 #define net_tcp_trace(...)
@@ -235,20 +240,22 @@
 	return optlen;
 }
 
-static void finalize_segment(struct net_context *context, struct net_buf *buf)
+static int finalize_segment(struct net_context *context, struct net_buf *buf)
 {
 #if defined(CONFIG_NET_IPV4)
 	if (net_nbuf_family(buf) == AF_INET) {
-		net_ipv4_finalize(context, buf);
+		return net_ipv4_finalize(context, buf);
 	} else
 #endif
 #if defined(CONFIG_NET_IPV6)
 	if (net_nbuf_family(buf) == AF_INET6) {
-		net_ipv6_finalize(context, buf);
+		return net_ipv6_finalize(context, buf);
 	}
 #endif
 	{
 	}
+
+	return 0;
 }
 
 static struct net_buf *prepare_segment(struct net_tcp *tcp,
@@ -329,9 +336,12 @@
 		net_buf_frag_add(buf, tail);
 	}
 
-	finalize_segment(context, buf);
+	if (finalize_segment(context, buf) < 0) {
+		net_nbuf_unref(buf);
+		return NULL;
+	}
 
-	net_tcp_trace("", buf);
+	net_tcp_trace(buf, tcp);
 
 	return buf;
 }
@@ -421,6 +431,9 @@
 	segment.optlen = optlen;
 
 	*send_buf = prepare_segment(tcp, &segment, *send_buf);
+	if (!*send_buf) {
+		return -EINVAL;
+	}
 
 	tcp->send_seq = seq;
 
@@ -523,10 +536,9 @@
 
 		net_tcp_set_syn_opt(tcp, options, &optionlen);
 
-		net_tcp_prepare_segment(tcp, NET_TCP_SYN | NET_TCP_ACK,
-					options, optionlen, NULL, remote, buf);
-		break;
-
+		return net_tcp_prepare_segment(tcp, NET_TCP_SYN | NET_TCP_ACK,
+					       options, optionlen, NULL, remote,
+					       buf);
 	case NET_TCP_FIN_WAIT_1:
 	case NET_TCP_LAST_ACK:
 		/* In the FIN_WAIT_1 and LAST_ACK states acknowledgment must
@@ -534,17 +546,14 @@
 		 */
 		tcp->send_seq--;
 
-		net_tcp_prepare_segment(tcp, NET_TCP_FIN | NET_TCP_ACK,
-					0, 0, NULL, remote, buf);
-		break;
-
+		return net_tcp_prepare_segment(tcp, NET_TCP_FIN | NET_TCP_ACK,
+					       0, 0, NULL, remote, buf);
 	default:
-		net_tcp_prepare_segment(tcp, NET_TCP_ACK, 0, 0, NULL, remote,
-					buf);
-		break;
+		return net_tcp_prepare_segment(tcp, NET_TCP_ACK, 0, 0, NULL,
+					       remote, buf);
 	}
 
-	return 0;
+	return -EINVAL;
 }
 
 int net_tcp_prepare_reset(struct net_tcp *tcp,
diff --git a/subsys/net/ip/utils.c b/subsys/net/ip/utils.c
index 31c7126..71dd8f3 100644
--- a/subsys/net/ip/utils.c
+++ b/subsys/net/ip/utils.c
@@ -24,6 +24,24 @@
 #include <net/nbuf.h>
 #include <net/net_core.h>
 
+const char *net_proto2str(enum net_ip_protocol proto)
+{
+	switch (proto) {
+	case IPPROTO_ICMP:
+		return "ICMPv4";
+	case IPPROTO_TCP:
+		return "TCP";
+	case IPPROTO_UDP:
+		return "UDP";
+	case IPPROTO_ICMPV6:
+		return "ICMPv6";
+	default:
+		break;
+	}
+
+	return "UNK_PROTO";
+}
+
 char *net_byte_to_hex(char *ptr, uint8_t byte, char base, bool pad)
 {
 	int i, val;
diff --git a/subsys/net/lib/dns/dns_pack.c b/subsys/net/lib/dns/dns_pack.c
index 077953f..cdf2bcd 100644
--- a/subsys/net/lib/dns/dns_pack.c
+++ b/subsys/net/lib/dns/dns_pack.c
@@ -143,9 +143,9 @@
 	/* TTL value */
 	*ttl = dns_answer_ttl(DNS_COMMON_UINT_SIZE, answer);
 	pos = dns_msg->answer_offset + DNS_ANSWER_MIN_SIZE;
-	len = dns_unpack_answer_rdlength(DNS_COMMON_UINT_SIZE, answer);
+	len = dns_answer_rdlength(DNS_COMMON_UINT_SIZE, answer);
 
-	switch (dns_response_type(DNS_COMMON_UINT_SIZE, answer)) {
+	switch (dns_answer_type(DNS_COMMON_UINT_SIZE, answer)) {
 	case DNS_RR_TYPE_A:
 	case DNS_RR_TYPE_AAAA:
 		set_dns_msg_response(dns_msg, DNS_RESPONSE_IP, pos, len);
diff --git a/subsys/net/lib/dns/dns_pack.h b/subsys/net/lib/dns/dns_pack.h
index 0d25aa0..8b50243 100644
--- a/subsys/net/lib/dns/dns_pack.h
+++ b/subsys/net/lib/dns/dns_pack.h
@@ -200,7 +200,7 @@
 	return ntohs(UNALIGNED_GET((uint16_t *)(question + 2)));
 }
 
-static inline int dns_response_type(uint16_t dname_size, uint8_t *answer)
+static inline int dns_answer_type(uint16_t dname_size, uint8_t *answer)
 {
 	/** Future versions must consider byte 0
 	 * 4.1.3. Resource record format
@@ -220,15 +220,10 @@
 
 static inline int dns_answer_ttl(uint16_t dname_size, uint8_t *answer)
 {
-	return htonl(UNALIGNED_GET((uint32_t *)(answer + dname_size + 4)));
+	return ntohl(UNALIGNED_GET((uint32_t *)(answer + dname_size + 4)));
 }
 
-static inline int dns_answer_rdlength(uint16_t dname_size, uint8_t *answer)
-{
-	return htons(UNALIGNED_GET((uint16_t *)(answer + dname_size + 8)));
-}
-
-static inline int dns_unpack_answer_rdlength(uint16_t dname_size,
+static inline int dns_answer_rdlength(uint16_t dname_size,
 					     uint8_t *answer)
 {
 	return ntohs(UNALIGNED_GET((uint16_t *)(answer + dname_size + 8)));
diff --git a/subsys/net/lib/http/Kconfig b/subsys/net/lib/http/Kconfig
index 8cceee9..ba0ebf2 100644
--- a/subsys/net/lib/http/Kconfig
+++ b/subsys/net/lib/http/Kconfig
@@ -14,7 +14,7 @@
 	bool
 	prompt "HTTP server support"
 	default n
-	depends on HTTP
+	select HTTP
 	help
 	Enables HTTP server routines
 
@@ -31,7 +31,7 @@
 	bool
 	prompt "HTTP client support"
 	default n
-	depends on HTTP
+	select HTTP
 	help
 	Enables HTTP client routines
 
@@ -39,7 +39,7 @@
 	bool
 	prompt "HTTP Parser support"
 	default n
-	depends on HTTP
+	select HTTP
 	help
 	This option enables the http_parser library from nodejs.
 	This parser requires some string-related routines commonly
diff --git a/subsys/net/lib/http/http_server.c b/subsys/net/lib/http/http_server.c
index 04b22d7..df866fd 100644
--- a/subsys/net/lib/http/http_server.c
+++ b/subsys/net/lib/http/http_server.c
@@ -89,12 +89,12 @@
 		if (rc != 0) {
 			goto exit_routine;
 		}
-	}
 
-	/* like EOF */
-	rc = http_add_chunk(tx, ctx->timeout, NULL);
-	if (rc != 0) {
-		goto exit_routine;
+		/* like EOF */
+		rc = http_add_chunk(tx, ctx->timeout, NULL);
+		if (rc != 0) {
+			goto exit_routine;
+		}
 	}
 
 	rc = net_context_send(tx, NULL, 0, NULL, NULL);
diff --git a/tests/net/6lo/src/main.c b/tests/net/6lo/src/main.c
index 04bb6a3..5e86b4d 100644
--- a/tests/net/6lo/src/main.c
+++ b/tests/net/6lo/src/main.c
@@ -106,8 +106,8 @@
 /* 6CO contexts */
 static struct net_icmpv6_nd_opt_6co ctx1 = {
 	.type = 0x22,
-	.len = 0x03,
-	.context_len = 0x80,
+	.len = 0x02,
+	.context_len = 0x40,
 	.flag = 0x11,
 	.reserved = 0,
 	.lifetime = 0x1234,
diff --git a/tests/net/arp/src/main.c b/tests/net/arp/src/main.c
index 52e0fcc..96b264e 100644
--- a/tests/net/arp/src/main.c
+++ b/tests/net/arp/src/main.c
@@ -47,13 +47,13 @@
 {
 	struct net_arp_context *context = dev->driver_data;
 
-	if (context->mac_addr[0] == 0x00) {
-		/* 10-00-00-00-00 to 10-00-00-00-FF Documentation RFC7042 */
-		context->mac_addr[0] = 0x10;
+	if (context->mac_addr[2] == 0x00) {
+		/* 00-00-5E-00-53-xx Documentation RFC 7042 */
+		context->mac_addr[0] = 0x00;
 		context->mac_addr[1] = 0x00;
-		context->mac_addr[2] = 0x00;
+		context->mac_addr[2] = 0x5E;
 		context->mac_addr[3] = 0x00;
-		context->mac_addr[4] = 0x00;
+		context->mac_addr[4] = 0x53;
 		context->mac_addr[5] = sys_rand32_get();
 	}
 
diff --git a/tests/net/context/prj.conf b/tests/net/context/prj.conf
index 4497523..ede193a 100644
--- a/tests/net/context/prj.conf
+++ b/tests/net/context/prj.conf
@@ -13,11 +13,14 @@
 CONFIG_TEST_RANDOM_GENERATOR=y
 CONFIG_NET_IPV6_ND=n
 CONFIG_NET_IPV6_DAD=n
+CONFIG_NET_IPV6_NBR_CACHE=n
 CONFIG_NET_IPV6_MLD=n
 CONFIG_NET_NBUF_TX_COUNT=10
 CONFIG_NET_NBUF_RX_COUNT=5
 CONFIG_NET_NBUF_RX_DATA_COUNT=10
 CONFIG_NET_NBUF_TX_DATA_COUNT=10
+#CONFIG_SYS_LOG_NET_LEVEL=4
+#CONFIG_NET_DEBUG_IPV6=y
 #CONFIG_NET_DEBUG_CONTEXT=y
 #CONFIG_NET_DEBUG_CORE=y
 #CONFIG_NET_DEBUG_IF=y
diff --git a/tests/net/context/src/main.c b/tests/net/context/src/main.c
index c1dc8ff..16c891f 100644
--- a/tests/net/context/src/main.c
+++ b/tests/net/context/src/main.c
@@ -1033,13 +1033,13 @@
 {
 	struct net_context_test *context = dev->driver_data;
 
-	if (context->mac_addr[0] == 0x00) {
-		/* 10-00-00-00-00 to 10-00-00-00-FF Documentation RFC7042 */
-		context->mac_addr[0] = 0x10;
+	if (context->mac_addr[2] == 0x00) {
+		/* 00-00-5E-00-53-xx Documentation RFC 7042 */
+		context->mac_addr[0] = 0x00;
 		context->mac_addr[1] = 0x00;
-		context->mac_addr[2] = 0x00;
+		context->mac_addr[2] = 0x5E;
 		context->mac_addr[3] = 0x00;
-		context->mac_addr[4] = 0x00;
+		context->mac_addr[4] = 0x53;
 		context->mac_addr[5] = sys_rand32_get();
 	}
 
diff --git a/tests/net/dhcpv4/prj.conf b/tests/net/dhcpv4/prj.conf
index d2c1aba..848ed60 100644
--- a/tests/net/dhcpv4/prj.conf
+++ b/tests/net/dhcpv4/prj.conf
@@ -17,6 +17,7 @@
 CONFIG_NET_DEBUG_CORE=y
 CONFIG_NET_DEBUG_DHCPV4=y
 CONFIG_NET_IPV6=n
+#CONFIG_SYS_LOG_NET_LEVEL=4
 
 CONFIG_NET_MGMT=y
 CONFIG_NET_MGMT_EVENT=y
diff --git a/tests/net/dhcpv4/src/main.c b/tests/net/dhcpv4/src/main.c
index 4459ba6..cda498f 100644
--- a/tests/net/dhcpv4/src/main.c
+++ b/tests/net/dhcpv4/src/main.c
@@ -33,8 +33,8 @@
 0x02, 0x01, 0x06, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x0a, 0xed, 0x48, 0x9e, 0x0a, 0xb8,
-0x09, 0x01, 0x0a, 0xed, 0x48, 0x02, 0x10, 0x00,
-0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+0x09, 0x01, 0x0a, 0xed, 0x48, 0x02, 0x00, 0x00,
+0x5E, 0x00, 0x53, 0x01, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -85,8 +85,8 @@
 0x02, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x0a, 0xed, 0x48, 0x9e, 0x00, 0x00, 0x00, 0x00,
-0x0a, 0xed, 0x48, 0x03, 0x10, 0x00, 0x00, 0x00,
-0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x0a, 0xed, 0x48, 0x03, 0x00, 0x00, 0x5E, 0x00,
+0x53, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -133,9 +133,9 @@
 };
 
 static const struct net_eth_addr src_addr = {
-	{ 0x10, 0x00, 0x00, 0x00, 0x00, 0x01 } };
+	{ 0x00, 0x00, 0x5E, 0x00, 0x53, 0x01 } };
 static const struct net_eth_addr dst_addr = {
-	{ 0x10, 0x00, 0x00, 0x00, 0x00, 0x02 } };
+	{ 0x00, 0x00, 0x5E, 0x00, 0x53, 0x02 } };
 static const struct in_addr server_addr = { { { 192, 0, 2, 1 } } };
 static const struct in_addr client_addr = { { { 255, 255, 255, 255 } } };
 
@@ -179,15 +179,13 @@
 {
 	struct net_dhcpv4_context *context = dev->driver_data;
 
-	if (context->mac_addr[0] == 0x00) {
-		/* 10-00-00-00-00 to 10-00-00-00-FF
-		 * Documentation RFC7042
-		 */
-		context->mac_addr[0] = 0x10;
+	if (context->mac_addr[2] == 0x00) {
+		/* 00-00-5E-00-53-xx Documentation RFC 7042 */
+		context->mac_addr[0] = 0x00;
 		context->mac_addr[1] = 0x00;
-		context->mac_addr[2] = 0x00;
+		context->mac_addr[2] = 0x5E;
 		context->mac_addr[3] = 0x00;
-		context->mac_addr[4] = 0x00;
+		context->mac_addr[4] = 0x53;
 		context->mac_addr[5] = 0x01;
 	}
 
diff --git a/tests/net/iface/src/main.c b/tests/net/iface/src/main.c
index 848da73..87bf339 100644
--- a/tests/net/iface/src/main.c
+++ b/tests/net/iface/src/main.c
@@ -75,13 +75,13 @@
 {
 	struct net_if_test *data = dev->driver_data;
 
-	if (data->mac_addr[0] == 0x00) {
-		/* 10-00-00-00-00 to 10-00-00-00-FF Documentation RFC7042 */
-		data->mac_addr[0] = 0x10;
+	if (data->mac_addr[2] == 0x00) {
+		/* 00-00-5E-00-53-xx Documentation RFC 7042 */
+		data->mac_addr[0] = 0x00;
 		data->mac_addr[1] = 0x00;
-		data->mac_addr[2] = 0x00;
+		data->mac_addr[2] = 0x5E;
 		data->mac_addr[3] = 0x00;
-		data->mac_addr[4] = 0x00;
+		data->mac_addr[4] = 0x53;
 		data->mac_addr[5] = sys_rand32_get();
 	}
 
diff --git a/tests/net/ip-addr/src/main.c b/tests/net/ip-addr/src/main.c
index df8c0a9..447e52d 100644
--- a/tests/net/ip-addr/src/main.c
+++ b/tests/net/ip-addr/src/main.c
@@ -118,13 +118,13 @@
 {
 	struct net_test_context *context = dev->driver_data;
 
-	if (context->mac_addr[0] == 0x00) {
-		/* 10-00-00-00-00 to 10-00-00-00-FF Documentation RFC7042 */
-		context->mac_addr[0] = 0x10;
+	if (context->mac_addr[2] == 0x00) {
+		/* 00-00-5E-00-53-xx Documentation RFC 7042 */
+		context->mac_addr[0] = 0x00;
 		context->mac_addr[1] = 0x00;
-		context->mac_addr[2] = 0x00;
+		context->mac_addr[2] = 0x5E;
 		context->mac_addr[3] = 0x00;
-		context->mac_addr[4] = 0x00;
+		context->mac_addr[4] = 0x53;
 		context->mac_addr[5] = sys_rand32_get();
 	}
 
diff --git a/tests/net/ipv6/src/main.c b/tests/net/ipv6/src/main.c
index 39e84d3..39066df 100644
--- a/tests/net/ipv6/src/main.c
+++ b/tests/net/ipv6/src/main.c
@@ -142,13 +142,13 @@
 {
 	struct net_test_ipv6 *context = dev->driver_data;
 
-	if (context->mac_addr[0] == 0x00) {
-		/* 10-00-00-00-00 to 10-00-00-00-FF Documentation RFC7042 */
-		context->mac_addr[0] = 0x10;
+	if (context->mac_addr[2] == 0x00) {
+		/* 00-00-5E-00-53-xx Documentation RFC 7042 */
+		context->mac_addr[0] = 0x00;
 		context->mac_addr[1] = 0x00;
-		context->mac_addr[2] = 0x00;
+		context->mac_addr[2] = 0x5E;
 		context->mac_addr[3] = 0x00;
-		context->mac_addr[4] = 0x00;
+		context->mac_addr[4] = 0x53;
 		context->mac_addr[5] = sys_rand32_get();
 	}
 
diff --git a/tests/net/lib/dns_packet/src/dns_packet.c b/tests/net/lib/dns_packet/src/dns_packet.c
index c739fd2..a42e176 100644
--- a/tests/net/lib/dns_packet/src/dns_packet.c
+++ b/tests/net/lib/dns_packet/src/dns_packet.c
@@ -157,6 +157,224 @@
 	return rc;
 }
 
+/* The DNS response min size is computed as follows:
+ * (hdr size) + (question min size) +  (RR min size)
+ */
+#define RESPONSE_MIN_SIZE	(DNS_HEADER_SIZE + 6 + 14)
+
+/* DNS QNAME size here is 2 because we use DNS pointers */
+#define NAME_PTR_SIZE	2
+/* DNS integer size */
+#define INT_SIZE	2
+/* DNS answer TTL size */
+#define ANS_TTL_SIZE	4
+
+struct dns_response_test {
+	/* domain name: example.com */
+	const char *dname;
+
+	/* expected result */
+	uint8_t *res;
+	/* expected result length */
+	uint16_t res_len;
+
+	/* transaction id */
+	uint16_t tid;
+	/* A, AAAA */
+	uint8_t answer_type;
+	/* answer counter */
+	uint8_t ancount;
+	/* answer TTL */
+	uint32_t ttl;
+	/* recursion available */
+	uint8_t ra;
+	/* data len */
+	uint8_t rdlen;
+	/* data */
+	const uint8_t *rdata;
+};
+
+/* This routine evaluates DNS responses with one RR, and assumes that the
+ * RR's name points to the DNS question's qname.
+ */
+static int eval_response1(struct dns_response_test *resp)
+{
+	uint8_t *ptr = resp->res;
+	uint16_t offset;
+	int  rc;
+
+	if (resp->res_len < RESPONSE_MIN_SIZE) {
+		rc = -EINVAL;
+		goto lb_exit;
+	}
+
+	if (dns_unpack_header_id(resp->res) != resp->tid) {
+		rc = -EINVAL;
+		goto lb_exit;
+	}
+
+	/* This is a response */
+	if (dns_header_qr(resp->res) != DNS_RESPONSE) {
+		rc = -EINVAL;
+		goto lb_exit;
+	}
+
+	/* For the DNS response, this value is standard query */
+	if (dns_header_opcode(resp->res) != DNS_QUERY) {
+		rc = -EINVAL;
+		goto lb_exit;
+	}
+
+	/* Authoritative Answer */
+	if (dns_header_aa(resp->res) != 0) {
+		rc = -EINVAL;
+		goto lb_exit;
+	}
+
+	/* TrunCation is always 0 */
+	if (dns_header_tc(resp->res) != 0) {
+		rc = -EINVAL;
+		goto lb_exit;
+	}
+
+	/* Recursion Desired is always 1 in the Zephyr DNS implementation */
+	if (dns_header_rd(resp->res) != 1) {
+		rc = -EINVAL;
+		goto lb_exit;
+	}
+
+	/* Recursion Available */
+	if (dns_header_ra(resp->res) != resp->ra) {
+		rc = -EINVAL;
+		goto lb_exit;
+	}
+
+	/* Z is always 0 */
+	if (dns_header_z(resp->res) != 0) {
+		rc = -EINVAL;
+		goto lb_exit;
+	}
+
+	/* Response code must be 0 (no error) */
+	if (dns_header_rcode(resp->res) != DNS_HEADER_NOERROR) {
+		rc = -EINVAL;
+		goto lb_exit;
+	}
+
+	/* Question counter must be 1 */
+	if (dns_header_qdcount(resp->res) != 1) {
+		rc = -EINVAL;
+		goto lb_exit;
+	}
+
+	/* Answer counter */
+	if (dns_header_ancount(resp->res) != resp->ancount) {
+		rc = -EINVAL;
+		goto lb_exit;
+	}
+
+	/* Name server resource records counter must be 0 */
+	if (dns_header_nscount(resp->res) != 0) {
+		rc = -EINVAL;
+		goto lb_exit;
+	}
+
+	/* Additional records counter must be 0 */
+	if (dns_header_arcount(resp->res) != 0) {
+		rc = -EINVAL;
+		goto lb_exit;
+	}
+
+	rc = dns_msg_pack_qname(&qname_len, qname, MAX_BUF_SIZE, resp->dname);
+	if (rc != 0) {
+		goto lb_exit;
+	}
+
+	offset = DNS_HEADER_SIZE;
+
+	/* DNS header + qname + qtype (int size) + qclass (int size) */
+	if (offset + qname_len + 2 * INT_SIZE >= resp->res_len) {
+		rc = -EINVAL;
+		goto lb_exit;
+	}
+
+	if (memcmp(qname, resp->res + offset, qname_len) != 0) {
+		rc = -EINVAL;
+		goto lb_exit;
+	}
+
+	offset += qname_len;
+
+	if (dns_unpack_query_qtype(resp->res + offset) != resp->answer_type) {
+		rc = -EINVAL;
+		goto lb_exit;
+	}
+
+	if (dns_unpack_query_qclass(resp->res + offset) != DNS_CLASS_IN) {
+		rc = -EINVAL;
+		goto lb_exit;
+	}
+
+	/* we add here qtype and qclass */
+	offset += INT_SIZE + INT_SIZE;
+
+	/* 0xc0 and 0x0c are derived from RFC 1035 4.1.4. Message compression.
+	 * 0x0c is the DNS Header Size (fixed size) and 0xc0 is the
+	 * DNS pointer marker.
+	 */
+	if (resp->res[offset + 0] != 0xc0 || resp->res[offset + 1] != 0x0c) {
+		rc = -EINVAL;
+		goto lb_exit;
+	}
+
+	/* simplify the following lines by applying the offset here */
+	resp->res += offset;
+	offset = NAME_PTR_SIZE;
+
+	if (dns_answer_type(NAME_PTR_SIZE, resp->res) != resp->answer_type) {
+		rc = -EINVAL;
+		goto lb_exit;
+	}
+
+	offset += INT_SIZE;
+
+	if (dns_answer_class(NAME_PTR_SIZE, resp->res) != DNS_CLASS_IN) {
+		rc = -EINVAL;
+		goto lb_exit;
+	}
+
+	offset += INT_SIZE;
+
+	if (dns_answer_ttl(NAME_PTR_SIZE, resp->res) != resp->ttl) {
+		rc = -EINVAL;
+		goto lb_exit;
+	}
+
+	offset += ANS_TTL_SIZE;
+
+	if (dns_answer_rdlength(NAME_PTR_SIZE, resp->res) != resp->rdlen) {
+		rc = -EINVAL;
+		goto lb_exit;
+	}
+
+	offset += INT_SIZE;
+
+	if (resp->rdlen + offset > resp->res_len) {
+		rc = -EINVAL;
+		goto lb_exit;
+	}
+
+	if (memcmp(resp->res + offset, resp->rdata, resp->rdlen) != 0) {
+		rc = -EINVAL;
+	}
+
+lb_exit:
+	resp->res = ptr;
+
+	return rc;
+}
+
+
 void test_dns_query(void)
 {
 	int rc;
@@ -178,9 +396,55 @@
 	assert_not_equal(rc, 0, "Query test with invalid ID failed");
 }
 
+/* DNS response for www.zephyrproject.org with the following parameters:
+ * Transaction ID: 0xb041
+ * Answer type: RR A
+ * Answer counter: 1
+ * TTL: 3028
+ * Recursion Available: 1
+ * RD len: 4 (IPv4 Address)
+ * RData: 140.211.169.8
+ */
+static uint8_t resp_ipv4[] = { 0xb0, 0x41, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
+			       0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77,
+			       0x0d, 0x7a, 0x65, 0x70, 0x68, 0x79, 0x72, 0x70,
+			       0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x03, 0x6f,
+			       0x72, 0x67, 0x00, 0x00, 0x01, 0x00, 0x01, 0xc0,
+			       0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0b,
+			       0xd4, 0x00, 0x04, 0x8c, 0xd3, 0xa9, 0x08 };
+
+static const uint8_t resp_ipv4_addr[] = {140, 211, 169, 8};
+
+void test_dns_response(void)
+{
+	struct dns_response_test test1 = { .dname = DNAME1,
+					   .res = resp_ipv4,
+					   .res_len = sizeof(resp_ipv4),
+					   .tid = 0xb041,
+					   .answer_type = DNS_RR_TYPE_A,
+					   .ancount = 1,
+					   .ttl = 3028,
+					   .ra = 1,
+					   .rdlen = 4, /* IPv4 test */
+					   .rdata = resp_ipv4_addr };
+	int rc;
+
+	rc = eval_response1(&test1);
+	assert_equal(rc, 0, "Response test failed for domain: "DNAME1);
+}
+
 void test_main(void)
 {
-	ztest_test_suite(dns_tests, ztest_unit_test(test_dns_query));
+	ztest_test_suite(dns_tests,
+			 ztest_unit_test(test_dns_query),
+			 ztest_unit_test(test_dns_response));
 
 	ztest_run_test_suite(dns_tests);
+
+	/* TODO:
+	 *	1) add malformed DNS data
+	 *	2) add validations against buffer overflows
+	 *	3) add debug info to detect the exit point (or split the tests)
+	 *	4) add test data with CNAME and more RR
+	 */
 }
diff --git a/tests/net/lib/http_header_fields/prj.conf b/tests/net/lib/http_header_fields/prj.conf
index 225061f..a530520 100644
--- a/tests/net/lib/http_header_fields/prj.conf
+++ b/tests/net/lib/http_header_fields/prj.conf
@@ -2,7 +2,6 @@
 CONFIG_RANDOM_GENERATOR=y
 CONFIG_TEST_RANDOM_GENERATOR=y
 
-CONFIG_HTTP=y
 CONFIG_HTTP_PARSER=y
 # Enable strict parser by uncommenting the following line
 # CONFIG_HTTP_PARSER_STRICT=y
diff --git a/tests/net/mgmt/src/mgmt.c b/tests/net/mgmt/src/mgmt.c
index 0440f28..bc138e2 100644
--- a/tests/net/mgmt/src/mgmt.c
+++ b/tests/net/mgmt/src/mgmt.c
@@ -13,13 +13,14 @@
 #include <net/net_mgmt.h>
 #include <net/nbuf.h>
 
-#define TEST_MGMT_REQUEST		0x0ABC1234
-#define TEST_MGMT_EVENT			0x8ABC1234
-#define TEST_MGMT_EVENT_UNHANDLED	0x8ABC4321
+#define TEST_MGMT_REQUEST		0x07AB1234
+#define TEST_MGMT_EVENT			0x87AB1234
+#define TEST_MGMT_EVENT_UNHANDLED	0x87AB4321
 
 /* Notifier infra */
 static uint32_t event2throw;
 static uint32_t throw_times;
+static int throw_sleep;
 static char __noinit __stack thrower_stack[512];
 static struct k_sem thrower_lock;
 
@@ -101,7 +102,10 @@
 			 event2throw, throw_times);
 
 		for (; throw_times; throw_times--) {
-			net_mgmt_event_notify(event2throw, NULL);
+			k_sleep(throw_sleep);
+
+			net_mgmt_event_notify(event2throw,
+					      net_if_get_default());
 		}
 	}
 }
@@ -152,10 +156,47 @@
 	return ret;
 }
 
+static int test_synchronous_event_listener(uint32_t times, bool on_iface)
+{
+	uint32_t event_mask;
+	int ret;
+
+	TC_PRINT("- Synchronous event listener %s\n",
+		 on_iface ? "on interface" : "");
+
+	event2throw = TEST_MGMT_EVENT | (on_iface ? NET_MGMT_IFACE_BIT : 0);
+	throw_times = times;
+	throw_sleep = K_MSEC(200);
+
+	event_mask = event2throw;
+
+	k_sem_give(&thrower_lock);
+
+	if (on_iface) {
+		ret = net_mgmt_event_wait_on_iface(net_if_get_default(),
+						   event_mask, NULL,
+						   K_SECONDS(1));
+	} else {
+		ret = net_mgmt_event_wait(event_mask, NULL, NULL,
+					  K_SECONDS(1));
+	}
+
+	if (ret < 0) {
+		if (ret == -ETIMEDOUT) {
+			TC_ERROR("Call timed out\n");
+		}
+
+		return TC_FAIL;
+	}
+
+	return TC_PASS;
+}
+
 static void initialize_event_tests(void)
 {
 	event2throw = 0;
 	throw_times = 0;
+	throw_sleep = K_NO_WAIT;
 
 	rx_event = 0;
 	rx_calls = 0;
@@ -259,6 +300,14 @@
 		goto end;
 	}
 
+	if (test_synchronous_event_listener(2, false) != TC_PASS) {
+		goto end;
+	}
+
+	if (test_synchronous_event_listener(2, true) != TC_PASS) {
+		goto end;
+	}
+
 	status = TC_PASS;
 
 end:
diff --git a/tests/net/mld/src/main.c b/tests/net/mld/src/main.c
index aa8ccdb..d10ab6a 100644
--- a/tests/net/mld/src/main.c
+++ b/tests/net/mld/src/main.c
@@ -70,13 +70,13 @@
 {
 	struct net_test_mld *context = dev->driver_data;
 
-	if (context->mac_addr[0] == 0x00) {
-		/* 10-00-00-00-00 to 10-00-00-00-FF Documentation RFC7042 */
-		context->mac_addr[0] = 0x10;
+	if (context->mac_addr[2] == 0x00) {
+		/* 00-00-5E-00-53-xx Documentation RFC 7042 */
+		context->mac_addr[0] = 0x00;
 		context->mac_addr[1] = 0x00;
-		context->mac_addr[2] = 0x00;
+		context->mac_addr[2] = 0x5E;
 		context->mac_addr[3] = 0x00;
-		context->mac_addr[4] = 0x00;
+		context->mac_addr[4] = 0x53;
 		context->mac_addr[5] = sys_rand32_get();
 	}
 
@@ -332,7 +332,7 @@
 	net_nbuf_append_be16(buf, 0); /* Resv, S, QRV and QQIC */
 	net_nbuf_append_be16(buf, 0); /* number of addresses */
 
-	buf = net_ipv6_finalize_raw(buf, NET_IPV6_NEXTHDR_HBHO);
+	net_ipv6_finalize_raw(buf, NET_IPV6_NEXTHDR_HBHO);
 
 	net_nbuf_set_iface(buf, iface);
 
diff --git a/tests/net/nbuf/src/main.c b/tests/net/nbuf/src/main.c
index a3ade34..c5e1318 100644
--- a/tests/net/nbuf/src/main.c
+++ b/tests/net/nbuf/src/main.c
@@ -624,25 +624,27 @@
 	tfrag = net_buf_frag_last(buf->frags);
 	off = tfrag->len;
 
-	if (!net_nbuf_append(buf, sizeof(test_rw_short), test_rw_short,
-			     K_FOREVER)) {
+	if (!net_nbuf_append(buf, (uint16_t)sizeof(test_rw_short),
+			     test_rw_short, K_FOREVER)) {
 		printk("net_nbuf_append failed\n");
 		return -EINVAL;
 	}
 
-	if (!net_nbuf_append(buf, sizeof(test_rw_short), test_rw_short,
-			     K_FOREVER)) {
+	if (!net_nbuf_append(buf, (uint16_t)sizeof(test_rw_short),
+			     test_rw_short, K_FOREVER)) {
 		printk("net_nbuf_append failed\n");
 		return -EINVAL;
 	}
 
-	tfrag = net_nbuf_skip(tfrag, off, &tpos, sizeof(test_rw_short));
+	tfrag = net_nbuf_skip(tfrag, off, &tpos,
+			      (uint16_t)sizeof(test_rw_short));
 	if (!tfrag) {
 		printk("net_nbuf_skip failed\n");
 		return -EINVAL;
 	}
 
-	tfrag = net_nbuf_read(tfrag, tpos, &tpos, sizeof(test_rw_short),
+	tfrag = net_nbuf_read(tfrag, tpos, &tpos,
+			      (uint16_t)sizeof(test_rw_short),
 			      verify_rw_short);
 	if (memcmp(test_rw_short, verify_rw_short, sizeof(test_rw_short))) {
 		printk("net_nbuf_read failed with mismatch data");
@@ -660,13 +662,13 @@
 	tfrag = net_buf_frag_last(buf->frags);
 	off = tfrag->len;
 
-	if (!net_nbuf_append(buf, sizeof(test_rw_long), test_rw_long,
+	if (!net_nbuf_append(buf, (uint16_t)sizeof(test_rw_long), test_rw_long,
 			     K_FOREVER)) {
 		printk("net_nbuf_append failed\n");
 		return -EINVAL;
 	}
 
-	if (!net_nbuf_append(buf, sizeof(test_rw_long), test_rw_long,
+	if (!net_nbuf_append(buf, (uint16_t)sizeof(test_rw_long), test_rw_long,
 			     K_FOREVER)) {
 		printk("net_nbuf_append failed\n");
 		return -EINVAL;
@@ -675,19 +677,21 @@
 	/* Try to pass fragment to net_nbuf_append(), this should fail
 	 * as we always need to pass the first buf into it.
 	 */
-	if (net_nbuf_append(buf->frags, sizeof(test_rw_short), test_rw_short,
-			    K_FOREVER)) {
+	if (net_nbuf_append(buf->frags, (uint16_t)sizeof(test_rw_short),
+			    test_rw_short, K_FOREVER)) {
 		printk("net_nbuf_append succeed but should have failed\n");
 		return -EINVAL;
 	}
 
-	tfrag = net_nbuf_skip(tfrag, off, &tpos, sizeof(test_rw_long));
+	tfrag = net_nbuf_skip(tfrag, off, &tpos,
+			      (uint16_t)sizeof(test_rw_long));
 	if (!tfrag) {
 		printk("net_nbuf_skip failed\n");
 		return -EINVAL;
 	}
 
-	tfrag = net_nbuf_read(tfrag, tpos, &tpos, sizeof(test_rw_long),
+	tfrag = net_nbuf_read(tfrag, tpos, &tpos,
+			      (uint16_t)sizeof(test_rw_long),
 			      verify_rw_long);
 	if (memcmp(test_rw_long, verify_rw_long, sizeof(test_rw_long))) {
 		printk("net_nbuf_read failed with mismatch data");
diff --git a/tests/net/route/src/main.c b/tests/net/route/src/main.c
index 21158b6..1c587cd 100644
--- a/tests/net/route/src/main.c
+++ b/tests/net/route/src/main.c
@@ -96,13 +96,13 @@
 {
 	struct net_route_test *route = dev->driver_data;
 
-	if (route->mac_addr[0] == 0x00) {
-		/* 10-00-00-00-00 to 10-00-00-00-FF Documentation RFC7042 */
-		route->mac_addr[0] = 0x10;
+	if (route->mac_addr[2] == 0x00) {
+		/* 00-00-5E-00-53-xx Documentation RFC 7042 */
+		route->mac_addr[0] = 0x00;
 		route->mac_addr[1] = 0x00;
-		route->mac_addr[2] = 0x00;
+		route->mac_addr[2] = 0x5E;
 		route->mac_addr[3] = 0x00;
-		route->mac_addr[4] = 0x00;
+		route->mac_addr[4] = 0x53;
 		route->mac_addr[5] = sys_rand32_get();
 	}
 
@@ -397,7 +397,9 @@
 
 	NET_ICMPV6_NA_BUF(buf)->flags = NET_ICMPV6_NA_FLAG_SOLICITED;
 
-	buf = net_ipv6_finalize_raw(buf, IPPROTO_ICMPV6);
+	if (net_ipv6_finalize_raw(buf, IPPROTO_ICMPV6) < 0) {
+		return false;
+	}
 
 	if (net_send_data(buf) < 0) {
 		TC_ERROR("Cannot send NA buffer\n");
diff --git a/tests/net/rpl/src/main.c b/tests/net/rpl/src/main.c
index cd1971a..e3b0b24 100644
--- a/tests/net/rpl/src/main.c
+++ b/tests/net/rpl/src/main.c
@@ -84,13 +84,13 @@
 {
 	struct net_rpl_test *rpl = dev->driver_data;
 
-	if (rpl->mac_addr[0] == 0x00) {
-		/* 10-00-00-00-00 to 10-00-00-00-FF Documentation RFC7042 */
-		rpl->mac_addr[0] = 0x10;
+	if (rpl->mac_addr[2] == 0x00) {
+		/* 00-00-5E-00-53-xx Documentation RFC 7042 */
+		rpl->mac_addr[0] = 0x00;
 		rpl->mac_addr[1] = 0x00;
-		rpl->mac_addr[2] = 0x00;
+		rpl->mac_addr[2] = 0x5E;
 		rpl->mac_addr[3] = 0x00;
-		rpl->mac_addr[4] = 0x00;
+		rpl->mac_addr[4] = 0x53;
 		rpl->mac_addr[5] = sys_rand32_get();
 	}
 
diff --git a/tests/net/tcp/src/main.c b/tests/net/tcp/src/main.c
index 4e13e4c..7efa5b1 100644
--- a/tests/net/tcp/src/main.c
+++ b/tests/net/tcp/src/main.c
@@ -93,13 +93,13 @@
 {
 	struct net_tcp_context *context = dev->driver_data;
 
-	if (context->mac_addr[0] == 0x00) {
-		/* 10-00-00-00-00 to 10-00-00-00-FF Documentation RFC7042 */
-		context->mac_addr[0] = 0x10;
+	if (context->mac_addr[2] == 0x00) {
+		/* 00-00-5E-00-53-xx Documentation RFC 7042 */
+		context->mac_addr[0] = 0x00;
 		context->mac_addr[1] = 0x00;
-		context->mac_addr[2] = 0x00;
+		context->mac_addr[2] = 0x5E;
 		context->mac_addr[3] = 0x00;
-		context->mac_addr[4] = 0x00;
+		context->mac_addr[4] = 0x53;
 		context->mac_addr[5] = sys_rand32_get();
 	}
 
diff --git a/tests/net/udp/src/main.c b/tests/net/udp/src/main.c
index 47b3c7c..5c721e0 100644
--- a/tests/net/udp/src/main.c
+++ b/tests/net/udp/src/main.c
@@ -55,13 +55,13 @@
 {
 	struct net_udp_context *context = dev->driver_data;
 
-	if (context->mac_addr[0] == 0x00) {
-		/* 10-00-00-00-00 to 10-00-00-00-FF Documentation RFC7042 */
-		context->mac_addr[0] = 0x10;
+	if (context->mac_addr[2] == 0x00) {
+		/* 00-00-5E-00-53-xx Documentation RFC 7042 */
+		context->mac_addr[0] = 0x00;
 		context->mac_addr[1] = 0x00;
-		context->mac_addr[2] = 0x00;
+		context->mac_addr[2] = 0x5E;
 		context->mac_addr[3] = 0x00;
-		context->mac_addr[4] = 0x00;
+		context->mac_addr[4] = 0x53;
 		context->mac_addr[5] = sys_rand32_get();
 	}