From 5cf9871d5b0b0266ef72bda1599a50b832fe1455 Mon Sep 17 00:00:00 2001
From: Simon Duquennoy <simonduq@sics.se>
Date: Mon, 21 Sep 2015 18:39:30 +0200
Subject: [PATCH] Added support for IEEE 802.15.4 frame version 2

---
 core/net/llsec/llsec802154.h |   6 +
 core/net/mac/frame802154.c   | 303 ++++++++++++++++++++++++++++++-----
 core/net/mac/frame802154.h   |  45 +++++-
 core/net/mac/framer-802154.c |  73 ++++-----
 4 files changed, 338 insertions(+), 89 deletions(-)

diff --git a/core/net/llsec/llsec802154.h b/core/net/llsec/llsec802154.h
index 6ab6a9793..2ccd30515 100644
--- a/core/net/llsec/llsec802154.h
+++ b/core/net/llsec/llsec802154.h
@@ -85,6 +85,12 @@
 #define LLSEC802154_USES_EXPLICIT_KEYS 0
 #endif /* LLSEC802154_CONF_USES_EXPLICIT_KEYS */
 
+#ifdef LLSEC802154_CONF_USES_FRAME_COUNTER
+#define LLSEC802154_USES_FRAME_COUNTER LLSEC802154_CONF_USES_FRAME_COUNTER
+#else /* LLSEC802154_CONF_USES_FRAME_COUNTER */
+#define LLSEC802154_USES_FRAME_COUNTER (LLSEC802154_SECURITY_LEVEL != FRAME802154_SECURITY_LEVEL_NONE)
+#endif /* LLSEC802154_CONF_USES_FRAME_COUNTER */
+
 #if UIP_BYTE_ORDER == UIP_LITTLE_ENDIAN
 #define LLSEC802154_HTONS(n) (n)
 #define LLSEC802154_HTONL(n) (n)
diff --git a/core/net/mac/frame802154.c b/core/net/mac/frame802154.c
index 3cd85d20b..c2982a014 100644
--- a/core/net/mac/frame802154.c
+++ b/core/net/mac/frame802154.c
@@ -44,11 +44,11 @@
  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  *  POSSIBILITY OF SUCH DAMAGE.
  *
-*/
+ */
 /*
  *  \brief This file is where the main functions that relate to frame
  *  manipulation will reside.
-*/
+ */
 
 /**
  *  \file
@@ -61,7 +61,7 @@
 /**
  *   \addtogroup frame802154
  *   @{
-*/
+ */
 
 #include "sys/cc.h"
 #include "net/mac/frame802154.h"
@@ -69,11 +69,18 @@
 #include "net/linkaddr.h"
 #include <string.h>
 
+/**  \brief The 16-bit identifier of the PAN on which the device is
+ *   operating.  If this value is 0xffff, the device is not
+ *   associated.
+ */
+static uint16_t mac_pan_id = IEEE802154_PANID;
+
 /**
  *  \brief Structure that contains the lengths of the various addressing and security fields
  *  in the 802.15.4 header.  This structure is used in \ref frame802154_create()
  */
 typedef struct {
+  uint8_t seqno_len;       /**<  Length (in bytes) of sequence number field */
   uint8_t dest_pid_len;    /**<  Length (in bytes) of destination PAN ID field */
   uint8_t dest_addr_len;   /**<  Length (in bytes) of destination address field */
   uint8_t src_pid_len;     /**<  Length (in bytes) of source PAN ID field */
@@ -111,30 +118,199 @@ get_key_id_len(uint8_t key_id_mode)
   }
 }
 #endif /* LLSEC802154_USES_EXPLICIT_KEYS */
