diff options
author | Phoebe Buckheister <phoebe.buckheister@itwm.fraunhofer.de> | 2014-03-14 16:24:01 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-03-14 22:15:26 -0400 |
commit | e6278d92005e9d6e374f269b4ce39c908a68ad5d (patch) | |
tree | 4991dd3441843d55104c0fdba78cf36ed5d75034 /net/mac802154/wpan.c | |
parent | 94b4f6c21cf54029377a0645675a9d81b6cf890d (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.c | 321 |
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 | ||
38 | static 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 | |||
49 | static 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 | |||
60 | static 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 | |||
67 | static int | 38 | static int |
68 | mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | 39 | mac802154_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) | |||
134 | static int mac802154_header_create(struct sk_buff *skb, | 105 | static 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 | ||
223 | static int | 156 | static int |
224 | mac802154_header_parse(const struct sk_buff *skb, unsigned char *haddr) | 157 | mac802154_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); | |
315 | malformed: | ||
316 | pr_debug("malformed packet\n"); | ||
317 | return 0; | ||
318 | } | 169 | } |
319 | 170 | ||
320 | static netdev_tx_t | 171 | static 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 | ||
465 | static int mac802154_parse_frame_start(struct sk_buff *skb) | 316 | static 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) | 333 | static 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; |
545 | err: | ||
546 | return -EINVAL; | ||
547 | } | 392 | } |
548 | 393 | ||
549 | void mac802154_wpans_rx(struct mac802154_priv *priv, struct sk_buff *skb) | 394 | void mac802154_wpans_rx(struct mac802154_priv *priv, struct sk_buff *skb) |