aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2009-08-23 22:19:30 -0400
committerDavid S. Miller <davem@davemloft.net>2009-08-23 22:19:30 -0400
commit940917226260d6e029f55742a34a7d7810983c75 (patch)
tree871af506fa09aa2717c6c27307838f43993dabaf
parent9818f660f433b58e770cfeb2ee9566f7b42ca0ae (diff)
parent929122cdd5d4c344e59f9b55f870a8fcf7aa0d27 (diff)
Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/lowpan/lowpan
-rw-r--r--Documentation/networking/ieee802154.txt9
-rw-r--r--drivers/ieee802154/fakehard.c62
-rw-r--r--include/linux/if_arp.h1
-rw-r--r--include/linux/nl802154.h2
-rw-r--r--include/net/ieee802154_netdev.h6
-rw-r--r--include/net/nl802154.h2
-rw-r--r--include/net/wpan-phy.h63
-rw-r--r--net/core/dev.c4
-rw-r--r--net/ieee802154/Makefile2
-rw-r--r--net/ieee802154/af_ieee802154.c4
-rw-r--r--net/ieee802154/netlink.c28
-rw-r--r--net/ieee802154/nl_policy.c1
-rw-r--r--net/ieee802154/raw.c3
-rw-r--r--net/ieee802154/wpan-class.c159
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
57See the header include/net/ieee802154_netdev.h. You have to implement Linux 57See the header include/net/ieee802154_netdev.h. You have to implement Linux
58net_device, with .type = ARPHRD_IEEE802154. Data is exchanged with socket family 58net_device, with .type = ARPHRD_IEEE802154. Data is exchanged with socket family
59code via plain sk_buffs. The control block of sk_buffs will contain additional 59code via plain sk_buffs. On skb reception skb->cb must contain additional
60info as described in the struct ieee802154_mac_cb. 60info as described in the struct ieee802154_mac_cb. During packet transmission
61the skb->cb is used to provide additional data to device's header_ops->create
62function. Be aware, that this data can be overriden later (when socket code
63submits skb to qdisc), so if you need something from that cb later, you should
64store info in the skb->data on your own.
61 65
62To hook the MLME interface you have to populate the ml_priv field of your 66To hook the MLME interface you have to populate the ml_priv field of your
63net_device with a pointer to struct ieee802154_mlme_ops instance. All fields are 67net_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
73in software. This is currently WIP. 77in software. This is currently WIP.
74 78
75See header include/net/mac802154.h and several drivers in drivers/ieee802154/. 79See 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
35struct 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 */
115static int fake_assoc_req(struct net_device *dev, 121static 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 */
181static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr, 194static 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 */
206static int fake_scan_req(struct net_device *dev, u8 type, u32 channels, 226static 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
313static 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
294static void ieee802154_fake_setup(struct net_device *dev) 322static 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
308static int __devinit ieee802154fake_probe(struct platform_device *pdev) 337static 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)
80struct ieee802154_mlme_ops { 80struct 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 */
97int ieee802154_nl_scan_confirm(struct net_device *dev, 97int 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
27struct 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
47struct wpan_phy *wpan_phy_alloc(size_t priv_size);
48int wpan_phy_register(struct device *parent, struct wpan_phy *phy);
49void wpan_phy_unregister(struct wpan_phy *phy);
50void wpan_phy_free(struct wpan_phy *phy);
51
52static inline void *wpan_phy_priv(struct wpan_phy *phy)
53{
54 BUG_ON(!phy);
55 return &phy->priv;
56}
57
58struct wpan_phy *wpan_phy_find(const char *str);
59static 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
275static const char *const netdev_lock_name[] = 275static 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
293static struct lock_class_key netdev_xmit_lock_key[ARRAY_SIZE(netdev_lock_type)]; 293static 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 @@
1obj-$(CONFIG_IEEE802154) += nl802154.o af_802154.o 1obj-$(CONFIG_IEEE802154) += nl802154.o af_802154.o wpan-class.o
2nl802154-y := netlink.o nl_policy.o 2nl802154-y := netlink.o nl_policy.o
3af_802154-y := af_ieee802154.o raw.o dgram.o 3af_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:
232EXPORT_SYMBOL(ieee802154_nl_beacon_indic); 232EXPORT_SYMBOL(ieee802154_nl_beacon_indic);
233 233
234int ieee802154_nl_scan_confirm(struct net_device *dev, 234int 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...) \
26static 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
41MASTER_SHOW(current_channel, "%d");
42MASTER_SHOW(current_page, "%d");
43MASTER_SHOW(channels_supported, "%#x");
44MASTER_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 );
47MASTER_SHOW(cca_mode, "%d");
48
49static 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
58static 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
64static struct class wpan_phy_class = {
65 .name = "ieee802154",
66 .dev_release = wpan_phy_release,
67 .dev_attrs = pmib_attrs,
68};
69
70static DEFINE_MUTEX(wpan_phy_mutex);
71static int wpan_phy_idx;
72
73static int wpan_phy_match(struct device *dev, void *data)
74{
75 return !strcmp(dev_name(dev), (const char *)data);
76}
77
78struct 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}
92EXPORT_SYMBOL(wpan_phy_find);
93
94static int wpan_phy_idx_valid(int idx)
95{
96 return idx >= 0;
97}
98
99struct 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}
123EXPORT_SYMBOL(wpan_phy_alloc);
124
125int wpan_phy_register(struct device *parent, struct wpan_phy *phy)
126{
127 phy->dev.parent = parent;
128
129 return device_add(&phy->dev);
130}
131EXPORT_SYMBOL(wpan_phy_register);
132
133void wpan_phy_unregister(struct wpan_phy *phy)
134{
135 device_del(&phy->dev);
136}
137EXPORT_SYMBOL(wpan_phy_unregister);
138
139void wpan_phy_free(struct wpan_phy *phy)
140{
141 put_device(&phy->dev);
142}
143EXPORT_SYMBOL(wpan_phy_free);
144
145static int __init wpan_phy_class_init(void)
146{
147 return class_register(&wpan_phy_class);
148}
149subsys_initcall(wpan_phy_class_init);
150
151static void __exit wpan_phy_class_exit(void)
152{
153 class_unregister(&wpan_phy_class);
154}
155module_exit(wpan_phy_class_exit);
156
157MODULE_DESCRIPTION("IEEE 802.15.4 device class");
158MODULE_LICENSE("GPL v2");
159