Merge tag 'gpio-v3.15-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw...
[sfrench/cifs-2.6.git] / net / ieee802154 / raw.c
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 <linux/slab.h>
29 #include <net/sock.h>
30 #include <net/af_ieee802154.h>
31 #include <net/ieee802154_netdev.h>
32
33 #include "af802154.h"
34
35 static HLIST_HEAD(raw_head);
36 static DEFINE_RWLOCK(raw_lock);
37
38 static void raw_hash(struct sock *sk)
39 {
40         write_lock_bh(&raw_lock);
41         sk_add_node(sk, &raw_head);
42         sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
43         write_unlock_bh(&raw_lock);
44 }
45
46 static void raw_unhash(struct sock *sk)
47 {
48         write_lock_bh(&raw_lock);
49         if (sk_del_node_init(sk))
50                 sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
51         write_unlock_bh(&raw_lock);
52 }
53
54 static void raw_close(struct sock *sk, long timeout)
55 {
56         sk_common_release(sk);
57 }
58
59 static int raw_bind(struct sock *sk, struct sockaddr *_uaddr, int len)
60 {
61         struct ieee802154_addr addr;
62         struct sockaddr_ieee802154 *uaddr = (struct sockaddr_ieee802154 *)_uaddr;
63         int err = 0;
64         struct net_device *dev = NULL;
65
66         if (len < sizeof(*uaddr))
67                 return -EINVAL;
68
69         uaddr = (struct sockaddr_ieee802154 *)_uaddr;
70         if (uaddr->family != AF_IEEE802154)
71                 return -EINVAL;
72
73         lock_sock(sk);
74
75         ieee802154_addr_from_sa(&addr, &uaddr->addr);
76         dev = ieee802154_get_dev(sock_net(sk), &addr);
77         if (!dev) {
78                 err = -ENODEV;
79                 goto out;
80         }
81
82         if (dev->type != ARPHRD_IEEE802154) {
83                 err = -ENODEV;
84                 goto out_put;
85         }
86
87         sk->sk_bound_dev_if = dev->ifindex;
88         sk_dst_reset(sk);
89
90 out_put:
91         dev_put(dev);
92 out:
93         release_sock(sk);
94
95         return err;
96 }
97
98 static int raw_connect(struct sock *sk, struct sockaddr *uaddr,
99                         int addr_len)
100 {
101         return -ENOTSUPP;
102 }
103
104 static int raw_disconnect(struct sock *sk, int flags)
105 {
106         return 0;
107 }
108
109 static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
110                        size_t size)
111 {
112         struct net_device *dev;
113         unsigned int mtu;
114         struct sk_buff *skb;
115         int hlen, tlen;
116         int err;
117
118         if (msg->msg_flags & MSG_OOB) {
119                 pr_debug("msg->msg_flags = 0x%x\n", msg->msg_flags);
120                 return -EOPNOTSUPP;
121         }
122
123         lock_sock(sk);
124         if (!sk->sk_bound_dev_if)
125                 dev = dev_getfirstbyhwtype(sock_net(sk), ARPHRD_IEEE802154);
126         else
127                 dev = dev_get_by_index(sock_net(sk), sk->sk_bound_dev_if);
128         release_sock(sk);
129
130         if (!dev) {
131                 pr_debug("no dev\n");
132                 err = -ENXIO;
133                 goto out;
134         }
135
136         mtu = dev->mtu;
137         pr_debug("name = %s, mtu = %u\n", dev->name, mtu);
138
139         if (size > mtu) {
140                 pr_debug("size = %Zu, mtu = %u\n", size, mtu);
141                 err = -EINVAL;
142                 goto out_dev;
143         }
144
145         hlen = LL_RESERVED_SPACE(dev);
146         tlen = dev->needed_tailroom;
147         skb = sock_alloc_send_skb(sk, hlen + tlen + size,
148                         msg->msg_flags & MSG_DONTWAIT, &err);
149         if (!skb)
150                 goto out_dev;
151
152         skb_reserve(skb, hlen);
153
154         skb_reset_mac_header(skb);
155         skb_reset_network_header(skb);
156
157         err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
158         if (err < 0)
159                 goto out_skb;
160
161         skb->dev = dev;
162         skb->sk  = sk;
163         skb->protocol = htons(ETH_P_IEEE802154);
164
165         dev_put(dev);
166
167         err = dev_queue_xmit(skb);
168         if (err > 0)
169                 err = net_xmit_errno(err);
170
171         return err ?: size;
172
173 out_skb:
174         kfree_skb(skb);
175 out_dev:
176         dev_put(dev);
177 out:
178         return err;
179 }
180
181 static int raw_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
182                        size_t len, int noblock, int flags, int *addr_len)
183 {
184         size_t copied = 0;
185         int err = -EOPNOTSUPP;
186         struct sk_buff *skb;
187
188         skb = skb_recv_datagram(sk, flags, noblock, &err);
189         if (!skb)
190                 goto out;
191
192         copied = skb->len;
193         if (len < copied) {
194                 msg->msg_flags |= MSG_TRUNC;
195                 copied = len;
196         }
197
198         err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
199         if (err)
200                 goto done;
201
202         sock_recv_ts_and_drops(msg, sk, skb);
203
204         if (flags & MSG_TRUNC)
205                 copied = skb->len;
206 done:
207         skb_free_datagram(sk, skb);
208 out:
209         if (err)
210                 return err;
211         return copied;
212 }
213
214 static int raw_rcv_skb(struct sock *sk, struct sk_buff *skb)
215 {
216         skb = skb_share_check(skb, GFP_ATOMIC);
217         if (!skb)
218                 return NET_RX_DROP;
219
220         if (sock_queue_rcv_skb(sk, skb) < 0) {
221                 kfree_skb(skb);
222                 return NET_RX_DROP;
223         }
224
225         return NET_RX_SUCCESS;
226 }
227
228
229 void ieee802154_raw_deliver(struct net_device *dev, struct sk_buff *skb)
230 {
231         struct sock *sk;
232
233         read_lock(&raw_lock);
234         sk_for_each(sk, &raw_head) {
235                 bh_lock_sock(sk);
236                 if (!sk->sk_bound_dev_if ||
237                     sk->sk_bound_dev_if == dev->ifindex) {
238
239                         struct sk_buff *clone;
240
241                         clone = skb_clone(skb, GFP_ATOMIC);
242                         if (clone)
243                                 raw_rcv_skb(sk, clone);
244                 }
245                 bh_unlock_sock(sk);
246         }
247         read_unlock(&raw_lock);
248 }
249
250 static int raw_getsockopt(struct sock *sk, int level, int optname,
251                     char __user *optval, int __user *optlen)
252 {
253         return -EOPNOTSUPP;
254 }
255
256 static int raw_setsockopt(struct sock *sk, int level, int optname,
257                     char __user *optval, unsigned int optlen)
258 {
259         return -EOPNOTSUPP;
260 }
261
262 struct proto ieee802154_raw_prot = {
263         .name           = "IEEE-802.15.4-RAW",
264         .owner          = THIS_MODULE,
265         .obj_size       = sizeof(struct sock),
266         .close          = raw_close,
267         .bind           = raw_bind,
268         .sendmsg        = raw_sendmsg,
269         .recvmsg        = raw_recvmsg,
270         .hash           = raw_hash,
271         .unhash         = raw_unhash,
272         .connect        = raw_connect,
273         .disconnect     = raw_disconnect,
274         .getsockopt     = raw_getsockopt,
275         .setsockopt     = raw_setsockopt,
276 };
277