diff options
author | Alexander Aring <alex.aring@gmail.com> | 2015-09-18 05:30:42 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2015-09-22 05:51:20 -0400 |
commit | 838b83d63d2909f9136f3030dc4fffa8230c31da (patch) | |
tree | 7efa76e2b2a2df882e4ad941ef01806ad0664e94 | |
parent | a1da67b8117ddbe88c770b48b5b1527393b8c9c0 (diff) |
ieee802154: introduce wpan_dev_header_ops
The current header_ops callback structure of net device are used mostly
from 802.15.4 upper-layers. Because this callback structure is a very
generic one, which is also used by e.g. DGRAM AF_PACKET sockets, we
can't make this callback structure 802.15.4 specific which is currently
is.
I saw the smallest "constraint" for calling this callback with
dev_hard_header/dev_parse_header by AF_PACKET which assign a 8 byte
array for address void pointers. Currently 802.15.4 specific protocols
like af802154 and 6LoWPAN will assign the "struct ieee802154_addr" as
these parameters which is greater than 8 bytes. The current callback
implementation for header_ops.create assumes always a complete
"struct ieee802154_addr" which AF_PACKET can't never handled and is
greater than 8 bytes.
For that reason we introduce now a "generic" create/parse header_ops
callback which allows handling with intra-pan extended addresses only.
This allows a small use-case with AF_PACKET to send "somehow" a valid
dataframe over DGRAM.
To keeping the current dev_hard_header behaviour we introduce a similar
callback structure "wpan_dev_header_ops" which contains 802.15.4 specific
upper-layer header creation functionality, which can be called by
wpan_dev_hard_header.
Signed-off-by: Alexander Aring <alex.aring@gmail.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
-rw-r--r-- | include/net/cfg802154.h | 33 | ||||
-rw-r--r-- | include/net/ieee802154_netdev.h | 9 | ||||
-rw-r--r-- | net/ieee802154/6lowpan/tx.c | 8 | ||||
-rw-r--r-- | net/ieee802154/socket.c | 4 | ||||
-rw-r--r-- | net/mac802154/iface.c | 91 |
5 files changed, 118 insertions, 27 deletions
diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index 76b1ffaea863..242273ccf34b 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h | |||
@@ -167,6 +167,26 @@ struct wpan_phy { | |||
167 | char priv[0] __aligned(NETDEV_ALIGN); | 167 | char priv[0] __aligned(NETDEV_ALIGN); |
168 | }; | 168 | }; |
169 | 169 | ||
170 | struct ieee802154_addr { | ||
171 | u8 mode; | ||
172 | __le16 pan_id; | ||
173 | union { | ||
174 | __le16 short_addr; | ||
175 | __le64 extended_addr; | ||
176 | }; | ||
177 | }; | ||
178 | |||
179 | struct wpan_dev_header_ops { | ||
180 | /* TODO create callback currently assumes ieee802154_mac_cb inside | ||
181 | * skb->cb. This should be changed to give these information as | ||
182 | * parameter. | ||
183 | */ | ||
184 | int (*create)(struct sk_buff *skb, struct net_device *dev, | ||
185 | const struct ieee802154_addr *daddr, | ||
186 | const struct ieee802154_addr *saddr, | ||
187 | unsigned int len); | ||
188 | }; | ||
189 | |||
170 | struct wpan_dev { | 190 | struct wpan_dev { |
171 | struct wpan_phy *wpan_phy; | 191 | struct wpan_phy *wpan_phy; |
172 | int iftype; | 192 | int iftype; |
@@ -175,6 +195,8 @@ struct wpan_dev { | |||
175 | struct list_head list; | 195 | struct list_head list; |
176 | struct net_device *netdev; | 196 | struct net_device *netdev; |
177 | 197 | ||
198 | const struct wpan_dev_header_ops *header_ops; | ||
199 | |||
178 | /* lowpan interface, set when the wpan_dev belongs to one lowpan_dev */ | 200 | /* lowpan interface, set when the wpan_dev belongs to one lowpan_dev */ |
179 | struct net_device *lowpan_dev; | 201 | struct net_device *lowpan_dev; |
180 | 202 | ||
@@ -205,6 +227,17 @@ struct wpan_dev { | |||
205 | 227 | ||
206 | #define to_phy(_dev) container_of(_dev, struct wpan_phy, dev) | 228 | #define to_phy(_dev) container_of(_dev, struct wpan_phy, dev) |
207 | 229 | ||
230 | static inline int | ||
231 | wpan_dev_hard_header(struct sk_buff *skb, struct net_device *dev, | ||
232 | const struct ieee802154_addr *daddr, | ||
233 | const struct ieee802154_addr *saddr, | ||
234 | unsigned int len) | ||
235 | { | ||
236 | struct wpan_dev *wpan_dev = dev->ieee802154_ptr; | ||
237 | |||
238 | return wpan_dev->header_ops->create(skb, dev, daddr, saddr, len); | ||
239 | } | ||
240 | |||
208 | struct wpan_phy * | 241 | struct wpan_phy * |
209 | wpan_phy_new(const struct cfg802154_ops *ops, size_t priv_size); | 242 | wpan_phy_new(const struct cfg802154_ops *ops, size_t priv_size); |
210 | static inline void wpan_phy_set_dev(struct wpan_phy *phy, struct device *dev) | 243 | static inline void wpan_phy_set_dev(struct wpan_phy *phy, struct device *dev) |
diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h index 95a71bc113b3..aebb9d8d7a11 100644 --- a/include/net/ieee802154_netdev.h +++ b/include/net/ieee802154_netdev.h | |||
@@ -50,15 +50,6 @@ struct ieee802154_sechdr { | |||
50 | }; | 50 | }; |
51 | }; | 51 | }; |
52 | 52 | ||
53 | struct ieee802154_addr { | ||
54 | u8 mode; | ||
55 | __le16 pan_id; | ||
56 | union { | ||
57 | __le16 short_addr; | ||
58 | __le64 extended_addr; | ||
59 | }; | ||
60 | }; | ||
61 | |||
62 | struct ieee802154_hdr_fc { | 53 | struct ieee802154_hdr_fc { |
63 | #if defined(__LITTLE_ENDIAN_BITFIELD) | 54 | #if defined(__LITTLE_ENDIAN_BITFIELD) |
64 | u16 type:3, | 55 | u16 type:3, |
diff --git a/net/ieee802154/6lowpan/tx.c b/net/ieee802154/6lowpan/tx.c index 54939d031ea5..6067e064a3fe 100644 --- a/net/ieee802154/6lowpan/tx.c +++ b/net/ieee802154/6lowpan/tx.c | |||
@@ -87,8 +87,8 @@ lowpan_alloc_frag(struct sk_buff *skb, int size, | |||
87 | skb_reset_network_header(frag); | 87 | skb_reset_network_header(frag); |
88 | *mac_cb(frag) = *mac_cb(skb); | 88 | *mac_cb(frag) = *mac_cb(skb); |
89 | 89 | ||
90 | rc = dev_hard_header(frag, wdev, 0, &master_hdr->dest, | 90 | rc = wpan_dev_hard_header(frag, wdev, &master_hdr->dest, |
91 | &master_hdr->source, size); | 91 | &master_hdr->source, size); |
92 | if (rc < 0) { | 92 | if (rc < 0) { |
93 | kfree_skb(frag); | 93 | kfree_skb(frag); |
94 | return ERR_PTR(rc); | 94 | return ERR_PTR(rc); |
@@ -228,8 +228,8 @@ static int lowpan_header(struct sk_buff *skb, struct net_device *ldev, | |||
228 | cb->ackreq = wpan_dev->ackreq; | 228 | cb->ackreq = wpan_dev->ackreq; |
229 | } | 229 | } |
230 | 230 | ||
231 | return dev_hard_header(skb, lowpan_dev_info(ldev)->wdev, ETH_P_IPV6, | 231 | return wpan_dev_hard_header(skb, lowpan_dev_info(ldev)->wdev, &da, &sa, |
232 | (void *)&da, (void *)&sa, 0); | 232 | 0); |
233 | } | 233 | } |
234 | 234 | ||
235 | netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *ldev) | 235 | netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *ldev) |
diff --git a/net/ieee802154/socket.c b/net/ieee802154/socket.c index b6eacf30ee7a..be77f211ce87 100644 --- a/net/ieee802154/socket.c +++ b/net/ieee802154/socket.c | |||
@@ -676,8 +676,8 @@ static int dgram_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) | |||
676 | cb->seclevel = ro->seclevel; | 676 | cb->seclevel = ro->seclevel; |
677 | cb->seclevel_override = ro->seclevel_override; | 677 | cb->seclevel_override = ro->seclevel_override; |
678 | 678 | ||
679 | err = dev_hard_header(skb, dev, ETH_P_IEEE802154, &dst_addr, | 679 | err = wpan_dev_hard_header(skb, dev, &dst_addr, |
680 | ro->bound ? &ro->src_addr : NULL, size); | 680 | ro->bound ? &ro->src_addr : NULL, size); |
681 | if (err < 0) | 681 | if (err < 0) |
682 | goto out_skb; | 682 | goto out_skb; |
683 | 683 | ||
diff --git a/net/mac802154/iface.c b/net/mac802154/iface.c index ed26952f9e14..8afe26d72971 100644 --- a/net/mac802154/iface.c +++ b/net/mac802154/iface.c | |||
@@ -367,12 +367,11 @@ static int mac802154_set_header_security(struct ieee802154_sub_if_data *sdata, | |||
367 | return 0; | 367 | return 0; |
368 | } | 368 | } |
369 | 369 | ||
370 | static int mac802154_header_create(struct sk_buff *skb, | 370 | static int ieee802154_header_create(struct sk_buff *skb, |
371 | struct net_device *dev, | 371 | struct net_device *dev, |
372 | unsigned short type, | 372 | const struct ieee802154_addr *daddr, |
373 | const void *daddr, | 373 | const struct ieee802154_addr *saddr, |
374 | const void *saddr, | 374 | unsigned len) |
375 | unsigned len) | ||
376 | { | 375 | { |
377 | struct ieee802154_hdr hdr; | 376 | struct ieee802154_hdr hdr; |
378 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); | 377 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); |
@@ -423,24 +422,91 @@ static int mac802154_header_create(struct sk_buff *skb, | |||
423 | return hlen; | 422 | return hlen; |
424 | } | 423 | } |
425 | 424 | ||
425 | static const struct wpan_dev_header_ops ieee802154_header_ops = { | ||
426 | .create = ieee802154_header_create, | ||
427 | }; | ||
428 | |||
429 | /* This header create functionality assumes a 8 byte array for | ||
430 | * source and destination pointer at maximum. To adapt this for | ||
431 | * the 802.15.4 dataframe header we use extended address handling | ||
432 | * here only and intra pan connection. fc fields are mostly fallback | ||
433 | * handling. For provide dev_hard_header for dgram sockets. | ||
434 | */ | ||
435 | static int mac802154_header_create(struct sk_buff *skb, | ||
436 | struct net_device *dev, | ||
437 | unsigned short type, | ||
438 | const void *daddr, | ||
439 | const void *saddr, | ||
440 | unsigned len) | ||
441 | { | ||
442 | struct ieee802154_hdr hdr; | ||
443 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); | ||
444 | struct wpan_dev *wpan_dev = &sdata->wpan_dev; | ||
445 | struct ieee802154_mac_cb cb = { }; | ||
446 | int hlen; | ||
447 | |||
448 | if (!daddr) | ||
449 | return -EINVAL; | ||
450 | |||
451 | memset(&hdr.fc, 0, sizeof(hdr.fc)); | ||
452 | hdr.fc.type = IEEE802154_FC_TYPE_DATA; | ||
453 | hdr.fc.ack_request = wpan_dev->ackreq; | ||
454 | hdr.seq = atomic_inc_return(&dev->ieee802154_ptr->dsn) & 0xFF; | ||
455 | |||
456 | /* TODO currently a workaround to give zero cb block to set | ||
457 | * security parameters defaults according MIB. | ||
458 | */ | ||
459 | if (mac802154_set_header_security(sdata, &hdr, &cb) < 0) | ||
460 | return -EINVAL; | ||
461 | |||
462 | hdr.dest.pan_id = wpan_dev->pan_id; | ||
463 | hdr.dest.mode = IEEE802154_ADDR_LONG; | ||
464 | memcpy(&hdr.dest.extended_addr, daddr, IEEE802154_EXTENDED_ADDR_LEN); | ||
465 | |||
466 | hdr.source.pan_id = hdr.dest.pan_id; | ||
467 | hdr.source.mode = IEEE802154_ADDR_LONG; | ||
468 | |||
469 | if (!saddr) | ||
470 | hdr.source.extended_addr = wpan_dev->extended_addr; | ||
471 | else | ||
472 | memcpy(&hdr.source.extended_addr, saddr, | ||
473 | IEEE802154_EXTENDED_ADDR_LEN); | ||
474 | |||
475 | hlen = ieee802154_hdr_push(skb, &hdr); | ||
476 | if (hlen < 0) | ||
477 | return -EINVAL; | ||
478 | |||
479 | skb_reset_mac_header(skb); | ||
480 | skb->mac_len = hlen; | ||
481 | |||
482 | if (len > ieee802154_max_payload(&hdr)) | ||
483 | return -EMSGSIZE; | ||
484 | |||
485 | return hlen; | ||
486 | } | ||
487 | |||
426 | static int | 488 | static int |
427 | mac802154_header_parse(const struct sk_buff *skb, unsigned char *haddr) | 489 | mac802154_header_parse(const struct sk_buff *skb, unsigned char *haddr) |
428 | { | 490 | { |
429 | struct ieee802154_hdr hdr; | 491 | struct ieee802154_hdr hdr; |
430 | struct ieee802154_addr *addr = (struct ieee802154_addr *)haddr; | ||
431 | 492 | ||
432 | if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0) { | 493 | if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0) { |
433 | pr_debug("malformed packet\n"); | 494 | pr_debug("malformed packet\n"); |
434 | return 0; | 495 | return 0; |
435 | } | 496 | } |
436 | 497 | ||
437 | *addr = hdr.source; | 498 | if (hdr.source.mode == IEEE802154_ADDR_LONG) { |
438 | return sizeof(*addr); | 499 | memcpy(haddr, &hdr.source.extended_addr, |
500 | IEEE802154_EXTENDED_ADDR_LEN); | ||
501 | return IEEE802154_EXTENDED_ADDR_LEN; | ||
502 | } | ||
503 | |||
504 | return 0; | ||
439 | } | 505 | } |
440 | 506 | ||
441 | static struct header_ops mac802154_header_ops = { | 507 | static const struct header_ops mac802154_header_ops = { |
442 | .create = mac802154_header_create, | 508 | .create = mac802154_header_create, |
443 | .parse = mac802154_header_parse, | 509 | .parse = mac802154_header_parse, |
444 | }; | 510 | }; |
445 | 511 | ||
446 | static const struct net_device_ops mac802154_wpan_ops = { | 512 | static const struct net_device_ops mac802154_wpan_ops = { |
@@ -513,6 +579,7 @@ ieee802154_setup_sdata(struct ieee802154_sub_if_data *sdata, | |||
513 | sdata->dev->netdev_ops = &mac802154_wpan_ops; | 579 | sdata->dev->netdev_ops = &mac802154_wpan_ops; |
514 | sdata->dev->ml_priv = &mac802154_mlme_wpan; | 580 | sdata->dev->ml_priv = &mac802154_mlme_wpan; |
515 | wpan_dev->promiscuous_mode = false; | 581 | wpan_dev->promiscuous_mode = false; |
582 | wpan_dev->header_ops = &ieee802154_header_ops; | ||
516 | 583 | ||
517 | mutex_init(&sdata->sec_mtx); | 584 | mutex_init(&sdata->sec_mtx); |
518 | 585 | ||