]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - net/bluetooth/bnep/core.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[mirror_ubuntu-bionic-kernel.git] / net / bluetooth / bnep / core.c
CommitLineData
8e87d142 1/*
1da177e4
LT
2 BNEP implementation for Linux Bluetooth stack (BlueZ).
3 Copyright (C) 2001-2002 Inventel Systemes
4 Written 2001-2002 by
96de0e25 5 Clément Moreau <clement.moreau@inventel.fr>
1da177e4
LT
6 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
8e87d142
YH
18 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
1da177e4
LT
21 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
8e87d142
YH
23 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
24 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
1da177e4
LT
25 SOFTWARE IS DISCLAIMED.
26*/
27
1da177e4
LT
28#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>
83144186 35#include <linux/freezer.h>
1da177e4 36#include <linux/errno.h>
1da177e4 37#include <linux/net.h>
5a0e3ad6 38#include <linux/slab.h>
f4d7cd4a 39#include <linux/kthread.h>
1da177e4
LT
40#include <net/sock.h>
41
42#include <linux/socket.h>
43#include <linux/file.h>
44
45#include <linux/netdevice.h>
46#include <linux/etherdevice.h>
47#include <linux/skbuff.h>
48
49#include <asm/unaligned.h>
50
51#include <net/bluetooth/bluetooth.h>
0a85b964 52#include <net/bluetooth/hci_core.h>
1da177e4
LT
53#include <net/bluetooth/l2cap.h>
54
55#include "bnep.h"
56
28111eb2
MH
57#define VERSION "1.3"
58
eb939922
RR
59static bool compress_src = true;
60static bool compress_dst = true;
1da177e4
LT
61
62static LIST_HEAD(bnep_session_list);
63static DECLARE_RWSEM(bnep_session_sem);
64
65static struct bnep_session *__bnep_get_session(u8 *dst)
66{
67 struct bnep_session *s;
1da177e4
LT
68
69 BT_DBG("");
70
8035ded4 71 list_for_each_entry(s, &bnep_session_list, list)
d3f4a687 72 if (!compare_ether_addr(dst, s->eh.h_source))
1da177e4 73 return s;
8035ded4 74
1da177e4
LT
75 return NULL;
76}
77
78static void __bnep_link_session(struct bnep_session *s)
79{
8e87d142 80 list_add(&s->list, &bnep_session_list);
1da177e4
LT
81}
82
83static void __bnep_unlink_session(struct bnep_session *s)
84{
85 list_del(&s->list);
1da177e4
LT
86}
87
88static int bnep_send(struct bnep_session *s, void *data, size_t len)
89{
90 struct socket *sock = s->sock;
91 struct kvec iv = { data, len };
92
93 return kernel_sendmsg(sock, &s->msg, &iv, 1, len);
94}
95
96static int bnep_send_rsp(struct bnep_session *s, u8 ctrl, u16 resp)
97{
98 struct bnep_control_rsp rsp;
99 rsp.type = BNEP_CONTROL;
100 rsp.ctrl = ctrl;
101 rsp.resp = htons(resp);
102 return bnep_send(s, &rsp, sizeof(rsp));
103}
104
105#ifdef CONFIG_BT_BNEP_PROTO_FILTER
106static inline void bnep_set_default_proto_filter(struct bnep_session *s)
107{
108 /* (IPv4, ARP) */
e41d2169
AV
109 s->proto_filter[0].start = ETH_P_IP;
110 s->proto_filter[0].end = ETH_P_ARP;
1da177e4 111 /* (RARP, AppleTalk) */
e41d2169
AV
112 s->proto_filter[1].start = ETH_P_RARP;
113 s->proto_filter[1].end = ETH_P_AARP;
1da177e4 114 /* (IPX, IPv6) */
e41d2169
AV
115 s->proto_filter[2].start = ETH_P_IPX;
116 s->proto_filter[2].end = ETH_P_IPV6;
1da177e4
LT
117}
118#endif
119
1bc5d448 120static int bnep_ctrl_set_netfilter(struct bnep_session *s, __be16 *data, int len)
1da177e4
LT
121{
122 int n;
123
124 if (len < 2)
125 return -EILSEQ;
126
83985319 127 n = get_unaligned_be16(data);
3aad75a1
SJ
128 data++;
129 len -= 2;
1da177e4
LT
130
131 if (len < n)
132 return -EILSEQ;
133
134 BT_DBG("filter len %d", n);
135
136#ifdef CONFIG_BT_BNEP_PROTO_FILTER
137 n /= 4;
138 if (n <= BNEP_MAX_PROTO_FILTERS) {
139 struct bnep_proto_filter *f = s->proto_filter;
140 int i;
141
142 for (i = 0; i < n; i++) {
83985319
HH
143 f[i].start = get_unaligned_be16(data++);
144 f[i].end = get_unaligned_be16(data++);
1da177e4
LT
145
146 BT_DBG("proto filter start %d end %d",
147 f[i].start, f[i].end);
148 }
149
150 if (i < BNEP_MAX_PROTO_FILTERS)
151 memset(f + i, 0, sizeof(*f));
152
153 if (n == 0)
154 bnep_set_default_proto_filter(s);
155
156 bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_SUCCESS);
157 } else {
158 bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_LIMIT_REACHED);
159 }
160#else
161 bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_UNSUPPORTED_REQ);
162#endif
163 return 0;
164}
165
166static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len)
167{
168 int n;
169
170 if (len < 2)
171 return -EILSEQ;
172
83985319 173 n = get_unaligned_be16(data);
3aad75a1
SJ
174 data += 2;
175 len -= 2;
1da177e4
LT
176
177 if (len < n)
178 return -EILSEQ;
179
180 BT_DBG("filter len %d", n);
181
182#ifdef CONFIG_BT_BNEP_MC_FILTER
183 n /= (ETH_ALEN * 2);
184
185 if (n > 0) {
a3d9bd4c
SJ
186 int i;
187
1da177e4
LT
188 s->mc_filter = 0;
189
190 /* Always send broadcast */
191 set_bit(bnep_mc_hash(s->dev->broadcast), (ulong *) &s->mc_filter);
192
193 /* Add address ranges to the multicast hash */
194 for (; n > 0; n--) {
195 u8 a1[6], *a2;
196
3aad75a1
SJ
197 memcpy(a1, data, ETH_ALEN);
198 data += ETH_ALEN;
199 a2 = data;
200 data += ETH_ALEN;
8e87d142 201
1da177e4
LT
202 BT_DBG("mc filter %s -> %s",
203 batostr((void *) a1), batostr((void *) a2));
204
1da177e4
LT
205 /* Iterate from a1 to a2 */
206 set_bit(bnep_mc_hash(a1), (ulong *) &s->mc_filter);
207 while (memcmp(a1, a2, 6) < 0 && s->mc_filter != ~0LL) {
a3d9bd4c
SJ
208 /* Increment a1 */
209 i = 5;
210 while (i >= 0 && ++a1[i--] == 0)
211 ;
212
1da177e4
LT
213 set_bit(bnep_mc_hash(a1), (ulong *) &s->mc_filter);
214 }
215 }
216 }
217
218 BT_DBG("mc filter hash 0x%llx", s->mc_filter);
219
220 bnep_send_rsp(s, BNEP_FILTER_MULTI_ADDR_RSP, BNEP_SUCCESS);
221#else
222 bnep_send_rsp(s, BNEP_FILTER_MULTI_ADDR_RSP, BNEP_FILTER_UNSUPPORTED_REQ);
223#endif
224 return 0;
225}
226
227static int bnep_rx_control(struct bnep_session *s, void *data, int len)
228{
229 u8 cmd = *(u8 *)data;
230 int err = 0;
231
3aad75a1
SJ
232 data++;
233 len--;
1da177e4
LT
234
235 switch (cmd) {
236 case BNEP_CMD_NOT_UNDERSTOOD:
1da177e4
LT
237 case BNEP_SETUP_CONN_RSP:
238 case BNEP_FILTER_NET_TYPE_RSP:
239 case BNEP_FILTER_MULTI_ADDR_RSP:
240 /* Ignore these for now */
241 break;
242
243 case BNEP_FILTER_NET_TYPE_SET:
244 err = bnep_ctrl_set_netfilter(s, data, len);
245 break;
246
247 case BNEP_FILTER_MULTI_ADDR_SET:
248 err = bnep_ctrl_set_mcfilter(s, data, len);
249 break;
250
cde9f807
VK
251 case BNEP_SETUP_CONN_REQ:
252 err = bnep_send_rsp(s, BNEP_SETUP_CONN_RSP, BNEP_CONN_NOT_ALLOWED);
253 break;
254
1da177e4
LT
255 default: {
256 u8 pkt[3];
257 pkt[0] = BNEP_CONTROL;
258 pkt[1] = BNEP_CMD_NOT_UNDERSTOOD;
259 pkt[2] = cmd;
260 bnep_send(s, pkt, sizeof(pkt));
261 }
262 break;
263 }
264
265 return err;
266}
267
268static int bnep_rx_extension(struct bnep_session *s, struct sk_buff *skb)
269{
270 struct bnep_ext_hdr *h;
271 int err = 0;
272
273 do {
274 h = (void *) skb->data;
275 if (!skb_pull(skb, sizeof(*h))) {
276 err = -EILSEQ;
277 break;
278 }
279
280 BT_DBG("type 0x%x len %d", h->type, h->len);
8e87d142 281
1da177e4
LT
282 switch (h->type & BNEP_TYPE_MASK) {
283 case BNEP_EXT_CONTROL:
284 bnep_rx_control(s, skb->data, skb->len);
285 break;
286
287 default:
288 /* Unknown extension, skip it. */
289 break;
290 }
291
292 if (!skb_pull(skb, h->len)) {
293 err = -EILSEQ;
294 break;
295 }
296 } while (!err && (h->type & BNEP_EXT_HEADER));
8e87d142 297
1da177e4
LT
298 return err;
299}
300
301static u8 __bnep_rx_hlen[] = {
302 ETH_HLEN, /* BNEP_GENERAL */
303 0, /* BNEP_CONTROL */
304 2, /* BNEP_COMPRESSED */
305 ETH_ALEN + 2, /* BNEP_COMPRESSED_SRC_ONLY */
306 ETH_ALEN + 2 /* BNEP_COMPRESSED_DST_ONLY */
307};
1da177e4
LT
308
309static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
310{
311 struct net_device *dev = s->dev;
312 struct sk_buff *nskb;
313 u8 type;
314
b4d7f0a4 315 dev->stats.rx_bytes += skb->len;
1da177e4 316
3aad75a1
SJ
317 type = *(u8 *) skb->data;
318 skb_pull(skb, 1);
1da177e4 319
a3d9bd4c 320 if ((type & BNEP_TYPE_MASK) >= sizeof(__bnep_rx_hlen))
1da177e4 321 goto badframe;
8e87d142 322
1da177e4
LT
323 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
459a98ed 329 skb_reset_mac_header(skb);
1da177e4
LT
330
331 /* Verify and pull out header */
332 if (!skb_pull(skb, __bnep_rx_hlen[type & BNEP_TYPE_MASK]))
333 goto badframe;
334
1bc5d448 335 s->eh.h_proto = get_unaligned((__be16 *) (skb->data - 2));
1da177e4
LT
336
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;
1bc5d448 346 s->eh.h_proto = get_unaligned((__be16 *) (skb->data - 2));
1da177e4 347 }
8e87d142 348
1da177e4
LT
349 /* 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) {
b4d7f0a4 353 dev->stats.rx_dropped++;
1da177e4
LT
354 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;
8e87d142 364
1da177e4
LT
365 case BNEP_COMPRESSED_SRC_ONLY:
366 memcpy(__skb_put(nskb, ETH_ALEN), s->eh.h_dest, ETH_ALEN);
98e399f8 367 memcpy(__skb_put(nskb, ETH_ALEN), skb_mac_header(skb), ETH_ALEN);
1bc5d448 368 put_unaligned(s->eh.h_proto, (__be16 *) __skb_put(nskb, 2));
1da177e4
LT
369 break;
370
371 case BNEP_COMPRESSED_DST_ONLY:
98e399f8 372 memcpy(__skb_put(nskb, ETH_ALEN), skb_mac_header(skb),
3aad75a1 373 ETH_ALEN);
98e399f8 374 memcpy(__skb_put(nskb, ETH_ALEN + 2), s->eh.h_source,
3aad75a1 375 ETH_ALEN + 2);
1da177e4
LT
376 break;
377
378 case BNEP_GENERAL:
98e399f8 379 memcpy(__skb_put(nskb, ETH_ALEN * 2), skb_mac_header(skb),
3aad75a1 380 ETH_ALEN * 2);
1bc5d448 381 put_unaligned(s->eh.h_proto, (__be16 *) __skb_put(nskb, 2));
1da177e4
LT
382 break;
383 }
384
d626f62b 385 skb_copy_from_linear_data(skb, __skb_put(nskb, skb->len), skb->len);
1da177e4 386 kfree_skb(skb);
8e87d142 387
b4d7f0a4 388 dev->stats.rx_packets++;
1da177e4
LT
389 nskb->ip_summed = CHECKSUM_NONE;
390 nskb->protocol = eth_type_trans(nskb, dev);
391 netif_rx_ni(nskb);
392 return 0;
393
394badframe:
b4d7f0a4 395 dev->stats.rx_errors++;
1da177e4
LT
396 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
28111eb2 425 if (compress_src && !compare_ether_addr(eh->h_dest, s->eh.h_source))
1da177e4
LT
426 type |= 0x01;
427
28111eb2 428 if (compress_dst && !compare_ether_addr(eh->h_source, s->eh.h_dest))
1da177e4
LT
429 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;
8e87d142 440
1da177e4
LT
441 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;
8e87d142 450
1da177e4
LT
451 /* FIXME: linearize skb */
452 {
453 len = kernel_sendmsg(sock, &s->msg, iv, il, len);
454 }
455 kfree_skb(skb);
456
457 if (len > 0) {
b4d7f0a4
SH
458 s->dev->stats.tx_bytes += len;
459 s->dev->stats.tx_packets++;
1da177e4
LT
460 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
1da177e4 476 set_user_nice(current, -15);
1da177e4
LT
477
478 init_waitqueue_entry(&wait, current);
aa395145 479 add_wait_queue(sk_sleep(sk), &wait);
38d57555 480 while (1) {
1da177e4
LT
481 set_current_state(TASK_INTERRUPTIBLE);
482
751c10a5 483 if (atomic_read(&s->terminate))
38d57555 484 break;
3aad75a1 485 /* RX */
1da177e4
LT
486 while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
487 skb_orphan(skb);
44935720
MM
488 if (!skb_linearize(skb))
489 bnep_rx_frame(s, skb);
490 else
491 kfree_skb(skb);
1da177e4
LT
492 }
493
494 if (sk->sk_state != BT_CONNECTED)
495 break;
8e87d142 496
3aad75a1 497 /* TX */
1da177e4
LT
498 while ((skb = skb_dequeue(&sk->sk_write_queue)))
499 if (bnep_tx_frame(s, skb))
500 break;
501 netif_wake_queue(dev);
8e87d142 502
1da177e4
LT
503 schedule();
504 }
38d57555 505 __set_current_state(TASK_RUNNING);
aa395145 506 remove_wait_queue(sk_sleep(sk), &wait);
1da177e4
LT
507
508 /* Cleanup session */
509 down_write(&bnep_session_sem);
510
511 /* Delete network device */
512 unregister_netdev(dev);
513
ec8dab36
MH
514 /* Wakeup user-space polling for socket errors */
515 s->sock->sk->sk_err = EUNATCH;
516
aa395145 517 wake_up_interruptible(sk_sleep(s->sock->sk));
ec8dab36 518
1da177e4
LT
519 /* Release the socket */
520 fput(s->sock->file);
521
522 __bnep_unlink_session(s);
523
524 up_write(&bnep_session_sem);
525 free_netdev(dev);
9b338c3d 526 module_put_and_exit(0);
1da177e4
LT
527 return 0;
528}
529
0a85b964
MH
530static struct device *bnep_get_device(struct bnep_session *session)
531{
532 bdaddr_t *src = &bt_sk(session->sock->sk)->src;
533 bdaddr_t *dst = &bt_sk(session->sock->sk)->dst;
534 struct hci_dev *hdev;
535 struct hci_conn *conn;
536
537 hdev = hci_get_route(dst, src);
538 if (!hdev)
539 return NULL;
540
541 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
0a85b964
MH
542
543 hci_dev_put(hdev);
544
b2cfcd75 545 return conn ? &conn->dev : NULL;
0a85b964
MH
546}
547
384912ed
MH
548static struct device_type bnep_type = {
549 .name = "bluetooth",
550};
551
1da177e4
LT
552int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
553{
554 struct net_device *dev;
555 struct bnep_session *s, *ss;
556 u8 dst[ETH_ALEN], src[ETH_ALEN];
557 int err;
558
559 BT_DBG("");
560
561 baswap((void *) dst, &bt_sk(sock->sk)->dst);
562 baswap((void *) src, &bt_sk(sock->sk)->src);
563
564 /* session struct allocated as private part of net_device */
565 dev = alloc_netdev(sizeof(struct bnep_session),
3aad75a1
SJ
566 (*req->device) ? req->device : "bnep%d",
567 bnep_net_setup);
67b52e55
TK
568 if (!dev)
569 return -ENOMEM;
1da177e4 570
1da177e4
LT
571 down_write(&bnep_session_sem);
572
573 ss = __bnep_get_session(dst);
574 if (ss && ss->state == BT_CONNECTED) {
575 err = -EEXIST;
576 goto failed;
577 }
578
524ad0a7 579 s = netdev_priv(dev);
1da177e4
LT
580
581 /* This is rx header therefore addresses are swapped.
3aad75a1 582 * ie. eh.h_dest is our local address. */
1da177e4
LT
583 memcpy(s->eh.h_dest, &src, ETH_ALEN);
584 memcpy(s->eh.h_source, &dst, ETH_ALEN);
585 memcpy(dev->dev_addr, s->eh.h_dest, ETH_ALEN);
586
0a85b964 587 s->dev = dev;
1da177e4
LT
588 s->sock = sock;
589 s->role = req->role;
590 s->state = BT_CONNECTED;
8e87d142 591
1da177e4
LT
592 s->msg.msg_flags = MSG_NOSIGNAL;
593
594#ifdef CONFIG_BT_BNEP_MC_FILTER
595 /* Set default mc filter */
596 set_bit(bnep_mc_hash(dev->broadcast), (ulong *) &s->mc_filter);
597#endif
598
599#ifdef CONFIG_BT_BNEP_PROTO_FILTER
600 /* Set default protocol filter */
601 bnep_set_default_proto_filter(s);
602#endif
603
0a85b964 604 SET_NETDEV_DEV(dev, bnep_get_device(s));
384912ed 605 SET_NETDEV_DEVTYPE(dev, &bnep_type);
0a85b964 606
1da177e4 607 err = register_netdev(dev);
3aad75a1 608 if (err)
1da177e4 609 goto failed;
1da177e4
LT
610
611 __bnep_link_session(s);
8e87d142 612
9b338c3d 613 __module_get(THIS_MODULE);
f4d7cd4a
SJ
614 s->task = kthread_run(bnep_session, s, "kbnepd %s", dev->name);
615 if (IS_ERR(s->task)) {
1da177e4 616 /* Session thread start failed, gotta cleanup. */
9b338c3d 617 module_put(THIS_MODULE);
1da177e4
LT
618 unregister_netdev(dev);
619 __bnep_unlink_session(s);
f4d7cd4a 620 err = PTR_ERR(s->task);
1da177e4
LT
621 goto failed;
622 }
623
624 up_write(&bnep_session_sem);
625 strcpy(req->device, dev->name);
626 return 0;
627
628failed:
629 up_write(&bnep_session_sem);
630 free_netdev(dev);
631 return err;
632}
633
634int bnep_del_connection(struct bnep_conndel_req *req)
635{
636 struct bnep_session *s;
637 int err = 0;
638
639 BT_DBG("");
640
641 down_read(&bnep_session_sem);
642
643 s = __bnep_get_session(req->dst);
751c10a5
PH
644 if (s) {
645 atomic_inc(&s->terminate);
646 wake_up_process(s->task);
647 } else
1da177e4
LT
648 err = -ENOENT;
649
650 up_read(&bnep_session_sem);
651 return err;
652}
653
654static void __bnep_copy_ci(struct bnep_conninfo *ci, struct bnep_session *s)
655{
5520d20f 656 memset(ci, 0, sizeof(*ci));
1da177e4
LT
657 memcpy(ci->dst, s->eh.h_source, ETH_ALEN);
658 strcpy(ci->device, s->dev->name);
659 ci->flags = s->flags;
660 ci->state = s->state;
661 ci->role = s->role;
662}
663
664int bnep_get_connlist(struct bnep_connlist_req *req)
665{
8035ded4 666 struct bnep_session *s;
1da177e4
LT
667 int err = 0, n = 0;
668
669 down_read(&bnep_session_sem);
670
8035ded4 671 list_for_each_entry(s, &bnep_session_list, list) {
1da177e4
LT
672 struct bnep_conninfo ci;
673
1da177e4 674 __bnep_copy_ci(&ci, s);
8e87d142 675
1da177e4
LT
676 if (copy_to_user(req->ci, &ci, sizeof(ci))) {
677 err = -EFAULT;
678 break;
679 }
680
681 if (++n >= req->cnum)
682 break;
683
684 req->ci++;
685 }
686 req->cnum = n;
687
688 up_read(&bnep_session_sem);
689 return err;
690}
691
692int bnep_get_conninfo(struct bnep_conninfo *ci)
693{
694 struct bnep_session *s;
695 int err = 0;
696
697 down_read(&bnep_session_sem);
698
699 s = __bnep_get_session(ci->dst);
700 if (s)
701 __bnep_copy_ci(ci, s);
702 else
703 err = -ENOENT;
704
705 up_read(&bnep_session_sem);
706 return err;
707}
708
709static int __init bnep_init(void)
8e87d142 710{
1da177e4
LT
711 char flt[50] = "";
712
1da177e4
LT
713#ifdef CONFIG_BT_BNEP_PROTO_FILTER
714 strcat(flt, "protocol ");
715#endif
716
717#ifdef CONFIG_BT_BNEP_MC_FILTER
718 strcat(flt, "multicast");
719#endif
720
721 BT_INFO("BNEP (Ethernet Emulation) ver %s", VERSION);
722 if (flt[0])
723 BT_INFO("BNEP filters: %s", flt);
724
725 bnep_sock_init();
726 return 0;
727}
728
729static void __exit bnep_exit(void)
730{
731 bnep_sock_cleanup();
732}
733
734module_init(bnep_init);
735module_exit(bnep_exit);
736
28111eb2
MH
737module_param(compress_src, bool, 0644);
738MODULE_PARM_DESC(compress_src, "Compress sources headers");
739
740module_param(compress_dst, bool, 0644);
741MODULE_PARM_DESC(compress_dst, "Compress destination headers");
742
63fbd24e 743MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
1da177e4
LT
744MODULE_DESCRIPTION("Bluetooth BNEP ver " VERSION);
745MODULE_VERSION(VERSION);
746MODULE_LICENSE("GPL");
747MODULE_ALIAS("bt-proto-4");