aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac802154/wpan.c
diff options
context:
space:
mode:
authorPhoebe Buckheister <phoebe.buckheister@itwm.fraunhofer.de>2014-03-14 16:24:01 -0400
committerDavid S. Miller <davem@davemloft.net>2014-03-14 22:15:26 -0400
commite6278d92005e9d6e374f269b4ce39c908a68ad5d (patch)
tree4991dd3441843d55104c0fdba78cf36ed5d75034 /net/mac802154/wpan.c
parent94b4f6c21cf54029377a0645675a9d81b6cf890d (diff)
mac802154: use header operations to create/parse headers
Use the operations on 802.15.4 header structs introduced in a previous patch to create and parse all headers in the mac802154 stack. This patch reduces code duplication between different parts of the mac802154 stack that needed information from headers, and also fixes a few bugs that seem to have gone unnoticed until now: * 802.15.4 dgram sockets would return a slightly incorrect value for the SIOCINQ ioctl * mac802154 would not drop frames with the "security enabled" bit set, even though it does not support security, in violation of the standard Signed-off-by: Phoebe Buckheister <phoebe.buckheister@itwm.fraunhofer.de> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/mac802154/wpan.c')
-rw-r--r--net/mac802154/wpan.c321
1 files changed, 83 insertions, 238 deletions
diff --git a/net/mac802154/wpan.c b/net/mac802154/wpan.c
index 43e886bb9073..051ed46ffca9 100644
--- a/net/mac802154/wpan.c
+++ b/net/mac802154/wpan.c
@@ -35,35 +35,6 @@
35 35
36#include "mac802154.h" 36#include "mac802154.h"
37 37
38static inline int mac802154_fetch_skb_u8(struct sk_buff *skb, u8 *val)
39{
40 if (unlikely(!pskb_may_pull(skb, 1)))
41 return -EINVAL;
42
43 *val = skb->data[0];
44 skb_pull(skb, 1);
45
46 return 0;
47}
48
49static inline int mac802154_fetch_skb_u16(struct sk_buff *skb, u16 *val)
50{
51 if (unlikely(!pskb_may_pull(skb, 2)))
52 return -EINVAL;
53
54 *val = skb->data[0] | (skb->data[1] << 8);
55 skb_pull(skb, 2);
56
57 return 0;
58}
59
60static inline void mac802154_haddr_copy_swap(u8 *dest, const u8 *src)
61{
62 int i;
63 for (i = 0; i < IEEE802154_ADDR_LEN; i++)
64 dest[IEEE802154_ADDR_LEN - i - 1] = src[i];
65}
66
67static int 38static int
68mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) 39mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
69{ 40{
@@ -134,25 +105,21 @@ static int mac802154_wpan_mac_addr(struct net_device *dev, void *p)
134static int mac802154_header_create(struct sk_buff *skb, 105static int mac802154_header_create(struct sk_buff *skb,
135 struct net_device *dev, 106 struct net_device *dev,
136 unsigned short type, 107 unsigned short type,
137 const void *_daddr, 108 const void *daddr,
138 const void *_saddr, 109 const void *saddr,
139 unsigned len) 110 unsigned len)
140{ 111{
141 const struct ieee802154_addr_sa *saddr = _saddr; 112 struct ieee802154_hdr hdr;
142 const struct ieee802154_addr_sa *daddr = _daddr;
143 struct ieee802154_addr_sa dev_addr;
144 struct mac802154_sub_if_data *priv = netdev_priv(dev); 113 struct mac802154_sub_if_data *priv = netdev_priv(dev);
145 int pos = 2; 114 int hlen;
146 u8 head[MAC802154_FRAME_HARD_HEADER_LEN];
147 u16 fc;
148 115
149 if (!daddr) 116 if (!daddr)
150 return -EINVAL; 117 return -EINVAL;
151 118
152 head[pos++] = mac_cb(skb)->seq; /* DSN/BSN */ 119 memset(&hdr.fc, 0, sizeof(hdr.fc));
153 fc = mac_cb_type(skb); 120 hdr.fc.type = mac_cb_type(skb);
154 if (mac_cb_is_ackreq(skb)) 121 hdr.fc.security_enabled = mac_cb_is_secen(skb);
155 fc |= IEEE802154_FC_ACK_REQ; 122 hdr.fc.ack_request = mac_cb_is_ackreq(skb);
156 123
157 if (!saddr) { 124 if (!saddr) {
158 spin_lock_bh(&priv->mib_lock); 125 spin_lock_bh(&priv->mib_lock);
@@ -160,161 +127,45 @@ static int mac802154_header_create(struct sk_buff *skb,
160 if (priv->short_addr == cpu_to_le16(IEEE802154_ADDR_BROADCAST) || 127 if (priv->short_addr == cpu_to_le16(IEEE802154_ADDR_BROADCAST) ||
161 priv->short_addr == cpu_to_le16(IEEE802154_ADDR_UNDEF) || 128 priv->short_addr == cpu_to_le16(IEEE802154_ADDR_UNDEF) ||
162 priv->pan_id == cpu_to_le16(IEEE802154_PANID_BROADCAST)) { 129 priv->pan_id == cpu_to_le16(IEEE802154_PANID_BROADCAST)) {
163 dev_addr.addr_type = IEEE802154_ADDR_LONG; 130 hdr.source.mode = IEEE802154_ADDR_LONG;
164 memcpy(dev_addr.hwaddr, dev->dev_addr, 131 hdr.source.extended_addr = priv->extended_addr;
165 IEEE802154_ADDR_LEN);
166 } else { 132 } else {
167 dev_addr.addr_type = IEEE802154_ADDR_SHORT; 133 hdr.source.mode = IEEE802154_ADDR_SHORT;
168 dev_addr.short_addr = le16_to_cpu(priv->short_addr); 134 hdr.source.short_addr = priv->short_addr;
169 } 135 }
170 136
171 dev_addr.pan_id = le16_to_cpu(priv->pan_id); 137 hdr.source.pan_id = priv->pan_id;
172 saddr = &dev_addr;
173 138
174 spin_unlock_bh(&priv->mib_lock); 139 spin_unlock_bh(&priv->mib_lock);
140 } else {
141 hdr.source = *(const struct ieee802154_addr *)saddr;
175 } 142 }
176 143
177 if (daddr->addr_type != IEEE802154_ADDR_NONE) { 144 hdr.dest = *(const struct ieee802154_addr *)daddr;
178 fc |= (daddr->addr_type << IEEE802154_FC_DAMODE_SHIFT);
179
180 head[pos++] = daddr->pan_id & 0xff;
181 head[pos++] = daddr->pan_id >> 8;
182
183 if (daddr->addr_type == IEEE802154_ADDR_SHORT) {
184 head[pos++] = daddr->short_addr & 0xff;
185 head[pos++] = daddr->short_addr >> 8;
186 } else {
187 mac802154_haddr_copy_swap(head + pos, daddr->hwaddr);
188 pos += IEEE802154_ADDR_LEN;
189 }
190 }
191
192 if (saddr->addr_type != IEEE802154_ADDR_NONE) {
193 fc |= (saddr->addr_type << IEEE802154_FC_SAMODE_SHIFT);
194
195 if ((saddr->pan_id == daddr->pan_id) &&
196 (saddr->pan_id != IEEE802154_PANID_BROADCAST)) {
197 /* PANID compression/intra PAN */
198 fc |= IEEE802154_FC_INTRA_PAN;
199 } else {
200 head[pos++] = saddr->pan_id & 0xff;
201 head[pos++] = saddr->pan_id >> 8;
202 }
203 145
204 if (saddr->addr_type == IEEE802154_ADDR_SHORT) { 146 hlen = ieee802154_hdr_push(skb, &hdr);
205 head[pos++] = saddr->short_addr & 0xff; 147 if (hlen < 0)
206 head[pos++] = saddr->short_addr >> 8; 148 return -EINVAL;
207 } else {
208 mac802154_haddr_copy_swap(head + pos, saddr->hwaddr);
209 pos += IEEE802154_ADDR_LEN;
210 }
211 }
212
213 head[0] = fc;
214 head[1] = fc >> 8;
215 149
216 memcpy(skb_push(skb, pos), head, pos);
217 skb_reset_mac_header(skb); 150 skb_reset_mac_header(skb);
218 skb->mac_len = pos; 151 skb->mac_len = hlen;
219 152
220 return pos; 153 return hlen;
221} 154}
222 155
223static int 156static int
224mac802154_header_parse(const struct sk_buff *skb, unsigned char *haddr) 157mac802154_header_parse(const struct sk_buff *skb, unsigned char *haddr)
225{ 158{
226 const u8 *hdr = skb_mac_header(skb); 159 struct ieee802154_hdr hdr;
227 const u8 *tail = skb_tail_pointer(skb); 160 struct ieee802154_addr *addr = (struct ieee802154_addr *)haddr;
228 struct ieee802154_addr_sa *addr = (struct ieee802154_addr_sa *)haddr;
229 u16 fc;
230 int da_type;
231
232 if (hdr + 3 > tail)
233 goto malformed;
234
235 fc = hdr[0] | (hdr[1] << 8);
236 161
237 hdr += 3; 162 if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0) {
238 163 pr_debug("malformed packet\n");
239 da_type = IEEE802154_FC_DAMODE(fc); 164 return 0;
240 addr->addr_type = IEEE802154_FC_SAMODE(fc);
241
242 switch (da_type) {
243 case IEEE802154_ADDR_NONE:
244 if (fc & IEEE802154_FC_INTRA_PAN)
245 goto malformed;
246 break;
247 case IEEE802154_ADDR_LONG:
248 if (fc & IEEE802154_FC_INTRA_PAN) {
249 if (hdr + 2 > tail)
250 goto malformed;
251 addr->pan_id = hdr[0] | (hdr[1] << 8);
252 hdr += 2;
253 }
254
255 if (hdr + IEEE802154_ADDR_LEN > tail)
256 goto malformed;
257
258 hdr += IEEE802154_ADDR_LEN;
259 break;
260 case IEEE802154_ADDR_SHORT:
261 if (fc & IEEE802154_FC_INTRA_PAN) {
262 if (hdr + 2 > tail)
263 goto malformed;
264 addr->pan_id = hdr[0] | (hdr[1] << 8);
265 hdr += 2;
266 }
267
268 if (hdr + 2 > tail)
269 goto malformed;
270
271 hdr += 2;
272 break;
273 default:
274 goto malformed;
275
276 }
277
278 switch (addr->addr_type) {
279 case IEEE802154_ADDR_NONE:
280 break;
281 case IEEE802154_ADDR_LONG:
282 if (!(fc & IEEE802154_FC_INTRA_PAN)) {
283 if (hdr + 2 > tail)
284 goto malformed;
285 addr->pan_id = hdr[0] | (hdr[1] << 8);
286 hdr += 2;
287 }
288
289 if (hdr + IEEE802154_ADDR_LEN > tail)
290 goto malformed;
291
292 mac802154_haddr_copy_swap(addr->hwaddr, hdr);
293 hdr += IEEE802154_ADDR_LEN;
294 break;
295 case IEEE802154_ADDR_SHORT:
296 if (!(fc & IEEE802154_FC_INTRA_PAN)) {
297 if (hdr + 2 > tail)
298 goto malformed;
299 addr->pan_id = hdr[0] | (hdr[1] << 8);
300 hdr += 2;
301 }
302
303 if (hdr + 2 > tail)
304 goto malformed;
305
306 addr->short_addr = hdr[0] | (hdr[1] << 8);
307 hdr += 2;
308 break;
309 default:
310 goto malformed;
311 } 165 }
312 166
313 return sizeof(struct ieee802154_addr_sa); 167 *addr = hdr.source;
314 168 return sizeof(*addr);
315malformed:
316 pr_debug("malformed packet\n");
317 return 0;
318} 169}
319 170
320static netdev_tx_t 171static netdev_tx_t
@@ -462,88 +313,82 @@ mac802154_subif_frame(struct mac802154_sub_if_data *sdata, struct sk_buff *skb)
462 } 313 }
463} 314}
464 315
465static int mac802154_parse_frame_start(struct sk_buff *skb) 316static void mac802154_print_addr(const char *name,
317 const struct ieee802154_addr *addr)
466{ 318{
467 u8 *head = skb->data; 319 if (addr->mode == IEEE802154_ADDR_NONE)
468 u16 fc; 320 pr_debug("%s not present\n", name);
469
470 if (mac802154_fetch_skb_u16(skb, &fc) ||
471 mac802154_fetch_skb_u8(skb, &(mac_cb(skb)->seq)))
472 goto err;
473 321
474 pr_debug("fc: %04x dsn: %02x\n", fc, head[2]); 322 pr_debug("%s PAN ID: %04x\n", name, le16_to_cpu(addr->pan_id));
323 if (addr->mode == IEEE802154_ADDR_SHORT) {
324 pr_debug("%s is short: %04x\n", name,
325 le16_to_cpu(addr->short_addr));
326 } else {
327 u64 hw = swab64((__force u64) addr->extended_addr);
475 328
476 mac_cb(skb)->flags = IEEE802154_FC_TYPE(fc); 329 pr_debug("%s is hardware: %8phC\n", name, &hw);
477 mac_cb(skb)->sa.addr_type = IEEE802154_FC_SAMODE(fc); 330 }
478 mac_cb(skb)->da.addr_type = IEEE802154_FC_DAMODE(fc); 331}
479 332
480 if (fc & IEEE802154_FC_INTRA_PAN) 333static int mac802154_parse_frame_start(struct sk_buff *skb)
481 mac_cb(skb)->flags |= MAC_CB_FLAG_INTRAPAN; 334{
335 struct ieee802154_hdr hdr;
336 int hlen;
482 337
483 if (mac_cb(skb)->da.addr_type != IEEE802154_ADDR_NONE) { 338 hlen = ieee802154_hdr_pull(skb, &hdr);
484 if (mac802154_fetch_skb_u16(skb, &(mac_cb(skb)->da.pan_id))) 339 if (hlen < 0)
485 goto err; 340 return -EINVAL;
486 341
487 /* source PAN id compression */ 342 skb->mac_len = hlen;
488 if (mac_cb_is_intrapan(skb))
489 mac_cb(skb)->sa.pan_id = mac_cb(skb)->da.pan_id;
490 343
491 pr_debug("dest PAN addr: %04x\n", mac_cb(skb)->da.pan_id); 344 pr_debug("fc: %04x dsn: %02x\n", le16_to_cpup((__le16 *)&hdr.fc),
345 hdr.seq);
492 346
493 if (mac_cb(skb)->da.addr_type == IEEE802154_ADDR_SHORT) { 347 mac_cb(skb)->flags = hdr.fc.type;
494 u16 *da = &(mac_cb(skb)->da.short_addr);
495 348
496 if (mac802154_fetch_skb_u16(skb, da)) 349 ieee802154_addr_to_sa(&mac_cb(skb)->sa, &hdr.source);
497 goto err; 350 ieee802154_addr_to_sa(&mac_cb(skb)->da, &hdr.dest);
498 351
499 pr_debug("destination address is short: %04x\n", 352 if (hdr.fc.ack_request)
500 mac_cb(skb)->da.short_addr); 353 mac_cb(skb)->flags |= MAC_CB_FLAG_ACKREQ;
501 } else { 354 if (hdr.fc.security_enabled)
502 if (!pskb_may_pull(skb, IEEE802154_ADDR_LEN)) 355 mac_cb(skb)->flags |= MAC_CB_FLAG_SECEN;
503 goto err;
504 356
505 mac802154_haddr_copy_swap(mac_cb(skb)->da.hwaddr, 357 mac802154_print_addr("destination", &hdr.dest);
506 skb->data); 358 mac802154_print_addr("source", &hdr.source);
507 skb_pull(skb, IEEE802154_ADDR_LEN);
508 359
509 pr_debug("destination address is hardware\n"); 360 if (hdr.fc.security_enabled) {
510 } 361 u64 key;
511 }
512 362
513 if (mac_cb(skb)->sa.addr_type != IEEE802154_ADDR_NONE) { 363 pr_debug("seclevel %i\n", hdr.sec.level);
514 /* non PAN-compression, fetch source address id */
515 if (!(mac_cb_is_intrapan(skb))) {
516 u16 *sa_pan = &(mac_cb(skb)->sa.pan_id);
517 364
518 if (mac802154_fetch_skb_u16(skb, sa_pan)) 365 switch (hdr.sec.key_id_mode) {
519 goto err; 366 case IEEE802154_SCF_KEY_IMPLICIT:
520 } 367 pr_debug("implicit key\n");
521 368 break;
522 pr_debug("source PAN addr: %04x\n", mac_cb(skb)->da.pan_id);
523
524 if (mac_cb(skb)->sa.addr_type == IEEE802154_ADDR_SHORT) {
525 u16 *sa = &(mac_cb(skb)->sa.short_addr);
526
527 if (mac802154_fetch_skb_u16(skb, sa))
528 goto err;
529 369
530 pr_debug("source address is short: %04x\n", 370 case IEEE802154_SCF_KEY_INDEX:
531 mac_cb(skb)->sa.short_addr); 371 pr_debug("key %02x\n", hdr.sec.key_id);
532 } else { 372 break;
533 if (!pskb_may_pull(skb, IEEE802154_ADDR_LEN))
534 goto err;
535 373
536 mac802154_haddr_copy_swap(mac_cb(skb)->sa.hwaddr, 374 case IEEE802154_SCF_KEY_SHORT_INDEX:
537 skb->data); 375 pr_debug("key %04x:%04x %02x\n",
538 skb_pull(skb, IEEE802154_ADDR_LEN); 376 le32_to_cpu(hdr.sec.short_src) >> 16,
377 le32_to_cpu(hdr.sec.short_src) & 0xffff,
378 hdr.sec.key_id);
379 break;
539 380
540 pr_debug("source address is hardware\n"); 381 case IEEE802154_SCF_KEY_HW_INDEX:
382 key = swab64((__force u64) hdr.sec.extended_src);
383 pr_debug("key source %8phC %02x\n", &key,
384 hdr.sec.key_id);
385 break;
541 } 386 }
387
388 return -EINVAL;
542 } 389 }
543 390
544 return 0; 391 return 0;
545err:
546 return -EINVAL;
547} 392}
548 393
549void mac802154_wpans_rx(struct mac802154_priv *priv, struct sk_buff *skb) 394void mac802154_wpans_rx(struct mac802154_priv *priv, struct sk_buff *skb)