aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorSergey Lapin <slapin@ossfans.org>2009-06-08 08:18:48 -0400
committerDavid S. Miller <davem@davemloft.net>2009-06-09 08:25:32 -0400
commit9ec7671603573ede31207eb5b0b3e1aa211b2854 (patch)
tree9cfb301ce6d1e1296a3a253feaa1a40d4c2b3bd9 /net
parentfcb94e422479da52ed90bab230c59617a0462416 (diff)
net: add IEEE 802.15.4 socket family implementation
Add support for communication over IEEE 802.15.4 networks. This implementation is neither certified nor complete, but aims to that goal. This commit contains only the socket interface for communication over IEEE 802.15.4 networks. One can either send RAW datagrams or use SOCK_DGRAM to encapsulate data inside normal IEEE 802.15.4 packets. Configuration interface, drivers and software MAC 802.15.4 implementation will follow. Initial implementation was done by Maxim Gorbachyov, Maxim Osipov and Pavel Smolensky as a research project at Siemens AG. Later the stack was heavily reworked to better suit the linux networking model, and is now maitained as an open project partially sponsored by Siemens. Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> Signed-off-by: Sergey Lapin <slapin@ossfans.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/Kconfig1
-rw-r--r--net/Makefile1
-rw-r--r--net/ieee802154/Kconfig12
-rw-r--r--net/ieee802154/Makefile4
-rw-r--r--net/ieee802154/af802154.h36
-rw-r--r--net/ieee802154/af_ieee802154.c372
-rw-r--r--net/ieee802154/dgram.c394
-rw-r--r--net/ieee802154/raw.c254
8 files changed, 1074 insertions, 0 deletions
diff --git a/net/Kconfig b/net/Kconfig
index c19f549c8e74..7051b9710675 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -179,6 +179,7 @@ source "net/lapb/Kconfig"
179source "net/econet/Kconfig" 179source "net/econet/Kconfig"
180source "net/wanrouter/Kconfig" 180source "net/wanrouter/Kconfig"
181source "net/phonet/Kconfig" 181source "net/phonet/Kconfig"
182source "net/ieee802154/Kconfig"
182source "net/sched/Kconfig" 183source "net/sched/Kconfig"
183source "net/dcb/Kconfig" 184source "net/dcb/Kconfig"
184 185
diff --git a/net/Makefile b/net/Makefile
index 9e00a55a901b..ba324aefda73 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -60,6 +60,7 @@ obj-$(CONFIG_NET_9P) += 9p/
60ifneq ($(CONFIG_DCB),) 60ifneq ($(CONFIG_DCB),)
61obj-y += dcb/ 61obj-y += dcb/
62endif 62endif
63obj-y += ieee802154/
63 64
64ifeq ($(CONFIG_NET),y) 65ifeq ($(CONFIG_NET),y)
65obj-$(CONFIG_SYSCTL) += sysctl_net.o 66obj-$(CONFIG_SYSCTL) += sysctl_net.o
diff --git a/net/ieee802154/Kconfig b/net/ieee802154/Kconfig
new file mode 100644
index 000000000000..1c1de97d264a
--- /dev/null
+++ b/net/ieee802154/Kconfig
@@ -0,0 +1,12 @@
1config IEEE802154
2 tristate "IEEE Std 802.15.4 Low-Rate Wireless Personal Area Networks support (EXPERIMENTAL)"
3 depends on EXPERIMENTAL
4 ---help---
5 IEEE Std 802.15.4 defines a low data rate, low power and low
6 complexity short range wireless personal area networks. It was
7 designed to organise networks of sensors, switches, etc automation
8 devices. Maximum allowed data rate is 250 kb/s and typical personal
9 operating space around 10m.
10
11 Say Y here to compile LR-WPAN support into the kernel or say M to
12 compile it as modules.
diff --git a/net/ieee802154/Makefile b/net/ieee802154/Makefile
new file mode 100644
index 000000000000..7451c7cc8c8e
--- /dev/null
+++ b/net/ieee802154/Makefile
@@ -0,0 +1,4 @@
1obj-$(CONFIG_IEEE802154) += af_802154.o
2af_802154-y := af_ieee802154.o raw.o dgram.o
3
4ccflags-y += -Wall -DDEBUG
diff --git a/net/ieee802154/af802154.h b/net/ieee802154/af802154.h
new file mode 100644
index 000000000000..b1ec52537522
--- /dev/null
+++ b/net/ieee802154/af802154.h
@@ -0,0 +1,36 @@
1/*
2 * Internal interfaces for ieee 802.15.4 address family.
3 *
4 * Copyright 2007, 2008, 2009 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 */
23
24#ifndef AF802154_H
25#define AF802154_H
26
27struct sk_buff;
28struct net_devce;
29extern struct proto ieee802154_raw_prot;
30extern struct proto ieee802154_dgram_prot;
31void ieee802154_raw_deliver(struct net_device *dev, struct sk_buff *skb);
32int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb);
33struct net_device *ieee802154_get_dev(struct net *net,
34 struct ieee802154_addr *addr);
35
36#endif
diff --git a/net/ieee802154/af_ieee802154.c b/net/ieee802154/af_ieee802154.c
new file mode 100644
index 000000000000..882a927cefae
--- /dev/null
+++ b/net/ieee802154/af_ieee802154.c
@@ -0,0 +1,372 @@
1/*
2 * IEEE802154.4 socket interface
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 * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
22 */
23
24#include <linux/net.h>
25#include <linux/capability.h>
26#include <linux/module.h>
27#include <linux/if_arp.h>
28#include <linux/if.h>
29#include <linux/termios.h> /* For TIOCOUTQ/INQ */
30#include <linux/list.h>
31#include <net/datalink.h>
32#include <net/psnap.h>
33#include <net/sock.h>
34#include <net/tcp_states.h>
35#include <net/route.h>
36
37#include <net/ieee802154/af_ieee802154.h>
38#include <net/ieee802154/netdevice.h>
39
40#include "af802154.h"
41
42#define DBG_DUMP(data, len) { \
43 int i; \
44 pr_debug("function: %s: data: len %d:\n", __func__, len); \
45 for (i = 0; i < len; i++) {\
46 pr_debug("%02x: %02x\n", i, (data)[i]); \
47 } \
48}
49
50/*
51 * Utility function for families
52 */
53struct net_device *ieee802154_get_dev(struct net *net,
54 struct ieee802154_addr *addr)
55{
56 struct net_device *dev = NULL;
57 struct net_device *tmp;
58 u16 pan_id, short_addr;
59
60 switch (addr->addr_type) {
61 case IEEE802154_ADDR_LONG:
62 rtnl_lock();
63 dev = dev_getbyhwaddr(net, ARPHRD_IEEE802154, addr->hwaddr);
64 if (dev)
65 dev_hold(dev);
66 rtnl_unlock();
67 break;
68 case IEEE802154_ADDR_SHORT:
69 if (addr->pan_id == 0xffff ||
70 addr->short_addr == IEEE802154_ADDR_UNDEF ||
71 addr->short_addr == 0xffff)
72 break;
73
74 rtnl_lock();
75
76 for_each_netdev(net, tmp) {
77 if (tmp->type != ARPHRD_IEEE802154)
78 continue;
79
80 pan_id = ieee802154_mlme_ops(tmp)->get_pan_id(tmp);
81 short_addr =
82 ieee802154_mlme_ops(tmp)->get_short_addr(tmp);
83
84 if (pan_id == addr->pan_id &&
85 short_addr == addr->short_addr) {
86 dev = tmp;
87 dev_hold(dev);
88 break;
89 }
90 }
91
92 rtnl_unlock();
93 break;
94 default:
95 pr_warning("Unsupported ieee802154 address type: %d\n",
96 addr->addr_type);
97 break;
98 }
99
100 return dev;
101}
102
103static int ieee802154_sock_release(struct socket *sock)
104{
105 struct sock *sk = sock->sk;
106
107 if (sk) {
108 sock->sk = NULL;
109 sk->sk_prot->close(sk, 0);
110 }
111 return 0;
112}
113static int ieee802154_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
114 struct msghdr *msg, size_t len)
115{
116 struct sock *sk = sock->sk;
117
118 return sk->sk_prot->sendmsg(iocb, sk, msg, len);
119}
120
121static int ieee802154_sock_bind(struct socket *sock, struct sockaddr *uaddr,
122 int addr_len)
123{
124 struct sock *sk = sock->sk;
125
126 if (sk->sk_prot->bind)
127 return sk->sk_prot->bind(sk, uaddr, addr_len);
128
129 return sock_no_bind(sock, uaddr, addr_len);
130}
131
132static int ieee802154_sock_connect(struct socket *sock, struct sockaddr *uaddr,
133 int addr_len, int flags)
134{
135 struct sock *sk = sock->sk;
136
137 if (uaddr->sa_family == AF_UNSPEC)
138 return sk->sk_prot->disconnect(sk, flags);
139
140 return sk->sk_prot->connect(sk, uaddr, addr_len);
141}
142
143static int ieee802154_dev_ioctl(struct sock *sk, struct ifreq __user *arg,
144 unsigned int cmd)
145{
146 struct ifreq ifr;
147 int ret = -EINVAL;
148 struct net_device *dev;
149
150 if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
151 return -EFAULT;
152
153 ifr.ifr_name[IFNAMSIZ-1] = 0;
154
155 dev_load(sock_net(sk), ifr.ifr_name);
156 dev = dev_get_by_name(sock_net(sk), ifr.ifr_name);
157 if (dev->type == ARPHRD_IEEE802154 ||
158 dev->type == ARPHRD_IEEE802154_PHY)
159 ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, cmd);
160
161 if (!ret && copy_to_user(arg, &ifr, sizeof(struct ifreq)))
162 ret = -EFAULT;
163 dev_put(dev);
164
165 return ret;
166}
167
168static int ieee802154_sock_ioctl(struct socket *sock, unsigned int cmd,
169 unsigned long arg)
170{
171 struct sock *sk = sock->sk;
172
173 switch (cmd) {
174 case SIOCGSTAMP:
175 return sock_get_timestamp(sk, (struct timeval __user *)arg);
176 case SIOCGSTAMPNS:
177 return sock_get_timestampns(sk, (struct timespec __user *)arg);
178 case SIOCGIFADDR:
179 case SIOCSIFADDR:
180 return ieee802154_dev_ioctl(sk, (struct ifreq __user *)arg,
181 cmd);
182 default:
183 if (!sk->sk_prot->ioctl)
184 return -ENOIOCTLCMD;
185 return sk->sk_prot->ioctl(sk, cmd, arg);
186 }
187}
188
189static const struct proto_ops ieee802154_raw_ops = {
190 .family = PF_IEEE802154,
191 .owner = THIS_MODULE,
192 .release = ieee802154_sock_release,
193 .bind = ieee802154_sock_bind,
194 .connect = ieee802154_sock_connect,
195 .socketpair = sock_no_socketpair,
196 .accept = sock_no_accept,
197 .getname = sock_no_getname,
198 .poll = datagram_poll,
199 .ioctl = ieee802154_sock_ioctl,
200 .listen = sock_no_listen,
201 .shutdown = sock_no_shutdown,
202 .setsockopt = sock_common_setsockopt,
203 .getsockopt = sock_common_getsockopt,
204 .sendmsg = ieee802154_sock_sendmsg,
205 .recvmsg = sock_common_recvmsg,
206 .mmap = sock_no_mmap,
207 .sendpage = sock_no_sendpage,
208#ifdef CONFIG_COMPAT
209 .compat_setsockopt = compat_sock_common_setsockopt,
210 .compat_getsockopt = compat_sock_common_getsockopt,
211#endif
212};
213
214static const struct proto_ops ieee802154_dgram_ops = {
215 .family = PF_IEEE802154,
216 .owner = THIS_MODULE,
217 .release = ieee802154_sock_release,
218 .bind = ieee802154_sock_bind,
219 .connect = ieee802154_sock_connect,
220 .socketpair = sock_no_socketpair,
221 .accept = sock_no_accept,
222 .getname = sock_no_getname,
223 .poll = datagram_poll,
224 .ioctl = ieee802154_sock_ioctl,
225 .listen = sock_no_listen,
226 .shutdown = sock_no_shutdown,
227 .setsockopt = sock_common_setsockopt,
228 .getsockopt = sock_common_getsockopt,
229 .sendmsg = ieee802154_sock_sendmsg,
230 .recvmsg = sock_common_recvmsg,
231 .mmap = sock_no_mmap,
232 .sendpage = sock_no_sendpage,
233#ifdef CONFIG_COMPAT
234 .compat_setsockopt = compat_sock_common_setsockopt,
235 .compat_getsockopt = compat_sock_common_getsockopt,
236#endif
237};
238
239
240/*
241 * Create a socket. Initialise the socket, blank the addresses
242 * set the state.
243 */
244static int ieee802154_create(struct net *net, struct socket *sock,
245 int protocol)
246{
247 struct sock *sk;
248 int rc;
249 struct proto *proto;
250 const struct proto_ops *ops;
251
252 if (net != &init_net)
253 return -EAFNOSUPPORT;
254
255 switch (sock->type) {
256 case SOCK_RAW:
257 proto = &ieee802154_raw_prot;
258 ops = &ieee802154_raw_ops;
259 break;
260 case SOCK_DGRAM:
261 proto = &ieee802154_dgram_prot;
262 ops = &ieee802154_dgram_ops;
263 break;
264 default:
265 rc = -ESOCKTNOSUPPORT;
266 goto out;
267 }
268
269 rc = -ENOMEM;
270 sk = sk_alloc(net, PF_IEEE802154, GFP_KERNEL, proto);
271 if (!sk)
272 goto out;
273 rc = 0;
274
275 sock->ops = ops;
276
277 sock_init_data(sock, sk);
278 /* FIXME: sk->sk_destruct */
279 sk->sk_family = PF_IEEE802154;
280
281 /* Checksums on by default */
282 sock_set_flag(sk, SOCK_ZAPPED);
283
284 if (sk->sk_prot->hash)
285 sk->sk_prot->hash(sk);
286
287 if (sk->sk_prot->init) {
288 rc = sk->sk_prot->init(sk);
289 if (rc)
290 sk_common_release(sk);
291 }
292out:
293 return rc;
294}
295
296static struct net_proto_family ieee802154_family_ops = {
297 .family = PF_IEEE802154,
298 .create = ieee802154_create,
299 .owner = THIS_MODULE,
300};
301
302static int ieee802154_rcv(struct sk_buff *skb, struct net_device *dev,
303 struct packet_type *pt, struct net_device *orig_dev)
304{
305 DBG_DUMP(skb->data, skb->len);
306 if (!netif_running(dev))
307 return -ENODEV;
308 pr_debug("got frame, type %d, dev %p\n", dev->type, dev);
309
310 if (!net_eq(dev_net(dev), &init_net))
311 goto drop;
312
313 ieee802154_raw_deliver(dev, skb);
314
315 if (dev->type != ARPHRD_IEEE802154)
316 goto drop;
317
318 if (skb->pkt_type != PACKET_OTHERHOST)
319 return ieee802154_dgram_deliver(dev, skb);
320
321drop:
322 kfree_skb(skb);
323 return NET_RX_DROP;
324}
325
326
327static struct packet_type ieee802154_packet_type = {
328 .type = __constant_htons(ETH_P_IEEE802154),
329 .func = ieee802154_rcv,
330};
331
332static int __init af_ieee802154_init(void)
333{
334 int rc = -EINVAL;
335
336 rc = proto_register(&ieee802154_raw_prot, 1);
337 if (rc)
338 goto out;
339
340 rc = proto_register(&ieee802154_dgram_prot, 1);
341 if (rc)
342 goto err_dgram;
343
344 /* Tell SOCKET that we are alive */
345 rc = sock_register(&ieee802154_family_ops);
346 if (rc)
347 goto err_sock;
348 dev_add_pack(&ieee802154_packet_type);
349
350 rc = 0;
351 goto out;
352
353err_sock:
354 proto_unregister(&ieee802154_dgram_prot);
355err_dgram:
356 proto_unregister(&ieee802154_raw_prot);
357out:
358 return rc;
359}
360static void __exit af_ieee802154_remove(void)
361{
362 dev_remove_pack(&ieee802154_packet_type);
363 sock_unregister(PF_IEEE802154);
364 proto_unregister(&ieee802154_dgram_prot);
365 proto_unregister(&ieee802154_raw_prot);
366}
367
368module_init(af_ieee802154_init);
369module_exit(af_ieee802154_remove);
370
371MODULE_LICENSE("GPL");
372MODULE_ALIAS_NETPROTO(PF_IEEE802154);
diff --git a/net/ieee802154/dgram.c b/net/ieee802154/dgram.c
new file mode 100644
index 000000000000..1f5ea11c2fdf
--- /dev/null
+++ b/net/ieee802154/dgram.c
@@ -0,0 +1,394 @@
1/*
2 * ZigBee socket interface
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 */
23
24#include <linux/net.h>
25#include <linux/module.h>
26#include <linux/if_arp.h>
27#include <linux/list.h>
28#include <net/sock.h>
29#include <net/ieee802154/af_ieee802154.h>
30#include <net/ieee802154/mac_def.h>
31#include <net/ieee802154/netdevice.h>
32
33#include <asm/ioctls.h>
34
35#include "af802154.h"
36
37static HLIST_HEAD(dgram_head);
38static DEFINE_RWLOCK(dgram_lock);
39
40struct dgram_sock {
41 struct sock sk;
42
43 int bound;
44 struct ieee802154_addr src_addr;
45 struct ieee802154_addr dst_addr;
46};
47
48static inline struct dgram_sock *dgram_sk(const struct sock *sk)
49{
50 return container_of(sk, struct dgram_sock, sk);
51}
52
53
54static void dgram_hash(struct sock *sk)
55{
56 write_lock_bh(&dgram_lock);
57 sk_add_node(sk, &dgram_head);
58 sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
59 write_unlock_bh(&dgram_lock);
60}
61
62static void dgram_unhash(struct sock *sk)
63{
64 write_lock_bh(&dgram_lock);
65 if (sk_del_node_init(sk))
66 sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
67 write_unlock_bh(&dgram_lock);
68}
69
70static int dgram_init(struct sock *sk)
71{
72 struct dgram_sock *ro = dgram_sk(sk);
73
74 ro->dst_addr.addr_type = IEEE802154_ADDR_LONG;
75 ro->dst_addr.pan_id = 0xffff;
76 memset(&ro->dst_addr.hwaddr, 0xff, sizeof(ro->dst_addr.hwaddr));
77 return 0;
78}
79
80static void dgram_close(struct sock *sk, long timeout)
81{
82 sk_common_release(sk);
83}
84
85static int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len)
86{
87 struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr;
88 struct dgram_sock *ro = dgram_sk(sk);
89 int err = 0;
90 struct net_device *dev;
91
92 ro->bound = 0;
93
94 if (len < sizeof(*addr))
95 return -EINVAL;
96
97 if (addr->family != AF_IEEE802154)
98 return -EINVAL;
99
100 lock_sock(sk);
101
102 dev = ieee802154_get_dev(sock_net(sk), &addr->addr);
103 if (!dev) {
104 err = -ENODEV;
105 goto out;
106 }
107
108 if (dev->type != ARPHRD_IEEE802154) {
109 err = -ENODEV;
110 goto out_put;
111 }
112
113 memcpy(&ro->src_addr, &addr->addr, sizeof(struct ieee802154_addr));
114
115 ro->bound = 1;
116out_put:
117 dev_put(dev);
118out:
119 release_sock(sk);
120
121 return err;
122}
123
124static int dgram_ioctl(struct sock *sk, int cmd, unsigned long arg)
125{
126 switch (cmd) {
127 case SIOCOUTQ:
128 {
129 int amount = atomic_read(&sk->sk_wmem_alloc);
130 return put_user(amount, (int __user *)arg);
131 }
132
133 case SIOCINQ:
134 {
135 struct sk_buff *skb;
136 unsigned long amount;
137
138 amount = 0;
139 spin_lock_bh(&sk->sk_receive_queue.lock);
140 skb = skb_peek(&sk->sk_receive_queue);
141 if (skb != NULL) {
142 /*
143 * We will only return the amount
144 * of this packet since that is all
145 * that will be read.
146 */
147 /* FIXME: parse the header for more correct value */
148 amount = skb->len - (3+8+8);
149 }
150 spin_unlock_bh(&sk->sk_receive_queue.lock);
151 return put_user(amount, (int __user *)arg);
152 }
153
154 }
155 return -ENOIOCTLCMD;
156}
157
158/* FIXME: autobind */
159static int dgram_connect(struct sock *sk, struct sockaddr *uaddr,
160 int len)
161{
162 struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr;
163 struct dgram_sock *ro = dgram_sk(sk);
164 int err = 0;
165
166 if (len < sizeof(*addr))
167 return -EINVAL;
168
169 if (addr->family != AF_IEEE802154)
170 return -EINVAL;
171
172 lock_sock(sk);
173
174 if (!ro->bound) {
175 err = -ENETUNREACH;
176 goto out;
177 }
178
179 memcpy(&ro->dst_addr, &addr->addr, sizeof(struct ieee802154_addr));
180
181out:
182 release_sock(sk);
183 return err;
184}
185
186static int dgram_disconnect(struct sock *sk, int flags)
187{
188 struct dgram_sock *ro = dgram_sk(sk);
189
190 lock_sock(sk);
191
192 ro->dst_addr.addr_type = IEEE802154_ADDR_LONG;
193 memset(&ro->dst_addr.hwaddr, 0xff, sizeof(ro->dst_addr.hwaddr));
194
195 release_sock(sk);
196
197 return 0;
198}
199
200static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk,
201 struct msghdr *msg, size_t size)
202{
203 struct net_device *dev;
204 unsigned mtu;
205 struct sk_buff *skb;
206 struct dgram_sock *ro = dgram_sk(sk);
207 int err;
208
209 if (msg->msg_flags & MSG_OOB) {
210 pr_debug("msg->msg_flags = 0x%x\n", msg->msg_flags);
211 return -EOPNOTSUPP;
212 }
213
214 if (!ro->bound)
215 dev = dev_getfirstbyhwtype(sock_net(sk), ARPHRD_IEEE802154);
216 else
217 dev = ieee802154_get_dev(sock_net(sk), &ro->src_addr);
218
219 if (!dev) {
220 pr_debug("no dev\n");
221 err = -ENXIO;
222 goto out;
223 }
224 mtu = dev->mtu;
225 pr_debug("name = %s, mtu = %u\n", dev->name, mtu);
226
227 skb = sock_alloc_send_skb(sk, LL_ALLOCATED_SPACE(dev) + size,
228 msg->msg_flags & MSG_DONTWAIT,
229 &err);
230 if (!skb)
231 goto out_dev;
232
233 skb_reserve(skb, LL_RESERVED_SPACE(dev));
234
235 skb_reset_network_header(skb);
236
237 mac_cb(skb)->flags = IEEE802154_FC_TYPE_DATA | MAC_CB_FLAG_ACKREQ;
238 mac_cb(skb)->seq = ieee802154_mlme_ops(dev)->get_dsn(dev);
239 err = dev_hard_header(skb, dev, ETH_P_IEEE802154, &ro->dst_addr,
240 ro->bound ? &ro->src_addr : NULL, size);
241 if (err < 0)
242 goto out_skb;
243
244 skb_reset_mac_header(skb);
245
246 err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
247 if (err < 0)
248 goto out_skb;
249
250 if (size > mtu) {
251 pr_debug("size = %u, mtu = %u\n", size, mtu);
252 err = -EINVAL;
253 goto out_skb;
254 }
255
256 skb->dev = dev;
257 skb->sk = sk;
258 skb->protocol = htons(ETH_P_IEEE802154);
259
260 dev_put(dev);
261
262 err = dev_queue_xmit(skb);
263 if (err > 0)
264 err = net_xmit_errno(err);
265
266 return err ?: size;
267
268out_skb:
269 kfree_skb(skb);
270out_dev:
271 dev_put(dev);
272out:
273 return err;
274}
275
276static int dgram_recvmsg(struct kiocb *iocb, struct sock *sk,
277 struct msghdr *msg, size_t len, int noblock, int flags,
278 int *addr_len)
279{
280 size_t copied = 0;
281 int err = -EOPNOTSUPP;
282 struct sk_buff *skb;
283
284 skb = skb_recv_datagram(sk, flags, noblock, &err);
285 if (!skb)
286 goto out;
287
288 copied = skb->len;
289 if (len < copied) {
290 msg->msg_flags |= MSG_TRUNC;
291 copied = len;
292 }
293
294 /* FIXME: skip headers if necessary ?! */
295 err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
296 if (err)
297 goto done;
298
299 sock_recv_timestamp(msg, sk, skb);
300
301 if (flags & MSG_TRUNC)
302 copied = skb->len;
303done:
304 skb_free_datagram(sk, skb);
305out:
306 if (err)
307 return err;
308 return copied;
309}
310
311static int dgram_rcv_skb(struct sock *sk, struct sk_buff *skb)
312{
313 if (sock_queue_rcv_skb(sk, skb) < 0) {
314 atomic_inc(&sk->sk_drops);
315 kfree_skb(skb);
316 return NET_RX_DROP;
317 }
318
319 return NET_RX_SUCCESS;
320}
321
322static inline int ieee802154_match_sock(u8 *hw_addr, u16 pan_id,
323 u16 short_addr, struct dgram_sock *ro)
324{
325 if (!ro->bound)
326 return 1;
327
328 if (ro->src_addr.addr_type == IEEE802154_ADDR_LONG &&
329 !memcmp(ro->src_addr.hwaddr, hw_addr, IEEE802154_ADDR_LEN))
330 return 1;
331
332 if (ro->src_addr.addr_type == IEEE802154_ADDR_SHORT &&
333 pan_id == ro->src_addr.pan_id &&
334 short_addr == ro->src_addr.short_addr)
335 return 1;
336
337 return 0;
338}
339
340int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb)
341{
342 struct sock *sk, *prev = NULL;
343 struct hlist_node *node;
344 int ret = NET_RX_SUCCESS;
345 u16 pan_id, short_addr;
346
347 /* Data frame processing */
348 BUG_ON(dev->type != ARPHRD_IEEE802154);
349
350 pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
351 short_addr = ieee802154_mlme_ops(dev)->get_short_addr(dev);
352
353 read_lock(&dgram_lock);
354 sk_for_each(sk, node, &dgram_head) {
355 if (ieee802154_match_sock(dev->dev_addr, pan_id, short_addr,
356 dgram_sk(sk))) {
357 if (prev) {
358 struct sk_buff *clone;
359 clone = skb_clone(skb, GFP_ATOMIC);
360 if (clone)
361 dgram_rcv_skb(prev, clone);
362 }
363
364 prev = sk;
365 }
366 }
367
368 if (prev)
369 dgram_rcv_skb(prev, skb);
370 else {
371 kfree_skb(skb);
372 ret = NET_RX_DROP;
373 }
374 read_unlock(&dgram_lock);
375
376 return ret;
377}
378
379struct proto ieee802154_dgram_prot = {
380 .name = "IEEE-802.15.4-MAC",
381 .owner = THIS_MODULE,
382 .obj_size = sizeof(struct dgram_sock),
383 .init = dgram_init,
384 .close = dgram_close,
385 .bind = dgram_bind,
386 .sendmsg = dgram_sendmsg,
387 .recvmsg = dgram_recvmsg,
388 .hash = dgram_hash,
389 .unhash = dgram_unhash,
390 .connect = dgram_connect,
391 .disconnect = dgram_disconnect,
392 .ioctl = dgram_ioctl,
393};
394
diff --git a/net/ieee802154/raw.c b/net/ieee802154/raw.c
new file mode 100644
index 000000000000..8b892e060491
--- /dev/null
+++ b/net/ieee802154/raw.c
@@ -0,0 +1,254 @@
1/*
2 * Raw IEEE 802.15.4 sockets
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 */
23
24#include <linux/net.h>
25#include <linux/module.h>
26#include <linux/if_arp.h>
27#include <linux/list.h>
28#include <net/sock.h>
29#include <net/ieee802154/af_ieee802154.h>
30
31#include "af802154.h"
32
33static HLIST_HEAD(raw_head);
34static DEFINE_RWLOCK(raw_lock);
35
36static void raw_hash(struct sock *sk)
37{
38 write_lock_bh(&raw_lock);
39 sk_add_node(sk, &raw_head);
40 sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
41 write_unlock_bh(&raw_lock);
42}
43
44static void raw_unhash(struct sock *sk)
45{
46 write_lock_bh(&raw_lock);
47 if (sk_del_node_init(sk))
48 sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
49 write_unlock_bh(&raw_lock);
50}
51
52static void raw_close(struct sock *sk, long timeout)
53{
54 sk_common_release(sk);
55}
56
57static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int len)
58{
59 struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr;
60 int err = 0;
61 struct net_device *dev = NULL;
62
63 if (len < sizeof(*addr))
64 return -EINVAL;
65
66 if (addr->family != AF_IEEE802154)
67 return -EINVAL;
68
69 lock_sock(sk);
70
71 dev = ieee802154_get_dev(sock_net(sk), &addr->addr);
72 if (!dev) {
73 err = -ENODEV;
74 goto out;
75 }
76
77 if (dev->type != ARPHRD_IEEE802154_PHY &&
78 dev->type != ARPHRD_IEEE802154) {
79 err = -ENODEV;
80 goto out_put;
81 }
82
83 sk->sk_bound_dev_if = dev->ifindex;
84 sk_dst_reset(sk);
85
86out_put:
87 dev_put(dev);
88out:
89 release_sock(sk);
90
91 return err;
92}
93
94static int raw_connect(struct sock *sk, struct sockaddr *uaddr,
95 int addr_len)
96{
97 return -ENOTSUPP;
98}
99
100static int raw_disconnect(struct sock *sk, int flags)
101{
102 return 0;
103}
104
105static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
106 size_t size)
107{
108 struct net_device *dev;
109 unsigned mtu;
110 struct sk_buff *skb;
111 int err;
112
113 if (msg->msg_flags & MSG_OOB) {
114 pr_debug("msg->msg_flags = 0x%x\n", msg->msg_flags);
115 return -EOPNOTSUPP;
116 }
117
118 lock_sock(sk);
119 if (!sk->sk_bound_dev_if)
120 dev = dev_getfirstbyhwtype(sock_net(sk), ARPHRD_IEEE802154);
121 else
122 dev = dev_get_by_index(sock_net(sk), sk->sk_bound_dev_if);
123 release_sock(sk);
124
125 if (!dev) {
126 pr_debug("no dev\n");
127 err = -ENXIO;
128 goto out;
129 }
130
131 mtu = dev->mtu;
132 pr_debug("name = %s, mtu = %u\n", dev->name, mtu);
133
134 if (size > mtu) {
135 pr_debug("size = %u, mtu = %u\n", size, mtu);
136 err = -EINVAL;
137 goto out_dev;
138 }
139
140 skb = sock_alloc_send_skb(sk, LL_ALLOCATED_SPACE(dev) + size,
141 msg->msg_flags & MSG_DONTWAIT, &err);
142 if (!skb)
143 goto out_dev;
144
145 skb_reserve(skb, LL_RESERVED_SPACE(dev));
146
147 skb_reset_mac_header(skb);
148 skb_reset_network_header(skb);
149
150 err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
151 if (err < 0)
152 goto out_skb;
153
154 skb->dev = dev;
155 skb->sk = sk;
156 skb->protocol = htons(ETH_P_IEEE802154);
157
158 dev_put(dev);
159
160 err = dev_queue_xmit(skb);
161 if (err > 0)
162 err = net_xmit_errno(err);
163
164 return err ?: size;
165
166out_skb:
167 kfree_skb(skb);
168out_dev:
169 dev_put(dev);
170out:
171 return err;
172}
173
174static int raw_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
175 size_t len, int noblock, int flags, int *addr_len)
176{
177 size_t copied = 0;
178 int err = -EOPNOTSUPP;
179 struct sk_buff *skb;
180
181 skb = skb_recv_datagram(sk, flags, noblock, &err);
182 if (!skb)
183 goto out;
184
185 copied = skb->len;
186 if (len < copied) {
187 msg->msg_flags |= MSG_TRUNC;
188 copied = len;
189 }
190
191 err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
192 if (err)
193 goto done;
194
195 sock_recv_timestamp(msg, sk, skb);
196
197 if (flags & MSG_TRUNC)
198 copied = skb->len;
199done:
200 skb_free_datagram(sk, skb);
201out:
202 if (err)
203 return err;
204 return copied;
205}
206
207static int raw_rcv_skb(struct sock *sk, struct sk_buff *skb)
208{
209 if (sock_queue_rcv_skb(sk, skb) < 0) {
210 atomic_inc(&sk->sk_drops);
211 kfree_skb(skb);
212 return NET_RX_DROP;
213 }
214
215 return NET_RX_SUCCESS;
216}
217
218
219void ieee802154_raw_deliver(struct net_device *dev, struct sk_buff *skb)
220{
221 struct sock *sk;
222 struct hlist_node *node;
223
224 read_lock(&raw_lock);
225 sk_for_each(sk, node, &raw_head) {
226 bh_lock_sock(sk);
227 if (!sk->sk_bound_dev_if ||
228 sk->sk_bound_dev_if == dev->ifindex) {
229
230 struct sk_buff *clone;
231
232 clone = skb_clone(skb, GFP_ATOMIC);
233 if (clone)
234 raw_rcv_skb(sk, clone);
235 }
236 bh_unlock_sock(sk);
237 }
238 read_unlock(&raw_lock);
239}
240
241struct proto ieee802154_raw_prot = {
242 .name = "IEEE-802.15.4-RAW",
243 .owner = THIS_MODULE,
244 .obj_size = sizeof(struct sock),
245 .close = raw_close,
246 .bind = raw_bind,
247 .sendmsg = raw_sendmsg,
248 .recvmsg = raw_recvmsg,
249 .hash = raw_hash,
250 .unhash = raw_unhash,
251 .connect = raw_connect,
252 .disconnect = raw_disconnect,
253};
254