struct dgram_sock {
        struct sock sk;
 
-       struct ieee802154_addr_sa src_addr;
-       struct ieee802154_addr_sa dst_addr;
+       struct ieee802154_addr src_addr;
+       struct ieee802154_addr dst_addr;
 
        unsigned int bound:1;
        unsigned int want_ack:1;
 {
        struct dgram_sock *ro = dgram_sk(sk);
 
-       ro->dst_addr.addr_type = IEEE802154_ADDR_LONG;
-       ro->dst_addr.pan_id = 0xffff;
+       ro->dst_addr.mode = IEEE802154_ADDR_LONG;
+       ro->dst_addr.pan_id = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
        ro->want_ack = 1;
-       memset(&ro->dst_addr.hwaddr, 0xff, sizeof(ro->dst_addr.hwaddr));
+       memset(&ro->dst_addr.extended_addr, 0xff, IEEE802154_ADDR_LEN);
        return 0;
 }
 
 static int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len)
 {
        struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr;
+       struct ieee802154_addr haddr;
        struct dgram_sock *ro = dgram_sk(sk);
        int err = -EINVAL;
        struct net_device *dev;
        if (addr->family != AF_IEEE802154)
                goto out;
 
-       dev = ieee802154_get_dev(sock_net(sk), &addr->addr);
+       ieee802154_addr_from_sa(&haddr, &addr->addr);
+       dev = ieee802154_get_dev(sock_net(sk), &haddr);
        if (!dev) {
                err = -ENODEV;
                goto out;
                goto out_put;
        }
 
-       memcpy(&ro->src_addr, &addr->addr, sizeof(struct ieee802154_addr_sa));
+       ro->src_addr = haddr;
 
        ro->bound = 1;
        err = 0;
                         * of this packet since that is all
                         * that will be read.
                         */
-                       /* FIXME: parse the header for more correct value */
-                       amount = skb->len - (3+8+8);
+                       amount = skb->len - ieee802154_hdr_length(skb);
                }
                spin_unlock_bh(&sk->sk_receive_queue.lock);
                return put_user(amount, (int __user *)arg);
                goto out;
        }
 
-       memcpy(&ro->dst_addr, &addr->addr, sizeof(struct ieee802154_addr_sa));
+       ieee802154_addr_from_sa(&ro->dst_addr, &addr->addr);
 
 out:
        release_sock(sk);
 
        lock_sock(sk);
 
-       ro->dst_addr.addr_type = IEEE802154_ADDR_LONG;
-       memset(&ro->dst_addr.hwaddr, 0xff, sizeof(ro->dst_addr.hwaddr));
+       ro->dst_addr.mode = IEEE802154_ADDR_LONG;
+       memset(&ro->dst_addr.extended_addr, 0xff, IEEE802154_ADDR_LEN);
 
        release_sock(sk);
 
        return NET_RX_SUCCESS;
 }
 
