diff options
author | David S. Miller <davem@davemloft.net> | 2009-08-23 22:19:30 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-08-23 22:19:30 -0400 |
commit | 940917226260d6e029f55742a34a7d7810983c75 (patch) | |
tree | 871af506fa09aa2717c6c27307838f43993dabaf | |
parent | 9818f660f433b58e770cfeb2ee9566f7b42ca0ae (diff) | |
parent | 929122cdd5d4c344e59f9b55f870a8fcf7aa0d27 (diff) |
Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/lowpan/lowpan
-rw-r--r-- | Documentation/networking/ieee802154.txt | 9 | ||||
-rw-r--r-- | drivers/ieee802154/fakehard.c | 62 | ||||
-rw-r--r-- | include/linux/if_arp.h | 1 | ||||
-rw-r--r-- | include/linux/nl802154.h | 2 | ||||
-rw-r--r-- | include/net/ieee802154_netdev.h | 6 | ||||
-rw-r--r-- | include/net/nl802154.h | 2 | ||||
-rw-r--r-- | include/net/wpan-phy.h | 63 | ||||
-rw-r--r-- | net/core/dev.c | 4 | ||||
-rw-r--r-- | net/ieee802154/Makefile | 2 | ||||
-rw-r--r-- | net/ieee802154/af_ieee802154.c | 4 | ||||
-rw-r--r-- | net/ieee802154/netlink.c | 28 | ||||
-rw-r--r-- | net/ieee802154/nl_policy.c | 1 | ||||
-rw-r--r-- | net/ieee802154/raw.c | 3 | ||||
-rw-r--r-- | net/ieee802154/wpan-class.c | 159 |
14 files changed, 318 insertions, 28 deletions
diff --git a/Documentation/networking/ieee802154.txt b/Documentation/networking/ieee802154.txt index 1c0c82c8bc7d..23c995e64032 100644 --- a/Documentation/networking/ieee802154.txt +++ b/Documentation/networking/ieee802154.txt | |||
@@ -56,8 +56,12 @@ HardMAC | |||
56 | 56 | ||
57 | See the header include/net/ieee802154_netdev.h. You have to implement Linux | 57 | See the header include/net/ieee802154_netdev.h. You have to implement Linux |
58 | net_device, with .type = ARPHRD_IEEE802154. Data is exchanged with socket family | 58 | net_device, with .type = ARPHRD_IEEE802154. Data is exchanged with socket family |
59 | code via plain sk_buffs. The control block of sk_buffs will contain additional | 59 | code via plain sk_buffs. On skb reception skb->cb must contain additional |
60 | info as described in the struct ieee802154_mac_cb. | 60 | info as described in the struct ieee802154_mac_cb. During packet transmission |
61 | the skb->cb is used to provide additional data to device's header_ops->create | ||
62 | function. Be aware, that this data can be overriden later (when socket code | ||
63 | submits skb to qdisc), so if you need something from that cb later, you should | ||
64 | store info in the skb->data on your own. | ||
61 | 65 | ||
62 | To hook the MLME interface you have to populate the ml_priv field of your | 66 | To hook the MLME interface you have to populate the ml_priv field of your |
63 | net_device with a pointer to struct ieee802154_mlme_ops instance. All fields are | 67 | net_device with a pointer to struct ieee802154_mlme_ops instance. All fields are |
@@ -73,3 +77,4 @@ We are going to provide intermediate layer implementing IEEE 802.15.4 MAC | |||
73 | in software. This is currently WIP. | 77 | in software. This is currently WIP. |
74 | 78 | ||
75 | See header include/net/mac802154.h and several drivers in drivers/ieee802154/. | 79 | See header include/net/mac802154.h and several drivers in drivers/ieee802154/. |
80 | |||
diff --git a/drivers/ieee802154/fakehard.c b/drivers/ieee802154/fakehard.c index 262536fae905..c1c9697f9fde 100644 --- a/drivers/ieee802154/fakehard.c +++ b/drivers/ieee802154/fakehard.c | |||
@@ -30,6 +30,12 @@ | |||
30 | #include <net/ieee802154_netdev.h> | 30 | #include <net/ieee802154_netdev.h> |
31 | #include <net/ieee802154.h> | 31 | #include <net/ieee802154.h> |
32 | #include <net/nl802154.h> | 32 | #include <net/nl802154.h> |
33 | #include <net/wpan-phy.h> | ||
34 | |||
35 | struct wpan_phy *net_to_phy(struct net_device *dev) | ||
36 | { | ||
37 | return container_of(dev->dev.parent, struct wpan_phy, dev); | ||
38 | } | ||
33 | 39 | ||
34 | /** | 40 | /** |
35 | * fake_get_pan_id - Retrieve the PAN ID of the device. | 41 | * fake_get_pan_id - Retrieve the PAN ID of the device. |
@@ -113,8 +119,15 @@ static u8 fake_get_bsn(struct net_device *dev) | |||
113 | * 802.15.4-2006 document. | 119 | * 802.15.4-2006 document. |
114 | */ | 120 | */ |
115 | static int fake_assoc_req(struct net_device *dev, | 121 | static int fake_assoc_req(struct net_device *dev, |
116 | struct ieee802154_addr *addr, u8 channel, u8 cap) | 122 | struct ieee802154_addr *addr, u8 channel, u8 page, u8 cap) |
117 | { | 123 | { |
124 | struct wpan_phy *phy = net_to_phy(dev); | ||
125 | |||
126 | mutex_lock(&phy->pib_lock); | ||
127 | phy->current_channel = channel; | ||
128 | phy->current_page = page; | ||
129 | mutex_unlock(&phy->pib_lock); | ||
130 | |||
118 | /* We simply emulate it here */ | 131 | /* We simply emulate it here */ |
119 | return ieee802154_nl_assoc_confirm(dev, fake_get_short_addr(dev), | 132 | return ieee802154_nl_assoc_confirm(dev, fake_get_short_addr(dev), |
120 | IEEE802154_SUCCESS); | 133 | IEEE802154_SUCCESS); |
@@ -179,10 +192,17 @@ static int fake_disassoc_req(struct net_device *dev, | |||
179 | * document, with 7.3.8 describing coordinator realignment. | 192 | * document, with 7.3.8 describing coordinator realignment. |
180 | */ | 193 | */ |
181 | static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr, | 194 | static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr, |
182 | u8 channel, | 195 | u8 channel, u8 page, |
183 | u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx, | 196 | u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx, |
184 | u8 coord_realign) | 197 | u8 coord_realign) |
185 | { | 198 | { |
199 | struct wpan_phy *phy = net_to_phy(dev); | ||
200 | |||
201 | mutex_lock(&phy->pib_lock); | ||
202 | phy->current_channel = channel; | ||
203 | phy->current_page = page; | ||
204 | mutex_unlock(&phy->pib_lock); | ||
205 | |||
186 | /* We don't emulate beacons here at all, so START should fail */ | 206 | /* We don't emulate beacons here at all, so START should fail */ |
187 | ieee802154_nl_start_confirm(dev, IEEE802154_INVALID_PARAMETER); | 207 | ieee802154_nl_start_confirm(dev, IEEE802154_INVALID_PARAMETER); |
188 | return 0; | 208 | return 0; |
@@ -204,11 +224,11 @@ static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr, | |||
204 | * Note: This is in section 7.5.2.1 of the IEEE 802.15.4-2006 document. | 224 | * Note: This is in section 7.5.2.1 of the IEEE 802.15.4-2006 document. |
205 | */ | 225 | */ |
206 | static int fake_scan_req(struct net_device *dev, u8 type, u32 channels, | 226 | static int fake_scan_req(struct net_device *dev, u8 type, u32 channels, |
207 | u8 duration) | 227 | u8 page, u8 duration) |
208 | { | 228 | { |
209 | u8 edl[27] = {}; | 229 | u8 edl[27] = {}; |
210 | return ieee802154_nl_scan_confirm(dev, IEEE802154_SUCCESS, type, | 230 | return ieee802154_nl_scan_confirm(dev, IEEE802154_SUCCESS, type, |
211 | channels, | 231 | channels, page, |
212 | type == IEEE802154_MAC_SCAN_ED ? edl : NULL); | 232 | type == IEEE802154_MAC_SCAN_ED ? edl : NULL); |
213 | } | 233 | } |
214 | 234 | ||
@@ -290,6 +310,14 @@ static const struct net_device_ops fake_ops = { | |||
290 | .ndo_set_mac_address = ieee802154_fake_mac_addr, | 310 | .ndo_set_mac_address = ieee802154_fake_mac_addr, |
291 | }; | 311 | }; |
292 | 312 | ||
313 | static void ieee802154_fake_destruct(struct net_device *dev) | ||
314 | { | ||
315 | struct wpan_phy *phy = net_to_phy(dev); | ||
316 | |||
317 | wpan_phy_unregister(phy); | ||
318 | free_netdev(dev); | ||
319 | wpan_phy_free(phy); | ||
320 | } | ||
293 | 321 | ||
294 | static void ieee802154_fake_setup(struct net_device *dev) | 322 | static void ieee802154_fake_setup(struct net_device *dev) |
295 | { | 323 | { |
@@ -302,22 +330,34 @@ static void ieee802154_fake_setup(struct net_device *dev) | |||
302 | dev->type = ARPHRD_IEEE802154; | 330 | dev->type = ARPHRD_IEEE802154; |
303 | dev->flags = IFF_NOARP | IFF_BROADCAST; | 331 | dev->flags = IFF_NOARP | IFF_BROADCAST; |
304 | dev->watchdog_timeo = 0; | 332 | dev->watchdog_timeo = 0; |
333 | dev->destructor = ieee802154_fake_destruct; | ||
305 | } | 334 | } |
306 | 335 | ||
307 | 336 | ||
308 | static int __devinit ieee802154fake_probe(struct platform_device *pdev) | 337 | static int __devinit ieee802154fake_probe(struct platform_device *pdev) |
309 | { | 338 | { |
310 | struct net_device *dev = | 339 | struct net_device *dev; |
311 | alloc_netdev(0, "hardwpan%d", ieee802154_fake_setup); | 340 | struct wpan_phy *phy = wpan_phy_alloc(0); |
312 | int err; | 341 | int err; |
313 | 342 | ||
314 | if (!dev) | 343 | if (!phy) |
344 | return -ENOMEM; | ||
345 | |||
346 | dev = alloc_netdev(0, "hardwpan%d", ieee802154_fake_setup); | ||
347 | if (!dev) { | ||
348 | wpan_phy_free(phy); | ||
315 | return -ENOMEM; | 349 | return -ENOMEM; |
350 | } | ||
351 | |||
352 | phy->dev.platform_data = dev; | ||
316 | 353 | ||
317 | memcpy(dev->dev_addr, "\xba\xbe\xca\xfe\xde\xad\xbe\xef", | 354 | memcpy(dev->dev_addr, "\xba\xbe\xca\xfe\xde\xad\xbe\xef", |
318 | dev->addr_len); | 355 | dev->addr_len); |
319 | memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); | 356 | memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); |
320 | 357 | ||
358 | phy->channels_supported = (1 << 27) - 1; | ||
359 | phy->transmit_power = 0xbf; | ||
360 | |||
321 | dev->netdev_ops = &fake_ops; | 361 | dev->netdev_ops = &fake_ops; |
322 | dev->ml_priv = &fake_mlme; | 362 | dev->ml_priv = &fake_mlme; |
323 | 363 | ||
@@ -331,15 +371,18 @@ static int __devinit ieee802154fake_probe(struct platform_device *pdev) | |||
331 | goto out; | 371 | goto out; |
332 | } | 372 | } |
333 | 373 | ||
334 | SET_NETDEV_DEV(dev, &pdev->dev); | 374 | SET_NETDEV_DEV(dev, &phy->dev); |
335 | 375 | ||
336 | platform_set_drvdata(pdev, dev); | 376 | platform_set_drvdata(pdev, dev); |
337 | 377 | ||
378 | err = wpan_phy_register(&pdev->dev, phy); | ||
379 | if (err) | ||
380 | goto out; | ||
381 | |||
338 | err = register_netdev(dev); | 382 | err = register_netdev(dev); |
339 | if (err < 0) | 383 | if (err < 0) |
340 | goto out; | 384 | goto out; |
341 | 385 | ||
342 | |||
343 | dev_info(&pdev->dev, "Added ieee802154 HardMAC hardware\n"); | 386 | dev_info(&pdev->dev, "Added ieee802154 HardMAC hardware\n"); |
344 | return 0; | 387 | return 0; |
345 | 388 | ||
@@ -352,7 +395,6 @@ static int __devexit ieee802154fake_remove(struct platform_device *pdev) | |||
352 | { | 395 | { |
353 | struct net_device *dev = platform_get_drvdata(pdev); | 396 | struct net_device *dev = platform_get_drvdata(pdev); |
354 | unregister_netdev(dev); | 397 | unregister_netdev(dev); |
355 | free_netdev(dev); | ||
356 | return 0; | 398 | return 0; |
357 | } | 399 | } |
358 | 400 | ||
diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h index b554300ef8bf..282eb37e2dec 100644 --- a/include/linux/if_arp.h +++ b/include/linux/if_arp.h | |||
@@ -87,7 +87,6 @@ | |||
87 | #define ARPHRD_IEEE80211_PRISM 802 /* IEEE 802.11 + Prism2 header */ | 87 | #define ARPHRD_IEEE80211_PRISM 802 /* IEEE 802.11 + Prism2 header */ |
88 | #define ARPHRD_IEEE80211_RADIOTAP 803 /* IEEE 802.11 + radiotap header */ | 88 | #define ARPHRD_IEEE80211_RADIOTAP 803 /* IEEE 802.11 + radiotap header */ |
89 | #define ARPHRD_IEEE802154 804 | 89 | #define ARPHRD_IEEE802154 804 |
90 | #define ARPHRD_IEEE802154_PHY 805 | ||
91 | 90 | ||
92 | #define ARPHRD_PHONET 820 /* PhoNet media type */ | 91 | #define ARPHRD_PHONET 820 /* PhoNet media type */ |
93 | #define ARPHRD_PHONET_PIPE 821 /* PhoNet pipe header */ | 92 | #define ARPHRD_PHONET_PIPE 821 /* PhoNet pipe header */ |
diff --git a/include/linux/nl802154.h b/include/linux/nl802154.h index 9a1af5f871a3..b7d9435d5a9f 100644 --- a/include/linux/nl802154.h +++ b/include/linux/nl802154.h | |||
@@ -64,6 +64,8 @@ enum { | |||
64 | IEEE802154_ATTR_COORD_REALIGN, | 64 | IEEE802154_ATTR_COORD_REALIGN, |
65 | IEEE802154_ATTR_SEC, | 65 | IEEE802154_ATTR_SEC, |
66 | 66 | ||
67 | IEEE802154_ATTR_PAGE, | ||
68 | |||
67 | __IEEE802154_ATTR_MAX, | 69 | __IEEE802154_ATTR_MAX, |
68 | }; | 70 | }; |
69 | 71 | ||
diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h index e2506af3e7c8..5dc6a61952de 100644 --- a/include/net/ieee802154_netdev.h +++ b/include/net/ieee802154_netdev.h | |||
@@ -80,7 +80,7 @@ static inline int mac_cb_type(struct sk_buff *skb) | |||
80 | struct ieee802154_mlme_ops { | 80 | struct ieee802154_mlme_ops { |
81 | int (*assoc_req)(struct net_device *dev, | 81 | int (*assoc_req)(struct net_device *dev, |
82 | struct ieee802154_addr *addr, | 82 | struct ieee802154_addr *addr, |
83 | u8 channel, u8 cap); | 83 | u8 channel, u8 page, u8 cap); |
84 | int (*assoc_resp)(struct net_device *dev, | 84 | int (*assoc_resp)(struct net_device *dev, |
85 | struct ieee802154_addr *addr, | 85 | struct ieee802154_addr *addr, |
86 | u16 short_addr, u8 status); | 86 | u16 short_addr, u8 status); |
@@ -89,10 +89,10 @@ struct ieee802154_mlme_ops { | |||
89 | u8 reason); | 89 | u8 reason); |
90 | int (*start_req)(struct net_device *dev, | 90 | int (*start_req)(struct net_device *dev, |
91 | struct ieee802154_addr *addr, | 91 | struct ieee802154_addr *addr, |
92 | u8 channel, u8 bcn_ord, u8 sf_ord, | 92 | u8 channel, u8 page, u8 bcn_ord, u8 sf_ord, |
93 | u8 pan_coord, u8 blx, u8 coord_realign); | 93 | u8 pan_coord, u8 blx, u8 coord_realign); |
94 | int (*scan_req)(struct net_device *dev, | 94 | int (*scan_req)(struct net_device *dev, |
95 | u8 type, u32 channels, u8 duration); | 95 | u8 type, u32 channels, u8 page, u8 duration); |
96 | 96 | ||
97 | /* | 97 | /* |
98 | * FIXME: these should become the part of PIB/MIB interface. | 98 | * FIXME: these should become the part of PIB/MIB interface. |
diff --git a/include/net/nl802154.h b/include/net/nl802154.h index e554ecd3727a..99d2ba1c7e03 100644 --- a/include/net/nl802154.h +++ b/include/net/nl802154.h | |||
@@ -95,7 +95,7 @@ int ieee802154_nl_disassoc_confirm(struct net_device *dev, | |||
95 | * Note: This API does not permit the return of an active scan result. | 95 | * Note: This API does not permit the return of an active scan result. |
96 | */ | 96 | */ |
97 | int ieee802154_nl_scan_confirm(struct net_device *dev, | 97 | int ieee802154_nl_scan_confirm(struct net_device *dev, |
98 | u8 status, u8 scan_type, u32 unscanned, | 98 | u8 status, u8 scan_type, u32 unscanned, u8 page, |
99 | u8 *edl/*, struct list_head *pan_desc_list */); | 99 | u8 *edl/*, struct list_head *pan_desc_list */); |
100 | 100 | ||
101 | /** | 101 | /** |
diff --git a/include/net/wpan-phy.h b/include/net/wpan-phy.h new file mode 100644 index 000000000000..547b1e271ac9 --- /dev/null +++ b/include/net/wpan-phy.h | |||
@@ -0,0 +1,63 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007, 2008, 2009 Siemens AG | ||
3 | * | ||
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. | ||
7 | * | ||
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. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License along | ||
14 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
15 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
16 | * | ||
17 | * Written by: | ||
18 | * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> | ||
19 | */ | ||
20 | |||
21 | #ifndef WPAN_PHY_H | ||
22 | #define WPAN_PHY_H | ||
23 | |||
24 | #include <linux/netdevice.h> | ||
25 | #include <linux/mutex.h> | ||
26 | |||
27 | struct wpan_phy { | ||
28 | struct mutex pib_lock; | ||
29 | |||
30 | /* | ||
31 | * This is a PIB acording to 802.15.4-2006. | ||
32 | * We do not provide timing-related variables, as they | ||
33 | * aren't used outside of driver | ||
34 | */ | ||
35 | u8 current_channel; | ||
36 | u8 current_page; | ||
37 | u32 channels_supported; | ||
38 | u8 transmit_power; | ||
39 | u8 cca_mode; | ||
40 | |||
41 | struct device dev; | ||
42 | int idx; | ||
43 | |||
44 | char priv[0] __attribute__((__aligned__(NETDEV_ALIGN))); | ||
45 | }; | ||
46 | |||
47 | struct wpan_phy *wpan_phy_alloc(size_t priv_size); | ||
48 | int wpan_phy_register(struct device *parent, struct wpan_phy *phy); | ||
49 | void wpan_phy_unregister(struct wpan_phy *phy); | ||
50 | void wpan_phy_free(struct wpan_phy *phy); | ||
51 | |||
52 | static inline void *wpan_phy_priv(struct wpan_phy *phy) | ||
53 | { | ||
54 | BUG_ON(!phy); | ||
55 | return &phy->priv; | ||
56 | } | ||
57 | |||
58 | struct wpan_phy *wpan_phy_find(const char *str); | ||
59 | static inline const char *wpan_phy_name(struct wpan_phy *phy) | ||
60 | { | ||
61 | return dev_name(&phy->dev); | ||
62 | } | ||
63 | #endif | ||
diff --git a/net/core/dev.c b/net/core/dev.c index 09fb03fa1ae6..4b837896ebd2 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -269,7 +269,7 @@ static const unsigned short netdev_lock_type[] = | |||
269 | ARPHRD_IRDA, ARPHRD_FCPP, ARPHRD_FCAL, ARPHRD_FCPL, | 269 | ARPHRD_IRDA, ARPHRD_FCPP, ARPHRD_FCAL, ARPHRD_FCPL, |
270 | ARPHRD_FCFABRIC, ARPHRD_IEEE802_TR, ARPHRD_IEEE80211, | 270 | ARPHRD_FCFABRIC, ARPHRD_IEEE802_TR, ARPHRD_IEEE80211, |
271 | ARPHRD_IEEE80211_PRISM, ARPHRD_IEEE80211_RADIOTAP, ARPHRD_PHONET, | 271 | ARPHRD_IEEE80211_PRISM, ARPHRD_IEEE80211_RADIOTAP, ARPHRD_PHONET, |
272 | ARPHRD_PHONET_PIPE, ARPHRD_IEEE802154, ARPHRD_IEEE802154_PHY, | 272 | ARPHRD_PHONET_PIPE, ARPHRD_IEEE802154, |
273 | ARPHRD_VOID, ARPHRD_NONE}; | 273 | ARPHRD_VOID, ARPHRD_NONE}; |
274 | 274 | ||
275 | static const char *const netdev_lock_name[] = | 275 | static const char *const netdev_lock_name[] = |
@@ -287,7 +287,7 @@ static const char *const netdev_lock_name[] = | |||
287 | "_xmit_IRDA", "_xmit_FCPP", "_xmit_FCAL", "_xmit_FCPL", | 287 | "_xmit_IRDA", "_xmit_FCPP", "_xmit_FCAL", "_xmit_FCPL", |
288 | "_xmit_FCFABRIC", "_xmit_IEEE802_TR", "_xmit_IEEE80211", | 288 | "_xmit_FCFABRIC", "_xmit_IEEE802_TR", "_xmit_IEEE80211", |
289 | "_xmit_IEEE80211_PRISM", "_xmit_IEEE80211_RADIOTAP", "_xmit_PHONET", | 289 | "_xmit_IEEE80211_PRISM", "_xmit_IEEE80211_RADIOTAP", "_xmit_PHONET", |
290 | "_xmit_PHONET_PIPE", "_xmit_IEEE802154", "_xmit_IEEE802154_PHY", | 290 | "_xmit_PHONET_PIPE", "_xmit_IEEE802154", |
291 | "_xmit_VOID", "_xmit_NONE"}; | 291 | "_xmit_VOID", "_xmit_NONE"}; |
292 | 292 | ||
293 | static struct lock_class_key netdev_xmit_lock_key[ARRAY_SIZE(netdev_lock_type)]; | 293 | static struct lock_class_key netdev_xmit_lock_key[ARRAY_SIZE(netdev_lock_type)]; |
diff --git a/net/ieee802154/Makefile b/net/ieee802154/Makefile index f99338a26100..4068a9f5113e 100644 --- a/net/ieee802154/Makefile +++ b/net/ieee802154/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | obj-$(CONFIG_IEEE802154) += nl802154.o af_802154.o | 1 | obj-$(CONFIG_IEEE802154) += nl802154.o af_802154.o wpan-class.o |
2 | nl802154-y := netlink.o nl_policy.o | 2 | nl802154-y := netlink.o nl_policy.o |
3 | af_802154-y := af_ieee802154.o raw.o dgram.o | 3 | af_802154-y := af_ieee802154.o raw.o dgram.o |
4 | 4 | ||
diff --git a/net/ieee802154/af_ieee802154.c b/net/ieee802154/af_ieee802154.c index d504c349cb0c..cd949d5e451b 100644 --- a/net/ieee802154/af_ieee802154.c +++ b/net/ieee802154/af_ieee802154.c | |||
@@ -147,9 +147,7 @@ static int ieee802154_dev_ioctl(struct sock *sk, struct ifreq __user *arg, | |||
147 | dev_load(sock_net(sk), ifr.ifr_name); | 147 | dev_load(sock_net(sk), ifr.ifr_name); |
148 | dev = dev_get_by_name(sock_net(sk), ifr.ifr_name); | 148 | dev = dev_get_by_name(sock_net(sk), ifr.ifr_name); |
149 | 149 | ||
150 | if ((dev->type == ARPHRD_IEEE802154 || | 150 | if (dev->type == ARPHRD_IEEE802154 && dev->netdev_ops->ndo_do_ioctl) |
151 | dev->type == ARPHRD_IEEE802154_PHY) && | ||
152 | dev->netdev_ops->ndo_do_ioctl) | ||
153 | ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, cmd); | 151 | ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, cmd); |
154 | 152 | ||
155 | if (!ret && copy_to_user(arg, &ifr, sizeof(struct ifreq))) | 153 | if (!ret && copy_to_user(arg, &ifr, sizeof(struct ifreq))) |
diff --git a/net/ieee802154/netlink.c b/net/ieee802154/netlink.c index cd0567f06716..2106ecbf0308 100644 --- a/net/ieee802154/netlink.c +++ b/net/ieee802154/netlink.c | |||
@@ -232,7 +232,7 @@ nla_put_failure: | |||
232 | EXPORT_SYMBOL(ieee802154_nl_beacon_indic); | 232 | EXPORT_SYMBOL(ieee802154_nl_beacon_indic); |
233 | 233 | ||
234 | int ieee802154_nl_scan_confirm(struct net_device *dev, | 234 | int ieee802154_nl_scan_confirm(struct net_device *dev, |
235 | u8 status, u8 scan_type, u32 unscanned, | 235 | u8 status, u8 scan_type, u32 unscanned, u8 page, |
236 | u8 *edl/* , struct list_head *pan_desc_list */) | 236 | u8 *edl/* , struct list_head *pan_desc_list */) |
237 | { | 237 | { |
238 | struct sk_buff *msg; | 238 | struct sk_buff *msg; |
@@ -251,6 +251,7 @@ int ieee802154_nl_scan_confirm(struct net_device *dev, | |||
251 | NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status); | 251 | NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status); |
252 | NLA_PUT_U8(msg, IEEE802154_ATTR_SCAN_TYPE, scan_type); | 252 | NLA_PUT_U8(msg, IEEE802154_ATTR_SCAN_TYPE, scan_type); |
253 | NLA_PUT_U32(msg, IEEE802154_ATTR_CHANNELS, unscanned); | 253 | NLA_PUT_U32(msg, IEEE802154_ATTR_CHANNELS, unscanned); |
254 | NLA_PUT_U8(msg, IEEE802154_ATTR_PAGE, page); | ||
254 | 255 | ||
255 | if (edl) | 256 | if (edl) |
256 | NLA_PUT(msg, IEEE802154_ATTR_ED_LIST, 27, edl); | 257 | NLA_PUT(msg, IEEE802154_ATTR_ED_LIST, 27, edl); |
@@ -349,6 +350,7 @@ static int ieee802154_associate_req(struct sk_buff *skb, | |||
349 | { | 350 | { |
350 | struct net_device *dev; | 351 | struct net_device *dev; |
351 | struct ieee802154_addr addr; | 352 | struct ieee802154_addr addr; |
353 | u8 page; | ||
352 | int ret = -EINVAL; | 354 | int ret = -EINVAL; |
353 | 355 | ||
354 | if (!info->attrs[IEEE802154_ATTR_CHANNEL] || | 356 | if (!info->attrs[IEEE802154_ATTR_CHANNEL] || |
@@ -374,8 +376,14 @@ static int ieee802154_associate_req(struct sk_buff *skb, | |||
374 | } | 376 | } |
375 | addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]); | 377 | addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]); |
376 | 378 | ||
379 | if (info->attrs[IEEE802154_ATTR_PAGE]) | ||
380 | page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]); | ||
381 | else | ||
382 | page = 0; | ||
383 | |||
377 | ret = ieee802154_mlme_ops(dev)->assoc_req(dev, &addr, | 384 | ret = ieee802154_mlme_ops(dev)->assoc_req(dev, &addr, |
378 | nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]), | 385 | nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]), |
386 | page, | ||
379 | nla_get_u8(info->attrs[IEEE802154_ATTR_CAPABILITY])); | 387 | nla_get_u8(info->attrs[IEEE802154_ATTR_CAPABILITY])); |
380 | 388 | ||
381 | dev_put(dev); | 389 | dev_put(dev); |
@@ -458,6 +466,7 @@ static int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info) | |||
458 | struct ieee802154_addr addr; | 466 | struct ieee802154_addr addr; |
459 | 467 | ||
460 | u8 channel, bcn_ord, sf_ord; | 468 | u8 channel, bcn_ord, sf_ord; |
469 | u8 page; | ||
461 | int pan_coord, blx, coord_realign; | 470 | int pan_coord, blx, coord_realign; |
462 | int ret; | 471 | int ret; |
463 | 472 | ||
@@ -488,13 +497,19 @@ static int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info) | |||
488 | blx = nla_get_u8(info->attrs[IEEE802154_ATTR_BAT_EXT]); | 497 | blx = nla_get_u8(info->attrs[IEEE802154_ATTR_BAT_EXT]); |
489 | coord_realign = nla_get_u8(info->attrs[IEEE802154_ATTR_COORD_REALIGN]); | 498 | coord_realign = nla_get_u8(info->attrs[IEEE802154_ATTR_COORD_REALIGN]); |
490 | 499 | ||
500 | if (info->attrs[IEEE802154_ATTR_PAGE]) | ||
501 | page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]); | ||
502 | else | ||
503 | page = 0; | ||
504 | |||
505 | |||
491 | if (addr.short_addr == IEEE802154_ADDR_BROADCAST) { | 506 | if (addr.short_addr == IEEE802154_ADDR_BROADCAST) { |
492 | ieee802154_nl_start_confirm(dev, IEEE802154_NO_SHORT_ADDRESS); | 507 | ieee802154_nl_start_confirm(dev, IEEE802154_NO_SHORT_ADDRESS); |
493 | dev_put(dev); | 508 | dev_put(dev); |
494 | return -EINVAL; | 509 | return -EINVAL; |
495 | } | 510 | } |
496 | 511 | ||
497 | ret = ieee802154_mlme_ops(dev)->start_req(dev, &addr, channel, | 512 | ret = ieee802154_mlme_ops(dev)->start_req(dev, &addr, channel, page, |
498 | bcn_ord, sf_ord, pan_coord, blx, coord_realign); | 513 | bcn_ord, sf_ord, pan_coord, blx, coord_realign); |
499 | 514 | ||
500 | dev_put(dev); | 515 | dev_put(dev); |
@@ -508,6 +523,7 @@ static int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info) | |||
508 | u8 type; | 523 | u8 type; |
509 | u32 channels; | 524 | u32 channels; |
510 | u8 duration; | 525 | u8 duration; |
526 | u8 page; | ||
511 | 527 | ||
512 | if (!info->attrs[IEEE802154_ATTR_SCAN_TYPE] || | 528 | if (!info->attrs[IEEE802154_ATTR_SCAN_TYPE] || |
513 | !info->attrs[IEEE802154_ATTR_CHANNELS] || | 529 | !info->attrs[IEEE802154_ATTR_CHANNELS] || |
@@ -522,7 +538,13 @@ static int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info) | |||
522 | channels = nla_get_u32(info->attrs[IEEE802154_ATTR_CHANNELS]); | 538 | channels = nla_get_u32(info->attrs[IEEE802154_ATTR_CHANNELS]); |
523 | duration = nla_get_u8(info->attrs[IEEE802154_ATTR_DURATION]); | 539 | duration = nla_get_u8(info->attrs[IEEE802154_ATTR_DURATION]); |
524 | 540 | ||
525 | ret = ieee802154_mlme_ops(dev)->scan_req(dev, type, channels, | 541 | if (info->attrs[IEEE802154_ATTR_PAGE]) |
542 | page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]); | ||
543 | else | ||
544 | page = 0; | ||
545 | |||
546 | |||
547 | ret = ieee802154_mlme_ops(dev)->scan_req(dev, type, channels, page, | ||
526 | duration); | 548 | duration); |
527 | 549 | ||
528 | dev_put(dev); | 550 | dev_put(dev); |
diff --git a/net/ieee802154/nl_policy.c b/net/ieee802154/nl_policy.c index 83cb4ccef90d..2363ebee02e7 100644 --- a/net/ieee802154/nl_policy.c +++ b/net/ieee802154/nl_policy.c | |||
@@ -33,6 +33,7 @@ const struct nla_policy ieee802154_policy[IEEE802154_ATTR_MAX + 1] = { | |||
33 | [IEEE802154_ATTR_HW_ADDR] = { .type = NLA_HW_ADDR, }, | 33 | [IEEE802154_ATTR_HW_ADDR] = { .type = NLA_HW_ADDR, }, |
34 | [IEEE802154_ATTR_PAN_ID] = { .type = NLA_U16, }, | 34 | [IEEE802154_ATTR_PAN_ID] = { .type = NLA_U16, }, |
35 | [IEEE802154_ATTR_CHANNEL] = { .type = NLA_U8, }, | 35 | [IEEE802154_ATTR_CHANNEL] = { .type = NLA_U8, }, |
36 | [IEEE802154_ATTR_PAGE] = { .type = NLA_U8, }, | ||
36 | [IEEE802154_ATTR_COORD_SHORT_ADDR] = { .type = NLA_U16, }, | 37 | [IEEE802154_ATTR_COORD_SHORT_ADDR] = { .type = NLA_U16, }, |
37 | [IEEE802154_ATTR_COORD_HW_ADDR] = { .type = NLA_HW_ADDR, }, | 38 | [IEEE802154_ATTR_COORD_HW_ADDR] = { .type = NLA_HW_ADDR, }, |
38 | [IEEE802154_ATTR_COORD_PAN_ID] = { .type = NLA_U16, }, | 39 | [IEEE802154_ATTR_COORD_PAN_ID] = { .type = NLA_U16, }, |
diff --git a/net/ieee802154/raw.c b/net/ieee802154/raw.c index 60dee69a1d04..4681501aae93 100644 --- a/net/ieee802154/raw.c +++ b/net/ieee802154/raw.c | |||
@@ -74,8 +74,7 @@ static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int len) | |||
74 | goto out; | 74 | goto out; |
75 | } | 75 | } |
76 | 76 | ||
77 | if (dev->type != ARPHRD_IEEE802154_PHY && | 77 | if (dev->type != ARPHRD_IEEE802154) { |
78 | dev->type != ARPHRD_IEEE802154) { | ||
79 | err = -ENODEV; | 78 | err = -ENODEV; |
80 | goto out_put; | 79 | goto out_put; |
81 | } | 80 | } |
diff --git a/net/ieee802154/wpan-class.c b/net/ieee802154/wpan-class.c new file mode 100644 index 000000000000..f306604da67a --- /dev/null +++ b/net/ieee802154/wpan-class.c | |||
@@ -0,0 +1,159 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007, 2008, 2009 Siemens AG | ||
3 | * | ||
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. | ||
7 | * | ||
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. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License along | ||
14 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
15 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/device.h> | ||
22 | |||
23 | #include <net/wpan-phy.h> | ||
24 | |||
25 | #define MASTER_SHOW_COMPLEX(name, format_string, args...) \ | ||
26 | static ssize_t name ## _show(struct device *dev, \ | ||
27 | struct device_attribute *attr, char *buf) \ | ||
28 | { \ | ||
29 | struct wpan_phy *phy = container_of(dev, struct wpan_phy, dev); \ | ||
30 | int ret; \ | ||
31 | \ | ||
32 | mutex_lock(&phy->pib_lock); \ | ||
33 | ret = sprintf(buf, format_string "\n", args); \ | ||
34 | mutex_unlock(&phy->pib_lock); \ | ||
35 | return ret; \ | ||
36 | } | ||
37 | |||
38 | #define MASTER_SHOW(field, format_string) \ | ||
39 | MASTER_SHOW_COMPLEX(field, format_string, phy->field) | ||
40 | |||
41 | MASTER_SHOW(current_channel, "%d"); | ||
42 | MASTER_SHOW(current_page, "%d"); | ||
43 | MASTER_SHOW(channels_supported, "%#x"); | ||
44 | MASTER_SHOW_COMPLEX(transmit_power, "%d +- %d dB", | ||
45 | ((signed char) (phy->transmit_power << 2)) >> 2, | ||
46 | (phy->transmit_power >> 6) ? (phy->transmit_power >> 6) * 3 : 1 ); | ||
47 | MASTER_SHOW(cca_mode, "%d"); | ||
48 | |||
49 | static struct device_attribute pmib_attrs[] = { | ||
50 | __ATTR_RO(current_channel), | ||
51 | __ATTR_RO(current_page), | ||
52 | __ATTR_RO(channels_supported), | ||
53 | __ATTR_RO(transmit_power), | ||
54 | __ATTR_RO(cca_mode), | ||
55 | {}, | ||
56 | }; | ||
57 | |||
58 | static void wpan_phy_release(struct device *d) | ||
59 | { | ||
60 | struct wpan_phy *phy = container_of(d, struct wpan_phy, dev); | ||
61 | kfree(phy); | ||
62 | } | ||
63 | |||
64 | static struct class wpan_phy_class = { | ||
65 | .name = "ieee802154", | ||
66 | .dev_release = wpan_phy_release, | ||
67 | .dev_attrs = pmib_attrs, | ||
68 | }; | ||
69 | |||
70 | static DEFINE_MUTEX(wpan_phy_mutex); | ||
71 | static int wpan_phy_idx; | ||
72 | |||
73 | static int wpan_phy_match(struct device *dev, void *data) | ||
74 | { | ||
75 | return !strcmp(dev_name(dev), (const char *)data); | ||
76 | } | ||
77 | |||
78 | struct wpan_phy *wpan_phy_find(const char *str) | ||
79 | { | ||
80 | struct device *dev; | ||
81 | |||
82 | if (WARN_ON(!str)) | ||
83 | return NULL; | ||
84 | |||
85 | dev = class_find_device(&wpan_phy_class, NULL, | ||
86 | (void *)str, wpan_phy_match); | ||
87 | if (!dev) | ||
88 | return NULL; | ||
89 | |||
90 | return container_of(dev, struct wpan_phy, dev); | ||
91 | } | ||
92 | EXPORT_SYMBOL(wpan_phy_find); | ||
93 | |||
94 | static int wpan_phy_idx_valid(int idx) | ||
95 | { | ||
96 | return idx >= 0; | ||
97 | } | ||
98 | |||
99 | struct wpan_phy *wpan_phy_alloc(size_t priv_size) | ||
100 | { | ||
101 | struct wpan_phy *phy = kzalloc(sizeof(*phy) + priv_size, | ||
102 | GFP_KERNEL); | ||
103 | |||
104 | mutex_lock(&wpan_phy_mutex); | ||
105 | phy->idx = wpan_phy_idx++; | ||
106 | if (unlikely(!wpan_phy_idx_valid(phy->idx))) { | ||
107 | wpan_phy_idx--; | ||
108 | mutex_unlock(&wpan_phy_mutex); | ||
109 | kfree(phy); | ||
110 | return NULL; | ||
111 | } | ||
112 | mutex_unlock(&wpan_phy_mutex); | ||
113 | |||
114 | mutex_init(&phy->pib_lock); | ||
115 | |||
116 | device_initialize(&phy->dev); | ||
117 | dev_set_name(&phy->dev, "wpan-phy%d", phy->idx); | ||
118 | |||
119 | phy->dev.class = &wpan_phy_class; | ||
120 | |||
121 | return phy; | ||
122 | } | ||
123 | EXPORT_SYMBOL(wpan_phy_alloc); | ||
124 | |||
125 | int wpan_phy_register(struct device *parent, struct wpan_phy *phy) | ||
126 | { | ||
127 | phy->dev.parent = parent; | ||
128 | |||
129 | return device_add(&phy->dev); | ||
130 | } | ||
131 | EXPORT_SYMBOL(wpan_phy_register); | ||
132 | |||
133 | void wpan_phy_unregister(struct wpan_phy *phy) | ||
134 | { | ||
135 | device_del(&phy->dev); | ||
136 | } | ||
137 | EXPORT_SYMBOL(wpan_phy_unregister); | ||
138 | |||
139 | void wpan_phy_free(struct wpan_phy *phy) | ||
140 | { | ||
141 | put_device(&phy->dev); | ||
142 | } | ||
143 | EXPORT_SYMBOL(wpan_phy_free); | ||
144 | |||
145 | static int __init wpan_phy_class_init(void) | ||
146 | { | ||
147 | return class_register(&wpan_phy_class); | ||
148 | } | ||
149 | subsys_initcall(wpan_phy_class_init); | ||
150 | |||
151 | static void __exit wpan_phy_class_exit(void) | ||
152 | { | ||
153 | class_unregister(&wpan_phy_class); | ||
154 | } | ||
155 | module_exit(wpan_phy_class_exit); | ||
156 | |||
157 | MODULE_DESCRIPTION("IEEE 802.15.4 device class"); | ||
158 | MODULE_LICENSE("GPL v2"); | ||
159 | |||