Root/
1 | /* |
2 | * ZigBee socket interface |
3 | * |
4 | * Copyright 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 | * Maxim Yu. Osipov <Maksim.Osipov@siemens.com> |
23 | */ |
24 | |
25 | #include <linux/net.h> |
26 | #include <linux/module.h> |
27 | #include <linux/if_arp.h> |
28 | #include <linux/list.h> |
29 | #include <net/sock.h> |
30 | //#include <net/ieee80215/netdev.h> |
31 | //#include <net/ieee80215/af_ieee80215.h> |
32 | //#include <net/ieee80215/mac_def.h> |
33 | #include <net/zigbee/nwk.h> |
34 | #include <asm/ioctls.h> |
35 | |
36 | static HLIST_HEAD(dgram_head); |
37 | static DEFINE_RWLOCK(dgram_lock); |
38 | |
39 | struct dgram_sock { |
40 | struct sock sk; |
41 | |
42 | int bound; |
43 | struct ieee80215_addr src_addr; |
44 | struct ieee80215_addr dst_addr; |
45 | }; |
46 | |
47 | static void dgram_hash(struct sock *sk) |
48 | { |
49 | write_lock_bh(&dgram_lock); |
50 | sk_add_node(sk, &dgram_head); |
51 | sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); |
52 | write_unlock_bh(&dgram_lock); |
53 | } |
54 | |
55 | static void dgram_unhash(struct sock *sk) |
56 | { |
57 | write_lock_bh(&dgram_lock); |
58 | if (sk_del_node_init(sk)) |
59 | sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); |
60 | write_unlock_bh(&dgram_lock); |
61 | } |
62 | |
63 | static int dgram_init(struct sock *sk) |
64 | { |
65 | struct dgram_sock *ro = container_of(sk, struct dgram_sock, sk); |
66 | |
67 | ro->dst_addr.addr_type = IEEE80215_ADDR_SHORT; |
68 | // ro->dst_addr.pan_id = 0xffff; |
69 | ro->dst_addr.short_addr = 0xffff; |
70 | return 0; |
71 | } |
72 | |
73 | static void dgram_close(struct sock *sk, long timeout) |
74 | { |
75 | sk_common_release(sk); |
76 | } |
77 | |
78 | static int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len) |
79 | { |
80 | struct sockaddr_ieee80215 *addr = (struct sockaddr_ieee80215 *)uaddr; |
81 | struct dgram_sock *ro = container_of(sk, struct dgram_sock, sk); |
82 | int err = 0; |
83 | |
84 | if (ro->bound) |
85 | return -EINVAL; |
86 | |
87 | if (len < sizeof(*addr)) |
88 | return -EINVAL; |
89 | |
90 | if ((addr->family != AF_ZIGBEE) || |
91 | (addr->addr.addr_type != IEEE80215_ADDR_SHORT)) |
92 | return -EINVAL; |
93 | |
94 | lock_sock(sk); |
95 | /* |
96 | * FIXME: should check here that address is not already in use |
97 | * Problem that this address is not independent - this is the |
98 | * address of the lower layer |
99 | */ |
100 | #if 0 |
101 | dev = ieee80215_get_dev(sock_net(sk), &addr->addr); |
102 | if (!dev) { |
103 | err = -ENODEV; |
104 | goto out; |
105 | } |
106 | |
107 | if (dev->type != ARPHRD_IEEE80215) { |
108 | err = -ENODEV; |
109 | goto out_put; |
110 | } |
111 | #endif |
112 | memcpy(&ro->src_addr, &addr->addr, sizeof(struct ieee80215_addr)); |
113 | |
114 | ro->bound = 1; |
115 | #if 0 |
116 | out_put: |
117 | dev_put(dev); |
118 | out: |
119 | #endif |
120 | release_sock(sk); |
121 | |
122 | return err; |
123 | } |
124 | |
125 | static int dgram_ioctl(struct sock *sk, int cmd, unsigned long arg) |
126 | { |
127 | switch (cmd) { |
128 | case SIOCOUTQ: |
129 | { |
130 | int amount = atomic_read(&sk->sk_wmem_alloc); |
131 | return put_user(amount, (int __user *)arg); |
132 | } |
133 | |
134 | case SIOCINQ: |
135 | { |
136 | struct sk_buff *skb; |
137 | unsigned long amount = 0; |
138 | |
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 | amount = skb->len - sizeof(struct nwkhdr); |
148 | } |
149 | spin_unlock_bh(&sk->sk_receive_queue.lock); |
150 | return put_user(amount, (int __user *)arg); |
151 | |
152 | } |
153 | #if 0 |
154 | /* May be implement here the commands */ |
155 | case IEEE80215_SIOC_NETWORK_DISCOVERY: |
156 | return ioctl_network_discovery(sk, (struct ieee80215_user_data __user *) arg); |
157 | break; |
158 | case IEEE80215_SIOC_NETWORK_FORMATION: |
159 | return ioctl_network_formation(sk, (struct ieee80215_user_data __user *) arg); |
160 | break; |
161 | case IEEE80215_SIOC_PERMIT_JOINING: |
162 | return ioctl_permit_joining(sk, (struct ieee80215_user_data __user *) arg); |
163 | break; |
164 | case IEEE80215_SIOC_START_ROUTER: |
165 | return ioctl_start_router(sk, (struct ieee80215_user_data __user *) arg); |
166 | break; |
167 | case IEEE80215_SIOC_JOIN: |
168 | return ioctl_mac_join(sk, (struct ieee80215_user_data __user *) arg); |
169 | break; |
170 | case IEEE80215_SIOC_MAC_CMD: |
171 | return ioctl_mac_cmd(sk, (struct ieee80215_user_data __user *) arg); |
172 | |
173 | break; |
174 | #endif |
175 | default: |
176 | return -ENOIOCTLCMD; |
177 | } |
178 | } |
179 | |
180 | // FIXME: autobind |
181 | static int dgram_connect(struct sock *sk, struct sockaddr *uaddr, |
182 | int len) |
183 | { |
184 | struct sockaddr_ieee80215 *addr = (struct sockaddr_ieee80215 *)uaddr; |
185 | struct dgram_sock *ro = container_of(sk, struct dgram_sock, sk); |
186 | |
187 | int err = 0; |
188 | |
189 | if (len < sizeof(*addr)) |
190 | return -EINVAL; |
191 | |
192 | if ((addr->family != AF_ZIGBEE) || |
193 | (addr->addr.addr_type != IEEE80215_ADDR_SHORT)) |
194 | return -EINVAL; |
195 | |
196 | lock_sock(sk); |
197 | |
198 | if (!ro->bound) { |
199 | err = -ENETUNREACH; |
200 | goto out; |
201 | } |
202 | |
203 | memcpy(&ro->dst_addr, &addr->addr, sizeof(struct ieee80215_addr)); |
204 | |
205 | out: |
206 | release_sock(sk); |
207 | return err; |
208 | } |
209 | |
210 | static int dgram_disconnect(struct sock *sk, int flags) |
211 | { |
212 | struct dgram_sock *ro = container_of(sk, struct dgram_sock, sk); |
213 | |
214 | lock_sock(sk); |
215 | |
216 | ro->dst_addr.addr_type = IEEE80215_ADDR_SHORT; |
217 | // ro->dst_addr.pan_id = 0xffff; |
218 | ro->dst_addr.short_addr = 0xffff; |
219 | |
220 | release_sock(sk); |
221 | |
222 | return 0; |
223 | } |
224 | |
225 | static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, |
226 | size_t size) |
227 | { |
228 | struct net_device *dev; |
229 | unsigned mtu; |
230 | struct sk_buff *skb; |
231 | struct dgram_sock *ro = container_of(sk, struct dgram_sock, sk); |
232 | |
233 | int err; |
234 | struct ieee80215_priv *hw; |
235 | |
236 | if (msg->msg_flags & MSG_OOB) { |
237 | pr_debug("msg->msg_flags = 0x%x\n", msg->msg_flags); |
238 | return -EOPNOTSUPP; |
239 | } |
240 | |
241 | if (!ro->bound) |
242 | dev = dev_getfirstbyhwtype(sock_net(sk), ARPHRD_IEEE80215); |
243 | else |
244 | dev = ieee80215_get_dev(sock_net(sk), &ro->src_addr); |
245 | |
246 | if (!dev) { |
247 | pr_debug("no dev\n"); |
248 | return -ENXIO; |
249 | } |
250 | hw = ieee80215_slave_get_hw(dev); |
251 | mtu = dev->mtu; |
252 | pr_debug("name = %s, mtu = %u\n", dev->name, mtu); |
253 | |
254 | skb = sock_alloc_send_skb(sk, LL_ALLOCATED_SPACE(dev) + size, msg->msg_flags & MSG_DONTWAIT, |
255 | &err); |
256 | if (!skb) { |
257 | dev_put(dev); |
258 | return err; |
259 | } |
260 | skb_reserve(skb, LL_RESERVED_SPACE(dev)); |
261 | |
262 | skb_reset_network_header(skb); |
263 | |
264 | MAC_CB(skb)->flags = IEEE80215_FC_TYPE_DATA | MAC_CB_FLAG_ACKREQ; |
265 | MAC_CB(skb)->seq = hw->dsn; |
266 | err = dev_hard_header(skb, dev, ETH_P_IEEE80215, &ro->dst_addr, ro->bound ? &ro->src_addr : NULL, size); |
267 | if (err < 0) { |
268 | kfree_skb(skb); |
269 | dev_put(dev); |
270 | return err; |
271 | } |
272 | |
273 | skb_reset_mac_header(skb); |
274 | |
275 | err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size); |
276 | if (err < 0) { |
277 | kfree_skb(skb); |
278 | dev_put(dev); |
279 | return err; |
280 | } |
281 | |
282 | if (size > mtu) { |
283 | pr_debug("size = %u, mtu = %u\n", size, mtu); |
284 | return -EINVAL; |
285 | } |
286 | |
287 | skb->dev = dev; |
288 | skb->sk = sk; |
289 | skb->protocol = htons(ETH_P_IEEE80215); |
290 | |
291 | err = dev_queue_xmit(skb); |
292 | hw->dsn++; |
293 | |
294 | dev_put(dev); |
295 | |
296 | if (err) |
297 | return err; |
298 | |
299 | return size; |
300 | } |
301 | |
302 | static int dgram_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, |
303 | size_t len, int noblock, int flags, int *addr_len) |
304 | { |
305 | size_t copied = 0; |
306 | int err = -EOPNOTSUPP; |
307 | struct sk_buff *skb; |
308 | |
309 | skb = skb_recv_datagram(sk, flags, noblock, &err); |
310 | if (!skb) |
311 | goto out; |
312 | |
313 | copied = skb->len; |
314 | if (len < copied) { |
315 | msg->msg_flags |= MSG_TRUNC; |
316 | copied = len; |
317 | } |
318 | |
319 | // FIXME: skip headers if necessary ?! |
320 | err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); |
321 | if (err) |
322 | goto done; |
323 | |
324 | sock_recv_timestamp(msg, sk, skb); |
325 | |
326 | if (flags & MSG_TRUNC) |
327 | copied = skb->len; |
328 | done: |
329 | skb_free_datagram(sk, skb); |
330 | out: |
331 | if (err) |
332 | return err; |
333 | return copied; |
334 | } |
335 | |
336 | static int dgram_rcv_skb(struct sock *sk, struct sk_buff *skb) |
337 | { |
338 | if (sock_queue_rcv_skb(sk, skb) < 0) { |
339 | atomic_inc(&sk->sk_drops); |
340 | kfree_skb(skb); |
341 | return NET_RX_DROP; |
342 | } |
343 | |
344 | return NET_RX_SUCCESS; |
345 | } |
346 | |
347 | int ieee80215_dgram_deliver(struct net_device *dev, struct sk_buff *skb) |
348 | { |
349 | struct sock *sk, *prev = NULL; |
350 | struct hlist_node*node; |
351 | int ret = NET_RX_SUCCESS; |
352 | |
353 | /* Data frame processing */ |
354 | |
355 | read_lock(&dgram_lock); |
356 | sk_for_each(sk, node, &dgram_head) { |
357 | struct dgram_sock *ro = container_of(sk, struct dgram_sock, sk); |
358 | if (!ro->bound || |
359 | (ro->src_addr.addr_type == IEEE80215_ADDR_LONG && |
360 | !memcmp(ro->src_addr.hwaddr, dev->dev_addr, IEEE80215_ADDR_LEN)) || |
361 | (ro->src_addr.addr_type == IEEE80215_ADDR_SHORT && |
362 | ieee80215_dev_get_pan_id(dev) == ro->src_addr.pan_id && |
363 | ieee80215_dev_get_short_addr(dev) == ro->src_addr.short_addr)) { |
364 | if (prev) { |
365 | struct sk_buff *clone; |
366 | clone = skb_clone(skb, GFP_ATOMIC); |
367 | if (clone) |
368 | dgram_rcv_skb(prev, clone); |
369 | } |
370 | |
371 | prev = sk; |
372 | } |
373 | } |
374 | |
375 | if (prev) |
376 | dgram_rcv_skb(prev, skb); |
377 | else { |
378 | kfree_skb(skb); |
379 | ret = NET_RX_DROP; |
380 | } |
381 | read_unlock(&dgram_lock); |
382 | |
383 | return ret; |
384 | } |
385 | |
386 | struct proto ieee80215_dgram_prot = { |
387 | .name = "ZigBEE", |
388 | .owner = THIS_MODULE, |
389 | .obj_size = sizeof(struct dgram_sock), |
390 | .init = dgram_init, |
391 | .close = dgram_close, |
392 | .bind = dgram_bind, |
393 | .sendmsg = dgram_sendmsg, |
394 | .recvmsg = dgram_recvmsg, |
395 | .hash = dgram_hash, |
396 | .unhash = dgram_unhash, |
397 | .connect = dgram_connect, |
398 | .disconnect = dgram_disconnect, |
399 | .ioctl = dgram_ioctl, |
400 | }; |
401 | |
402 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9