2 * Copyright (C) 2014 Fraunhofer ITWM
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2
6 * as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
14 * Phoebe Buckheister <phoebe.buckheister@itwm.fraunhofer.de>
17 #include <net/mac802154.h>
18 #include <net/ieee802154.h>
19 #include <net/ieee802154_netdev.h>
22 ieee802154_hdr_push_addr(u8
*buf
, const struct ieee802154_addr
*addr
,
27 if (addr
->mode
== IEEE802154_ADDR_NONE
)
31 memcpy(buf
+ pos
, &addr
->pan_id
, 2);
36 case IEEE802154_ADDR_SHORT
:
37 memcpy(buf
+ pos
, &addr
->short_addr
, 2);
41 case IEEE802154_ADDR_LONG
:
42 memcpy(buf
+ pos
, &addr
->extended_addr
, IEEE802154_ADDR_LEN
);
43 pos
+= IEEE802154_ADDR_LEN
;
54 ieee802154_hdr_push_sechdr(u8
*buf
, const struct ieee802154_sechdr
*hdr
)
59 memcpy(buf
+ 1, &hdr
->frame_counter
, 4);
61 switch (hdr
->key_id_mode
) {
62 case IEEE802154_SCF_KEY_IMPLICIT
:
65 case IEEE802154_SCF_KEY_INDEX
:
68 case IEEE802154_SCF_KEY_SHORT_INDEX
:
69 memcpy(buf
+ pos
, &hdr
->short_src
, 4);
73 case IEEE802154_SCF_KEY_HW_INDEX
:
74 memcpy(buf
+ pos
, &hdr
->extended_src
, IEEE802154_ADDR_LEN
);
75 pos
+= IEEE802154_ADDR_LEN
;
79 buf
[pos
++] = hdr
->key_id
;
85 ieee802154_hdr_push(struct sk_buff
*skb
, const struct ieee802154_hdr
*hdr
)
87 u8 buf
[MAC802154_FRAME_HARD_HEADER_LEN
];
90 struct ieee802154_hdr_fc fc
= hdr
->fc
;
92 buf
[pos
++] = hdr
->seq
;
94 fc
.dest_addr_mode
= hdr
->dest
.mode
;
96 rc
= ieee802154_hdr_push_addr(buf
+ pos
, &hdr
->dest
, false);
101 fc
.source_addr_mode
= hdr
->source
.mode
;
103 if (hdr
->source
.pan_id
== hdr
->dest
.pan_id
&&
104 hdr
->dest
.mode
!= IEEE802154_ADDR_NONE
)
107 rc
= ieee802154_hdr_push_addr(buf
+ pos
, &hdr
->source
, fc
.intra_pan
);
112 if (fc
.security_enabled
) {
115 rc
= ieee802154_hdr_push_sechdr(buf
+ pos
, &hdr
->sec
);
124 memcpy(skb_push(skb
, pos
), buf
, pos
);
128 EXPORT_SYMBOL_GPL(ieee802154_hdr_push
);
131 ieee802154_hdr_get_addr(const u8
*buf
, int mode
, bool omit_pan
,
132 struct ieee802154_addr
*addr
)
138 if (mode
== IEEE802154_ADDR_NONE
)
142 memcpy(&addr
->pan_id
, buf
+ pos
, 2);
146 if (mode
== IEEE802154_ADDR_SHORT
) {
147 memcpy(&addr
->short_addr
, buf
+ pos
, 2);
150 memcpy(&addr
->extended_addr
, buf
+ pos
, IEEE802154_ADDR_LEN
);
151 return pos
+ IEEE802154_ADDR_LEN
;
155 static int ieee802154_hdr_addr_len(int mode
, bool omit_pan
)
157 int pan_len
= omit_pan
? 0 : 2;
160 case IEEE802154_ADDR_NONE
: return 0;
161 case IEEE802154_ADDR_SHORT
: return 2 + pan_len
;
162 case IEEE802154_ADDR_LONG
: return IEEE802154_ADDR_LEN
+ pan_len
;
163 default: return -EINVAL
;
168 ieee802154_hdr_get_sechdr(const u8
*buf
, struct ieee802154_sechdr
*hdr
)
173 memcpy(&hdr
->frame_counter
, buf
+ 1, 4);
175 switch (hdr
->key_id_mode
) {
176 case IEEE802154_SCF_KEY_IMPLICIT
:
179 case IEEE802154_SCF_KEY_INDEX
:
182 case IEEE802154_SCF_KEY_SHORT_INDEX
:
183 memcpy(&hdr
->short_src
, buf
+ pos
, 4);
187 case IEEE802154_SCF_KEY_HW_INDEX
:
188 memcpy(&hdr
->extended_src
, buf
+ pos
, IEEE802154_ADDR_LEN
);
189 pos
+= IEEE802154_ADDR_LEN
;
193 hdr
->key_id
= buf
[pos
++];
198 static int ieee802154_sechdr_lengths
[4] = {
199 [IEEE802154_SCF_KEY_IMPLICIT
] = 5,
200 [IEEE802154_SCF_KEY_INDEX
] = 6,
201 [IEEE802154_SCF_KEY_SHORT_INDEX
] = 10,
202 [IEEE802154_SCF_KEY_HW_INDEX
] = 14,
205 static int ieee802154_hdr_sechdr_len(u8 sc
)
207 return ieee802154_sechdr_lengths
[IEEE802154_SCF_KEY_ID_MODE(sc
)];
210 static int ieee802154_hdr_minlen(const struct ieee802154_hdr
*hdr
)
214 dlen
= ieee802154_hdr_addr_len(hdr
->fc
.dest_addr_mode
, false);
215 slen
= ieee802154_hdr_addr_len(hdr
->fc
.source_addr_mode
,
218 if (slen
< 0 || dlen
< 0)
221 return 3 + dlen
+ slen
+ hdr
->fc
.security_enabled
;
225 ieee802154_hdr_get_addrs(const u8
*buf
, struct ieee802154_hdr
*hdr
)
229 pos
+= ieee802154_hdr_get_addr(buf
+ pos
, hdr
->fc
.dest_addr_mode
,
231 pos
+= ieee802154_hdr_get_addr(buf
+ pos
, hdr
->fc
.source_addr_mode
,
232 hdr
->fc
.intra_pan
, &hdr
->source
);
234 if (hdr
->fc
.intra_pan
)
235 hdr
->source
.pan_id
= hdr
->dest
.pan_id
;
241 ieee802154_hdr_pull(struct sk_buff
*skb
, struct ieee802154_hdr
*hdr
)
245 if (!pskb_may_pull(skb
, 3))
248 memcpy(hdr
, skb
->data
, 3);
250 rc
= ieee802154_hdr_minlen(hdr
);
251 if (rc
< 0 || !pskb_may_pull(skb
, rc
))
254 pos
+= ieee802154_hdr_get_addrs(skb
->data
+ pos
, hdr
);
256 if (hdr
->fc
.security_enabled
) {
257 int want
= pos
+ ieee802154_hdr_sechdr_len(skb
->data
[pos
]);
259 if (!pskb_may_pull(skb
, want
))
262 pos
+= ieee802154_hdr_get_sechdr(skb
->data
+ pos
, &hdr
->sec
);
268 EXPORT_SYMBOL_GPL(ieee802154_hdr_pull
);
271 ieee802154_hdr_peek_addrs(const struct sk_buff
*skb
, struct ieee802154_hdr
*hdr
)
273 const u8
*buf
= skb_mac_header(skb
);
276 if (buf
+ 3 > skb_tail_pointer(skb
))
281 rc
= ieee802154_hdr_minlen(hdr
);
282 if (rc
< 0 || buf
+ rc
> skb_tail_pointer(skb
))
285 pos
+= ieee802154_hdr_get_addrs(buf
+ pos
, hdr
);
288 EXPORT_SYMBOL_GPL(ieee802154_hdr_peek_addrs
);
291 ieee802154_hdr_peek(const struct sk_buff
*skb
, struct ieee802154_hdr
*hdr
)
293 const u8
*buf
= skb_mac_header(skb
);
296 pos
= ieee802154_hdr_peek_addrs(skb
, hdr
);
300 if (hdr
->fc
.security_enabled
) {
301 u8 key_id_mode
= IEEE802154_SCF_KEY_ID_MODE(*(buf
+ pos
));
302 int want
= pos
+ ieee802154_sechdr_lengths
[key_id_mode
];
304 if (buf
+ want
> skb_tail_pointer(skb
))
307 pos
+= ieee802154_hdr_get_sechdr(buf
+ pos
, &hdr
->sec
);
312 EXPORT_SYMBOL_GPL(ieee802154_hdr_peek
);
314 int ieee802154_max_payload(const struct ieee802154_hdr
*hdr
)
316 int hlen
= ieee802154_hdr_minlen(hdr
);
318 if (hdr
->fc
.security_enabled
) {
319 hlen
+= ieee802154_sechdr_lengths
[hdr
->sec
.key_id_mode
] - 1;
320 hlen
+= ieee802154_sechdr_authtag_len(&hdr
->sec
);
323 return IEEE802154_MTU
- hlen
- IEEE802154_MFR_SIZE
;
325 EXPORT_SYMBOL_GPL(ieee802154_max_payload
);