[Rime 协议栈] 802.15.4 帧 frame

概述

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

相关定义

struct framer

1
2
3
4
5
6
7
struct framer {

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

};

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

framer_802154

1
2
3
4
5
const struct framer framer_802154 = {
hdr_length,
create,
parse
};

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

frame802154_t

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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的定义分别如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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;

相关函数

hdr_length

1
2
3
4
static int hdr_length(void)
{
return create_frame(FRAME802154_DATAFRAME, 0);
}

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

create

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

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

create_frame

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
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,进行不同的处理。