Contiki之MAC协议:802.15.4帧frame

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/tidyjiang/article/details/51526613

1 概述

Rime协议栈传递下来的数据(包括由变色龙的头部转换模块生成的头部),都传入到FRAMER层。FRAMER层这这些数据的基础之上,按照IEEE 802.15.4协议规范,在数据的前面加上帧头,封装成一个完整的帧。
这部分的博客涉及到IEEE802.15.4协议的知识,必须先学习该协议。可以参考博客《IEEE 802.15.4协议完整中文版 目录

2 相关定义

struct framer

struct framer {

  int (* length)(void);
  int (* create)(void);
  int (* parse)(void);

};

定义了一个帧处理结构体,其中
length:计算帧的头部尺寸
create:创建一个帧
parse:解析一个帧

framer_802154

const struct framer framer_802154 = {
  hdr_length,
  create,
  parse
};

定义了一个具体的802.15.4帧处理的结构体。

frame802154_t

typedef struct {
  /** dest_addr字段和src_addr字段必须出现在帧的最前面,以确保它们与CPU字对齐。(???目前还不明白)
   * Needed as they are accessed directly as linkaddr_t*. 
   * 注意,我们这里没有直接使用linkaddr_t,因为协议中规定的地址地段占8字节,
   * 而不是LINKADDR_SIZE字节。
   **/
  uint8_t dest_addr[8];           /**< 目的地址 */
  uint8_t src_addr[8];            /**< 源地址 */
  frame802154_fcf_t fcf;          /**< 帧控制字段  */
  uint8_t seq;                    /**< 序列号 */
  uint16_t dest_pid;              /**< 目的PAN ID */
  uint16_t src_pid;               /**< 源PAN ID */
  frame802154_aux_hdr_t aux_hdr;  /**< 附加的安全相关的头部 */
  uint8_t *payload;               /**< 指向帧的实际数据 */
  int payload_len;                /**< 收集数据的长度 */
} frame802154_t;

定义了一个802.15.4帧的帧头结构。frame802154_fcf_tframe802154_aux_hdr_t的定义分别如下:

typedef struct {
  uint8_t frame_type;        /**< 3 bit. Frame type field, see 802.15.4 */
  uint8_t security_enabled;  /**< 1 bit. True if security is used in this frame */
  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; */  /**< 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 */
} frame802154_fcf_t;
----------------------------------
typedef struct {
  frame802154_scf_t security_control;        /**< Security control bitfield */
  frame802154_frame_counter_t frame_counter; /**< Frame counter, used for security */
  frame802154_key_source_t key_source;       /**< Key Source subfield */
  uint8_t key_index;                         /**< Key Index subfield */
} frame802154_aux_hdr_t;

3 相关函数

hdr_length

static int hdr_length(void)
{
  return create_frame(FRAME802154_DATAFRAME, 0);
}

调用create_frame函数计算帧头长度,咋个计算的?下面将看到。

create

static int create(void)
{
  return create_frame(FRAME802154_DATAFRAME, 1);
}

调用create_frame函数创建一个帧。与hdr_length()函数不同的是,传入的第二个参数为1。

create_frame

static int create_frame(int type, int do_create)
{
  frame802154_t params;
  int hdr_len;

  if(frame802154_get_pan_id() == 0xffff) {
    return -1;
  }

  /* 初始化帧头为0 */
  memset(&params, 0, sizeof(params));

  if(!initialized) {
    initialized = 1;
    mac_dsn = random_rand() & 0xff;
  }

  /* 构建帧控制字段FCF结构体 */
  params.fcf.frame_type = packetbuf_attr(PACKETBUF_ATTR_FRAME_TYPE);
  params.fcf.frame_pending = packetbuf_attr(PACKETBUF_ATTR_PENDING);
  if(packetbuf_holds_broadcast()) {
    params.fcf.ack_required = 0;
  } 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;

  /* 填充IEEE 802.15.4版本. */
  params.fcf.frame_version = FRAME802154_VERSION;

#if LLSEC802154_USES_AUX_HEADER
  if(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL)) {
    params.fcf.security_enabled = 1;
  }
  /* 设置安全相关属性 */
  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);
  params.aux_hdr.key_source.u16[0] = packetbuf_attr(PACKETBUF_ATTR_KEY_SOURCE_BYTES_0_1);
#endif /* LLSEC802154_USES_EXPLICIT_KEYS */
#endif /* LLSEC802154_USES_AUX_HEADER */

  /* Increment and set the data sequence number. */
  if(!do_create) {
    /* Only length calculation - no sequence number is needed and
       should not be consumed. */

  } else if(packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO)) {
    params.seq = packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO);

  } else {
    /* Ensure that the sequence number 0 is not used as it would bypass the above check. */
    if(mac_dsn == 0) {
      mac_dsn++;
    }
    params.seq = mac_dsn++;
    packetbuf_set_attr(PACKETBUF_ATTR_MAC_SEQNO, params.seq);
  }

  /* Complete the addressing fields. */
  /**
     \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 = 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));
    /* Use short address mode if linkaddr size is small */
    if(LINKADDR_SIZE == 2) {
      params.fcf.dest_addr_mode = FRAME802154_SHORTADDRMODE;
    } else {
      params.fcf.dest_addr_mode = FRAME802154_LONGADDRMODE;
    }
  }

  /* Set the source PAN ID to the global variable. */
  params.src_pid = frame802154_get_pan_id();

  /*
   * Set up the source address using only the long address mode for
   * phase 1.
   */
  linkaddr_copy((linkaddr_t *)&params.src_addr, &linkaddr_node_addr);

  params.payload = packetbuf_dataptr();
  params.payload_len = packetbuf_datalen();
  hdr_len = frame802154_hdrlen(&params);
  if(!do_create) {
    /* Only calculate header length */
    return hdr_len;
  } else if(packetbuf_hdralloc(hdr_len)) {
    frame802154_create(&params, packetbuf_hdrptr());

    PRINTF("15.4-OUT: %2X", params.fcf.frame_type);
    PRINTADDR(params.dest_addr);
    PRINTF("%d %u (%u)\n", hdr_len, packetbuf_datalen(), packetbuf_totlen());

    return hdr_len;
  } else {
    PRINTF("15.4-OUT: too large header: %u\n", hdr_len);
    return FRAMER_FAILED;
  }
}

函数比较长,但是其作用很容易理解:定义一个帧头结构体,然后给结构体各个成员填值。通过判断标志do_create,进行不同的处理。

4 小结

展开阅读全文

没有更多推荐了,返回首页