aboutsummaryrefslogtreecommitdiffstats
path: root/net/ieee802154
diff options
context:
space:
mode:
Diffstat (limited to 'net/ieee802154')
-rw-r--r--net/ieee802154/Makefile4
-rw-r--r--net/ieee802154/af_ieee802154.c13
-rw-r--r--net/ieee802154/dgram.c4
-rw-r--r--net/ieee802154/ieee802154.h53
-rw-r--r--net/ieee802154/netlink.c614
-rw-r--r--net/ieee802154/nl-mac.c618
-rw-r--r--net/ieee802154/nl-phy.c345
-rw-r--r--net/ieee802154/nl_policy.c2
-rw-r--r--net/ieee802154/raw.c4
-rw-r--r--net/ieee802154/wpan-class.c76
10 files changed, 1135 insertions, 598 deletions
diff --git a/net/ieee802154/Makefile b/net/ieee802154/Makefile
index 4068a9f5113e..ce2d33582859 100644
--- a/net/ieee802154/Makefile
+++ b/net/ieee802154/Makefile
@@ -1,5 +1,5 @@
1obj-$(CONFIG_IEEE802154) += nl802154.o af_802154.o wpan-class.o 1obj-$(CONFIG_IEEE802154) += ieee802154.o af_802154.o
2nl802154-y := netlink.o nl_policy.o 2ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o wpan-class.o
3af_802154-y := af_ieee802154.o raw.o dgram.o 3af_802154-y := af_ieee802154.o raw.o dgram.o
4 4
5ccflags-y += -Wall -DDEBUG 5ccflags-y += -Wall -DDEBUG
diff --git a/net/ieee802154/af_ieee802154.c b/net/ieee802154/af_ieee802154.c
index cd949d5e451b..93c91b633a56 100644
--- a/net/ieee802154/af_ieee802154.c
+++ b/net/ieee802154/af_ieee802154.c
@@ -28,6 +28,7 @@
28#include <linux/if.h> 28#include <linux/if.h>
29#include <linux/termios.h> /* For TIOCOUTQ/INQ */ 29#include <linux/termios.h> /* For TIOCOUTQ/INQ */
30#include <linux/list.h> 30#include <linux/list.h>
31#include <linux/slab.h>
31#include <net/datalink.h> 32#include <net/datalink.h>
32#include <net/psnap.h> 33#include <net/psnap.h>
33#include <net/sock.h> 34#include <net/sock.h>
@@ -126,6 +127,9 @@ static int ieee802154_sock_connect(struct socket *sock, struct sockaddr *uaddr,
126{ 127{
127 struct sock *sk = sock->sk; 128 struct sock *sk = sock->sk;
128 129
130 if (addr_len < sizeof(uaddr->sa_family))
131 return -EINVAL;
132
129 if (uaddr->sa_family == AF_UNSPEC) 133 if (uaddr->sa_family == AF_UNSPEC)
130 return sk->sk_prot->disconnect(sk, flags); 134 return sk->sk_prot->disconnect(sk, flags);
131 135
@@ -147,6 +151,9 @@ static int ieee802154_dev_ioctl(struct sock *sk, struct ifreq __user *arg,
147 dev_load(sock_net(sk), ifr.ifr_name); 151 dev_load(sock_net(sk), ifr.ifr_name);
148 dev = dev_get_by_name(sock_net(sk), ifr.ifr_name); 152 dev = dev_get_by_name(sock_net(sk), ifr.ifr_name);
149 153
154 if (!dev)
155 return -ENODEV;
156
150 if (dev->type == ARPHRD_IEEE802154 && dev->netdev_ops->ndo_do_ioctl) 157 if (dev->type == ARPHRD_IEEE802154 && dev->netdev_ops->ndo_do_ioctl)
151 ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, cmd); 158 ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, cmd);
152 159
@@ -234,14 +241,14 @@ static const struct proto_ops ieee802154_dgram_ops = {
234 * set the state. 241 * set the state.
235 */ 242 */
236static int ieee802154_create(struct net *net, struct socket *sock, 243static int ieee802154_create(struct net *net, struct socket *sock,
237 int protocol) 244 int protocol, int kern)
238{ 245{
239 struct sock *sk; 246 struct sock *sk;
240 int rc; 247 int rc;
241 struct proto *proto; 248 struct proto *proto;
242 const struct proto_ops *ops; 249 const struct proto_ops *ops;
243 250
244 if (net != &init_net) 251 if (!net_eq(net, &init_net))
245 return -EAFNOSUPPORT; 252 return -EAFNOSUPPORT;
246 253
247 switch (sock->type) { 254 switch (sock->type) {
@@ -285,7 +292,7 @@ out:
285 return rc; 292 return rc;
286} 293}
287 294
288static struct net_proto_family ieee802154_family_ops = { 295static const struct net_proto_family ieee802154_family_ops = {
289 .family = PF_IEEE802154, 296 .family = PF_IEEE802154,
290 .create = ieee802154_create, 297 .create = ieee802154_create,
291 .owner = THIS_MODULE, 298 .owner = THIS_MODULE,
diff --git a/net/ieee802154/dgram.c b/net/ieee802154/dgram.c
index a413b1bf4465..1a3334c2609a 100644
--- a/net/ieee802154/dgram.c
+++ b/net/ieee802154/dgram.c
@@ -25,6 +25,7 @@
25#include <linux/module.h> 25#include <linux/module.h>
26#include <linux/if_arp.h> 26#include <linux/if_arp.h>
27#include <linux/list.h> 27#include <linux/list.h>
28#include <linux/slab.h>
28#include <net/sock.h> 29#include <net/sock.h>
29#include <net/af_ieee802154.h> 30#include <net/af_ieee802154.h>
30#include <net/ieee802154.h> 31#include <net/ieee802154.h>
@@ -303,7 +304,7 @@ static int dgram_recvmsg(struct kiocb *iocb, struct sock *sk,
303 if (err) 304 if (err)
304 goto done; 305 goto done;
305 306
306 sock_recv_timestamp(msg, sk, skb); 307 sock_recv_ts_and_drops(msg, sk, skb);
307 308
308 if (flags & MSG_TRUNC) 309 if (flags & MSG_TRUNC)
309 copied = skb->len; 310 copied = skb->len;
@@ -318,7 +319,6 @@ out:
318static int dgram_rcv_skb(struct sock *sk, struct sk_buff *skb) 319static int dgram_rcv_skb(struct sock *sk, struct sk_buff *skb)
319{ 320{
320 if (sock_queue_rcv_skb(sk, skb) < 0) { 321 if (sock_queue_rcv_skb(sk, skb) < 0) {
321 atomic_inc(&sk->sk_drops);
322 kfree_skb(skb); 322 kfree_skb(skb);
323 return NET_RX_DROP; 323 return NET_RX_DROP;
324 } 324 }
diff --git a/net/ieee802154/ieee802154.h b/net/ieee802154/ieee802154.h
new file mode 100644
index 000000000000..aadec428e6ec
--- /dev/null
+++ b/net/ieee802154/ieee802154.h
@@ -0,0 +1,53 @@
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#ifndef IEEE_802154_LOCAL_H
19#define IEEE_802154_LOCAL_H
20
21int __init ieee802154_nl_init(void);
22void __exit ieee802154_nl_exit(void);
23
24#define IEEE802154_OP(_cmd, _func) \
25 { \
26 .cmd = _cmd, \
27 .policy = ieee802154_policy, \
28 .doit = _func, \
29 .dumpit = NULL, \
30 .flags = GENL_ADMIN_PERM, \
31 }
32
33#define IEEE802154_DUMP(_cmd, _func, _dump) \
34 { \
35 .cmd = _cmd, \
36 .policy = ieee802154_policy, \
37 .doit = _func, \
38 .dumpit = _dump, \
39 }
40
41struct genl_info;
42
43struct sk_buff *ieee802154_nl_create(int flags, u8 req);
44int ieee802154_nl_mcast(struct sk_buff *msg, unsigned int group);
45struct sk_buff *ieee802154_nl_new_reply(struct genl_info *info,
46 int flags, u8 req);
47int ieee802154_nl_reply(struct sk_buff *msg, struct genl_info *info);
48
49extern struct genl_family nl802154_family;
50int nl802154_mac_register(void);
51int nl802154_phy_register(void);
52
53#endif
diff --git a/net/ieee802154/netlink.c b/net/ieee802154/netlink.c
index ca767bde17a4..c8097ae2482f 100644
--- a/net/ieee802154/netlink.c
+++ b/net/ieee802154/netlink.c
@@ -23,21 +23,16 @@
23 */ 23 */
24 24
25#include <linux/kernel.h> 25#include <linux/kernel.h>
26#include <linux/if_arp.h> 26#include <linux/gfp.h>
27#include <linux/netdevice.h>
28#include <net/netlink.h>
29#include <net/genetlink.h> 27#include <net/genetlink.h>
30#include <net/sock.h>
31#include <linux/nl802154.h> 28#include <linux/nl802154.h>
32#include <net/af_ieee802154.h> 29
33#include <net/nl802154.h> 30#include "ieee802154.h"
34#include <net/ieee802154.h>
35#include <net/ieee802154_netdev.h>
36 31
37static unsigned int ieee802154_seq_num; 32static unsigned int ieee802154_seq_num;
38static DEFINE_SPINLOCK(ieee802154_seq_lock); 33static DEFINE_SPINLOCK(ieee802154_seq_lock);
39 34
40static struct genl_family ieee802154_coordinator_family = { 35struct genl_family nl802154_family = {
41 .id = GENL_ID_GENERATE, 36 .id = GENL_ID_GENERATE,
42 .hdrsize = 0, 37 .hdrsize = 0,
43 .name = IEEE802154_NL_NAME, 38 .name = IEEE802154_NL_NAME,
@@ -45,16 +40,8 @@ static struct genl_family ieee802154_coordinator_family = {
45 .maxattr = IEEE802154_ATTR_MAX, 40 .maxattr = IEEE802154_ATTR_MAX,
46}; 41};
47 42
48static struct genl_multicast_group ieee802154_coord_mcgrp = {
49 .name = IEEE802154_MCAST_COORD_NAME,
50};
51
52static struct genl_multicast_group ieee802154_beacon_mcgrp = {
53 .name = IEEE802154_MCAST_BEACON_NAME,
54};
55
56/* Requests to userspace */ 43/* Requests to userspace */
57static struct sk_buff *ieee802154_nl_create(int flags, u8 req) 44struct sk_buff *ieee802154_nl_create(int flags, u8 req)
58{ 45{
59 void *hdr; 46 void *hdr;
60 struct sk_buff *msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); 47 struct sk_buff *msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC);
@@ -65,7 +52,7 @@ static struct sk_buff *ieee802154_nl_create(int flags, u8 req)
65 52
66 spin_lock_irqsave(&ieee802154_seq_lock, f); 53 spin_lock_irqsave(&ieee802154_seq_lock, f);
67 hdr = genlmsg_put(msg, 0, ieee802154_seq_num++, 54 hdr = genlmsg_put(msg, 0, ieee802154_seq_num++,
68 &ieee802154_coordinator_family, flags, req); 55 &nl802154_family, flags, req);
69 spin_unlock_irqrestore(&ieee802154_seq_lock, f); 56 spin_unlock_irqrestore(&ieee802154_seq_lock, f);
70 if (!hdr) { 57 if (!hdr) {
71 nlmsg_free(msg); 58 nlmsg_free(msg);
@@ -75,7 +62,7 @@ static struct sk_buff *ieee802154_nl_create(int flags, u8 req)
75 return msg; 62 return msg;
76} 63}
77 64
78static int ieee802154_nl_finish(struct sk_buff *msg) 65int ieee802154_nl_mcast(struct sk_buff *msg, unsigned int group)
79{ 66{
80 /* XXX: nlh is right at the start of msg */ 67 /* XXX: nlh is right at the start of msg */
81 void *hdr = genlmsg_data(NLMSG_DATA(msg->data)); 68 void *hdr = genlmsg_data(NLMSG_DATA(msg->data));
@@ -83,607 +70,70 @@ static int ieee802154_nl_finish(struct sk_buff *msg)
83 if (genlmsg_end(msg, hdr) < 0) 70 if (genlmsg_end(msg, hdr) < 0)
84 goto out; 71 goto out;
85 72
86 return genlmsg_multicast(msg, 0, ieee802154_coord_mcgrp.id, 73 return genlmsg_multicast(msg, 0, group, GFP_ATOMIC);
87 GFP_ATOMIC);
88out: 74out:
89 nlmsg_free(msg); 75 nlmsg_free(msg);
90 return -ENOBUFS; 76 return -ENOBUFS;
91} 77}
92 78
93int ieee802154_nl_assoc_indic(struct net_device *dev, 79struct sk_buff *ieee802154_nl_new_reply(struct genl_info *info,
94 struct ieee802154_addr *addr, u8 cap) 80 int flags, u8 req)
95{
96 struct sk_buff *msg;
97
98 pr_debug("%s\n", __func__);
99
100 if (addr->addr_type != IEEE802154_ADDR_LONG) {
101 pr_err("%s: received non-long source address!\n", __func__);
102 return -EINVAL;
103 }
104
105 msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_INDIC);
106 if (!msg)
107 return -ENOBUFS;
108
109 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
110 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
111 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
112 dev->dev_addr);
113
114 NLA_PUT(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN,
115 addr->hwaddr);
116
117 NLA_PUT_U8(msg, IEEE802154_ATTR_CAPABILITY, cap);
118
119 return ieee802154_nl_finish(msg);
120
121nla_put_failure:
122 nlmsg_free(msg);
123 return -ENOBUFS;
124}
125EXPORT_SYMBOL(ieee802154_nl_assoc_indic);
126
127int ieee802154_nl_assoc_confirm(struct net_device *dev, u16 short_addr,
128 u8 status)
129{
130 struct sk_buff *msg;
131
132 pr_debug("%s\n", __func__);
133
134 msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_CONF);
135 if (!msg)
136 return -ENOBUFS;
137
138 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
139 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
140 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
141 dev->dev_addr);
142
143 NLA_PUT_U16(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr);
144 NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status);
145
146 return ieee802154_nl_finish(msg);
147
148nla_put_failure:
149 nlmsg_free(msg);
150 return -ENOBUFS;
151}
152EXPORT_SYMBOL(ieee802154_nl_assoc_confirm);
153
154int ieee802154_nl_disassoc_indic(struct net_device *dev,
155 struct ieee802154_addr *addr, u8 reason)
156{
157 struct sk_buff *msg;
158
159 pr_debug("%s\n", __func__);
160
161 msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_INDIC);
162 if (!msg)
163 return -ENOBUFS;
164
165 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
166 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
167 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
168 dev->dev_addr);
169
170 if (addr->addr_type == IEEE802154_ADDR_LONG)
171 NLA_PUT(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN,
172 addr->hwaddr);
173 else
174 NLA_PUT_U16(msg, IEEE802154_ATTR_SRC_SHORT_ADDR,
175 addr->short_addr);
176
177 NLA_PUT_U8(msg, IEEE802154_ATTR_REASON, reason);
178
179 return ieee802154_nl_finish(msg);
180
181nla_put_failure:
182 nlmsg_free(msg);
183 return -ENOBUFS;
184}
185EXPORT_SYMBOL(ieee802154_nl_disassoc_indic);
186
187int ieee802154_nl_disassoc_confirm(struct net_device *dev, u8 status)
188{
189 struct sk_buff *msg;
190
191 pr_debug("%s\n", __func__);
192
193 msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_CONF);
194 if (!msg)
195 return -ENOBUFS;
196
197 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
198 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
199 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
200 dev->dev_addr);
201
202 NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status);
203
204 return ieee802154_nl_finish(msg);
205
206nla_put_failure:
207 nlmsg_free(msg);
208 return -ENOBUFS;
209}
210EXPORT_SYMBOL(ieee802154_nl_disassoc_confirm);
211
212int ieee802154_nl_beacon_indic(struct net_device *dev,
213 u16 panid, u16 coord_addr)
214{
215 struct sk_buff *msg;
216
217 pr_debug("%s\n", __func__);
218
219 msg = ieee802154_nl_create(0, IEEE802154_BEACON_NOTIFY_INDIC);
220 if (!msg)
221 return -ENOBUFS;
222
223 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
224 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
225 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
226 dev->dev_addr);
227 NLA_PUT_U16(msg, IEEE802154_ATTR_COORD_SHORT_ADDR, coord_addr);
228 NLA_PUT_U16(msg, IEEE802154_ATTR_COORD_PAN_ID, panid);
229
230 return ieee802154_nl_finish(msg);
231
232nla_put_failure:
233 nlmsg_free(msg);
234 return -ENOBUFS;
235}
236EXPORT_SYMBOL(ieee802154_nl_beacon_indic);
237
238int ieee802154_nl_scan_confirm(struct net_device *dev,
239 u8 status, u8 scan_type, u32 unscanned, u8 page,
240 u8 *edl/* , struct list_head *pan_desc_list */)
241{
242 struct sk_buff *msg;
243
244 pr_debug("%s\n", __func__);
245
246 msg = ieee802154_nl_create(0, IEEE802154_SCAN_CONF);
247 if (!msg)
248 return -ENOBUFS;
249
250 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
251 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
252 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
253 dev->dev_addr);
254
255 NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status);
256 NLA_PUT_U8(msg, IEEE802154_ATTR_SCAN_TYPE, scan_type);
257 NLA_PUT_U32(msg, IEEE802154_ATTR_CHANNELS, unscanned);
258 NLA_PUT_U8(msg, IEEE802154_ATTR_PAGE, page);
259
260 if (edl)
261 NLA_PUT(msg, IEEE802154_ATTR_ED_LIST, 27, edl);
262
263 return ieee802154_nl_finish(msg);
264
265nla_put_failure:
266 nlmsg_free(msg);
267 return -ENOBUFS;
268}
269EXPORT_SYMBOL(ieee802154_nl_scan_confirm);
270
271int ieee802154_nl_start_confirm(struct net_device *dev, u8 status)
272{
273 struct sk_buff *msg;
274
275 pr_debug("%s\n", __func__);
276
277 msg = ieee802154_nl_create(0, IEEE802154_START_CONF);
278 if (!msg)
279 return -ENOBUFS;
280
281 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
282 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
283 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
284 dev->dev_addr);
285
286 NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status);
287
288 return ieee802154_nl_finish(msg);
289
290nla_put_failure:
291 nlmsg_free(msg);
292 return -ENOBUFS;
293}
294EXPORT_SYMBOL(ieee802154_nl_start_confirm);
295
296static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 pid,
297 u32 seq, int flags, struct net_device *dev)
298{ 81{
299 void *hdr; 82 void *hdr;
83 struct sk_buff *msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC);
300 84
301 pr_debug("%s\n", __func__); 85 if (!msg)
302
303 hdr = genlmsg_put(msg, 0, seq, &ieee802154_coordinator_family, flags,
304 IEEE802154_LIST_IFACE);
305 if (!hdr)
306 goto out;
307
308 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
309 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
310
311 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
312 dev->dev_addr);
313 NLA_PUT_U16(msg, IEEE802154_ATTR_SHORT_ADDR,
314 ieee802154_mlme_ops(dev)->get_short_addr(dev));
315 NLA_PUT_U16(msg, IEEE802154_ATTR_PAN_ID,
316 ieee802154_mlme_ops(dev)->get_pan_id(dev));
317 return genlmsg_end(msg, hdr);
318
319nla_put_failure:
320 genlmsg_cancel(msg, hdr);
321out:
322 return -EMSGSIZE;
323}
324
325/* Requests from userspace */
326static struct net_device *ieee802154_nl_get_dev(struct genl_info *info)
327{
328 struct net_device *dev;
329
330 if (info->attrs[IEEE802154_ATTR_DEV_NAME]) {
331 char name[IFNAMSIZ + 1];
332 nla_strlcpy(name, info->attrs[IEEE802154_ATTR_DEV_NAME],
333 sizeof(name));
334 dev = dev_get_by_name(&init_net, name);
335 } else if (info->attrs[IEEE802154_ATTR_DEV_INDEX])
336 dev = dev_get_by_index(&init_net,
337 nla_get_u32(info->attrs[IEEE802154_ATTR_DEV_INDEX]));
338 else
339 return NULL;
340
341 if (!dev)
342 return NULL; 86 return NULL;
343 87
344 if (dev->type != ARPHRD_IEEE802154) { 88 hdr = genlmsg_put_reply(msg, info,
345 dev_put(dev); 89 &nl802154_family, flags, req);
90 if (!hdr) {
91 nlmsg_free(msg);
346 return NULL; 92 return NULL;
347 } 93 }
348 94
349 return dev; 95 return msg;
350}
351
352static int ieee802154_associate_req(struct sk_buff *skb,
353 struct genl_info *info)
354{
355 struct net_device *dev;
356 struct ieee802154_addr addr;
357 u8 page;
358 int ret = -EINVAL;
359
360 if (!info->attrs[IEEE802154_ATTR_CHANNEL] ||
361 !info->attrs[IEEE802154_ATTR_COORD_PAN_ID] ||
362 (!info->attrs[IEEE802154_ATTR_COORD_HW_ADDR] &&
363 !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]) ||
364 !info->attrs[IEEE802154_ATTR_CAPABILITY])
365 return -EINVAL;
366
367 dev = ieee802154_nl_get_dev(info);
368 if (!dev)
369 return -ENODEV;
370
371 if (info->attrs[IEEE802154_ATTR_COORD_HW_ADDR]) {
372 addr.addr_type = IEEE802154_ADDR_LONG;
373 nla_memcpy(addr.hwaddr,
374 info->attrs[IEEE802154_ATTR_COORD_HW_ADDR],
375 IEEE802154_ADDR_LEN);
376 } else {
377 addr.addr_type = IEEE802154_ADDR_SHORT;
378 addr.short_addr = nla_get_u16(
379 info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]);
380 }
381 addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
382
383 if (info->attrs[IEEE802154_ATTR_PAGE])
384 page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
385 else
386 page = 0;
387
388 ret = ieee802154_mlme_ops(dev)->assoc_req(dev, &addr,
389 nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]),
390 page,
391 nla_get_u8(info->attrs[IEEE802154_ATTR_CAPABILITY]));
392
393 dev_put(dev);
394 return ret;
395}
396
397static int ieee802154_associate_resp(struct sk_buff *skb,
398 struct genl_info *info)
399{
400 struct net_device *dev;
401 struct ieee802154_addr addr;
402 int ret = -EINVAL;
403
404 if (!info->attrs[IEEE802154_ATTR_STATUS] ||
405 !info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] ||
406 !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR])
407 return -EINVAL;
408
409 dev = ieee802154_nl_get_dev(info);
410 if (!dev)
411 return -ENODEV;
412
413 addr.addr_type = IEEE802154_ADDR_LONG;
414 nla_memcpy(addr.hwaddr, info->attrs[IEEE802154_ATTR_DEST_HW_ADDR],
415 IEEE802154_ADDR_LEN);
416 addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
417
418
419 ret = ieee802154_mlme_ops(dev)->assoc_resp(dev, &addr,
420 nla_get_u16(info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]),
421 nla_get_u8(info->attrs[IEEE802154_ATTR_STATUS]));
422
423 dev_put(dev);
424 return ret;
425}
426
427static int ieee802154_disassociate_req(struct sk_buff *skb,
428 struct genl_info *info)
429{
430 struct net_device *dev;
431 struct ieee802154_addr addr;
432 int ret = -EINVAL;
433
434 if ((!info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] &&
435 !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]) ||
436 !info->attrs[IEEE802154_ATTR_REASON])
437 return -EINVAL;
438
439 dev = ieee802154_nl_get_dev(info);
440 if (!dev)
441 return -ENODEV;
442
443 if (info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]) {
444 addr.addr_type = IEEE802154_ADDR_LONG;
445 nla_memcpy(addr.hwaddr,
446 info->attrs[IEEE802154_ATTR_DEST_HW_ADDR],
447 IEEE802154_ADDR_LEN);
448 } else {
449 addr.addr_type = IEEE802154_ADDR_SHORT;
450 addr.short_addr = nla_get_u16(
451 info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]);
452 }
453 addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
454
455 ret = ieee802154_mlme_ops(dev)->disassoc_req(dev, &addr,
456 nla_get_u8(info->attrs[IEEE802154_ATTR_REASON]));
457
458 dev_put(dev);
459 return ret;
460}
461
462/*
463 * PANid, channel, beacon_order = 15, superframe_order = 15,
464 * PAN_coordinator, battery_life_extension = 0,
465 * coord_realignment = 0, security_enable = 0
466*/
467static int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info)
468{
469 struct net_device *dev;
470 struct ieee802154_addr addr;
471
472 u8 channel, bcn_ord, sf_ord;
473 u8 page;
474 int pan_coord, blx, coord_realign;
475 int ret;
476
477 if (!info->attrs[IEEE802154_ATTR_COORD_PAN_ID] ||
478 !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR] ||
479 !info->attrs[IEEE802154_ATTR_CHANNEL] ||
480 !info->attrs[IEEE802154_ATTR_BCN_ORD] ||
481 !info->attrs[IEEE802154_ATTR_SF_ORD] ||
482 !info->attrs[IEEE802154_ATTR_PAN_COORD] ||
483 !info->attrs[IEEE802154_ATTR_BAT_EXT] ||
484 !info->attrs[IEEE802154_ATTR_COORD_REALIGN]
485 )
486 return -EINVAL;
487
488 dev = ieee802154_nl_get_dev(info);
489 if (!dev)
490 return -ENODEV;
491
492 addr.addr_type = IEEE802154_ADDR_SHORT;
493 addr.short_addr = nla_get_u16(
494 info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]);
495 addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
496
497 channel = nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]);
498 bcn_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_BCN_ORD]);
499 sf_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_SF_ORD]);
500 pan_coord = nla_get_u8(info->attrs[IEEE802154_ATTR_PAN_COORD]);
501 blx = nla_get_u8(info->attrs[IEEE802154_ATTR_BAT_EXT]);
502 coord_realign = nla_get_u8(info->attrs[IEEE802154_ATTR_COORD_REALIGN]);
503
504 if (info->attrs[IEEE802154_ATTR_PAGE])
505 page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
506 else
507 page = 0;
508
509
510 if (addr.short_addr == IEEE802154_ADDR_BROADCAST) {
511 ieee802154_nl_start_confirm(dev, IEEE802154_NO_SHORT_ADDRESS);
512 dev_put(dev);
513 return -EINVAL;
514 }
515
516 ret = ieee802154_mlme_ops(dev)->start_req(dev, &addr, channel, page,
517 bcn_ord, sf_ord, pan_coord, blx, coord_realign);
518
519 dev_put(dev);
520 return ret;
521}
522
523static int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info)
524{
525 struct net_device *dev;
526 int ret;
527 u8 type;
528 u32 channels;
529 u8 duration;
530 u8 page;
531
532 if (!info->attrs[IEEE802154_ATTR_SCAN_TYPE] ||
533 !info->attrs[IEEE802154_ATTR_CHANNELS] ||
534 !info->attrs[IEEE802154_ATTR_DURATION])
535 return -EINVAL;
536
537 dev = ieee802154_nl_get_dev(info);
538 if (!dev)
539 return -ENODEV;
540
541 type = nla_get_u8(info->attrs[IEEE802154_ATTR_SCAN_TYPE]);
542 channels = nla_get_u32(info->attrs[IEEE802154_ATTR_CHANNELS]);
543 duration = nla_get_u8(info->attrs[IEEE802154_ATTR_DURATION]);
544
545 if (info->attrs[IEEE802154_ATTR_PAGE])
546 page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
547 else
548 page = 0;
549
550
551 ret = ieee802154_mlme_ops(dev)->scan_req(dev, type, channels, page,
552 duration);
553
554 dev_put(dev);
555 return ret;
556} 96}
557 97
558static int ieee802154_list_iface(struct sk_buff *skb, 98int ieee802154_nl_reply(struct sk_buff *msg, struct genl_info *info)
559 struct genl_info *info)
560{ 99{
561 /* Request for interface name, index, type, IEEE address, 100 /* XXX: nlh is right at the start of msg */
562 PAN Id, short address */ 101 void *hdr = genlmsg_data(NLMSG_DATA(msg->data));
563 struct sk_buff *msg;
564 struct net_device *dev = NULL;
565 int rc = -ENOBUFS;
566
567 pr_debug("%s\n", __func__);
568
569 dev = ieee802154_nl_get_dev(info);
570 if (!dev)
571 return -ENODEV;
572
573 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
574 if (!msg)
575 goto out_dev;
576
577 rc = ieee802154_nl_fill_iface(msg, info->snd_pid, info->snd_seq,
578 0, dev);
579 if (rc < 0)
580 goto out_free;
581 102
582 dev_put(dev); 103 if (genlmsg_end(msg, hdr) < 0)
104 goto out;
583 105
584 return genlmsg_unicast(&init_net, msg, info->snd_pid); 106 return genlmsg_reply(msg, info);
585out_free: 107out:
586 nlmsg_free(msg); 108 nlmsg_free(msg);
587out_dev: 109 return -ENOBUFS;
588 dev_put(dev);
589 return rc;
590
591}
592
593static int ieee802154_dump_iface(struct sk_buff *skb,
594 struct netlink_callback *cb)
595{
596 struct net *net = sock_net(skb->sk);
597 struct net_device *dev;
598 int idx;
599 int s_idx = cb->args[0];
600
601 pr_debug("%s\n", __func__);
602
603 idx = 0;
604 for_each_netdev(net, dev) {
605 if (idx < s_idx || (dev->type != ARPHRD_IEEE802154))
606 goto cont;
607
608 if (ieee802154_nl_fill_iface(skb, NETLINK_CB(cb->skb).pid,
609 cb->nlh->nlmsg_seq, NLM_F_MULTI, dev) < 0)
610 break;
611cont:
612 idx++;
613 }
614 cb->args[0] = idx;
615
616 return skb->len;
617} 110}
618 111
619#define IEEE802154_OP(_cmd, _func) \ 112int __init ieee802154_nl_init(void)
620 { \
621 .cmd = _cmd, \
622 .policy = ieee802154_policy, \
623 .doit = _func, \
624 .dumpit = NULL, \
625 .flags = GENL_ADMIN_PERM, \
626 }
627
628#define IEEE802154_DUMP(_cmd, _func, _dump) \
629 { \
630 .cmd = _cmd, \
631 .policy = ieee802154_policy, \
632 .doit = _func, \
633 .dumpit = _dump, \
634 }
635
636static struct genl_ops ieee802154_coordinator_ops[] = {
637 IEEE802154_OP(IEEE802154_ASSOCIATE_REQ, ieee802154_associate_req),
638 IEEE802154_OP(IEEE802154_ASSOCIATE_RESP, ieee802154_associate_resp),
639 IEEE802154_OP(IEEE802154_DISASSOCIATE_REQ, ieee802154_disassociate_req),
640 IEEE802154_OP(IEEE802154_SCAN_REQ, ieee802154_scan_req),
641 IEEE802154_OP(IEEE802154_START_REQ, ieee802154_start_req),
642 IEEE802154_DUMP(IEEE802154_LIST_IFACE, ieee802154_list_iface,
643 ieee802154_dump_iface),
644};
645
646static int __init ieee802154_nl_init(void)
647{ 113{
648 int rc; 114 int rc;
649 int i;
650 115
651 rc = genl_register_family(&ieee802154_coordinator_family); 116 rc = genl_register_family(&nl802154_family);
652 if (rc) 117 if (rc)
653 goto fail; 118 goto fail;
654 119
655 rc = genl_register_mc_group(&ieee802154_coordinator_family, 120 rc = nl802154_mac_register();
656 &ieee802154_coord_mcgrp);
657 if (rc) 121 if (rc)
658 goto fail; 122 goto fail;
659 123
660 rc = genl_register_mc_group(&ieee802154_coordinator_family, 124 rc = nl802154_phy_register();
661 &ieee802154_beacon_mcgrp);
662 if (rc) 125 if (rc)
663 goto fail; 126 goto fail;
664 127
665
666 for (i = 0; i < ARRAY_SIZE(ieee802154_coordinator_ops); i++) {
667 rc = genl_register_ops(&ieee802154_coordinator_family,
668 &ieee802154_coordinator_ops[i]);
669 if (rc)
670 goto fail;
671 }
672
673 return 0; 128 return 0;
674 129
675fail: 130fail:
676 genl_unregister_family(&ieee802154_coordinator_family); 131 genl_unregister_family(&nl802154_family);
677 return rc; 132 return rc;
678} 133}
679module_init(ieee802154_nl_init);
680 134
681static void __exit ieee802154_nl_exit(void) 135void __exit ieee802154_nl_exit(void)
682{ 136{
683 genl_unregister_family(&ieee802154_coordinator_family); 137 genl_unregister_family(&nl802154_family);
684} 138}
685module_exit(ieee802154_nl_exit);
686
687MODULE_LICENSE("GPL v2");
688MODULE_DESCRIPTION("ieee 802.15.4 configuration interface");
689 139
diff --git a/net/ieee802154/nl-mac.c b/net/ieee802154/nl-mac.c
new file mode 100644
index 000000000000..71ee1108d4f8
--- /dev/null
+++ b/net/ieee802154/nl-mac.c
@@ -0,0 +1,618 @@
1/*
2 * Netlink inteface for IEEE 802.15.4 stack
3 *
4 * Copyright 2007, 2008 Siemens AG
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2
8 * as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Written by:
20 * Sergey Lapin <slapin@ossfans.org>
21 * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
22 * Maxim Osipov <maxim.osipov@siemens.com>
23 */
24
25#include <linux/gfp.h>
26#include <linux/kernel.h>
27#include <linux/if_arp.h>
28#include <linux/netdevice.h>
29#include <net/netlink.h>
30#include <net/genetlink.h>
31#include <net/sock.h>
32#include <linux/nl802154.h>
33#include <net/af_ieee802154.h>
34#include <net/nl802154.h>
35#include <net/ieee802154.h>
36#include <net/ieee802154_netdev.h>
37#include <net/wpan-phy.h>
38
39#include "ieee802154.h"
40
41static struct genl_multicast_group ieee802154_coord_mcgrp = {
42 .name = IEEE802154_MCAST_COORD_NAME,
43};
44
45static struct genl_multicast_group ieee802154_beacon_mcgrp = {
46 .name = IEEE802154_MCAST_BEACON_NAME,
47};
48
49int ieee802154_nl_assoc_indic(struct net_device *dev,
50 struct ieee802154_addr *addr, u8 cap)
51{
52 struct sk_buff *msg;
53
54 pr_debug("%s\n", __func__);
55
56 if (addr->addr_type != IEEE802154_ADDR_LONG) {
57 pr_err("%s: received non-long source address!\n", __func__);
58 return -EINVAL;
59 }
60
61 msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_INDIC);
62 if (!msg)
63 return -ENOBUFS;
64
65 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
66 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
67 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
68 dev->dev_addr);
69
70 NLA_PUT(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN,
71 addr->hwaddr);
72
73 NLA_PUT_U8(msg, IEEE802154_ATTR_CAPABILITY, cap);
74
75 return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
76
77nla_put_failure:
78 nlmsg_free(msg);
79 return -ENOBUFS;
80}
81EXPORT_SYMBOL(ieee802154_nl_assoc_indic);
82
83int ieee802154_nl_assoc_confirm(struct net_device *dev, u16 short_addr,
84 u8 status)
85{
86 struct sk_buff *msg;
87
88 pr_debug("%s\n", __func__);
89
90 msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_CONF);
91 if (!msg)
92 return -ENOBUFS;
93
94 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
95 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
96 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
97 dev->dev_addr);
98
99 NLA_PUT_U16(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr);
100 NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status);
101
102 return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
103
104nla_put_failure:
105 nlmsg_free(msg);
106 return -ENOBUFS;
107}
108EXPORT_SYMBOL(ieee802154_nl_assoc_confirm);
109
110int ieee802154_nl_disassoc_indic(struct net_device *dev,
111 struct ieee802154_addr *addr, u8 reason)
112{
113 struct sk_buff *msg;
114
115 pr_debug("%s\n", __func__);
116
117 msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_INDIC);
118 if (!msg)
119 return -ENOBUFS;
120
121 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
122 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
123 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
124 dev->dev_addr);
125
126 if (addr->addr_type == IEEE802154_ADDR_LONG)
127 NLA_PUT(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN,
128 addr->hwaddr);
129 else
130 NLA_PUT_U16(msg, IEEE802154_ATTR_SRC_SHORT_ADDR,
131 addr->short_addr);
132
133 NLA_PUT_U8(msg, IEEE802154_ATTR_REASON, reason);
134
135 return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
136
137nla_put_failure:
138 nlmsg_free(msg);
139 return -ENOBUFS;
140}
141EXPORT_SYMBOL(ieee802154_nl_disassoc_indic);
142
143int ieee802154_nl_disassoc_confirm(struct net_device *dev, u8 status)
144{
145 struct sk_buff *msg;
146
147 pr_debug("%s\n", __func__);
148
149 msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_CONF);
150 if (!msg)
151 return -ENOBUFS;
152
153 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
154 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
155 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
156 dev->dev_addr);
157
158 NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status);
159
160 return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
161
162nla_put_failure:
163 nlmsg_free(msg);
164 return -ENOBUFS;
165}
166EXPORT_SYMBOL(ieee802154_nl_disassoc_confirm);
167
168int ieee802154_nl_beacon_indic(struct net_device *dev,
169 u16 panid, u16 coord_addr)
170{
171 struct sk_buff *msg;
172
173 pr_debug("%s\n", __func__);
174
175 msg = ieee802154_nl_create(0, IEEE802154_BEACON_NOTIFY_INDIC);
176 if (!msg)
177 return -ENOBUFS;
178
179 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
180 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
181 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
182 dev->dev_addr);
183 NLA_PUT_U16(msg, IEEE802154_ATTR_COORD_SHORT_ADDR, coord_addr);
184 NLA_PUT_U16(msg, IEEE802154_ATTR_COORD_PAN_ID, panid);
185
186 return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
187
188nla_put_failure:
189 nlmsg_free(msg);
190 return -ENOBUFS;
191}
192EXPORT_SYMBOL(ieee802154_nl_beacon_indic);
193
194int ieee802154_nl_scan_confirm(struct net_device *dev,
195 u8 status, u8 scan_type, u32 unscanned, u8 page,
196 u8 *edl/* , struct list_head *pan_desc_list */)
197{
198 struct sk_buff *msg;
199
200 pr_debug("%s\n", __func__);
201
202 msg = ieee802154_nl_create(0, IEEE802154_SCAN_CONF);
203 if (!msg)
204 return -ENOBUFS;
205
206 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
207 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
208 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
209 dev->dev_addr);
210
211 NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status);
212 NLA_PUT_U8(msg, IEEE802154_ATTR_SCAN_TYPE, scan_type);
213 NLA_PUT_U32(msg, IEEE802154_ATTR_CHANNELS, unscanned);
214 NLA_PUT_U8(msg, IEEE802154_ATTR_PAGE, page);
215
216 if (edl)
217 NLA_PUT(msg, IEEE802154_ATTR_ED_LIST, 27, edl);
218
219 return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
220
221nla_put_failure:
222 nlmsg_free(msg);
223 return -ENOBUFS;
224}
225EXPORT_SYMBOL(ieee802154_nl_scan_confirm);
226
227int ieee802154_nl_start_confirm(struct net_device *dev, u8 status)
228{
229 struct sk_buff *msg;
230
231 pr_debug("%s\n", __func__);
232
233 msg = ieee802154_nl_create(0, IEEE802154_START_CONF);
234 if (!msg)
235 return -ENOBUFS;
236
237 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
238 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
239 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
240 dev->dev_addr);
241
242 NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status);
243
244 return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
245
246nla_put_failure:
247 nlmsg_free(msg);
248 return -ENOBUFS;
249}
250EXPORT_SYMBOL(ieee802154_nl_start_confirm);
251
252static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 pid,
253 u32 seq, int flags, struct net_device *dev)
254{
255 void *hdr;
256 struct wpan_phy *phy;
257
258 pr_debug("%s\n", __func__);
259
260 hdr = genlmsg_put(msg, 0, seq, &nl802154_family, flags,
261 IEEE802154_LIST_IFACE);
262 if (!hdr)
263 goto out;
264
265 phy = ieee802154_mlme_ops(dev)->get_phy(dev);
266 BUG_ON(!phy);
267
268 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
269 NLA_PUT_STRING(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy));
270 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
271
272 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
273 dev->dev_addr);
274 NLA_PUT_U16(msg, IEEE802154_ATTR_SHORT_ADDR,
275 ieee802154_mlme_ops(dev)->get_short_addr(dev));
276 NLA_PUT_U16(msg, IEEE802154_ATTR_PAN_ID,
277 ieee802154_mlme_ops(dev)->get_pan_id(dev));
278 wpan_phy_put(phy);
279 return genlmsg_end(msg, hdr);
280
281nla_put_failure:
282 wpan_phy_put(phy);
283 genlmsg_cancel(msg, hdr);
284out:
285 return -EMSGSIZE;
286}
287
288/* Requests from userspace */
289static struct net_device *ieee802154_nl_get_dev(struct genl_info *info)
290{
291 struct net_device *dev;
292
293 if (info->attrs[IEEE802154_ATTR_DEV_NAME]) {
294 char name[IFNAMSIZ + 1];
295 nla_strlcpy(name, info->attrs[IEEE802154_ATTR_DEV_NAME],
296 sizeof(name));
297 dev = dev_get_by_name(&init_net, name);
298 } else if (info->attrs[IEEE802154_ATTR_DEV_INDEX])
299 dev = dev_get_by_index(&init_net,
300 nla_get_u32(info->attrs[IEEE802154_ATTR_DEV_INDEX]));
301 else
302 return NULL;
303
304 if (!dev)
305 return NULL;
306
307 if (dev->type != ARPHRD_IEEE802154) {
308 dev_put(dev);
309 return NULL;
310 }
311
312 return dev;
313}
314
315static int ieee802154_associate_req(struct sk_buff *skb,
316 struct genl_info *info)
317{
318 struct net_device *dev;
319 struct ieee802154_addr addr;
320 u8 page;
321 int ret = -EINVAL;
322
323 if (!info->attrs[IEEE802154_ATTR_CHANNEL] ||
324 !info->attrs[IEEE802154_ATTR_COORD_PAN_ID] ||
325 (!info->attrs[IEEE802154_ATTR_COORD_HW_ADDR] &&
326 !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]) ||
327 !info->attrs[IEEE802154_ATTR_CAPABILITY])
328 return -EINVAL;
329
330 dev = ieee802154_nl_get_dev(info);
331 if (!dev)
332 return -ENODEV;
333
334 if (info->attrs[IEEE802154_ATTR_COORD_HW_ADDR]) {
335 addr.addr_type = IEEE802154_ADDR_LONG;
336 nla_memcpy(addr.hwaddr,
337 info->attrs[IEEE802154_ATTR_COORD_HW_ADDR],
338 IEEE802154_ADDR_LEN);
339 } else {
340 addr.addr_type = IEEE802154_ADDR_SHORT;
341 addr.short_addr = nla_get_u16(
342 info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]);
343 }
344 addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
345
346 if (info->attrs[IEEE802154_ATTR_PAGE])
347 page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
348 else
349 page = 0;
350
351 ret = ieee802154_mlme_ops(dev)->assoc_req(dev, &addr,
352 nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]),
353 page,
354 nla_get_u8(info->attrs[IEEE802154_ATTR_CAPABILITY]));
355
356 dev_put(dev);
357 return ret;
358}
359
360static int ieee802154_associate_resp(struct sk_buff *skb,
361 struct genl_info *info)
362{
363 struct net_device *dev;
364 struct ieee802154_addr addr;
365 int ret = -EINVAL;
366
367 if (!info->attrs[IEEE802154_ATTR_STATUS] ||
368 !info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] ||
369 !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR])
370 return -EINVAL;
371
372 dev = ieee802154_nl_get_dev(info);
373 if (!dev)
374 return -ENODEV;
375
376 addr.addr_type = IEEE802154_ADDR_LONG;
377 nla_memcpy(addr.hwaddr, info->attrs[IEEE802154_ATTR_DEST_HW_ADDR],
378 IEEE802154_ADDR_LEN);
379 addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
380
381
382 ret = ieee802154_mlme_ops(dev)->assoc_resp(dev, &addr,
383 nla_get_u16(info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]),
384 nla_get_u8(info->attrs[IEEE802154_ATTR_STATUS]));
385
386 dev_put(dev);
387 return ret;
388}
389
390static int ieee802154_disassociate_req(struct sk_buff *skb,
391 struct genl_info *info)
392{
393 struct net_device *dev;
394 struct ieee802154_addr addr;
395 int ret = -EINVAL;
396
397 if ((!info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] &&
398 !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]) ||
399 !info->attrs[IEEE802154_ATTR_REASON])
400 return -EINVAL;
401
402 dev = ieee802154_nl_get_dev(info);
403 if (!dev)
404 return -ENODEV;
405
406 if (info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]) {
407 addr.addr_type = IEEE802154_ADDR_LONG;
408 nla_memcpy(addr.hwaddr,
409 info->attrs[IEEE802154_ATTR_DEST_HW_ADDR],
410 IEEE802154_ADDR_LEN);
411 } else {
412 addr.addr_type = IEEE802154_ADDR_SHORT;
413 addr.short_addr = nla_get_u16(
414 info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]);
415 }
416 addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
417
418 ret = ieee802154_mlme_ops(dev)->disassoc_req(dev, &addr,
419 nla_get_u8(info->attrs[IEEE802154_ATTR_REASON]));
420
421 dev_put(dev);
422 return ret;
423}
424
425/*
426 * PANid, channel, beacon_order = 15, superframe_order = 15,
427 * PAN_coordinator, battery_life_extension = 0,
428 * coord_realignment = 0, security_enable = 0
429*/
430static int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info)
431{
432 struct net_device *dev;
433 struct ieee802154_addr addr;
434
435 u8 channel, bcn_ord, sf_ord;
436 u8 page;
437 int pan_coord, blx, coord_realign;
438 int ret;
439
440 if (!info->attrs[IEEE802154_ATTR_COORD_PAN_ID] ||
441 !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR] ||
442 !info->attrs[IEEE802154_ATTR_CHANNEL] ||
443 !info->attrs[IEEE802154_ATTR_BCN_ORD] ||
444 !info->attrs[IEEE802154_ATTR_SF_ORD] ||
445 !info->attrs[IEEE802154_ATTR_PAN_COORD] ||
446 !info->attrs[IEEE802154_ATTR_BAT_EXT] ||
447 !info->attrs[IEEE802154_ATTR_COORD_REALIGN]
448 )
449 return -EINVAL;
450
451 dev = ieee802154_nl_get_dev(info);
452 if (!dev)
453 return -ENODEV;
454
455 addr.addr_type = IEEE802154_ADDR_SHORT;
456 addr.short_addr = nla_get_u16(
457 info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]);
458 addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
459
460 channel = nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]);
461 bcn_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_BCN_ORD]);
462 sf_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_SF_ORD]);
463 pan_coord = nla_get_u8(info->attrs[IEEE802154_ATTR_PAN_COORD]);
464 blx = nla_get_u8(info->attrs[IEEE802154_ATTR_BAT_EXT]);
465 coord_realign = nla_get_u8(info->attrs[IEEE802154_ATTR_COORD_REALIGN]);
466
467 if (info->attrs[IEEE802154_ATTR_PAGE])
468 page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
469 else
470 page = 0;
471
472
473 if (addr.short_addr == IEEE802154_ADDR_BROADCAST) {
474 ieee802154_nl_start_confirm(dev, IEEE802154_NO_SHORT_ADDRESS);
475 dev_put(dev);
476 return -EINVAL;
477 }
478
479 ret = ieee802154_mlme_ops(dev)->start_req(dev, &addr, channel, page,
480 bcn_ord, sf_ord, pan_coord, blx, coord_realign);
481
482 dev_put(dev);
483 return ret;
484}
485
486static int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info)
487{
488 struct net_device *dev;
489 int ret;
490 u8 type;
491 u32 channels;
492 u8 duration;
493 u8 page;
494
495 if (!info->attrs[IEEE802154_ATTR_SCAN_TYPE] ||
496 !info->attrs[IEEE802154_ATTR_CHANNELS] ||
497 !info->attrs[IEEE802154_ATTR_DURATION])
498 return -EINVAL;
499
500 dev = ieee802154_nl_get_dev(info);
501 if (!dev)
502 return -ENODEV;
503
504 type = nla_get_u8(info->attrs[IEEE802154_ATTR_SCAN_TYPE]);
505 channels = nla_get_u32(info->attrs[IEEE802154_ATTR_CHANNELS]);
506 duration = nla_get_u8(info->attrs[IEEE802154_ATTR_DURATION]);
507
508 if (info->attrs[IEEE802154_ATTR_PAGE])
509 page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
510 else
511 page = 0;
512
513
514 ret = ieee802154_mlme_ops(dev)->scan_req(dev, type, channels, page,
515 duration);
516
517 dev_put(dev);
518 return ret;
519}
520
521static int ieee802154_list_iface(struct sk_buff *skb,
522 struct genl_info *info)
523{
524 /* Request for interface name, index, type, IEEE address,
525 PAN Id, short address */
526 struct sk_buff *msg;
527 struct net_device *dev = NULL;
528 int rc = -ENOBUFS;
529
530 pr_debug("%s\n", __func__);
531
532 dev = ieee802154_nl_get_dev(info);
533 if (!dev)
534 return -ENODEV;
535
536 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
537 if (!msg)
538 goto out_dev;
539
540 rc = ieee802154_nl_fill_iface(msg, info->snd_pid, info->snd_seq,
541 0, dev);
542 if (rc < 0)
543 goto out_free;
544
545 dev_put(dev);
546
547 return genlmsg_reply(msg, info);
548out_free:
549 nlmsg_free(msg);
550out_dev:
551 dev_put(dev);
552 return rc;
553
554}
555
556static int ieee802154_dump_iface(struct sk_buff *skb,
557 struct netlink_callback *cb)
558{
559 struct net *net = sock_net(skb->sk);
560 struct net_device *dev;
561 int idx;
562 int s_idx = cb->args[0];
563
564 pr_debug("%s\n", __func__);
565
566 idx = 0;
567 for_each_netdev(net, dev) {
568 if (idx < s_idx || (dev->type != ARPHRD_IEEE802154))
569 goto cont;
570
571 if (ieee802154_nl_fill_iface(skb, NETLINK_CB(cb->skb).pid,
572 cb->nlh->nlmsg_seq, NLM_F_MULTI, dev) < 0)
573 break;
574cont:
575 idx++;
576 }
577 cb->args[0] = idx;
578
579 return skb->len;
580}
581
582static struct genl_ops ieee802154_coordinator_ops[] = {
583 IEEE802154_OP(IEEE802154_ASSOCIATE_REQ, ieee802154_associate_req),
584 IEEE802154_OP(IEEE802154_ASSOCIATE_RESP, ieee802154_associate_resp),
585 IEEE802154_OP(IEEE802154_DISASSOCIATE_REQ, ieee802154_disassociate_req),
586 IEEE802154_OP(IEEE802154_SCAN_REQ, ieee802154_scan_req),
587 IEEE802154_OP(IEEE802154_START_REQ, ieee802154_start_req),
588 IEEE802154_DUMP(IEEE802154_LIST_IFACE, ieee802154_list_iface,
589 ieee802154_dump_iface),
590};
591
592/*
593 * No need to unregister as family unregistration will do it.
594 */
595int nl802154_mac_register(void)
596{
597 int i;
598 int rc;
599
600 rc = genl_register_mc_group(&nl802154_family,
601 &ieee802154_coord_mcgrp);
602 if (rc)
603 return rc;
604
605 rc = genl_register_mc_group(&nl802154_family,
606 &ieee802154_beacon_mcgrp);
607 if (rc)
608 return rc;
609
610 for (i = 0; i < ARRAY_SIZE(ieee802154_coordinator_ops); i++) {
611 rc = genl_register_ops(&nl802154_family,
612 &ieee802154_coordinator_ops[i]);
613 if (rc)
614 return rc;
615 }
616
617 return 0;
618}
diff --git a/net/ieee802154/nl-phy.c b/net/ieee802154/nl-phy.c
new file mode 100644
index 000000000000..ed0eab39f531
--- /dev/null
+++ b/net/ieee802154/nl-phy.c
@@ -0,0 +1,345 @@
1/*
2 * Netlink inteface for IEEE 802.15.4 stack
3 *
4 * Copyright 2007, 2008 Siemens AG
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2
8 * as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Written by:
20 * Sergey Lapin <slapin@ossfans.org>
21 * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
22 * Maxim Osipov <maxim.osipov@siemens.com>
23 */
24
25#include <linux/kernel.h>
26#include <linux/slab.h>
27#include <net/netlink.h>
28#include <net/genetlink.h>
29#include <net/wpan-phy.h>
30#include <net/af_ieee802154.h>
31#include <net/ieee802154_netdev.h>
32#include <net/rtnetlink.h> /* for rtnl_{un,}lock */
33#include <linux/nl802154.h>
34
35#include "ieee802154.h"
36
37static int ieee802154_nl_fill_phy(struct sk_buff *msg, u32 pid,
38 u32 seq, int flags, struct wpan_phy *phy)
39{
40 void *hdr;
41 int i, pages = 0;
42 uint32_t *buf = kzalloc(32 * sizeof(uint32_t), GFP_KERNEL);
43
44 pr_debug("%s\n", __func__);
45
46 if (!buf)
47 goto out;
48
49 hdr = genlmsg_put(msg, 0, seq, &nl802154_family, flags,
50 IEEE802154_LIST_PHY);
51 if (!hdr)
52 goto out;
53
54 mutex_lock(&phy->pib_lock);
55 NLA_PUT_STRING(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy));
56
57 NLA_PUT_U8(msg, IEEE802154_ATTR_PAGE, phy->current_page);
58 NLA_PUT_U8(msg, IEEE802154_ATTR_CHANNEL, phy->current_channel);
59 for (i = 0; i < 32; i++) {
60 if (phy->channels_supported[i])
61 buf[pages++] = phy->channels_supported[i] | (i << 27);
62 }
63 if (pages)
64 NLA_PUT(msg, IEEE802154_ATTR_CHANNEL_PAGE_LIST,
65 pages * sizeof(uint32_t), buf);
66
67 mutex_unlock(&phy->pib_lock);
68 return genlmsg_end(msg, hdr);
69
70nla_put_failure:
71 mutex_unlock(&phy->pib_lock);
72 genlmsg_cancel(msg, hdr);
73out:
74 kfree(buf);
75 return -EMSGSIZE;
76}
77
78static int ieee802154_list_phy(struct sk_buff *skb,
79 struct genl_info *info)
80{
81 /* Request for interface name, index, type, IEEE address,
82 PAN Id, short address */
83 struct sk_buff *msg;
84 struct wpan_phy *phy;
85 const char *name;
86 int rc = -ENOBUFS;
87
88 pr_debug("%s\n", __func__);
89
90 if (!info->attrs[IEEE802154_ATTR_PHY_NAME])
91 return -EINVAL;
92
93 name = nla_data(info->attrs[IEEE802154_ATTR_PHY_NAME]);
94 if (name[nla_len(info->attrs[IEEE802154_ATTR_PHY_NAME]) - 1] != '\0')
95 return -EINVAL; /* phy name should be null-terminated */
96
97
98 phy = wpan_phy_find(name);
99 if (!phy)
100 return -ENODEV;
101
102 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
103 if (!msg)
104 goto out_dev;
105
106 rc = ieee802154_nl_fill_phy(msg, info->snd_pid, info->snd_seq,
107 0, phy);
108 if (rc < 0)
109 goto out_free;
110
111 wpan_phy_put(phy);
112
113 return genlmsg_reply(msg, info);
114out_free:
115 nlmsg_free(msg);
116out_dev:
117 wpan_phy_put(phy);
118 return rc;
119
120}
121
122struct dump_phy_data {
123 struct sk_buff *skb;
124 struct netlink_callback *cb;
125 int idx, s_idx;
126};
127
128static int ieee802154_dump_phy_iter(struct wpan_phy *phy, void *_data)
129{
130 int rc;
131 struct dump_phy_data *data = _data;
132
133 pr_debug("%s\n", __func__);
134
135 if (data->idx++ < data->s_idx)
136 return 0;
137
138 rc = ieee802154_nl_fill_phy(data->skb,
139 NETLINK_CB(data->cb->skb).pid,
140 data->cb->nlh->nlmsg_seq,
141 NLM_F_MULTI,
142 phy);
143
144 if (rc < 0) {
145 data->idx--;
146 return rc;
147 }
148
149 return 0;
150}
151
152static int ieee802154_dump_phy(struct sk_buff *skb,
153 struct netlink_callback *cb)
154{
155 struct dump_phy_data data = {
156 .cb = cb,
157 .skb = skb,
158 .s_idx = cb->args[0],
159 .idx = 0,
160 };
161
162 pr_debug("%s\n", __func__);
163
164 wpan_phy_for_each(ieee802154_dump_phy_iter, &data);
165
166 cb->args[0] = data.idx;
167
168 return skb->len;
169}
170
171static int ieee802154_add_iface(struct sk_buff *skb,
172 struct genl_info *info)
173{
174 struct sk_buff *msg;
175 struct wpan_phy *phy;
176 const char *name;
177 const char *devname;
178 int rc = -ENOBUFS;
179 struct net_device *dev;
180
181 pr_debug("%s\n", __func__);
182
183 if (!info->attrs[IEEE802154_ATTR_PHY_NAME])
184 return -EINVAL;
185
186 name = nla_data(info->attrs[IEEE802154_ATTR_PHY_NAME]);
187 if (name[nla_len(info->attrs[IEEE802154_ATTR_PHY_NAME]) - 1] != '\0')
188 return -EINVAL; /* phy name should be null-terminated */
189
190 if (info->attrs[IEEE802154_ATTR_DEV_NAME]) {
191 devname = nla_data(info->attrs[IEEE802154_ATTR_DEV_NAME]);
192 if (devname[nla_len(info->attrs[IEEE802154_ATTR_DEV_NAME]) - 1]
193 != '\0')
194 return -EINVAL; /* phy name should be null-terminated */
195 } else {
196 devname = "wpan%d";
197 }
198
199 if (strlen(devname) >= IFNAMSIZ)
200 return -ENAMETOOLONG;
201
202 phy = wpan_phy_find(name);
203 if (!phy)
204 return -ENODEV;
205
206 msg = ieee802154_nl_new_reply(info, 0, IEEE802154_ADD_IFACE);
207 if (!msg)
208 goto out_dev;
209
210 if (!phy->add_iface) {
211 rc = -EINVAL;
212 goto nla_put_failure;
213 }
214
215 dev = phy->add_iface(phy, devname);
216 if (IS_ERR(dev)) {
217 rc = PTR_ERR(dev);
218 goto nla_put_failure;
219 }
220
221 NLA_PUT_STRING(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy));
222 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
223
224 dev_put(dev);
225
226 wpan_phy_put(phy);
227
228 return ieee802154_nl_reply(msg, info);
229
230nla_put_failure:
231 nlmsg_free(msg);
232out_dev:
233 wpan_phy_put(phy);
234 return rc;
235}
236
237static int ieee802154_del_iface(struct sk_buff *skb,
238 struct genl_info *info)
239{
240 struct sk_buff *msg;
241 struct wpan_phy *phy;
242 const char *name;
243 int rc;
244 struct net_device *dev;
245
246 pr_debug("%s\n", __func__);
247
248 if (!info->attrs[IEEE802154_ATTR_DEV_NAME])
249 return -EINVAL;
250
251 name = nla_data(info->attrs[IEEE802154_ATTR_DEV_NAME]);
252 if (name[nla_len(info->attrs[IEEE802154_ATTR_DEV_NAME]) - 1] != '\0')
253 return -EINVAL; /* name should be null-terminated */
254
255 dev = dev_get_by_name(genl_info_net(info), name);
256 if (!dev)
257 return -ENODEV;
258
259 phy = ieee802154_mlme_ops(dev)->get_phy(dev);
260 BUG_ON(!phy);
261
262 rc = -EINVAL;
263 /* phy name is optional, but should be checked if it's given */
264 if (info->attrs[IEEE802154_ATTR_PHY_NAME]) {
265 struct wpan_phy *phy2;
266
267 const char *pname =
268 nla_data(info->attrs[IEEE802154_ATTR_PHY_NAME]);
269 if (pname[nla_len(info->attrs[IEEE802154_ATTR_PHY_NAME]) - 1]
270 != '\0')
271 /* name should be null-terminated */
272 goto out_dev;
273
274 phy2 = wpan_phy_find(pname);
275 if (!phy2)
276 goto out_dev;
277
278 if (phy != phy2) {
279 wpan_phy_put(phy2);
280 goto out_dev;
281 }
282 }
283
284 rc = -ENOBUFS;
285
286 msg = ieee802154_nl_new_reply(info, 0, IEEE802154_DEL_IFACE);
287 if (!msg)
288 goto out_dev;
289
290 if (!phy->del_iface) {
291 rc = -EINVAL;
292 goto nla_put_failure;
293 }
294
295 rtnl_lock();
296 phy->del_iface(phy, dev);
297
298 /* We don't have device anymore */
299 dev_put(dev);
300 dev = NULL;
301
302 rtnl_unlock();
303
304
305 NLA_PUT_STRING(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy));
306 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, name);
307
308 wpan_phy_put(phy);
309
310 return ieee802154_nl_reply(msg, info);
311
312nla_put_failure:
313 nlmsg_free(msg);
314out_dev:
315 wpan_phy_put(phy);
316 if (dev)
317 dev_put(dev);
318
319 return rc;
320}
321
322static struct genl_ops ieee802154_phy_ops[] = {
323 IEEE802154_DUMP(IEEE802154_LIST_PHY, ieee802154_list_phy,
324 ieee802154_dump_phy),
325 IEEE802154_OP(IEEE802154_ADD_IFACE, ieee802154_add_iface),
326 IEEE802154_OP(IEEE802154_DEL_IFACE, ieee802154_del_iface),
327};
328
329/*
330 * No need to unregister as family unregistration will do it.
331 */
332int nl802154_phy_register(void)
333{
334 int i;
335 int rc;
336
337 for (i = 0; i < ARRAY_SIZE(ieee802154_phy_ops); i++) {
338 rc = genl_register_ops(&nl802154_family,
339 &ieee802154_phy_ops[i]);
340 if (rc)
341 return rc;
342 }
343
344 return 0;
345}
diff --git a/net/ieee802154/nl_policy.c b/net/ieee802154/nl_policy.c
index 2363ebee02e7..6adda4d46f95 100644
--- a/net/ieee802154/nl_policy.c
+++ b/net/ieee802154/nl_policy.c
@@ -27,6 +27,7 @@
27const struct nla_policy ieee802154_policy[IEEE802154_ATTR_MAX + 1] = { 27const struct nla_policy ieee802154_policy[IEEE802154_ATTR_MAX + 1] = {
28 [IEEE802154_ATTR_DEV_NAME] = { .type = NLA_STRING, }, 28 [IEEE802154_ATTR_DEV_NAME] = { .type = NLA_STRING, },
29 [IEEE802154_ATTR_DEV_INDEX] = { .type = NLA_U32, }, 29 [IEEE802154_ATTR_DEV_INDEX] = { .type = NLA_U32, },
30 [IEEE802154_ATTR_PHY_NAME] = { .type = NLA_STRING, },
30 31
31 [IEEE802154_ATTR_STATUS] = { .type = NLA_U8, }, 32 [IEEE802154_ATTR_STATUS] = { .type = NLA_U8, },
32 [IEEE802154_ATTR_SHORT_ADDR] = { .type = NLA_U16, }, 33 [IEEE802154_ATTR_SHORT_ADDR] = { .type = NLA_U16, },
@@ -50,5 +51,6 @@ const struct nla_policy ieee802154_policy[IEEE802154_ATTR_MAX + 1] = {
50 [IEEE802154_ATTR_CHANNELS] = { .type = NLA_U32, }, 51 [IEEE802154_ATTR_CHANNELS] = { .type = NLA_U32, },
51 [IEEE802154_ATTR_DURATION] = { .type = NLA_U8, }, 52 [IEEE802154_ATTR_DURATION] = { .type = NLA_U8, },
52 [IEEE802154_ATTR_ED_LIST] = { .len = 27 }, 53 [IEEE802154_ATTR_ED_LIST] = { .len = 27 },
54 [IEEE802154_ATTR_CHANNEL_PAGE_LIST] = { .len = 32 * 4, },
53}; 55};
54 56
diff --git a/net/ieee802154/raw.c b/net/ieee802154/raw.c
index 30e74eee07d6..10970ca85748 100644
--- a/net/ieee802154/raw.c
+++ b/net/ieee802154/raw.c
@@ -25,6 +25,7 @@
25#include <linux/module.h> 25#include <linux/module.h>
26#include <linux/if_arp.h> 26#include <linux/if_arp.h>
27#include <linux/list.h> 27#include <linux/list.h>
28#include <linux/slab.h>
28#include <net/sock.h> 29#include <net/sock.h>
29#include <net/af_ieee802154.h> 30#include <net/af_ieee802154.h>
30 31
@@ -191,7 +192,7 @@ static int raw_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
191 if (err) 192 if (err)
192 goto done; 193 goto done;
193 194
194 sock_recv_timestamp(msg, sk, skb); 195 sock_recv_ts_and_drops(msg, sk, skb);
195 196
196 if (flags & MSG_TRUNC) 197 if (flags & MSG_TRUNC)
197 copied = skb->len; 198 copied = skb->len;
@@ -206,7 +207,6 @@ out:
206static int raw_rcv_skb(struct sock *sk, struct sk_buff *skb) 207static int raw_rcv_skb(struct sock *sk, struct sk_buff *skb)
207{ 208{
208 if (sock_queue_rcv_skb(sk, skb) < 0) { 209 if (sock_queue_rcv_skb(sk, skb) < 0) {
209 atomic_inc(&sk->sk_drops);
210 kfree_skb(skb); 210 kfree_skb(skb);
211 return NET_RX_DROP; 211 return NET_RX_DROP;
212 } 212 }
diff --git a/net/ieee802154/wpan-class.c b/net/ieee802154/wpan-class.c
index f306604da67a..3d803a1b9fb6 100644
--- a/net/ieee802154/wpan-class.c
+++ b/net/ieee802154/wpan-class.c
@@ -16,12 +16,15 @@
16 * 16 *
17 */ 17 */
18 18
19#include <linux/slab.h>
19#include <linux/kernel.h> 20#include <linux/kernel.h>
20#include <linux/module.h> 21#include <linux/module.h>
21#include <linux/device.h> 22#include <linux/device.h>
22 23
23#include <net/wpan-phy.h> 24#include <net/wpan-phy.h>
24 25
26#include "ieee802154.h"
27
25#define MASTER_SHOW_COMPLEX(name, format_string, args...) \ 28#define MASTER_SHOW_COMPLEX(name, format_string, args...) \
26static ssize_t name ## _show(struct device *dev, \ 29static ssize_t name ## _show(struct device *dev, \
27 struct device_attribute *attr, char *buf) \ 30 struct device_attribute *attr, char *buf) \
@@ -30,7 +33,7 @@ static ssize_t name ## _show(struct device *dev, \
30 int ret; \ 33 int ret; \
31 \ 34 \
32 mutex_lock(&phy->pib_lock); \ 35 mutex_lock(&phy->pib_lock); \
33 ret = sprintf(buf, format_string "\n", args); \ 36 ret = snprintf(buf, PAGE_SIZE, format_string "\n", args); \
34 mutex_unlock(&phy->pib_lock); \ 37 mutex_unlock(&phy->pib_lock); \
35 return ret; \ 38 return ret; \
36} 39}
@@ -40,12 +43,30 @@ static ssize_t name ## _show(struct device *dev, \
40 43
41MASTER_SHOW(current_channel, "%d"); 44MASTER_SHOW(current_channel, "%d");
42MASTER_SHOW(current_page, "%d"); 45MASTER_SHOW(current_page, "%d");
43MASTER_SHOW(channels_supported, "%#x");
44MASTER_SHOW_COMPLEX(transmit_power, "%d +- %d dB", 46MASTER_SHOW_COMPLEX(transmit_power, "%d +- %d dB",
45 ((signed char) (phy->transmit_power << 2)) >> 2, 47 ((signed char) (phy->transmit_power << 2)) >> 2,
46 (phy->transmit_power >> 6) ? (phy->transmit_power >> 6) * 3 : 1 ); 48 (phy->transmit_power >> 6) ? (phy->transmit_power >> 6) * 3 : 1 );
47MASTER_SHOW(cca_mode, "%d"); 49MASTER_SHOW(cca_mode, "%d");
48 50
51static ssize_t channels_supported_show(struct device *dev,
52 struct device_attribute *attr, char *buf)
53{
54 struct wpan_phy *phy = container_of(dev, struct wpan_phy, dev);
55 int ret;
56 int i, len = 0;
57
58 mutex_lock(&phy->pib_lock);
59 for (i = 0; i < 32; i++) {
60 ret = snprintf(buf + len, PAGE_SIZE - len,
61 "%#09x\n", phy->channels_supported[i]);
62 if (ret < 0)
63 break;
64 len += ret;
65 }
66 mutex_unlock(&phy->pib_lock);
67 return len;
68}
69
49static struct device_attribute pmib_attrs[] = { 70static struct device_attribute pmib_attrs[] = {
50 __ATTR_RO(current_channel), 71 __ATTR_RO(current_channel),
51 __ATTR_RO(current_page), 72 __ATTR_RO(current_page),
@@ -91,6 +112,31 @@ struct wpan_phy *wpan_phy_find(const char *str)
91} 112}
92EXPORT_SYMBOL(wpan_phy_find); 113EXPORT_SYMBOL(wpan_phy_find);
93 114
115struct wpan_phy_iter_data {
116 int (*fn)(struct wpan_phy *phy, void *data);
117 void *data;
118};
119
120static int wpan_phy_iter(struct device *dev, void *_data)
121{
122 struct wpan_phy_iter_data *wpid = _data;
123 struct wpan_phy *phy = container_of(dev, struct wpan_phy, dev);
124 return wpid->fn(phy, wpid->data);
125}
126
127int wpan_phy_for_each(int (*fn)(struct wpan_phy *phy, void *data),
128 void *data)
129{
130 struct wpan_phy_iter_data wpid = {
131 .fn = fn,
132 .data = data,
133 };
134
135 return class_for_each_device(&wpan_phy_class, NULL,
136 &wpid, wpan_phy_iter);
137}
138EXPORT_SYMBOL(wpan_phy_for_each);
139
94static int wpan_phy_idx_valid(int idx) 140static int wpan_phy_idx_valid(int idx)
95{ 141{
96 return idx >= 0; 142 return idx >= 0;
@@ -118,14 +164,15 @@ struct wpan_phy *wpan_phy_alloc(size_t priv_size)
118 164
119 phy->dev.class = &wpan_phy_class; 165 phy->dev.class = &wpan_phy_class;
120 166
167 phy->current_channel = -1; /* not initialised */
168 phy->current_page = 0; /* for compatibility */
169
121 return phy; 170 return phy;
122} 171}
123EXPORT_SYMBOL(wpan_phy_alloc); 172EXPORT_SYMBOL(wpan_phy_alloc);
124 173
125int wpan_phy_register(struct device *parent, struct wpan_phy *phy) 174int wpan_phy_register(struct wpan_phy *phy)
126{ 175{
127 phy->dev.parent = parent;
128
129 return device_add(&phy->dev); 176 return device_add(&phy->dev);
130} 177}
131EXPORT_SYMBOL(wpan_phy_register); 178EXPORT_SYMBOL(wpan_phy_register);
@@ -144,16 +191,31 @@ EXPORT_SYMBOL(wpan_phy_free);
144 191
145static int __init wpan_phy_class_init(void) 192static int __init wpan_phy_class_init(void)
146{ 193{
147 return class_register(&wpan_phy_class); 194 int rc;
195 rc = class_register(&wpan_phy_class);
196 if (rc)
197 goto err;
198
199 rc = ieee802154_nl_init();
200 if (rc)
201 goto err_nl;
202
203 return 0;
204err_nl:
205 class_unregister(&wpan_phy_class);
206err:
207 return rc;
148} 208}
149subsys_initcall(wpan_phy_class_init); 209subsys_initcall(wpan_phy_class_init);
150 210
151static void __exit wpan_phy_class_exit(void) 211static void __exit wpan_phy_class_exit(void)
152{ 212{
213 ieee802154_nl_exit();
153 class_unregister(&wpan_phy_class); 214 class_unregister(&wpan_phy_class);
154} 215}
155module_exit(wpan_phy_class_exit); 216module_exit(wpan_phy_class_exit);
156 217
157MODULE_DESCRIPTION("IEEE 802.15.4 device class");
158MODULE_LICENSE("GPL v2"); 218MODULE_LICENSE("GPL v2");
219MODULE_DESCRIPTION("IEEE 802.15.4 configuration interface");
220MODULE_AUTHOR("Dmitry Eremin-Solenikov");
159 221