#define IEEE802154_ACK_PSDU_LEN                5
 #define IEEE802154_MIN_PSDU_LEN                9
 #define IEEE802154_FCS_LEN             2
+#define IEEE802154_MAX_AUTH_TAG_LEN    16
+
+/*  General MAC frame format:
+ *  2 bytes: Frame Control
+ *  1 byte:  Sequence Number
+ * 20 bytes: Addressing fields
+ * 14 bytes: Auxiliary Security Header
+ */
+#define IEEE802154_MAX_HEADER_LEN      (2 + 1 + 20 + 14)
+#define IEEE802154_MIN_HEADER_LEN      (IEEE802154_ACK_PSDU_LEN - \
+                                        IEEE802154_FCS_LEN)
 
 #define IEEE802154_PAN_ID_BROADCAST    0xffff
 #define IEEE802154_ADDR_SHORT_BROADCAST        0xffff
 
 #define UIP_PROTO_UDP                  17 /* ipv6 next header value for UDP */
 #define UIP_FRAGH_LEN                  8  /* ipv6 fragment header size */
 
+#define LOWPAN_NHC_MAX_ID_LEN  1
+/* Max IPHC Header len without IPv6 hdr specific inline data.
+ * Useful for getting the "extra" bytes we need at worst case compression.
+ *
+ * LOWPAN_IPHC + CID + LOWPAN_NHC_MAX_ID_LEN
+ */
+#define LOWPAN_IPHC_MAX_HEADER_LEN     (2 + 1 + LOWPAN_NHC_MAX_ID_LEN)
+
 /*
  * ipv6 address based on mac
  * second bit-flip (Universe/Local) is done according RFC2464
 
 
 #include <net/cfg802154.h>
 
-/* General MAC frame format:
- *  2 bytes: Frame Control
- *  1 byte:  Sequence Number
- * 20 bytes: Addressing fields
- * 14 bytes: Auxiliary Security Header
- */
-#define MAC802154_FRAME_HARD_HEADER_LEN                (2 + 1 + 20 + 14)
-
 /**
  * enum ieee802154_hw_addr_filt_flags - hardware address filtering flags
  *
 
 #include <net/6lowpan.h>
 #include <net/ipv6.h>
 
-#define LOWPAN_NHC_MAX_ID_LEN  1
-
 /**
  * LOWPAN_NHC - helper macro to generate nh id fields and lowpan_nhc struct
  *
 
        ldev->addr_len          = IEEE802154_ADDR_LEN;
        memset(ldev->broadcast, 0xff, IEEE802154_ADDR_LEN);
        ldev->type              = ARPHRD_6LOWPAN;
-       /* Frame Control + Sequence Number + Address fields + Security Header */
-       ldev->hard_header_len   = 2 + 1 + 20 + 14;
-       ldev->needed_tailroom   = 2; /* FCS */
+       /* We need an ipv6hdr as minimum len when calling xmit */
+       ldev->hard_header_len   = sizeof(struct ipv6hdr);
        ldev->mtu               = IPV6_MIN_MTU;
        ldev->priv_flags        |= IFF_NO_QUEUE;
        ldev->flags             = IFF_BROADCAST | IFF_MULTICAST;
        lowpan_dev_info(ldev)->wdev = wdev;
        /* Set the lowpan hardware address to the wpan hardware address. */
        memcpy(ldev->dev_addr, wdev->dev_addr, IEEE802154_ADDR_LEN);
+       /* We need headroom for possible wpan_dev_hard_header call and tailroom
+        * for encryption/fcs handling. The lowpan interface will replace
+        * the IPv6 header with 6LoWPAN header. At worst case the 6LoWPAN
+        * header has LOWPAN_IPHC_MAX_HEADER_LEN more bytes than the IPv6
+        * header.
+        */
+       ldev->needed_headroom = LOWPAN_IPHC_MAX_HEADER_LEN +
+                               wdev->needed_headroom;
+       ldev->needed_tailroom = wdev->needed_tailroom;
 
        lowpan_netdev_setup(ldev, LOWPAN_LLTYPE_IEEE802154);
 
 
 
 #include <net/6lowpan.h>
 #include <net/ieee802154_netdev.h>
+#include <net/mac802154.h>
 
 #include "6lowpan_i.h"
 
                        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)
        struct sk_buff *frag;
        int rc;
 
-       frag = alloc_skb(wdev->hard_header_len + wdev->needed_tailroom + size,
+       frag = alloc_skb(wdev->needed_headroom + wdev->needed_tailroom + size,
                         GFP_ATOMIC);
 
        if (likely(frag)) {
                frag->dev = wdev;
                frag->priority = skb->priority;
-               skb_reserve(frag, wdev->hard_header_len);
+               skb_reserve(frag, wdev->needed_headroom);
                skb_reset_network_header(frag);
                *mac_cb(frag) = *mac_cb(skb);
 
 
 int
 ieee802154_hdr_push(struct sk_buff *skb, struct ieee802154_hdr *hdr)
 {
-       u8 buf[MAC802154_FRAME_HARD_HEADER_LEN];
+       u8 buf[IEEE802154_MAX_HEADER_LEN];
        int pos = 2;
        int rc;
        struct ieee802154_hdr_fc *fc = &hdr->fc;
 
        dev->addr_len           = IEEE802154_EXTENDED_ADDR_LEN;
        memset(dev->broadcast, 0xff, IEEE802154_EXTENDED_ADDR_LEN);
 
-       dev->hard_header_len    = MAC802154_FRAME_HARD_HEADER_LEN;
-       dev->needed_tailroom    = 2 + 16; /* FCS + MIC */
+       /* Let hard_header_len set to IEEE802154_MIN_HEADER_LEN. AF_PACKET
+        * will not send frames without any payload, but ack frames
+        * has no payload, so substract one that we can send a 3 bytes
+        * frame. The xmit callback assumes at least a hard header where two
+        * bytes fc and sequence field are set.
+        */
+       dev->hard_header_len    = IEEE802154_MIN_HEADER_LEN - 1;
+       /* The auth_tag header is for security and places in private payload
+        * room of mac frame which stucks between payload and FCS field.
+        */
+       dev->needed_tailroom    = IEEE802154_MAX_AUTH_TAG_LEN +
+                                 IEEE802154_FCS_LEN;
        dev->mtu                = IEEE802154_MTU;
        dev->tx_queue_len       = 300;
        dev->flags              = IFF_NOARP | IFF_BROADCAST;
        if (!ndev)
                return ERR_PTR(-ENOMEM);
 
-       ndev->needed_headroom = local->hw.extra_tx_headroom;
+       ndev->needed_headroom = local->hw.extra_tx_headroom +
+                               IEEE802154_MAX_HEADER_LEN;
 
        ret = dev_alloc_name(ndev, ndev->name);
        if (ret < 0)
 
                put_unaligned_le16(crc, skb_put(skb, 2));
        }
 
-       if (skb_cow_head(skb, local->hw.extra_tx_headroom))
-               goto err_tx;
-
        /* Stop the netif queue on each sub_if_data object. */
        ieee802154_stop_queue(&local->hw);