blob: ef09c7b3a8585451a9a1f1ec4ec29b5650988019 [file] [log] [blame]
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 BNEP implementation for Linux Bluetooth stack (BlueZ).
3 Copyright (C) 2001-2002 Inventel Systemes
4 Written 2001-2002 by
Jan Engelhardt96de0e22007-10-19 23:21:04 +02005 Clément Moreau <clement.moreau@inventel.fr>
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 David Libault <david.libault@inventel.fr>
7
8 Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License version 2 as
12 published by the Free Software Foundation;
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
17 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090018 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
Linus Torvalds1da177e2005-04-16 15:20:36 -070021 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090023 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
24 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
Linus Torvalds1da177e2005-04-16 15:20:36 -070025 SOFTWARE IS DISCLAIMED.
26*/
27
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <linux/module.h>
29
30#include <linux/kernel.h>
31#include <linux/sched.h>
32#include <linux/signal.h>
33#include <linux/init.h>
34#include <linux/wait.h>
Rafael J. Wysocki83144182007-07-17 04:03:35 -070035#include <linux/freezer.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <linux/errno.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include <linux/net.h>
38#include <net/sock.h>
39
40#include <linux/socket.h>
41#include <linux/file.h>
42
43#include <linux/netdevice.h>
44#include <linux/etherdevice.h>
45#include <linux/skbuff.h>
46
47#include <asm/unaligned.h>
48
49#include <net/bluetooth/bluetooth.h>
Marcel Holtmann0a85b962006-07-06 13:09:02 +020050#include <net/bluetooth/hci_core.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070051#include <net/bluetooth/l2cap.h>
52
53#include "bnep.h"
54
Marcel Holtmann28111eb2008-08-07 22:26:54 +020055#define VERSION "1.3"
56
57static int compress_src = 1;
58static int compress_dst = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
60static LIST_HEAD(bnep_session_list);
61static DECLARE_RWSEM(bnep_session_sem);
62
63static struct bnep_session *__bnep_get_session(u8 *dst)
64{
65 struct bnep_session *s;
66 struct list_head *p;
67
68 BT_DBG("");
69
70 list_for_each(p, &bnep_session_list) {
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090071 s = list_entry(p, struct bnep_session, list);
Kris Katterjohnd3f4a682006-01-09 16:01:43 -080072 if (!compare_ether_addr(dst, s->eh.h_source))
Linus Torvalds1da177e2005-04-16 15:20:36 -070073 return s;
74 }
75 return NULL;
76}
77
78static void __bnep_link_session(struct bnep_session *s)
79{
80 /* It's safe to call __module_get() here because sessions are added
Thadeu Lima de Souza Cascardo94e2bd62009-10-16 15:20:49 +020081 by the socket layer which has to hold the reference to this module.
Linus Torvalds1da177e2005-04-16 15:20:36 -070082 */
83 __module_get(THIS_MODULE);
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090084 list_add(&s->list, &bnep_session_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -070085}
86
87static void __bnep_unlink_session(struct bnep_session *s)
88{
89 list_del(&s->list);
90 module_put(THIS_MODULE);
91}
92
93static int bnep_send(struct bnep_session *s, void *data, size_t len)
94{
95 struct socket *sock = s->sock;
96 struct kvec iv = { data, len };
97
98 return kernel_sendmsg(sock, &s->msg, &iv, 1, len);
99}
100
101static int bnep_send_rsp(struct bnep_session *s, u8 ctrl, u16 resp)
102{
103 struct bnep_control_rsp rsp;
104 rsp.type = BNEP_CONTROL;
105 rsp.ctrl = ctrl;
106 rsp.resp = htons(resp);
107 return bnep_send(s, &rsp, sizeof(rsp));
108}
109
110#ifdef CONFIG_BT_BNEP_PROTO_FILTER
111static inline void bnep_set_default_proto_filter(struct bnep_session *s)
112{
113 /* (IPv4, ARP) */
Al Viroe41d2162006-11-08 00:27:36 -0800114 s->proto_filter[0].start = ETH_P_IP;
115 s->proto_filter[0].end = ETH_P_ARP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 /* (RARP, AppleTalk) */
Al Viroe41d2162006-11-08 00:27:36 -0800117 s->proto_filter[1].start = ETH_P_RARP;
118 s->proto_filter[1].end = ETH_P_AARP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 /* (IPX, IPv6) */
Al Viroe41d2162006-11-08 00:27:36 -0800120 s->proto_filter[2].start = ETH_P_IPX;
121 s->proto_filter[2].end = ETH_P_IPV6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122}
123#endif
124
Al Viro1bc5d442006-11-08 00:27:57 -0800125static int bnep_ctrl_set_netfilter(struct bnep_session *s, __be16 *data, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126{
127 int n;
128
129 if (len < 2)
130 return -EILSEQ;
131
Harvey Harrison83985312008-05-02 16:25:46 -0700132 n = get_unaligned_be16(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133 data++; len -= 2;
134
135 if (len < n)
136 return -EILSEQ;
137
138 BT_DBG("filter len %d", n);
139
140#ifdef CONFIG_BT_BNEP_PROTO_FILTER
141 n /= 4;
142 if (n <= BNEP_MAX_PROTO_FILTERS) {
143 struct bnep_proto_filter *f = s->proto_filter;
144 int i;
145
146 for (i = 0; i < n; i++) {
Harvey Harrison83985312008-05-02 16:25:46 -0700147 f[i].start = get_unaligned_be16(data++);
148 f[i].end = get_unaligned_be16(data++);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149
150 BT_DBG("proto filter start %d end %d",
151 f[i].start, f[i].end);
152 }
153
154 if (i < BNEP_MAX_PROTO_FILTERS)
155 memset(f + i, 0, sizeof(*f));
156
157 if (n == 0)
158 bnep_set_default_proto_filter(s);
159
160 bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_SUCCESS);
161 } else {
162 bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_LIMIT_REACHED);
163 }
164#else
165 bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_UNSUPPORTED_REQ);
166#endif
167 return 0;
168}
169
170static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len)
171{
172 int n;
173
174 if (len < 2)
175 return -EILSEQ;
176
Harvey Harrison83985312008-05-02 16:25:46 -0700177 n = get_unaligned_be16(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 data += 2; len -= 2;
179
180 if (len < n)
181 return -EILSEQ;
182
183 BT_DBG("filter len %d", n);
184
185#ifdef CONFIG_BT_BNEP_MC_FILTER
186 n /= (ETH_ALEN * 2);
187
188 if (n > 0) {
189 s->mc_filter = 0;
190
191 /* Always send broadcast */
192 set_bit(bnep_mc_hash(s->dev->broadcast), (ulong *) &s->mc_filter);
193
194 /* Add address ranges to the multicast hash */
195 for (; n > 0; n--) {
196 u8 a1[6], *a2;
197
198 memcpy(a1, data, ETH_ALEN); data += ETH_ALEN;
199 a2 = data; data += ETH_ALEN;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900200
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 BT_DBG("mc filter %s -> %s",
202 batostr((void *) a1), batostr((void *) a2));
203
204 #define INCA(a) { int i = 5; while (i >=0 && ++a[i--] == 0); }
205
206 /* Iterate from a1 to a2 */
207 set_bit(bnep_mc_hash(a1), (ulong *) &s->mc_filter);
208 while (memcmp(a1, a2, 6) < 0 && s->mc_filter != ~0LL) {
209 INCA(a1);
210 set_bit(bnep_mc_hash(a1), (ulong *) &s->mc_filter);
211 }
212 }
213 }
214
215 BT_DBG("mc filter hash 0x%llx", s->mc_filter);
216
217 bnep_send_rsp(s, BNEP_FILTER_MULTI_ADDR_RSP, BNEP_SUCCESS);
218#else
219 bnep_send_rsp(s, BNEP_FILTER_MULTI_ADDR_RSP, BNEP_FILTER_UNSUPPORTED_REQ);
220#endif
221 return 0;
222}
223
224static int bnep_rx_control(struct bnep_session *s, void *data, int len)
225{
226 u8 cmd = *(u8 *)data;
227 int err = 0;
228
229 data++; len--;
230
231 switch (cmd) {
232 case BNEP_CMD_NOT_UNDERSTOOD:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 case BNEP_SETUP_CONN_RSP:
234 case BNEP_FILTER_NET_TYPE_RSP:
235 case BNEP_FILTER_MULTI_ADDR_RSP:
236 /* Ignore these for now */
237 break;
238
239 case BNEP_FILTER_NET_TYPE_SET:
240 err = bnep_ctrl_set_netfilter(s, data, len);
241 break;
242
243 case BNEP_FILTER_MULTI_ADDR_SET:
244 err = bnep_ctrl_set_mcfilter(s, data, len);
245 break;
246
Vikram Kandukuricde9f802009-12-03 15:12:51 +0530247 case BNEP_SETUP_CONN_REQ:
248 err = bnep_send_rsp(s, BNEP_SETUP_CONN_RSP, BNEP_CONN_NOT_ALLOWED);
249 break;
250
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 default: {
252 u8 pkt[3];
253 pkt[0] = BNEP_CONTROL;
254 pkt[1] = BNEP_CMD_NOT_UNDERSTOOD;
255 pkt[2] = cmd;
256 bnep_send(s, pkt, sizeof(pkt));
257 }
258 break;
259 }
260
261 return err;
262}
263
264static int bnep_rx_extension(struct bnep_session *s, struct sk_buff *skb)
265{
266 struct bnep_ext_hdr *h;
267 int err = 0;
268
269 do {
270 h = (void *) skb->data;
271 if (!skb_pull(skb, sizeof(*h))) {
272 err = -EILSEQ;
273 break;
274 }
275
276 BT_DBG("type 0x%x len %d", h->type, h->len);
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900277
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 switch (h->type & BNEP_TYPE_MASK) {
279 case BNEP_EXT_CONTROL:
280 bnep_rx_control(s, skb->data, skb->len);
281 break;
282
283 default:
284 /* Unknown extension, skip it. */
285 break;
286 }
287
288 if (!skb_pull(skb, h->len)) {
289 err = -EILSEQ;
290 break;
291 }
292 } while (!err && (h->type & BNEP_EXT_HEADER));
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900293
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 return err;
295}
296
297static u8 __bnep_rx_hlen[] = {
298 ETH_HLEN, /* BNEP_GENERAL */
299 0, /* BNEP_CONTROL */
300 2, /* BNEP_COMPRESSED */
301 ETH_ALEN + 2, /* BNEP_COMPRESSED_SRC_ONLY */
302 ETH_ALEN + 2 /* BNEP_COMPRESSED_DST_ONLY */
303};
304#define BNEP_RX_TYPES (sizeof(__bnep_rx_hlen) - 1)
305
306static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
307{
308 struct net_device *dev = s->dev;
309 struct sk_buff *nskb;
310 u8 type;
311
Stephen Hemmingerb4d7f0a2009-01-07 17:23:17 -0800312 dev->stats.rx_bytes += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313
314 type = *(u8 *) skb->data; skb_pull(skb, 1);
315
316 if ((type & BNEP_TYPE_MASK) > BNEP_RX_TYPES)
317 goto badframe;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900318
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) {
320 bnep_rx_control(s, skb->data, skb->len);
321 kfree_skb(skb);
322 return 0;
323 }
324
Arnaldo Carvalho de Melo459a98e2007-03-19 15:30:44 -0700325 skb_reset_mac_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326
327 /* Verify and pull out header */
328 if (!skb_pull(skb, __bnep_rx_hlen[type & BNEP_TYPE_MASK]))
329 goto badframe;
330
Al Viro1bc5d442006-11-08 00:27:57 -0800331 s->eh.h_proto = get_unaligned((__be16 *) (skb->data - 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332
333 if (type & BNEP_EXT_HEADER) {
334 if (bnep_rx_extension(s, skb) < 0)
335 goto badframe;
336 }
337
338 /* Strip 802.1p header */
339 if (ntohs(s->eh.h_proto) == 0x8100) {
340 if (!skb_pull(skb, 4))
341 goto badframe;
Al Viro1bc5d442006-11-08 00:27:57 -0800342 s->eh.h_proto = get_unaligned((__be16 *) (skb->data - 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 }
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900344
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 /* We have to alloc new skb and copy data here :(. Because original skb
346 * may not be modified and because of the alignment requirements. */
347 nskb = alloc_skb(2 + ETH_HLEN + skb->len, GFP_KERNEL);
348 if (!nskb) {
Stephen Hemmingerb4d7f0a2009-01-07 17:23:17 -0800349 dev->stats.rx_dropped++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 kfree_skb(skb);
351 return -ENOMEM;
352 }
353 skb_reserve(nskb, 2);
354
355 /* Decompress header and construct ether frame */
356 switch (type & BNEP_TYPE_MASK) {
357 case BNEP_COMPRESSED:
358 memcpy(__skb_put(nskb, ETH_HLEN), &s->eh, ETH_HLEN);
359 break;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900360
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 case BNEP_COMPRESSED_SRC_ONLY:
362 memcpy(__skb_put(nskb, ETH_ALEN), s->eh.h_dest, ETH_ALEN);
Arnaldo Carvalho de Melo98e399f2007-03-19 15:33:04 -0700363 memcpy(__skb_put(nskb, ETH_ALEN), skb_mac_header(skb), ETH_ALEN);
Al Viro1bc5d442006-11-08 00:27:57 -0800364 put_unaligned(s->eh.h_proto, (__be16 *) __skb_put(nskb, 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 break;
366
367 case BNEP_COMPRESSED_DST_ONLY:
Arnaldo Carvalho de Melo98e399f2007-03-19 15:33:04 -0700368 memcpy(__skb_put(nskb, ETH_ALEN), skb_mac_header(skb),
369 ETH_ALEN);
370 memcpy(__skb_put(nskb, ETH_ALEN + 2), s->eh.h_source,
371 ETH_ALEN + 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 break;
373
374 case BNEP_GENERAL:
Arnaldo Carvalho de Melo98e399f2007-03-19 15:33:04 -0700375 memcpy(__skb_put(nskb, ETH_ALEN * 2), skb_mac_header(skb),
376 ETH_ALEN * 2);
Al Viro1bc5d442006-11-08 00:27:57 -0800377 put_unaligned(s->eh.h_proto, (__be16 *) __skb_put(nskb, 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 break;
379 }
380
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -0300381 skb_copy_from_linear_data(skb, __skb_put(nskb, skb->len), skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 kfree_skb(skb);
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900383
Stephen Hemmingerb4d7f0a2009-01-07 17:23:17 -0800384 dev->stats.rx_packets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 nskb->ip_summed = CHECKSUM_NONE;
386 nskb->protocol = eth_type_trans(nskb, dev);
387 netif_rx_ni(nskb);
388 return 0;
389
390badframe:
Stephen Hemmingerb4d7f0a2009-01-07 17:23:17 -0800391 dev->stats.rx_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 kfree_skb(skb);
393 return 0;
394}
395
396static u8 __bnep_tx_types[] = {
397 BNEP_GENERAL,
398 BNEP_COMPRESSED_SRC_ONLY,
399 BNEP_COMPRESSED_DST_ONLY,
400 BNEP_COMPRESSED
401};
402
403static inline int bnep_tx_frame(struct bnep_session *s, struct sk_buff *skb)
404{
405 struct ethhdr *eh = (void *) skb->data;
406 struct socket *sock = s->sock;
407 struct kvec iv[3];
408 int len = 0, il = 0;
409 u8 type = 0;
410
411 BT_DBG("skb %p dev %p type %d", skb, skb->dev, skb->pkt_type);
412
413 if (!skb->dev) {
414 /* Control frame sent by us */
415 goto send;
416 }
417
418 iv[il++] = (struct kvec) { &type, 1 };
419 len++;
420
Marcel Holtmann28111eb2008-08-07 22:26:54 +0200421 if (compress_src && !compare_ether_addr(eh->h_dest, s->eh.h_source))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 type |= 0x01;
423
Marcel Holtmann28111eb2008-08-07 22:26:54 +0200424 if (compress_dst && !compare_ether_addr(eh->h_source, s->eh.h_dest))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 type |= 0x02;
426
427 if (type)
428 skb_pull(skb, ETH_ALEN * 2);
429
430 type = __bnep_tx_types[type];
431 switch (type) {
432 case BNEP_COMPRESSED_SRC_ONLY:
433 iv[il++] = (struct kvec) { eh->h_source, ETH_ALEN };
434 len += ETH_ALEN;
435 break;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900436
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 case BNEP_COMPRESSED_DST_ONLY:
438 iv[il++] = (struct kvec) { eh->h_dest, ETH_ALEN };
439 len += ETH_ALEN;
440 break;
441 }
442
443send:
444 iv[il++] = (struct kvec) { skb->data, skb->len };
445 len += skb->len;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900446
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 /* FIXME: linearize skb */
448 {
449 len = kernel_sendmsg(sock, &s->msg, iv, il, len);
450 }
451 kfree_skb(skb);
452
453 if (len > 0) {
Stephen Hemmingerb4d7f0a2009-01-07 17:23:17 -0800454 s->dev->stats.tx_bytes += len;
455 s->dev->stats.tx_packets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 return 0;
457 }
458
459 return len;
460}
461
462static int bnep_session(void *arg)
463{
464 struct bnep_session *s = arg;
465 struct net_device *dev = s->dev;
466 struct sock *sk = s->sock->sk;
467 struct sk_buff *skb;
468 wait_queue_t wait;
469
470 BT_DBG("");
471
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900472 daemonize("kbnepd %s", dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 set_user_nice(current, -15);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474
475 init_waitqueue_entry(&wait, current);
476 add_wait_queue(sk->sk_sleep, &wait);
477 while (!atomic_read(&s->killed)) {
478 set_current_state(TASK_INTERRUPTIBLE);
479
480 // RX
481 while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
482 skb_orphan(skb);
483 bnep_rx_frame(s, skb);
484 }
485
486 if (sk->sk_state != BT_CONNECTED)
487 break;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900488
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 // TX
490 while ((skb = skb_dequeue(&sk->sk_write_queue)))
491 if (bnep_tx_frame(s, skb))
492 break;
493 netif_wake_queue(dev);
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900494
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 schedule();
496 }
497 set_current_state(TASK_RUNNING);
498 remove_wait_queue(sk->sk_sleep, &wait);
499
500 /* Cleanup session */
501 down_write(&bnep_session_sem);
502
503 /* Delete network device */
504 unregister_netdev(dev);
505
Marcel Holtmannec8dab32008-07-14 20:13:53 +0200506 /* Wakeup user-space polling for socket errors */
507 s->sock->sk->sk_err = EUNATCH;
508
509 wake_up_interruptible(s->sock->sk->sk_sleep);
510
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 /* Release the socket */
512 fput(s->sock->file);
513
514 __bnep_unlink_session(s);
515
516 up_write(&bnep_session_sem);
517 free_netdev(dev);
518 return 0;
519}
520
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200521static struct device *bnep_get_device(struct bnep_session *session)
522{
523 bdaddr_t *src = &bt_sk(session->sock->sk)->src;
524 bdaddr_t *dst = &bt_sk(session->sock->sk)->dst;
525 struct hci_dev *hdev;
526 struct hci_conn *conn;
527
528 hdev = hci_get_route(dst, src);
529 if (!hdev)
530 return NULL;
531
532 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200533
534 hci_dev_put(hdev);
535
Marcel Holtmannb2cfcd72006-10-15 17:31:05 +0200536 return conn ? &conn->dev : NULL;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200537}
538
Marcel Holtmann384912e2009-08-31 21:08:19 +0000539static struct device_type bnep_type = {
540 .name = "bluetooth",
541};
542
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
544{
545 struct net_device *dev;
546 struct bnep_session *s, *ss;
547 u8 dst[ETH_ALEN], src[ETH_ALEN];
548 int err;
549
550 BT_DBG("");
551
552 baswap((void *) dst, &bt_sk(sock->sk)->dst);
553 baswap((void *) src, &bt_sk(sock->sk)->src);
554
555 /* session struct allocated as private part of net_device */
556 dev = alloc_netdev(sizeof(struct bnep_session),
557 (*req->device) ? req->device : "bnep%d",
558 bnep_net_setup);
Tobias Klauser67b52e52006-03-21 23:53:16 -0800559 if (!dev)
560 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 down_write(&bnep_session_sem);
563
564 ss = __bnep_get_session(dst);
565 if (ss && ss->state == BT_CONNECTED) {
566 err = -EEXIST;
567 goto failed;
568 }
569
Wang Chen524ad0a2008-11-12 23:39:10 -0800570 s = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571
572 /* This is rx header therefore addresses are swapped.
573 * ie eh.h_dest is our local address. */
574 memcpy(s->eh.h_dest, &src, ETH_ALEN);
575 memcpy(s->eh.h_source, &dst, ETH_ALEN);
576 memcpy(dev->dev_addr, s->eh.h_dest, ETH_ALEN);
577
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200578 s->dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 s->sock = sock;
580 s->role = req->role;
581 s->state = BT_CONNECTED;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900582
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 s->msg.msg_flags = MSG_NOSIGNAL;
584
585#ifdef CONFIG_BT_BNEP_MC_FILTER
586 /* Set default mc filter */
587 set_bit(bnep_mc_hash(dev->broadcast), (ulong *) &s->mc_filter);
588#endif
589
590#ifdef CONFIG_BT_BNEP_PROTO_FILTER
591 /* Set default protocol filter */
592 bnep_set_default_proto_filter(s);
593#endif
594
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200595 SET_NETDEV_DEV(dev, bnep_get_device(s));
Marcel Holtmann384912e2009-08-31 21:08:19 +0000596 SET_NETDEV_DEVTYPE(dev, &bnep_type);
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200597
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 err = register_netdev(dev);
599 if (err) {
600 goto failed;
601 }
602
603 __bnep_link_session(s);
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900604
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 err = kernel_thread(bnep_session, s, CLONE_KERNEL);
606 if (err < 0) {
607 /* Session thread start failed, gotta cleanup. */
608 unregister_netdev(dev);
609 __bnep_unlink_session(s);
610 goto failed;
611 }
612
613 up_write(&bnep_session_sem);
614 strcpy(req->device, dev->name);
615 return 0;
616
617failed:
618 up_write(&bnep_session_sem);
619 free_netdev(dev);
620 return err;
621}
622
623int bnep_del_connection(struct bnep_conndel_req *req)
624{
625 struct bnep_session *s;
626 int err = 0;
627
628 BT_DBG("");
629
630 down_read(&bnep_session_sem);
631
632 s = __bnep_get_session(req->dst);
633 if (s) {
634 /* Wakeup user-space which is polling for socket errors.
Thadeu Lima de Souza Cascardo94e2bd62009-10-16 15:20:49 +0200635 * This is temporary hack until we have shutdown in L2CAP */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 s->sock->sk->sk_err = EUNATCH;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900637
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 /* Kill session thread */
639 atomic_inc(&s->killed);
640 wake_up_interruptible(s->sock->sk->sk_sleep);
641 } else
642 err = -ENOENT;
643
644 up_read(&bnep_session_sem);
645 return err;
646}
647
648static void __bnep_copy_ci(struct bnep_conninfo *ci, struct bnep_session *s)
649{
650 memcpy(ci->dst, s->eh.h_source, ETH_ALEN);
651 strcpy(ci->device, s->dev->name);
652 ci->flags = s->flags;
653 ci->state = s->state;
654 ci->role = s->role;
655}
656
657int bnep_get_connlist(struct bnep_connlist_req *req)
658{
659 struct list_head *p;
660 int err = 0, n = 0;
661
662 down_read(&bnep_session_sem);
663
664 list_for_each(p, &bnep_session_list) {
665 struct bnep_session *s;
666 struct bnep_conninfo ci;
667
668 s = list_entry(p, struct bnep_session, list);
669
670 __bnep_copy_ci(&ci, s);
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900671
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 if (copy_to_user(req->ci, &ci, sizeof(ci))) {
673 err = -EFAULT;
674 break;
675 }
676
677 if (++n >= req->cnum)
678 break;
679
680 req->ci++;
681 }
682 req->cnum = n;
683
684 up_read(&bnep_session_sem);
685 return err;
686}
687
688int bnep_get_conninfo(struct bnep_conninfo *ci)
689{
690 struct bnep_session *s;
691 int err = 0;
692
693 down_read(&bnep_session_sem);
694
695 s = __bnep_get_session(ci->dst);
696 if (s)
697 __bnep_copy_ci(ci, s);
698 else
699 err = -ENOENT;
700
701 up_read(&bnep_session_sem);
702 return err;
703}
704
705static int __init bnep_init(void)
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900706{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 char flt[50] = "";
708
709 l2cap_load();
710
711#ifdef CONFIG_BT_BNEP_PROTO_FILTER
712 strcat(flt, "protocol ");
713#endif
714
715#ifdef CONFIG_BT_BNEP_MC_FILTER
716 strcat(flt, "multicast");
717#endif
718
719 BT_INFO("BNEP (Ethernet Emulation) ver %s", VERSION);
720 if (flt[0])
721 BT_INFO("BNEP filters: %s", flt);
722
723 bnep_sock_init();
724 return 0;
725}
726
727static void __exit bnep_exit(void)
728{
729 bnep_sock_cleanup();
730}
731
732module_init(bnep_init);
733module_exit(bnep_exit);
734
Marcel Holtmann28111eb2008-08-07 22:26:54 +0200735module_param(compress_src, bool, 0644);
736MODULE_PARM_DESC(compress_src, "Compress sources headers");
737
738module_param(compress_dst, bool, 0644);
739MODULE_PARM_DESC(compress_dst, "Compress destination headers");
740
Marcel Holtmann63fbd242008-08-18 13:23:53 +0200741MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742MODULE_DESCRIPTION("Bluetooth BNEP ver " VERSION);
743MODULE_VERSION(VERSION);
744MODULE_LICENSE("GPL");
745MODULE_ALIAS("bt-proto-4");