+/*---------------------------------------------------------------------------*/
+/* Get current PAN ID */
+uint16_t
+frame802154_get_pan_id(void)
+{
+  return mac_pan_id;
+}
+/*---------------------------------------------------------------------------*/
+/* Set current PAN ID */
+void
+frame802154_set_pan_id(uint16_t pan_id)
+{
+  mac_pan_id = pan_id;
+}
+/*----------------------------------------------------------------------------*/
+/* Tells whether a given Frame Control Field indicates a frame with
+ * source PANID and/or destination PANID */
+void
+frame802154_has_panid(frame802154_fcf_t *fcf, int *has_src_pan_id, int *has_dest_pan_id)
+{
+  int src_pan_id = 0;
+  int dest_pan_id = 0;
+
+  if(fcf == NULL) {
+    return;
+  }
+
+  if(fcf->frame_version == FRAME802154_IEEE802154E_2012) {
+    if(!fcf->panid_compression) {
+      /* Compressed PAN ID == no PAN ID at all */
+      if(fcf->dest_addr_mode == fcf->dest_addr_mode) {
+        /* No address or both addresses: include destination PAN ID */
+        dest_pan_id = 1;
+      } else if(fcf->dest_addr_mode) {
+        /* Only dest address, include dest PAN ID */
+        dest_pan_id = 1;
+      } else if(fcf->src_addr_mode) {
+        /* Only src address, include src PAN ID */
+        src_pan_id = 1;
+      }
+    }
+    if(fcf->dest_addr_mode == 0 && fcf->dest_addr_mode == 1) {
+      /* No address included, include dest PAN ID conditionally */
+      if(!fcf->panid_compression) {
+        dest_pan_id = 1;
+      }
+    }
+    /* Remove the following rule the day rows 2 and 3 from table 2a are fixed: */
+    if(fcf->dest_addr_mode == 0 && fcf->dest_addr_mode == 0) {
+      /* Not meaningful, we include a PAN ID iff the compress flag is set, but
+       * this is what the standard currently stipulates */
+      dest_pan_id = fcf->panid_compression;
+    }
+  } else {
+    /* No PAN ID in ACK */
+    if(fcf->frame_type != FRAME802154_ACKFRAME) {
+      if(!fcf->panid_compression && fcf->src_addr_mode & 3) {
+        /* If compressed, don't inclue source PAN ID */
+        src_pan_id = 1;
+      }
+      if(fcf->dest_addr_mode & 3) {
+        dest_pan_id = 1;
+      }
+    }
+  }
+
+  if(has_src_pan_id != NULL) {
+    *has_src_pan_id = src_pan_id;
+  }
+  if(has_dest_pan_id != NULL) {
+    *has_dest_pan_id = dest_pan_id;
+  }
+}
+/*---------------------------------------------------------------------------*/
+/* Check if the destination PAN ID, if any, matches ours */
+int
+frame802154_check_dest_panid(frame802154_t *frame)
+{
+  int has_dest_panid;
+
+  if(frame == NULL) {
+    return 0;
+  }
+  frame802154_has_panid(&frame->fcf, NULL, &has_dest_panid);
+  if(has_dest_panid
+     && frame->dest_pid != frame802154_get_pan_id()
+     && frame->dest_pid != FRAME802154_BROADCASTPANDID) {
+    /* Packet to another PAN */
+    return 0;
+  }
+  return 1;
+}
+/*---------------------------------------------------------------------------*/
+/* Check is the address is a broadcast address, whatever its size */
+int
+frame802154_is_broadcast_addr(uint8_t mode, uint8_t *addr)
+{
+  int i = mode == FRAME802154_SHORTADDRMODE ? 2 : 8;
+  while(i-- > 0) {
+    if(addr[i] != 0xff) {
+      return 0;
+    }
+  }
+  return 1;
+}
+/*---------------------------------------------------------------------------*/
+/* Check and extract source and destination linkaddr from frame */
+int
+frame802154_extract_linkaddr(frame802154_t *frame,
+                             linkaddr_t *source_address, linkaddr_t *dest_address)
+{
+  int src_addr_len;
+  int dest_addr_len;
+
+  if(frame == NULL) {
+    return 0;
+  }
+  /* Check and extract source address */
+  src_addr_len = frame->fcf.src_addr_mode ?
+    ((frame->fcf.src_addr_mode == FRAME802154_SHORTADDRMODE) ? 2 : 8) : 0;
+  if(src_addr_len == 0 || frame802154_is_broadcast_addr(frame->fcf.src_addr_mode, frame->src_addr)) {
+    /* Broadcast address */
+    if(source_address != NULL) {
+      linkaddr_copy(source_address, &linkaddr_null);
+    }
+  } else {
+    /* Unicast address */
+    if(src_addr_len != LINKADDR_SIZE) {
+      /* Destination address has a size we can not handle */
+      return 0;
+    }
+    if(source_address != NULL) {
+      linkaddr_copy(source_address, (linkaddr_t *)frame->src_addr);
+    }
+  }
+
+  /* Check and extract destination address */
+  dest_addr_len = frame->fcf.dest_addr_mode ?
+    ((frame->fcf.dest_addr_mode == FRAME802154_SHORTADDRMODE) ? 2 : 8) : 0;
+  if(dest_addr_len == 0 || frame802154_is_broadcast_addr(frame->fcf.dest_addr_mode, frame->dest_addr)) {
+    /* Broadcast address */
+    if(dest_address != NULL) {
+      linkaddr_copy(dest_address, &linkaddr_null);
+    }
+  } else {
+    /* Unicast address */
+    if(dest_addr_len != LINKADDR_SIZE) {
+      /* Destination address has a size we can not handle */
+      return 0;
+    }
+    if(dest_address != NULL) {
+      linkaddr_copy(dest_address, (linkaddr_t *)frame->dest_addr);
+    }
+  }
+
+  return 1;
+}
 /*----------------------------------------------------------------------------*/
 static void
 field_len(frame802154_t *p, field_length_t *flen)
 {
+  int has_src_panid;
+  int has_dest_panid;
+
   /* init flen to zeros */
   memset(flen, 0, sizeof(field_length_t));
 
   /* Determine lengths of each field based on fcf and other args */
-  if(p->fcf.dest_addr_mode & 3) {
-    flen->dest_pid_len = 2;
+  if((p->fcf.sequence_number_suppression & 1) == 0) {
+    flen->seqno_len = 1;
   }
-  if(p->fcf.src_addr_mode & 3) {
+
+  /* IEEE802.15.4e changes the meaning of PAN ID Compression (see Table 2a).
+   * In this case, we leave the decision whether to compress PAN ID or not
+   * up to the caller. */
+  if(p->fcf.frame_version < FRAME802154_IEEE802154E_2012) {
+    /* Set PAN ID compression bit if src pan id matches dest pan id. */
+    if(p->fcf.dest_addr_mode & 3 && p->fcf.src_addr_mode & 3 &&
+       p->src_pid == p->dest_pid) {
+      p->fcf.panid_compression = 1;
+    } else {
+      p->fcf.panid_compression = 0;
+    }
+  }
+
+  frame802154_has_panid(&p->fcf, &has_src_panid, &has_dest_panid);
+
+  if(has_src_panid) {
     flen->src_pid_len = 2;
   }
 
-  /* Set PAN ID compression bit if src pan id matches dest pan id. */
-  if(p->fcf.dest_addr_mode & 3 && p->fcf.src_addr_mode & 3 &&
-     p->src_pid == p->dest_pid) {
-    p->fcf.panid_compression = 1;
-
-    /* compressed header, only do dest pid */
-    flen->src_pid_len = 0;
-  } else {
-    p->fcf.panid_compression = 0;
+  if(has_dest_panid) {
+    flen->dest_pid_len = 2;
   }
 
   /* determine address lengths */
@@ -144,9 +320,16 @@ field_len(frame802154_t *p, field_length_t *flen)
 #if LLSEC802154_SECURITY_LEVEL
   /* Aux security header */
   if(p->fcf.security_enabled & 1) {
-    flen->aux_sec_len = 5
+    flen->aux_sec_len = 1; /* FCF + possibly frame counter and key ID */
+    if(p->aux_hdr.security_control.frame_counter_suppression == 0) {
+      if(p->aux_hdr.security_control.frame_counter_size == 1) {
+        flen->aux_sec_len += 5;
+      } else {
+        flen->aux_sec_len += 4;
+      }
+    }
 #if LLSEC802154_USES_EXPLICIT_KEYS
-        + get_key_id_len(p->aux_hdr.security_control.key_id_mode);
+    flen->aux_sec_len += get_key_id_len(p->aux_hdr.security_control.key_id_mode);
 #endif /* LLSEC802154_USES_EXPLICIT_KEYS */
     ;
   }
@@ -161,14 +344,14 @@ field_len(frame802154_t *p, field_length_t *flen)
  *   frame to send.
  *
  *   \return The length of the frame header.
-*/
+ */
 int
 frame802154_hdrlen(frame802154_t *p)
 {
   field_length_t flen;
   field_len(p, &flen);
-  return 3 + flen.dest_pid_len + flen.dest_addr_len +
-    flen.src_pid_len + flen.src_addr_len + flen.aux_sec_len;
+  return 2 + flen.seqno_len + flen.dest_pid_len + flen.dest_addr_len +
+         flen.src_pid_len + flen.src_addr_len + flen.aux_sec_len;
 }
 /*----------------------------------------------------------------------------*/
 /**
@@ -181,7 +364,7 @@ frame802154_hdrlen(frame802154_t *p)
  *   \param buf Pointer to the buffer to use for the frame.
  *
  *   \return The length of the frame header
-*/
+ */
 int
 frame802154_create(frame802154_t *p, uint8_t *buf)
 {
@@ -193,7 +376,7 @@ frame802154_create(frame802154_t *p, uint8_t *buf)
 #endif /* LLSEC802154_USES_EXPLICIT_KEYS */
 
   field_len(p, &flen);
-  
+
   /* OK, now we have field lengths.  Time to actually construct */
   /* the outgoing frame, and store it in buf */
   buf[0] = (p->fcf.frame_type & 7) |
@@ -201,13 +384,18 @@ frame802154_create(frame802154_t *p, uint8_t *buf)
     ((p->fcf.frame_pending & 1) << 4) |
     ((p->fcf.ack_required & 1) << 5) |
     ((p->fcf.panid_compression & 1) << 6);
-  buf[1] = ((p->fcf.dest_addr_mode & 3) << 2) |
+  buf[1] = ((p->fcf.sequence_number_suppression & 1)) |
+    ((p->fcf.ie_list_present & 1)) << 1 |
+    ((p->fcf.dest_addr_mode & 3) << 2) |
     ((p->fcf.frame_version & 3) << 4) |
     ((p->fcf.src_addr_mode & 3) << 6);
 
-  /* sequence number */
-  buf[2] = p->seq;
-  pos = 3;
+  pos = 2;
+
+  /* Sequence number */
+  if(flen.seqno_len == 1) {
+    buf[pos++] = p->seq;
+  }
 
   /* Destination PAN ID */
   if(flen.dest_pid_len == 2) {
@@ -230,17 +418,24 @@ frame802154_create(frame802154_t *p, uint8_t *buf)
   for(c = flen.src_addr_len; c > 0; c--) {
     buf[pos++] = p->src_addr[c - 1];
   }
-
 #if LLSEC802154_SECURITY_LEVEL
   /* Aux header */
   if(flen.aux_sec_len) {
     buf[pos++] = p->aux_hdr.security_control.security_level
 #if LLSEC802154_USES_EXPLICIT_KEYS
-        | (p->aux_hdr.security_control.key_id_mode << 3)
+      | (p->aux_hdr.security_control.key_id_mode << 3)
 #endif /* LLSEC802154_USES_EXPLICIT_KEYS */
+      | (p->aux_hdr.security_control.frame_counter_suppression << 5)
+      | (p->aux_hdr.security_control.frame_counter_size << 6)
     ;
-    memcpy(buf + pos, p->aux_hdr.frame_counter.u8, 4);
-    pos += 4;
+    if(p->aux_hdr.security_control.frame_counter_suppression == 0) {
+      /* We support only 4-byte counters */
+      memcpy(buf + pos, p->aux_hdr.frame_counter.u8, 4);
+      pos += 4;
+      if(p->aux_hdr.security_control.frame_counter_size == 1) {
+        pos++;
+      }
+    }
 
 #if LLSEC802154_USES_EXPLICIT_KEYS
     key_id_mode = p->aux_hdr.security_control.key_id_mode;
@@ -272,11 +467,13 @@ frame802154_parse(uint8_t *data, int len, frame802154_t *pf)
   uint8_t *p;
   frame802154_fcf_t fcf;
   int c;
+  int has_src_panid;
+  int has_dest_panid;
 #if LLSEC802154_USES_EXPLICIT_KEYS
   uint8_t key_id_mode;
 #endif /* LLSEC802154_USES_EXPLICIT_KEYS */
 
-  if(len < 3) {
+  if(len < 2) {
     return 0;
   }
 
@@ -289,20 +486,32 @@ frame802154_parse(uint8_t *data, int len, frame802154_t *pf)
   fcf.ack_required = (p[0] >> 5) & 1;
   fcf.panid_compression = (p[0] >> 6) & 1;
 
+  fcf.sequence_number_suppression = p[1] & 1;
+  fcf.ie_list_present = (p[1] >> 1) & 1;
   fcf.dest_addr_mode = (p[1] >> 2) & 3;
   fcf.frame_version = (p[1] >> 4) & 3;
   fcf.src_addr_mode = (p[1] >> 6) & 3;
 
   /* copy fcf and seqNum */
   memcpy(&pf->fcf, &fcf, sizeof(frame802154_fcf_t));
-  pf->seq = p[2];
-  p += 3;                             /* Skip first three bytes */
+  p += 2;                             /* Skip first two bytes */
+
+  if(fcf.sequence_number_suppression == 0) {
+    pf->seq = p[0];
+    p++;
+  }
+
+  frame802154_has_panid(&fcf, &has_src_panid, &has_dest_panid);
 
   /* Destination address, if any */
   if(fcf.dest_addr_mode) {
-    /* Destination PAN */
-    pf->dest_pid = p[0] + (p[1] << 8);
-    p += 2;
+    if(has_dest_panid) {
+      /* Destination PAN */
+      pf->dest_pid = p[0] + (p[1] << 8);
+      p += 2;
+    } else {
+      pf->dest_pid = 0;
+    }
 
     /* Destination address */
 /*     l = addr_len(fcf.dest_addr_mode); */
@@ -329,9 +538,12 @@ frame802154_parse(uint8_t *data, int len, frame802154_t *pf)
   /* Source address, if any */
   if(fcf.src_addr_mode) {
     /* Source PAN */
-    if(!fcf.panid_compression) {
+    if(has_src_panid) {
       pf->src_pid = p[0] + (p[1] << 8);
       p += 2;
+      if(!has_dest_panid) {
+        pf->dest_pid = pf->src_pid;
+      }
     } else {
       pf->src_pid = pf->dest_pid;
     }
@@ -357,18 +569,25 @@ frame802154_parse(uint8_t *data, int len, frame802154_t *pf)
     linkaddr_copy((linkaddr_t *)&(pf->src_addr), &linkaddr_null);
     pf->src_pid = 0;
   }
-  
+
 #if LLSEC802154_SECURITY_LEVEL
   if(fcf.security_enabled) {
     pf->aux_hdr.security_control.security_level = p[0] & 7;
 #if LLSEC802154_USES_EXPLICIT_KEYS
     pf->aux_hdr.security_control.key_id_mode = (p[0] >> 3) & 3;
 #endif /* LLSEC802154_USES_EXPLICIT_KEYS */
+    pf->aux_hdr.security_control.frame_counter_suppression = p[0] >> 5;
+    pf->aux_hdr.security_control.frame_counter_size = p[0] >> 6;
     p += 1;
-    
-    memcpy(pf->aux_hdr.frame_counter.u8, p, 4);
-    p += 4;
-    
+
+    if(pf->aux_hdr.security_control.frame_counter_suppression == 0) {
+      memcpy(pf->aux_hdr.frame_counter.u8, p, 4);
+      p += 4;
+      if(pf->aux_hdr.security_control.frame_counter_size == 1) {
+        p ++;
+      }
+    }
+
 #if LLSEC802154_USES_EXPLICIT_KEYS
     key_id_mode = pf->aux_hdr.security_control.key_id_mode;
     if(key_id_mode) {
diff --git a/core/net/mac/frame802154.h b/core/net/mac/frame802154.h
index 64a367120..defb64b53 100644
--- a/core/net/mac/frame802154.h
+++ b/core/net/mac/frame802154.h
@@ -41,7 +41,7 @@
  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  *  POSSIBILITY OF SUCH DAMAGE.
-*/
+ */
 
 /**
  *    \addtogroup net
@@ -59,14 +59,14 @@
  *  This file converts to and from a structure to a packed 802.15.4
  *  frame.
  *
-*/
-
+ */
 
 /* Includes */
 #ifndef FRAME_802154_H
 #define FRAME_802154_H
 
 #include "contiki-conf.h"
+#include "net/linkaddr.h"
 
 #ifdef IEEE802154_CONF_PANID
 #define IEEE802154_PANID           IEEE802154_CONF_PANID
@@ -74,6 +74,18 @@
 #define IEEE802154_PANID           0xABCD
 #endif /* IEEE802154_CONF_PANID */
 
+#ifdef FRAME802154_CONF_VERSION
+#define FRAME802154_VERSION FRAME802154_CONF_VERSION
+#else /* FRAME802154_CONF_VERSION */
+#define FRAME802154_VERSION FRAME802154_IEEE802154_2006
+#endif /* FRAME802154_CONF_VERSION */
+
+#ifdef FRAME802154_CONF_SUPPR_SEQNO
+#define FRAME802154_SUPPR_SEQNO FRAME802154_CONF_SUPPR_SEQNO
+#else /* FRAME802154_CONF_SUPPR_SEQNO */
+#define FRAME802154_SUPPR_SEQNO 0
+#endif /* FRAME802154_CONF_SUPPR_SEQNO */
+
 /* Macros & Defines */
 
 /** \brief These are some definitions of values used in the FCF.  See the 802.15.4 spec for details.
@@ -97,8 +109,9 @@
 #define FRAME802154_BROADCASTADDR   (0xFFFF)
 #define FRAME802154_BROADCASTPANDID (0xFFFF)
 
-#define FRAME802154_IEEE802154_2003 (0x00)
-#define FRAME802154_IEEE802154_2006 (0x01)
+#define FRAME802154_IEEE802154_2003  (0x00)
+#define FRAME802154_IEEE802154_2006  (0x01)
+#define FRAME802154_IEEE802154E_2012 (0x02)
 
 #define FRAME802154_SECURITY_LEVEL_NONE        (0)
 #define FRAME802154_SECURITY_LEVEL_MIC_32      (1)
@@ -125,7 +138,7 @@
  *            3. Addressing fields    - 4 - 20 bytes  - Variable
  *            4. Aux security header  - 0 - 14 bytes  - Variable
  *            5. CRC                  - 2 bytes       - Fixed
-*/
+ */
 
 /**
  * \brief Defines the bitfields of the frame control field (FCF).
@@ -136,7 +149,9 @@ typedef struct {
   uint8_t frame_pending;     /**< 1 bit. True if sender has more data to send */
   uint8_t ack_required;      /**< 1 bit. Is an ack frame required? */
   uint8_t panid_compression; /**< 1 bit. Is this a compressed header? */
-  /*   uint8_t reserved; */  /**< 3 bit. Unused bits */
+  /*   uint8_t reserved; */  /**< 1 bit. Unused bit */
+  uint8_t sequence_number_suppression; /**< 1 bit. Does the header omit sequence number?, see 802.15.4e */
+  uint8_t ie_list_present;   /**< 1 bit. Does the header contain Information Elements?, see 802.15.4e */
   uint8_t dest_addr_mode;    /**< 2 bit. Destination address mode, see 802.15.4 */
   uint8_t frame_version;     /**< 2 bit. 802.15.4 frame version */
   uint8_t src_addr_mode;     /**< 2 bit. Source address mode, see 802.15.4 */
@@ -146,6 +161,8 @@ typedef struct {
 typedef struct {
   uint8_t  security_level; /**< 3 bit. security level      */
   uint8_t  key_id_mode;    /**< 2 bit. Key identifier mode */
+  uint8_t  frame_counter_suppression;  /**< 1 bit. Frame counter suppression */
+  uint8_t  frame_counter_size;  /**< 1 bit. Frame counter size (0: 4 bytes, 1: 5 bytes) */
   uint8_t  reserved;       /**< 3 bit. Reserved bits       */
 } frame802154_scf_t;
 
@@ -193,6 +210,20 @@ int frame802154_hdrlen(frame802154_t *p);
 int frame802154_create(frame802154_t *p, uint8_t *buf);
 int frame802154_parse(uint8_t *data, int length, frame802154_t *pf);
 
+/* Get current PAN ID */
+uint16_t frame802154_get_pan_id(void);
+/* Set current PAN ID */
+void frame802154_set_pan_id(uint16_t pan_id);
+/* Tells whether a given Frame Control Field indicates a frame with
+ * source PANID and/or destination PANID */
+void frame802154_has_panid(frame802154_fcf_t *fcf, int *has_src_pan_id, int *has_dest_pan_id);
+/* Check if the destination PAN ID, if any, matches ours */
+int frame802154_check_dest_panid(frame802154_t *frame);
+/* Check is the address is a broadcast address, whatever its size */
+int frame802154_is_broadcast_addr(uint8_t mode, uint8_t *addr);
+/* Check and extract source and destination linkaddr from frame */
+int frame802154_extract_linkaddr(frame802154_t *frame, linkaddr_t *source_address, linkaddr_t *dest_address);
+
 /** @} */
 #endif /* FRAME_802154_H */
 /** @} */
diff --git a/core/net/mac/framer-802154.c b/core/net/mac/framer-802154.c
index ce96f6239..14ccc5aa3 100644
--- a/core/net/mac/framer-802154.c
+++ b/core/net/mac/framer-802154.c
@@ -62,30 +62,6 @@ static uint8_t mac_dsn;
 
 static uint8_t initialized = 0;
 
-/**  \brief The 16-bit identifier of the PAN on which the device is
- *   sending to.  If this value is 0xffff, the device is not
- *   associated.
- */
-static const uint16_t mac_dst_pan_id = IEEE802154_PANID;
-
-/**  \brief The 16-bit identifier of the PAN on which the device is
- *   operating.  If this value is 0xffff, the device is not
- *   associated.
- */
-static const uint16_t mac_src_pan_id = IEEE802154_PANID;
-
-/*---------------------------------------------------------------------------*/
-static int
-is_broadcast_addr(uint8_t mode, uint8_t *addr)
-{
-  int i = mode == FRAME802154_SHORTADDRMODE ? 2 : 8;
-  while(i-- > 0) {
-    if(addr[i] != 0xff) {
-      return 0;
-    }
-  }
-  return 1;
-}
 /*---------------------------------------------------------------------------*/
 static int
 create_frame(int type, int do_create)
@@ -93,6 +69,10 @@ create_frame(int type, int do_create)
   frame802154_t params;
   int hdr_len;
 
+  if(frame802154_get_pan_id() == 0xffff) {
+    return -1;
+  }
+
   /* init to zeros */
   memset(&params, 0, sizeof(params));
 
@@ -109,10 +89,14 @@ create_frame(int type, int do_create)
   } else {
     params.fcf.ack_required = packetbuf_attr(PACKETBUF_ATTR_MAC_ACK);
   }
+  /* We do not compress PAN ID in outgoing frames, i.e. include one PAN ID (dest by default)
+   * There is one exception, seemingly a typo in Table 2a: rows 2 and 3: when there is no
+   * source nor destination address, we have dest PAN ID iff compression is *set*. */
   params.fcf.panid_compression = 0;
+  params.fcf.sequence_number_suppression = FRAME802154_SUPPR_SEQNO;
 
-  /* Insert IEEE 802.15.4 (2006) version bits. */
-  params.fcf.frame_version = FRAME802154_IEEE802154_2006;
+  /* Insert IEEE 802.15.4 version bits. */
+  params.fcf.frame_version = FRAME802154_VERSION;
   
 #if LLSEC802154_SECURITY_LEVEL
   if(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL)) {
@@ -120,8 +104,13 @@ create_frame(int type, int do_create)
   }
   /* Setting security-related attributes */
   params.aux_hdr.security_control.security_level = packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL);
+#if LLSEC802154_USES_FRAME_COUNTER
   params.aux_hdr.frame_counter.u16[0] = packetbuf_attr(PACKETBUF_ATTR_FRAME_COUNTER_BYTES_0_1);
   params.aux_hdr.frame_counter.u16[1] = packetbuf_attr(PACKETBUF_ATTR_FRAME_COUNTER_BYTES_2_3);
+#else /* LLSEC802154_USES_FRAME_COUNTER */
+  params.aux_hdr.security_control.frame_counter_suppression = 1;
+  params.aux_hdr.security_control.frame_counter_size = 1;
+#endif /* LLSEC802154_USES_FRAME_COUNTER */
 #if LLSEC802154_USES_EXPLICIT_KEYS
   params.aux_hdr.security_control.key_id_mode = packetbuf_attr(PACKETBUF_ATTR_KEY_ID_MODE);
   params.aux_hdr.key_index = packetbuf_attr(PACKETBUF_ATTR_KEY_INDEX);
@@ -150,21 +139,20 @@ create_frame(int type, int do_create)
   /**
      \todo For phase 1 the addresses are all long. We'll need a mechanism
      in the rime attributes to tell the mac to use long or short for phase 2.
-  */
+   */
   if(LINKADDR_SIZE == 2) {
     /* Use short address mode if linkaddr size is short. */
     params.fcf.src_addr_mode = FRAME802154_SHORTADDRMODE;
   } else {
     params.fcf.src_addr_mode = FRAME802154_LONGADDRMODE;
   }
-  params.dest_pid = mac_dst_pan_id;
+  params.dest_pid = frame802154_get_pan_id();
 
   if(packetbuf_holds_broadcast()) {
     /* Broadcast requires short address mode. */
     params.fcf.dest_addr_mode = FRAME802154_SHORTADDRMODE;
     params.dest_addr[0] = 0xFF;
     params.dest_addr[1] = 0xFF;
-
   } else {
     linkaddr_copy((linkaddr_t *)&params.dest_addr,
                   packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
@@ -177,7 +165,7 @@ create_frame(int type, int do_create)
   }
 
   /* Set the source PAN ID to the global variable. */
-  params.src_pid = mac_src_pan_id;
+  params.src_pid = frame802154_get_pan_id();
 
   /*
    * Set up the source address using only the long address mode for
@@ -191,7 +179,6 @@ create_frame(int type, int do_create)
   if(!do_create) {
     /* Only calculate header length */
     return hdr_len;
-
   } else if(packetbuf_hdralloc(hdr_len)) {
     frame802154_create(&params, packetbuf_hdrptr());
 
@@ -223,35 +210,41 @@ parse(void)
 {
   frame802154_t frame;
   int hdr_len;
-  
+
   hdr_len = frame802154_parse(packetbuf_dataptr(), packetbuf_datalen(), &frame);
-  
+
   if(hdr_len && packetbuf_hdrreduce(hdr_len)) {
     packetbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, frame.fcf.frame_type);
-    
+
     if(frame.fcf.dest_addr_mode) {
-      if(frame.dest_pid != mac_src_pan_id &&
-          frame.dest_pid != FRAME802154_BROADCASTPANDID) {
+      if(frame.dest_pid != frame802154_get_pan_id() &&
+         frame.dest_pid != FRAME802154_BROADCASTPANDID) {
         /* Packet to another PAN */
         PRINTF("15.4: for another pan %u\n", frame.dest_pid);
         return FRAMER_FAILED;
       }
-      if(!is_broadcast_addr(frame.fcf.dest_addr_mode, frame.dest_addr)) {
+      if(!frame802154_is_broadcast_addr(frame.fcf.dest_addr_mode, frame.dest_addr)) {
         packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, (linkaddr_t *)&frame.dest_addr);
       }
     }
     packetbuf_set_addr(PACKETBUF_ADDR_SENDER, (linkaddr_t *)&frame.src_addr);
     packetbuf_set_attr(PACKETBUF_ATTR_PENDING, frame.fcf.frame_pending);
-    packetbuf_set_attr(PACKETBUF_ATTR_MAC_SEQNO, frame.seq);
+    if(frame.fcf.sequence_number_suppression == 0) {
+      packetbuf_set_attr(PACKETBUF_ATTR_MAC_SEQNO, frame.seq);
+    } else {
+      packetbuf_set_attr(PACKETBUF_ATTR_MAC_SEQNO, 0xffff);
+    }
 #if NETSTACK_CONF_WITH_RIME
     packetbuf_set_attr(PACKETBUF_ATTR_PACKET_ID, frame.seq);
 #endif
-    
+
 #if LLSEC802154_SECURITY_LEVEL
     if(frame.fcf.security_enabled) {
       packetbuf_set_attr(PACKETBUF_ATTR_SECURITY_LEVEL, frame.aux_hdr.security_control.security_level);
+#if LLSEC802154_USES_FRAME_COUNTER
       packetbuf_set_attr(PACKETBUF_ATTR_FRAME_COUNTER_BYTES_0_1, frame.aux_hdr.frame_counter.u16[0]);
       packetbuf_set_attr(PACKETBUF_ATTR_FRAME_COUNTER_BYTES_2_3, frame.aux_hdr.frame_counter.u16[1]);
+#endif /* LLSEC802154_USES_FRAME_COUNTER */
 #if LLSEC802154_USES_EXPLICIT_KEYS
       packetbuf_set_attr(PACKETBUF_ATTR_KEY_ID_MODE, frame.aux_hdr.security_control.key_id_mode);
       packetbuf_set_attr(PACKETBUF_ATTR_KEY_INDEX, frame.aux_hdr.key_index);
@@ -264,7 +257,7 @@ parse(void)
     PRINTADDR(packetbuf_addr(PACKETBUF_ADDR_SENDER));
     PRINTADDR(packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
     PRINTF("%d %u (%u)\n", hdr_len, packetbuf_datalen(), packetbuf_totlen());
-    
+
     return hdr_len;
   }
   return FRAMER_FAILED;