blob: 940b4e129741b8fb3a6535e872658e46084baa6a [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>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090038#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include <net/sock.h>
40
41#include <linux/socket.h>
42#include <linux/file.h>
43
44#include <linux/netdevice.h>
45#include <linux/etherdevice.h>
46#include <linux/skbuff.h>
47
48#include <asm/unaligned.h>
49
50#include <net/bluetooth/bluetooth.h>
Marcel Holtmann0a85b962006-07-06 13:09:02 +020051#include <net/bluetooth/hci_core.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#include <net/bluetooth/l2cap.h>
53
54#include "bnep.h"
55
Marcel Holtmann28111eb2008-08-07 22:26:54 +020056#define VERSION "1.3"
57
58static int compress_src = 1;
59static int compress_dst = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070060
61static LIST_HEAD(bnep_session_list);
62static DECLARE_RWSEM(bnep_session_sem);
63
64static struct bnep_session *__bnep_get_session(u8 *dst)
65{
66 struct bnep_session *s;
67 struct list_head *p;
68
69 BT_DBG("");
70
71 list_for_each(p, &bnep_session_list) {
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090072 s = list_entry(p, struct bnep_session, list);
Kris Katterjohnd3f4a682006-01-09 16:01:43 -080073 if (!compare_ether_addr(dst, s->eh.h_source))
Linus Torvalds1da177e2005-04-16 15:20:36 -070074 return s;
75 }
76 return NULL;
77}
78
79static void __bnep_link_session(struct bnep_session *s)
80{
81 /* It's safe to call __module_get() here because sessions are added
Thadeu Lima de Souza Cascardo94e2bd62009-10-16 15:20:49 +020082 by the socket layer which has to hold the reference to this module.
Linus Torvalds1da177e2005-04-16 15:20:36 -070083 */
84 __module_get(THIS_MODULE);
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090085 list_add(&s->list, &bnep_session_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -070086}
87
88static void __bnep_unlink_session(struct bnep_session *s)
89{
90 list_del(&s->list);
91 module_put(THIS_MODULE);
92}
93
94static int bnep_send(struct bnep_session *s, void *data, size_t len)
95{
96 struct socket *sock = s->sock;
97 struct kvec iv = { data, len };
98
99 return kernel_sendmsg(sock, &s->msg, &iv, 1, len);
100}
101
102static int bnep_send_rsp(struct bnep_session *s, u8 ctrl, u16 resp)
103{
104 struct bnep_control_rsp rsp;
105 rsp.type = BNEP_CONTROL;
106 rsp.ctrl = ctrl;
107 rsp.resp = htons(resp);
108 return bnep_send(s, &rsp, sizeof(rsp));
109}
110
111#ifdef CONFIG_BT_BNEP_PROTO_FILTER
112static inline void bnep_set_default_proto_filter(struct bnep_session *s)
113{
114 /* (IPv4, ARP) */
Al Viroe41d2162006-11-08 00:27:36 -0800115 s->proto_filter[0].start = ETH_P_IP;
116 s->proto_filter[0].end = ETH_P_ARP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 /* (RARP, AppleTalk) */
Al Viroe41d2162006-11-08 00:27:36 -0800118 s->proto_filter[1].start = ETH_P_RARP;
119 s->proto_filter[1].end = ETH_P_AARP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120 /* (IPX, IPv6) */
Al Viroe41d2162006-11-08 00:27:36 -0800121 s->proto_filter[2].start = ETH_P_IPX;
122 s->proto_filter[2].end = ETH_P_IPV6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123}
124#endif
125
Al Viro1bc5d442006-11-08 00:27:57 -0800126static int bnep_ctrl_set_netfilter(struct bnep_session *s, __be16 *data, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127{
128 int n;
129
130 if (len < 2)
131 return -EILSEQ;
132
Harvey Harrison83985312008-05-02 16:25:46 -0700133 n = get_unaligned_be16(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 data++; len -= 2;
135
136 if (len < n)
137 return -EILSEQ;
138
139 BT_DBG("filter len %d", n);
140
141#ifdef CONFIG_BT_BNEP_PROTO_FILTER
142 n /= 4;
143 if (n <= BNEP_MAX_PROTO_FILTERS) {
144 struct bnep_proto_filter *f = s->proto_filter;
145 int i;
146
147 for (i = 0; i < n; i++) {
Harvey Harrison83985312008-05-02 16:25:46 -0700148 f[i].start = get_unaligned_be16(data++);
149 f[i].end = get_unaligned_be16(data++);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150
151 BT_DBG("proto filter start %d end %d",
152 f[i].start, f[i].end);
153 }
154
155 if (i < BNEP_MAX_PROTO_FILTERS)
156 memset(f + i, 0, sizeof(*f));
157
158 if (n == 0)
159 bnep_set_default_proto_filter(s);
160
161 bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_SUCCESS);
162 } else {
163 bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_LIMIT_REACHED);
164 }
165#else
166 bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_UNSUPPORTED_REQ);
167#endif
168 return 0;
169}
170
171static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len)
172{
173 int n;
174
175 if (len < 2)
176 return -EILSEQ;
177
Harvey Harrison83985312008-05-02 16:25:46 -0700178 n = get_unaligned_be16(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 data += 2; len -= 2;
180
181 if (len < n)
182 return -EILSEQ;
183
184 BT_DBG("filter len %d", n);
185
186#ifdef CONFIG_BT_BNEP_MC_FILTER
187 n /= (ETH_ALEN * 2);
188
189 if (n > 0) {
Szymon Janca3d9bd42011-03-21 14:19:57 +0100190 int i;
191
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 s->mc_filter = 0;
193
194 /* Always send broadcast */
195 set_bit(bnep_mc_hash(s->dev->broadcast), (ulong *) &s->mc_filter);
196
197 /* Add address ranges to the multicast hash */
198 for (; n > 0; n--) {
199 u8 a1[6], *a2;
200
201 memcpy(a1, data, ETH_ALEN); data += ETH_ALEN;
202 a2 = data; data += ETH_ALEN;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900203
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 BT_DBG("mc filter %s -> %s",
205 batostr((void *) a1), batostr((void *) a2));
206
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 /* Iterate from a1 to a2 */
208 set_bit(bnep_mc_hash(a1), (ulong *) &s->mc_filter);
209 while (memcmp(a1, a2, 6) < 0 && s->mc_filter != ~0LL) {
Szymon Janca3d9bd42011-03-21 14:19:57 +0100210 /* Increment a1 */
211 i = 5;
212 while (i >= 0 && ++a1[i--] == 0)
213 ;
214
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 set_bit(bnep_mc_hash(a1), (ulong *) &s->mc_filter);
216 }
217 }
218 }
219
220 BT_DBG("mc filter hash 0x%llx", s->mc_filter);
221
222 bnep_send_rsp(s, BNEP_FILTER_MULTI_ADDR_RSP, BNEP_SUCCESS);
223#else
224 bnep_send_rsp(s, BNEP_FILTER_MULTI_ADDR_RSP, BNEP_FILTER_UNSUPPORTED_REQ);
225#endif
226 return 0;
227}
228
229static int bnep_rx_control(struct bnep_session *s, void *data, int len)
230{
231 u8 cmd = *(u8 *)data;
232 int err = 0;
233
234 data++; len--;
235
236 switch (cmd) {
237 case BNEP_CMD_NOT_UNDERSTOOD:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 case BNEP_SETUP_CONN_RSP:
239 case BNEP_FILTER_NET_TYPE_RSP:
240 case BNEP_FILTER_MULTI_ADDR_RSP:
241 /* Ignore these for now */
242 break;
243
244 case BNEP_FILTER_NET_TYPE_SET:
245 err = bnep_ctrl_set_netfilter(s, data, len);
246 break;
247
248 case BNEP_FILTER_MULTI_ADDR_SET:
249 err = bnep_ctrl_set_mcfilter(s, data, len);
250 break;
251
Vikram Kandukuricde9f802009-12-03 15:12:51 +0530252 case BNEP_SETUP_CONN_REQ:
253 err = bnep_send_rsp(s, BNEP_SETUP_CONN_RSP, BNEP_CONN_NOT_ALLOWED);
254 break;
255
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 default: {
257 u8 pkt[3];
258 pkt[0] = BNEP_CONTROL;
259 pkt[1] = BNEP_CMD_NOT_UNDERSTOOD;
260 pkt[2] = cmd;
261 bnep_send(s, pkt, sizeof(pkt));
262 }
263 break;
264 }
265
266 return err;
267}
268
269static int bnep_rx_extension(struct bnep_session *s, struct sk_buff *skb)
270{
271 struct bnep_ext_hdr *h;
272 int err = 0;
273
274 do {
275 h = (void *) skb->data;
276 if (!skb_pull(skb, sizeof(*h))) {
277 err = -EILSEQ;
278 break;
279 }
280
281 BT_DBG("type 0x%x len %d", h->type, h->len);
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900282
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 switch (h->type & BNEP_TYPE_MASK) {
284 case BNEP_EXT_CONTROL:
285 bnep_rx_control(s, skb->data, skb->len);
286 break;
287
288 default:
289 /* Unknown extension, skip it. */
290 break;
291 }
292
293 if (!skb_pull(skb, h->len)) {
294 err = -EILSEQ;
295 break;
296 }
297 } while (!err && (h->type & BNEP_EXT_HEADER));
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900298
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 return err;
300}
301
302static u8 __bnep_rx_hlen[] = {
303 ETH_HLEN, /* BNEP_GENERAL */
304 0, /* BNEP_CONTROL */
305 2, /* BNEP_COMPRESSED */
306 ETH_ALEN + 2, /* BNEP_COMPRESSED_SRC_ONLY */
307 ETH_ALEN + 2 /* BNEP_COMPRESSED_DST_ONLY */
308};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309
310static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
311{
312 struct net_device *dev = s->dev;
313 struct sk_buff *nskb;
314 u8 type;
315
Stephen Hemmingerb4d7f0a2009-01-07 17:23:17 -0800316 dev->stats.rx_bytes += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317
318 type = *(u8 *) skb->data; skb_pull(skb, 1);
319
Szymon Janca3d9bd42011-03-21 14:19:57 +0100320 if ((type & BNEP_TYPE_MASK) >= sizeof(__bnep_rx_hlen))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 goto badframe;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900322
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) {
324 bnep_rx_control(s, skb->data, skb->len);
325 kfree_skb(skb);
326 return 0;
327 }
328
Arnaldo Carvalho de Melo459a98e2007-03-19 15:30:44 -0700329 skb_reset_mac_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330
331 /* Verify and pull out header */
332 if (!skb_pull(skb, __bnep_rx_hlen[type & BNEP_TYPE_MASK]))
333 goto badframe;
334
Al Viro1bc5d442006-11-08 00:27:57 -0800335 s->eh.h_proto = get_unaligned((__be16 *) (skb->data - 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336
337 if (type & BNEP_EXT_HEADER) {
338 if (bnep_rx_extension(s, skb) < 0)
339 goto badframe;
340 }
341
342 /* Strip 802.1p header */
343 if (ntohs(s->eh.h_proto) == 0x8100) {
344 if (!skb_pull(skb, 4))
345 goto badframe;
Al Viro1bc5d442006-11-08 00:27:57 -0800346 s->eh.h_proto = get_unaligned((__be16 *) (skb->data - 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 }
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900348
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 /* We have to alloc new skb and copy data here :(. Because original skb
350 * may not be modified and because of the alignment requirements. */
351 nskb = alloc_skb(2 + ETH_HLEN + skb->len, GFP_KERNEL);
352 if (!nskb) {
Stephen Hemmingerb4d7f0a2009-01-07 17:23:17 -0800353 dev->stats.rx_dropped++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 kfree_skb(skb);
355 return -ENOMEM;
356 }
357 skb_reserve(nskb, 2);
358
359 /* Decompress header and construct ether frame */
360 switch (type & BNEP_TYPE_MASK) {
361 case BNEP_COMPRESSED:
362 memcpy(__skb_put(nskb, ETH_HLEN), &s->eh, ETH_HLEN);
363 break;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900364
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 case BNEP_COMPRESSED_SRC_ONLY:
366 memcpy(__skb_put(nskb, ETH_ALEN), s->eh.h_dest, ETH_ALEN);
Arnaldo Carvalho de Melo98e399f2007-03-19 15:33:04 -0700367 memcpy(__skb_put(nskb, ETH_ALEN), skb_mac_header(skb), ETH_ALEN);
Al Viro1bc5d442006-11-08 00:27:57 -0800368 put_unaligned(s->eh.h_proto, (__be16 *) __skb_put(nskb, 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 break;
370
371 case BNEP_COMPRESSED_DST_ONLY:
Arnaldo Carvalho de Melo98e399f2007-03-19 15:33:04 -0700372 memcpy(__skb_put(nskb, ETH_ALEN), skb_mac_header(skb),
373 ETH_ALEN);
374 memcpy(__skb_put(nskb, ETH_ALEN + 2), s->eh.h_source,
375 ETH_ALEN + 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 break;
377
378 case BNEP_GENERAL:
Arnaldo Carvalho de Melo98e399f2007-03-19 15:33:04 -0700379 memcpy(__skb_put(nskb, ETH_ALEN * 2), skb_mac_header(skb),
380 ETH_ALEN * 2);
Al Viro1bc5d442006-11-08 00:27:57 -0800381 put_unaligned(s->eh.h_proto, (__be16 *) __skb_put(nskb, 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 break;
383 }
384
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -0300385 skb_copy_from_linear_data(skb, __skb_put(nskb, skb->len), skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 kfree_skb(skb);
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900387
Stephen Hemmingerb4d7f0a2009-01-07 17:23:17 -0800388 dev->stats.rx_packets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 nskb->ip_summed = CHECKSUM_NONE;
390 nskb->protocol = eth_type_trans(nskb, dev);
391 netif_rx_ni(nskb);
392 return 0;
393
394badframe:
Stephen Hemmingerb4d7f0a2009-01-07 17:23:17 -0800395 dev->stats.rx_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 kfree_skb(skb);
397 return 0;
398}
399
400static u8 __bnep_tx_types[] = {
401 BNEP_GENERAL,
402 BNEP_COMPRESSED_SRC_ONLY,
403 BNEP_COMPRESSED_DST_ONLY,
404 BNEP_COMPRESSED
405};
406
407static inline int bnep_tx_frame(struct bnep_session *s, struct sk_buff *skb)
408{
409 struct ethhdr *eh = (void *) skb->data;
410 struct socket *sock = s->sock;
411 struct kvec iv[3];
412 int len = 0, il = 0;
413 u8 type = 0;
414
415 BT_DBG("skb %p dev %p type %d", skb, skb->dev, skb->pkt_type);
416
417 if (!skb->dev) {
418 /* Control frame sent by us */
419 goto send;
420 }
421
422 iv[il++] = (struct kvec) { &type, 1 };
423 len++;
424
Marcel Holtmann28111eb2008-08-07 22:26:54 +0200425 if (compress_src && !compare_ether_addr(eh->h_dest, s->eh.h_source))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 type |= 0x01;
427
Marcel Holtmann28111eb2008-08-07 22:26:54 +0200428 if (compress_dst && !compare_ether_addr(eh->h_source, s->eh.h_dest))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 type |= 0x02;
430
431 if (type)
432 skb_pull(skb, ETH_ALEN * 2);
433
434 type = __bnep_tx_types[type];
435 switch (type) {
436 case BNEP_COMPRESSED_SRC_ONLY:
437 iv[il++] = (struct kvec) { eh->h_source, ETH_ALEN };
438 len += ETH_ALEN;
439 break;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900440
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 case BNEP_COMPRESSED_DST_ONLY:
442 iv[il++] = (struct kvec) { eh->h_dest, ETH_ALEN };
443 len += ETH_ALEN;
444 break;
445 }
446
447send:
448 iv[il++] = (struct kvec) { skb->data, skb->len };
449 len += skb->len;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900450
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 /* FIXME: linearize skb */
452 {
453 len = kernel_sendmsg(sock, &s->msg, iv, il, len);
454 }
455 kfree_skb(skb);
456
457 if (len > 0) {
Stephen Hemmingerb4d7f0a2009-01-07 17:23:17 -0800458 s->dev->stats.tx_bytes += len;
459 s->dev->stats.tx_packets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 return 0;
461 }
462
463 return len;
464}
465
466static int bnep_session(void *arg)
467{
468 struct bnep_session *s = arg;
469 struct net_device *dev = s->dev;
470 struct sock *sk = s->sock->sk;
471 struct sk_buff *skb;
472 wait_queue_t wait;
473
474 BT_DBG("");
475
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900476 daemonize("kbnepd %s", dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 set_user_nice(current, -15);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478
479 init_waitqueue_entry(&wait, current);
Eric Dumazetaa395142010-04-20 13:03:51 +0000480 add_wait_queue(sk_sleep(sk), &wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 while (!atomic_read(&s->killed)) {
482 set_current_state(TASK_INTERRUPTIBLE);
483
484 // RX
485 while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
486 skb_orphan(skb);
487 bnep_rx_frame(s, skb);
488 }
489
490 if (sk->sk_state != BT_CONNECTED)
491 break;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900492
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 // TX
494 while ((skb = skb_dequeue(&sk->sk_write_queue)))
495 if (bnep_tx_frame(s, skb))
496 break;
497 netif_wake_queue(dev);
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900498
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 schedule();
500 }
501 set_current_state(TASK_RUNNING);
Eric Dumazetaa395142010-04-20 13:03:51 +0000502 remove_wait_queue(sk_sleep(sk), &wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503
504 /* Cleanup session */
505 down_write(&bnep_session_sem);
506
507 /* Delete network device */
508 unregister_netdev(dev);
509
Marcel Holtmannec8dab32008-07-14 20:13:53 +0200510 /* Wakeup user-space polling for socket errors */
511 s->sock->sk->sk_err = EUNATCH;
512
Eric Dumazetaa395142010-04-20 13:03:51 +0000513 wake_up_interruptible(sk_sleep(s->sock->sk));
Marcel Holtmannec8dab32008-07-14 20:13:53 +0200514
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 /* Release the socket */
516 fput(s->sock->file);
517
518 __bnep_unlink_session(s);
519
520 up_write(&bnep_session_sem);
521 free_netdev(dev);
522 return 0;
523}
524
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200525static struct device *bnep_get_device(struct bnep_session *session)
526{
527 bdaddr_t *src = &bt_sk(session->sock->sk)->src;
528 bdaddr_t *dst = &bt_sk(session->sock->sk)->dst;
529 struct hci_dev *hdev;
530 struct hci_conn *conn;
531
532 hdev = hci_get_route(dst, src);
533 if (!hdev)
534 return NULL;
535
536 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200537
538 hci_dev_put(hdev);
539
Marcel Holtmannb2cfcd72006-10-15 17:31:05 +0200540 return conn ? &conn->dev : NULL;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200541}
542
Marcel Holtmann384912e2009-08-31 21:08:19 +0000543static struct device_type bnep_type = {
544 .name = "bluetooth",
545};
546
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
548{
549 struct net_device *dev;
550 struct bnep_session *s, *ss;
551 u8 dst[ETH_ALEN], src[ETH_ALEN];
552 int err;
553
554 BT_DBG("");
555
556 baswap((void *) dst, &bt_sk(sock->sk)->dst);
557 baswap((void *) src, &bt_sk(sock->sk)->src);
558
559 /* session struct allocated as private part of net_device */
560 dev = alloc_netdev(sizeof(struct bnep_session),
561 (*req->device) ? req->device : "bnep%d",
562 bnep_net_setup);
Tobias Klauser67b52e52006-03-21 23:53:16 -0800563 if (!dev)
564 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 down_write(&bnep_session_sem);
567
568 ss = __bnep_get_session(dst);
569 if (ss && ss->state == BT_CONNECTED) {
570 err = -EEXIST;
571 goto failed;
572 }
573
Wang Chen524ad0a2008-11-12 23:39:10 -0800574 s = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575
576 /* This is rx header therefore addresses are swapped.
577 * ie eh.h_dest is our local address. */
578 memcpy(s->eh.h_dest, &src, ETH_ALEN);
579 memcpy(s->eh.h_source, &dst, ETH_ALEN);
580 memcpy(dev->dev_addr, s->eh.h_dest, ETH_ALEN);
581
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200582 s->dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 s->sock = sock;
584 s->role = req->role;
585 s->state = BT_CONNECTED;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900586
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 s->msg.msg_flags = MSG_NOSIGNAL;
588
589#ifdef CONFIG_BT_BNEP_MC_FILTER
590 /* Set default mc filter */
591 set_bit(bnep_mc_hash(dev->broadcast), (ulong *) &s->mc_filter);
592#endif
593
594#ifdef CONFIG_BT_BNEP_PROTO_FILTER
595 /* Set default protocol filter */
596 bnep_set_default_proto_filter(s);
597#endif
598
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200599 SET_NETDEV_DEV(dev, bnep_get_device(s));
Marcel Holtmann384912e2009-08-31 21:08:19 +0000600 SET_NETDEV_DEVTYPE(dev, &bnep_type);
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200601
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 err = register_netdev(dev);
603 if (err) {
604 goto failed;
605 }
606
607 __bnep_link_session(s);
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900608
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 err = kernel_thread(bnep_session, s, CLONE_KERNEL);
610 if (err < 0) {
611 /* Session thread start failed, gotta cleanup. */
612 unregister_netdev(dev);
613 __bnep_unlink_session(s);
614 goto failed;
615 }
616
617 up_write(&bnep_session_sem);
618 strcpy(req->device, dev->name);
619 return 0;
620
621failed:
622 up_write(&bnep_session_sem);
623 free_netdev(dev);
624 return err;
625}
626
627int bnep_del_connection(struct bnep_conndel_req *req)
628{
629 struct bnep_session *s;
630 int err = 0;
631
632 BT_DBG("");
633
634 down_read(&bnep_session_sem);
635
636 s = __bnep_get_session(req->dst);
637 if (s) {
638 /* Wakeup user-space which is polling for socket errors.
Thadeu Lima de Souza Cascardo94e2bd62009-10-16 15:20:49 +0200639 * This is temporary hack until we have shutdown in L2CAP */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 s->sock->sk->sk_err = EUNATCH;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900641
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 /* Kill session thread */
643 atomic_inc(&s->killed);
Eric Dumazetaa395142010-04-20 13:03:51 +0000644 wake_up_interruptible(sk_sleep(s->sock->sk));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 } else
646 err = -ENOENT;
647
648 up_read(&bnep_session_sem);
649 return err;
650}
651
652static void __bnep_copy_ci(struct bnep_conninfo *ci, struct bnep_session *s)
653{
Vasiliy Kulikov5520d202010-10-30 18:26:21 +0400654 memset(ci, 0, sizeof(*ci));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 memcpy(ci->dst, s->eh.h_source, ETH_ALEN);
656 strcpy(ci->device, s->dev->name);
657 ci->flags = s->flags;
658 ci->state = s->state;
659 ci->role = s->role;
660}
661
662int bnep_get_connlist(struct bnep_connlist_req *req)
663{
664 struct list_head *p;
665 int err = 0, n = 0;
666
667 down_read(&bnep_session_sem);
668
669 list_for_each(p, &bnep_session_list) {
670 struct bnep_session *s;
671 struct bnep_conninfo ci;
672
673 s = list_entry(p, struct bnep_session, list);
674
675 __bnep_copy_ci(&ci, s);
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900676
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 if (copy_to_user(req->ci, &ci, sizeof(ci))) {
678 err = -EFAULT;
679 break;
680 }
681
682 if (++n >= req->cnum)
683 break;
684
685 req->ci++;
686 }
687 req->cnum = n;
688
689 up_read(&bnep_session_sem);
690 return err;
691}
692
693int bnep_get_conninfo(struct bnep_conninfo *ci)
694{
695 struct bnep_session *s;
696 int err = 0;
697
698 down_read(&bnep_session_sem);
699
700 s = __bnep_get_session(ci->dst);
701 if (s)
702 __bnep_copy_ci(ci, s);
703 else
704 err = -ENOENT;
705
706 up_read(&bnep_session_sem);
707 return err;
708}
709
710static int __init bnep_init(void)
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900711{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 char flt[50] = "";
713
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714#ifdef CONFIG_BT_BNEP_PROTO_FILTER
715 strcat(flt, "protocol ");
716#endif
717
718#ifdef CONFIG_BT_BNEP_MC_FILTER
719 strcat(flt, "multicast");
720#endif
721
722 BT_INFO("BNEP (Ethernet Emulation) ver %s", VERSION);
723 if (flt[0])
724 BT_INFO("BNEP filters: %s", flt);
725
726 bnep_sock_init();
727 return 0;
728}
729
730static void __exit bnep_exit(void)
731{
732 bnep_sock_cleanup();
733}
734
735module_init(bnep_init);
736module_exit(bnep_exit);
737
Marcel Holtmann28111eb2008-08-07 22:26:54 +0200738module_param(compress_src, bool, 0644);
739MODULE_PARM_DESC(compress_src, "Compress sources headers");
740
741module_param(compress_dst, bool, 0644);
742MODULE_PARM_DESC(compress_dst, "Compress destination headers");
743
Marcel Holtmann63fbd242008-08-18 13:23:53 +0200744MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745MODULE_DESCRIPTION("Bluetooth BNEP ver " VERSION);
746MODULE_VERSION(VERSION);
747MODULE_LICENSE("GPL");
748MODULE_ALIAS("bt-proto-4");