-static inline int ieee802154_match_sock(u8 *hw_addr, u16 pan_id,
-               u16 short_addr, struct dgram_sock *ro)
+static inline bool
+ieee802154_match_sock(__le64 hw_addr, __le16 pan_id, __le16 short_addr,
+                     struct dgram_sock *ro)
 {
        if (!ro->bound)
-               return 1;
+               return true;
 
-       if (ro->src_addr.addr_type == IEEE802154_ADDR_LONG &&
-           !memcmp(ro->src_addr.hwaddr, hw_addr, IEEE802154_ADDR_LEN))
-               return 1;
+       if (ro->src_addr.mode == IEEE802154_ADDR_LONG &&
+           hw_addr == ro->src_addr.extended_addr)
+               return true;
 
-       if (ro->src_addr.addr_type == IEEE802154_ADDR_SHORT &&
-                    pan_id == ro->src_addr.pan_id &&
-                    short_addr == ro->src_addr.short_addr)
-               return 1;
+       if (ro->src_addr.mode == IEEE802154_ADDR_SHORT &&
+           pan_id == ro->src_addr.pan_id &&
+           short_addr == ro->src_addr.short_addr)
+               return true;
 
-       return 0;
+       return false;
 }
 
 int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb)
 {
        struct sock *sk, *prev = NULL;
        int ret = NET_RX_SUCCESS;
-       u16 pan_id, short_addr;
+       __le16 pan_id, short_addr;
+       __le64 hw_addr;
 
        /* Data frame processing */
        BUG_ON(dev->type != ARPHRD_IEEE802154);
 
-       pan_id = le16_to_cpu(ieee802154_mlme_ops(dev)->get_pan_id(dev));
-       short_addr = le16_to_cpu(ieee802154_mlme_ops(dev)->get_short_addr(dev));
+       pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
+       short_addr = ieee802154_mlme_ops(dev)->get_short_addr(dev);
+       hw_addr = ieee802154_devaddr_from_raw(dev->dev_addr);
 
        read_lock(&dgram_lock);
        sk_for_each(sk, &dgram_head) {
-               if (ieee802154_match_sock(dev->dev_addr, pan_id, short_addr,
-                                       dgram_sk(sk))) {
+               if (ieee802154_match_sock(hw_addr, pan_id, short_addr,
+                                         dgram_sk(sk))) {
                        if (prev) {
                                struct sk_buff *clone;
                                clone = skb_clone(skb, GFP_ATOMIC);
 
 
 #include "mac802154.h"
 
-static inline int mac802154_fetch_skb_u8(struct sk_buff *skb, u8 *val)
-{
-       if (unlikely(!pskb_may_pull(skb, 1)))
-               return -EINVAL;
-
-       *val = skb->data[0];
-       skb_pull(skb, 1);
-
-       return 0;
-}
-
-static inline int mac802154_fetch_skb_u16(struct sk_buff *skb, u16 *val)
-{
-       if (unlikely(!pskb_may_pull(skb, 2)))
-               return -EINVAL;
-
-       *val = skb->data[0] | (skb->data[1] << 8);
-       skb_pull(skb, 2);
-
-       return 0;
-}
-
-static inline void mac802154_haddr_copy_swap(u8 *dest, const u8 *src)
-{
-       int i;
-       for (i = 0; i < IEEE802154_ADDR_LEN; i++)
-               dest[IEEE802154_ADDR_LEN - i - 1] = src[i];
-}
-
 static int
 mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
 static int mac802154_header_create(struct sk_buff *skb,
                                   struct net_device *dev,
                                   unsigned short type,
-                                  const void *_daddr,
-                                  const void *_saddr,
+                                  const void *daddr,
+                                  const void *saddr,
                                   unsigned len)
 {
-       const struct ieee802154_addr_sa *saddr = _saddr;
-       const struct ieee802154_addr_sa *daddr = _daddr;
-       struct ieee802154_addr_sa dev_addr;
+       struct ieee802154_hdr hdr;
        struct mac802154_sub_if_data *priv = netdev_priv(dev);
-       int pos = 2;
-       u8 head[MAC802154_FRAME_HARD_HEADER_LEN];
-       u16 fc;
+       int hlen;
 
        if (!daddr)
                return -EINVAL;
 
-       head[pos++] = mac_cb(skb)->seq; /* DSN/BSN */
-       fc = mac_cb_type(skb);
-       if (mac_cb_is_ackreq(skb))
-               fc |= IEEE802154_FC_ACK_REQ;
+       memset(&hdr.fc, 0, sizeof(hdr.fc));
+       hdr.fc.type = mac_cb_type(skb);
+       hdr.fc.security_enabled = mac_cb_is_secen(skb);
+       hdr.fc.ack_request = mac_cb_is_ackreq(skb);
 
        if (!saddr) {
                spin_lock_bh(&priv->mib_lock);
                if (priv->short_addr == cpu_to_le16(IEEE802154_ADDR_BROADCAST) ||
                    priv->short_addr == cpu_to_le16(IEEE802154_ADDR_UNDEF) ||
                    priv->pan_id == cpu_to_le16(IEEE802154_PANID_BROADCAST)) {
-                       dev_addr.addr_type = IEEE802154_ADDR_LONG;
-                       memcpy(dev_addr.hwaddr, dev->dev_addr,
-                              IEEE802154_ADDR_LEN);
+                       hdr.source.mode = IEEE802154_ADDR_LONG;
+                       hdr.source.extended_addr = priv->extended_addr;
                } else {
-                       dev_addr.addr_type = IEEE802154_ADDR_SHORT;
-                       dev_addr.short_addr = le16_to_cpu(priv->short_addr);
+                       hdr.source.mode = IEEE802154_ADDR_SHORT;
+                       hdr.source.short_addr = priv->short_addr;
                }
 
-               dev_addr.pan_id = le16_to_cpu(priv->pan_id);
-               saddr = &dev_addr;
+               hdr.source.pan_id = priv->pan_id;
 
                spin_unlock_bh(&priv->mib_lock);
+       } else {
+               hdr.source = *(const struct ieee802154_addr *)saddr;
        }
 
-       if (daddr->addr_type != IEEE802154_ADDR_NONE) {
-               fc |= (daddr->addr_type << IEEE802154_FC_DAMODE_SHIFT);
-
-               head[pos++] = daddr->pan_id & 0xff;
-               head[pos++] = daddr->pan_id >> 8;
-
-               if (daddr->addr_type == IEEE802154_ADDR_SHORT) {
-                       head[pos++] = daddr->short_addr & 0xff;
-                       head[pos++] = daddr->short_addr >> 8;
-               } else {
-                       mac802154_haddr_copy_swap(head + pos, daddr->hwaddr);
-                       pos += IEEE802154_ADDR_LEN;
-               }
-       }
-
-       if (saddr->addr_type != IEEE802154_ADDR_NONE) {
-               fc |= (saddr->addr_type << IEEE802154_FC_SAMODE_SHIFT);
-
-               if ((saddr->pan_id == daddr->pan_id) &&
-                   (saddr->pan_id != IEEE802154_PANID_BROADCAST)) {
-                       /* PANID compression/intra PAN */
-                       fc |= IEEE802154_FC_INTRA_PAN;
-               } else {
-                       head[pos++] = saddr->pan_id & 0xff;
-                       head[pos++] = saddr->pan_id >> 8;
-               }
+       hdr.dest = *(const struct ieee802154_addr *)daddr;
 
-               if (saddr->addr_type == IEEE802154_ADDR_SHORT) {
-                       head[pos++] = saddr->short_addr & 0xff;
-                       head[pos++] = saddr->short_addr >> 8;
-               } else {
-                       mac802154_haddr_copy_swap(head + pos, saddr->hwaddr);
-                       pos += IEEE802154_ADDR_LEN;
-               }
-       }
-
-       head[0] = fc;
-       head[1] = fc >> 8;
+       hlen = ieee802154_hdr_push(skb, &hdr);
+       if (hlen < 0)
+               return -EINVAL;
 
-       memcpy(skb_push(skb, pos), head, pos);
        skb_reset_mac_header(skb);
-       skb->mac_len = pos;
+       skb->mac_len = hlen;
 
-       return pos;
+       return hlen;
 }
 
 static int
 mac802154_header_parse(const struct sk_buff *skb, unsigned char *haddr)
 {
-       const u8 *hdr = skb_mac_header(skb);
-       const u8 *tail = skb_tail_pointer(skb);
-       struct ieee802154_addr_sa *addr = (struct ieee802154_addr_sa *)haddr;
-       u16 fc;
-       int da_type;
-
-       if (hdr + 3 > tail)
-               goto malformed;
-
-       fc = hdr[0] | (hdr[1] << 8);
+       struct ieee802154_hdr hdr;
+       struct ieee802154_addr *addr = (struct ieee802154_addr *)haddr;
 
-       hdr += 3;
-
-       da_type = IEEE802154_FC_DAMODE(fc);
-       addr->addr_type = IEEE802154_FC_SAMODE(fc);
-
-       switch (da_type) {
-       case IEEE802154_ADDR_NONE:
-               if (fc & IEEE802154_FC_INTRA_PAN)
-                       goto malformed;
-               break;
-       case IEEE802154_ADDR_LONG:
-               if (fc & IEEE802154_FC_INTRA_PAN) {
-                       if (hdr + 2 > tail)
-                               goto malformed;
-                       addr->pan_id = hdr[0] | (hdr[1] << 8);
-                       hdr += 2;
-               }
-
-               if (hdr + IEEE802154_ADDR_LEN > tail)
-                       goto malformed;
-
-               hdr += IEEE802154_ADDR_LEN;
-               break;
-       case IEEE802154_ADDR_SHORT:
-               if (fc & IEEE802154_FC_INTRA_PAN) {
-                       if (hdr + 2 > tail)
-                               goto malformed;
-                       addr->pan_id = hdr[0] | (hdr[1] << 8);
-                       hdr += 2;
-               }
-
-               if (hdr + 2 > tail)
-                       goto malformed;
-
-               hdr += 2;
-               break;
-       default:
-               goto malformed;
-
-       }
-
-       switch (addr->addr_type) {
-       case IEEE802154_ADDR_NONE:
-               break;
-       case IEEE802154_ADDR_LONG:
-               if (!(fc & IEEE802154_FC_INTRA_PAN)) {
-                       if (hdr + 2 > tail)
-                               goto malformed;
-                       addr->pan_id = hdr[0] | (hdr[1] << 8);
-                       hdr += 2;
-               }
-
-               if (hdr + IEEE802154_ADDR_LEN > tail)
-                       goto malformed;
-
-               mac802154_haddr_copy_swap(addr->hwaddr, hdr);
-               hdr += IEEE802154_ADDR_LEN;
-               break;
-       case IEEE802154_ADDR_SHORT:
-               if (!(fc & IEEE802154_FC_INTRA_PAN)) {
-                       if (hdr + 2 > tail)
-                               goto malformed;
-                       addr->pan_id = hdr[0] | (hdr[1] << 8);
-                       hdr += 2;
-               }
-
-               if (hdr + 2 > tail)
-                       goto malformed;
-
-               addr->short_addr = hdr[0] | (hdr[1] << 8);
-               hdr += 2;
-               break;
-       default:
-               goto malformed;
+       if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0) {
+               pr_debug("malformed packet\n");
+               return 0;
        }
 
-       return sizeof(struct ieee802154_addr_sa);
-
-malformed:
-       pr_debug("malformed packet\n");
-       return 0;
+       *addr = hdr.source;
+       return sizeof(*addr);
 }
 
 static netdev_tx_t
        }
 }
 
-static int mac802154_parse_frame_start(struct sk_buff *skb)
+static void mac802154_print_addr(const char *name,
+                                const struct ieee802154_addr *addr)
 {
-       u8 *head = skb->data;
-       u16 fc;
-
-       if (mac802154_fetch_skb_u16(skb, &fc) ||
-           mac802154_fetch_skb_u8(skb, &(mac_cb(skb)->seq)))
-               goto err;
+       if (addr->mode == IEEE802154_ADDR_NONE)
+               pr_debug("%s not present\n", name);
 
-       pr_debug("fc: %04x dsn: %02x\n", fc, head[2]);
+       pr_debug("%s PAN ID: %04x\n", name, le16_to_cpu(addr->pan_id));
+       if (addr->mode == IEEE802154_ADDR_SHORT) {
+               pr_debug("%s is short: %04x\n", name,
+                        le16_to_cpu(addr->short_addr));
+       } else {
+               u64 hw = swab64((__force u64) addr->extended_addr);
 
-       mac_cb(skb)->flags = IEEE802154_FC_TYPE(fc);
-       mac_cb(skb)->sa.addr_type = IEEE802154_FC_SAMODE(fc);
-       mac_cb(skb)->da.addr_type = IEEE802154_FC_DAMODE(fc);
+               pr_debug("%s is hardware: %8phC\n", name, &hw);
+       }
+}
 
-       if (fc & IEEE802154_FC_INTRA_PAN)
-               mac_cb(skb)->flags |= MAC_CB_FLAG_INTRAPAN;
+static int mac802154_parse_frame_start(struct sk_buff *skb)
+{
+       struct ieee802154_hdr hdr;
+       int hlen;
 
-       if (mac_cb(skb)->da.addr_type != IEEE802154_ADDR_NONE) {
-               if (mac802154_fetch_skb_u16(skb, &(mac_cb(skb)->da.pan_id)))
-                       goto err;
+       hlen = ieee802154_hdr_pull(skb, &hdr);
+       if (hlen < 0)
+               return -EINVAL;
 
-               /* source PAN id compression */
-               if (mac_cb_is_intrapan(skb))
-                       mac_cb(skb)->sa.pan_id = mac_cb(skb)->da.pan_id;
+       skb->mac_len = hlen;
 
-               pr_debug("dest PAN addr: %04x\n", mac_cb(skb)->da.pan_id);
+       pr_debug("fc: %04x dsn: %02x\n", le16_to_cpup((__le16 *)&hdr.fc),
+                hdr.seq);
 
-               if (mac_cb(skb)->da.addr_type == IEEE802154_ADDR_SHORT) {
-                       u16 *da = &(mac_cb(skb)->da.short_addr);
+       mac_cb(skb)->flags = hdr.fc.type;
 
-                       if (mac802154_fetch_skb_u16(skb, da))
-                               goto err;
+       ieee802154_addr_to_sa(&mac_cb(skb)->sa, &hdr.source);
+       ieee802154_addr_to_sa(&mac_cb(skb)->da, &hdr.dest);
 
-                       pr_debug("destination address is short: %04x\n",
-                                mac_cb(skb)->da.short_addr);
-               } else {
-                       if (!pskb_may_pull(skb, IEEE802154_ADDR_LEN))
-                               goto err;
+       if (hdr.fc.ack_request)
+               mac_cb(skb)->flags |= MAC_CB_FLAG_ACKREQ;
+       if (hdr.fc.security_enabled)
+               mac_cb(skb)->flags |= MAC_CB_FLAG_SECEN;
 
-                       mac802154_haddr_copy_swap(mac_cb(skb)->da.hwaddr,
-                                                 skb->data);
-                       skb_pull(skb, IEEE802154_ADDR_LEN);
+       mac802154_print_addr("destination", &hdr.dest);
+       mac802154_print_addr("source", &hdr.source);
 
-                       pr_debug("destination address is hardware\n");
-               }
-       }
+       if (hdr.fc.security_enabled) {
+               u64 key;
 
-       if (mac_cb(skb)->sa.addr_type != IEEE802154_ADDR_NONE) {
-               /* non PAN-compression, fetch source address id */
-               if (!(mac_cb_is_intrapan(skb))) {
-                       u16 *sa_pan = &(mac_cb(skb)->sa.pan_id);
+               pr_debug("seclevel %i\n", hdr.sec.level);
 
-                       if (mac802154_fetch_skb_u16(skb, sa_pan))
-                               goto err;
-               }
-
-               pr_debug("source PAN addr: %04x\n", mac_cb(skb)->da.pan_id);
-
-               if (mac_cb(skb)->sa.addr_type == IEEE802154_ADDR_SHORT) {
-                       u16 *sa = &(mac_cb(skb)->sa.short_addr);
-
-                       if (mac802154_fetch_skb_u16(skb, sa))
-                               goto err;
+               switch (hdr.sec.key_id_mode) {
+               case IEEE802154_SCF_KEY_IMPLICIT:
+                       pr_debug("implicit key\n");
+                       break;
 
-                       pr_debug("source address is short: %04x\n",
-                                mac_cb(skb)->sa.short_addr);
-               } else {
-                       if (!pskb_may_pull(skb, IEEE802154_ADDR_LEN))
-                               goto err;
+               case IEEE802154_SCF_KEY_INDEX:
+                       pr_debug("key %02x\n", hdr.sec.key_id);
+                       break;
 
-                       mac802154_haddr_copy_swap(mac_cb(skb)->sa.hwaddr,
-                                                 skb->data);
-                       skb_pull(skb, IEEE802154_ADDR_LEN);
+               case IEEE802154_SCF_KEY_SHORT_INDEX:
+                       pr_debug("key %04x:%04x %02x\n",
+                                le32_to_cpu(hdr.sec.short_src) >> 16,
+                                le32_to_cpu(hdr.sec.short_src) & 0xffff,
+                                hdr.sec.key_id);
+                       break;
 
-                       pr_debug("source address is hardware\n");
+               case IEEE802154_SCF_KEY_HW_INDEX:
+                       key = swab64((__force u64) hdr.sec.extended_src);
+                       pr_debug("key source %8phC %02x\n", &key,
+                                hdr.sec.key_id);
+                       break;
                }
+
+               return -EINVAL;
        }
 
        return 0;
-err:
-       return -EINVAL;
 }
 
 void mac802154_wpans_rx(struct mac802154_priv *priv, struct sk_buff *skb)