diff --git a/include/net/6lowpan.h b/include/net/6lowpan.h
index 90d9d08..9a6282b 100644
--- a/include/net/6lowpan.h
+++ b/include/net/6lowpan.h
@@ -133,6 +133,18 @@ lowpan_iphc_ctx_is_compression(const struct lowpan_iphc_ctx *ctx)
 	return test_bit(LOWPAN_IPHC_CTX_FLAG_COMPRESSION, &ctx->flags);
 }
 
+struct lowpan_addr_info {
+	unsigned char daddr[EUI64_ADDR_LEN];
+	unsigned char saddr[EUI64_ADDR_LEN];
+};
+
+static inline struct
+lowpan_addr_info *lowpan_addr_info(const struct sk_buff *skb)
+{
+	return (struct lowpan_addr_info *)(skb->data -
+					   sizeof(struct lowpan_addr_info));
+}
+
 struct lowpan_dev {
 	enum lowpan_lltypes lltype;
 	struct dentry *iface_debugfs;
diff --git a/net/6lowpan/core.c b/net/6lowpan/core.c
index 00ffab3..b01effd 100644
--- a/net/6lowpan/core.c
+++ b/net/6lowpan/core.c
@@ -18,6 +18,33 @@
 
 #include "6lowpan_i.h"
 
+/* TODO I think AF_PACKET DGRAM (sending/receiving) RAW (sending) makes no
+ * sense here. We should disable it, the right use-case would be AF_INET6
+ * RAW/DGRAM sockets.
+ */
+static int lowpan_header_create(struct sk_buff *skb, struct net_device *dev,
+				unsigned short type, const void *daddr,
+				const void *saddr, unsigned int len)
+{
+	struct lowpan_addr_info *info = lowpan_addr_info(skb);
+
+	if (WARN_ON_ONCE(type != ETH_P_IPV6))
+		return -EINVAL;
+
+	memcpy(info->daddr, daddr, dev->addr_len);
+
+	if (saddr)
+		memcpy(info->saddr, saddr, dev->addr_len);
+	else
+		memcpy(info->saddr, dev->dev_addr, dev->addr_len);
+
+	return 0;
+}
+
+static struct header_ops header_ops = {
+	.create	= lowpan_header_create,
+};
+
 int lowpan_register_netdevice(struct net_device *dev,
 			      enum lowpan_lltypes lltype)
 {
@@ -28,6 +55,14 @@ int lowpan_register_netdevice(struct net_device *dev,
 	dev->mtu = IPV6_MIN_MTU;
 	dev->priv_flags |= IFF_NO_QUEUE;
 
+	dev->header_ops = &header_ops;
+
+	/* We need at least headroom for lowpan_addr_info to get necessary
+	 * address information from header create to xmit callback.
+	 */
+	if (dev->needed_headroom < sizeof(struct lowpan_addr_info))
+		dev->needed_headroom += sizeof(struct lowpan_addr_info);
+
 	lowpan_dev(dev)->lltype = lltype;
 
 	spin_lock_init(&lowpan_dev(dev)->ctx.lock);
diff --git a/net/ieee802154/6lowpan/6lowpan_i.h b/net/ieee802154/6lowpan/6lowpan_i.h
index 39b739f..709c22c 100644
--- a/net/ieee802154/6lowpan/6lowpan_i.h
+++ b/net/ieee802154/6lowpan/6lowpan_i.h
@@ -48,9 +48,6 @@ int lowpan_net_frag_init(void);
 void lowpan_rx_init(void);
 void lowpan_rx_exit(void);
 
-int lowpan_header_create(struct sk_buff *skb, struct net_device *dev,
-			 unsigned short type, const void *_daddr,
-			 const void *_saddr, unsigned int len);
 netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *dev);
 
 int lowpan_iphc_decompress(struct sk_buff *skb);
diff --git a/net/ieee802154/6lowpan/core.c b/net/ieee802154/6lowpan/core.c
index f70edcc..096a194 100644
--- a/net/ieee802154/6lowpan/core.c
+++ b/net/ieee802154/6lowpan/core.c
@@ -54,10 +54,6 @@
 
 static int open_count;
 
-static struct header_ops lowpan_header_ops = {
-	.create	= lowpan_header_create,
-};
-
 static int lowpan_dev_init(struct net_device *ldev)
 {
 	netdev_lockdep_set_classes(ldev);
@@ -106,7 +102,6 @@ static void lowpan_setup(struct net_device *ldev)
 	ldev->flags		= IFF_BROADCAST | IFF_MULTICAST;
 
 	ldev->netdev_ops	= &lowpan_netdev_ops;
-	ldev->header_ops	= &lowpan_header_ops;
 	ldev->destructor	= free_netdev;
 	ldev->features		|= NETIF_F_NETNS_LOCAL;
 }
diff --git a/net/ieee802154/6lowpan/tx.c b/net/ieee802154/6lowpan/tx.c
index a7a1b12..f56b9cd 100644
--- a/net/ieee802154/6lowpan/tx.c
+++ b/net/ieee802154/6lowpan/tx.c
@@ -18,48 +18,23 @@
 #define LOWPAN_FRAG1_HEAD_SIZE	0x4
 #define LOWPAN_FRAGN_HEAD_SIZE	0x5
 
-struct lowpan_addr_info {
-	struct ieee802154_addr daddr;
-	struct ieee802154_addr saddr;
-};
-
-static inline struct
-lowpan_addr_info *lowpan_skb_priv(const struct sk_buff *skb)
-{
-	return (struct lowpan_addr_info *)(skb->data -
-			sizeof(struct lowpan_addr_info));
-}
-
-/* This callback will be called from AF_PACKET and IPv6 stack, the AF_PACKET
- * sockets gives an 8 byte array for addresses only!
- *
- * TODO I think AF_PACKET DGRAM (sending/receiving) RAW (sending) makes no
- * sense here. We should disable it, the right use-case would be AF_INET6
- * RAW/DGRAM sockets.
- */
-int lowpan_header_create(struct sk_buff *skb, struct net_device *ldev,
-			 unsigned short type, const void *daddr,
-			 const void *saddr, unsigned int len)
+static void lowpan_addr_lookup(struct net_device *ldev, struct sk_buff *skb,
+			       struct ieee802154_addr *daddr,
+			       struct ieee802154_addr *saddr)
 {
 	struct wpan_dev *wpan_dev = lowpan_802154_dev(ldev)->wdev->ieee802154_ptr;
-	struct lowpan_addr_info *info = lowpan_skb_priv(skb);
+	struct lowpan_addr_info *info = lowpan_addr_info(skb);
 	struct lowpan_802154_neigh *llneigh = NULL;
 	const struct ipv6hdr *hdr = ipv6_hdr(skb);
 	struct neighbour *n;
 
-	/* TODO:
-	 * if this package isn't ipv6 one, where should it be routed?
-	 */
-	if (type != ETH_P_IPV6)
-		return 0;
-
 	/* intra-pan communication */
-	info->saddr.pan_id = wpan_dev->pan_id;
-	info->daddr.pan_id = info->saddr.pan_id;
+	saddr->pan_id = wpan_dev->pan_id;
+	daddr->pan_id = saddr->pan_id;
 
-	if (!memcmp(daddr, ldev->broadcast, EUI64_ADDR_LEN)) {
-		info->daddr.short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
-		info->daddr.mode = IEEE802154_ADDR_SHORT;
+	if (!memcmp(info->daddr, ldev->broadcast, EUI64_ADDR_LEN)) {
+		daddr->short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
+		daddr->mode = IEEE802154_ADDR_SHORT;
 	} else {
 		__le16 short_addr = cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC);
 
@@ -73,32 +48,25 @@ int lowpan_header_create(struct sk_buff *skb, struct net_device *ldev,
 
 		if (llneigh &&
 		    lowpan_802154_is_valid_src_short_addr(short_addr)) {
-			info->daddr.short_addr = short_addr;
-			info->daddr.mode = IEEE802154_ADDR_SHORT;
+			daddr->short_addr = short_addr;
+			daddr->mode = IEEE802154_ADDR_SHORT;
 		} else {
-			info->daddr.mode = IEEE802154_ADDR_LONG;
-			ieee802154_be64_to_le64(&info->daddr.extended_addr,
-						daddr);
+			daddr->mode = IEEE802154_ADDR_LONG;
+			ieee802154_be64_to_le64(&daddr->extended_addr,
+						info->daddr);
 		}
 
 		if (n)
 			neigh_release(n);
 	}
 
-	if (!saddr) {
-		if (lowpan_802154_is_valid_src_short_addr(wpan_dev->short_addr)) {
-			info->saddr.mode = IEEE802154_ADDR_SHORT;
-			info->saddr.short_addr = wpan_dev->short_addr;
-		} else {
-			info->saddr.mode = IEEE802154_ADDR_LONG;
-			info->saddr.extended_addr = wpan_dev->extended_addr;
-		}
+	if (lowpan_802154_is_valid_src_short_addr(wpan_dev->short_addr)) {
+		saddr->mode = IEEE802154_ADDR_SHORT;
+		saddr->short_addr = wpan_dev->short_addr;
 	} else {
-		info->saddr.mode = IEEE802154_ADDR_LONG;
-		ieee802154_be64_to_le64(&info->saddr.extended_addr, saddr);
+		saddr->mode = IEEE802154_ADDR_LONG;
+		ieee802154_be64_to_le64(&saddr->extended_addr, info->saddr);
 	}
-
-	return 0;
 }
 
 static struct sk_buff*
@@ -227,33 +195,33 @@ err:
 }
 
 static int lowpan_header(struct sk_buff *skb, struct net_device *ldev,
-			 u16 *dgram_size, u16 *dgram_offset)
+			 u16 *dgram_size, u16 *dgram_offset,
+			 const struct ieee802154_addr *daddr,
+			 const struct ieee802154_addr *saddr)
 {
 	struct wpan_dev *wpan_dev = lowpan_802154_dev(ldev)->wdev->ieee802154_ptr;
 	struct ieee802154_mac_cb *cb = mac_cb_init(skb);
-	struct lowpan_addr_info info;
-
-	memcpy(&info, lowpan_skb_priv(skb), sizeof(info));
 
 	*dgram_size = skb->len;
-	lowpan_header_compress(skb, ldev, &info.daddr, &info.saddr);
+	lowpan_header_compress(skb, ldev, daddr, saddr);
 	/* dgram_offset = (saved bytes after compression) + lowpan header len */
 	*dgram_offset = (*dgram_size - skb->len) + skb_network_header_len(skb);
 
 	cb->type = IEEE802154_FC_TYPE_DATA;
 
-	if (info.daddr.mode == IEEE802154_ADDR_SHORT &&
-	    ieee802154_is_broadcast_short_addr(info.daddr.short_addr))
+	if (daddr->mode == IEEE802154_ADDR_SHORT &&
+	    ieee802154_is_broadcast_short_addr(daddr->short_addr))
 		cb->ackreq = false;
 	else
 		cb->ackreq = wpan_dev->ackreq;
 
-	return wpan_dev_hard_header(skb, lowpan_802154_dev(ldev)->wdev,
-				    &info.daddr, &info.saddr, 0);
+	return wpan_dev_hard_header(skb, lowpan_802154_dev(ldev)->wdev, daddr,
+				    saddr, 0);
 }
 
 netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *ldev)
 {
+	struct ieee802154_addr daddr, saddr;
 	struct ieee802154_hdr wpan_hdr;
 	int max_single, ret;
 	u16 dgram_size, dgram_offset;
@@ -262,6 +230,8 @@ netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *ldev)
 
 	WARN_ON_ONCE(skb->len > IPV6_MIN_MTU);
 
+	lowpan_addr_lookup(ldev, skb, &daddr, &saddr);
+
 	/* We must take a copy of the skb before we modify/replace the ipv6
 	 * header as the header could be used elsewhere
 	 */
@@ -269,7 +239,8 @@ netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *ldev)
 	if (!skb)
 		return NET_XMIT_DROP;
 
-	ret = lowpan_header(skb, ldev, &dgram_size, &dgram_offset);
+	ret = lowpan_header(skb, ldev, &dgram_size, &dgram_offset, &daddr,
+			    &saddr);
 	if (ret < 0) {
 		kfree_skb(skb);
 		return NET_XMIT_DROP;
