Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/net/bluetooth/bnep/core.c
26285 views
1
/*
2
BNEP implementation for Linux Bluetooth stack (BlueZ).
3
Copyright (C) 2001-2002 Inventel Systemes
4
Written 2001-2002 by
5
ClĂ©ment Moreau <[email protected]>
6
David Libault <[email protected]>
7
8
Copyright (C) 2002 Maxim Krasnyansky <[email protected]>
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
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
21
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
23
ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
24
COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
25
SOFTWARE IS DISCLAIMED.
26
*/
27
28
#include <linux/module.h>
29
#include <linux/kthread.h>
30
#include <linux/file.h>
31
#include <linux/etherdevice.h>
32
#include <linux/unaligned.h>
33
34
#include <net/bluetooth/bluetooth.h>
35
#include <net/bluetooth/l2cap.h>
36
#include <net/bluetooth/hci_core.h>
37
38
#include "bnep.h"
39
40
#define VERSION "1.3"
41
42
static bool compress_src = true;
43
static bool compress_dst = true;
44
45
static LIST_HEAD(bnep_session_list);
46
static DECLARE_RWSEM(bnep_session_sem);
47
48
static struct bnep_session *__bnep_get_session(u8 *dst)
49
{
50
struct bnep_session *s;
51
52
BT_DBG("");
53
54
list_for_each_entry(s, &bnep_session_list, list)
55
if (ether_addr_equal(dst, s->eh.h_source))
56
return s;
57
58
return NULL;
59
}
60
61
static void __bnep_link_session(struct bnep_session *s)
62
{
63
list_add(&s->list, &bnep_session_list);
64
}
65
66
static void __bnep_unlink_session(struct bnep_session *s)
67
{
68
list_del(&s->list);
69
}
70
71
static int bnep_send(struct bnep_session *s, void *data, size_t len)
72
{
73
struct socket *sock = s->sock;
74
struct kvec iv = { data, len };
75
76
return kernel_sendmsg(sock, &s->msg, &iv, 1, len);
77
}
78
79
static int bnep_send_rsp(struct bnep_session *s, u8 ctrl, u16 resp)
80
{
81
struct bnep_control_rsp rsp;
82
rsp.type = BNEP_CONTROL;
83
rsp.ctrl = ctrl;
84
rsp.resp = htons(resp);
85
return bnep_send(s, &rsp, sizeof(rsp));
86
}
87
88
#ifdef CONFIG_BT_BNEP_PROTO_FILTER
89
static inline void bnep_set_default_proto_filter(struct bnep_session *s)
90
{
91
/* (IPv4, ARP) */
92
s->proto_filter[0].start = ETH_P_IP;
93
s->proto_filter[0].end = ETH_P_ARP;
94
/* (RARP, AppleTalk) */
95
s->proto_filter[1].start = ETH_P_RARP;
96
s->proto_filter[1].end = ETH_P_AARP;
97
/* (IPX, IPv6) */
98
s->proto_filter[2].start = ETH_P_IPX;
99
s->proto_filter[2].end = ETH_P_IPV6;
100
}
101
#endif
102
103
static int bnep_ctrl_set_netfilter(struct bnep_session *s, __be16 *data, int len)
104
{
105
int n;
106
107
if (len < 2)
108
return -EILSEQ;
109
110
n = get_unaligned_be16(data);
111
data++;
112
len -= 2;
113
114
if (len < n)
115
return -EILSEQ;
116
117
BT_DBG("filter len %d", n);
118
119
#ifdef CONFIG_BT_BNEP_PROTO_FILTER
120
n /= 4;
121
if (n <= BNEP_MAX_PROTO_FILTERS) {
122
struct bnep_proto_filter *f = s->proto_filter;
123
int i;
124
125
for (i = 0; i < n; i++) {
126
f[i].start = get_unaligned_be16(data++);
127
f[i].end = get_unaligned_be16(data++);
128
129
BT_DBG("proto filter start %u end %u",
130
f[i].start, f[i].end);
131
}
132
133
if (i < BNEP_MAX_PROTO_FILTERS)
134
memset(f + i, 0, sizeof(*f));
135
136
if (n == 0)
137
bnep_set_default_proto_filter(s);
138
139
bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_SUCCESS);
140
} else {
141
bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_LIMIT_REACHED);
142
}
143
#else
144
bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_UNSUPPORTED_REQ);
145
#endif
146
return 0;
147
}
148
149
static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len)
150
{
151
int n;
152
153
if (len < 2)
154
return -EILSEQ;
155
156
n = get_unaligned_be16(data);
157
data += 2;
158
len -= 2;
159
160
if (len < n)
161
return -EILSEQ;
162
163
BT_DBG("filter len %d", n);
164
165
#ifdef CONFIG_BT_BNEP_MC_FILTER
166
n /= (ETH_ALEN * 2);
167
168
if (n > 0) {
169
int i;
170
171
s->mc_filter = 0;
172
173
/* Always send broadcast */
174
set_bit(bnep_mc_hash(s->dev->broadcast), (ulong *) &s->mc_filter);
175
176
/* Add address ranges to the multicast hash */
177
for (; n > 0; n--) {
178
u8 a1[6], *a2;
179
180
memcpy(a1, data, ETH_ALEN);
181
data += ETH_ALEN;
182
a2 = data;
183
data += ETH_ALEN;
184
185
BT_DBG("mc filter %pMR -> %pMR", a1, a2);
186
187
/* Iterate from a1 to a2 */
188
set_bit(bnep_mc_hash(a1), (ulong *) &s->mc_filter);
189
while (memcmp(a1, a2, 6) < 0 && s->mc_filter != ~0LL) {
190
/* Increment a1 */
191
i = 5;
192
while (i >= 0 && ++a1[i--] == 0)
193
;
194
195
set_bit(bnep_mc_hash(a1), (ulong *) &s->mc_filter);
196
}
197
}
198
}
199
200
BT_DBG("mc filter hash 0x%llx", s->mc_filter);
201
202
bnep_send_rsp(s, BNEP_FILTER_MULTI_ADDR_RSP, BNEP_SUCCESS);
203
#else
204
bnep_send_rsp(s, BNEP_FILTER_MULTI_ADDR_RSP, BNEP_FILTER_UNSUPPORTED_REQ);
205
#endif
206
return 0;
207
}
208
209
static int bnep_rx_control(struct bnep_session *s, void *data, int len)
210
{
211
u8 cmd = *(u8 *)data;
212
int err = 0;
213
214
data++;
215
len--;
216
217
switch (cmd) {
218
case BNEP_CMD_NOT_UNDERSTOOD:
219
case BNEP_SETUP_CONN_RSP:
220
case BNEP_FILTER_NET_TYPE_RSP:
221
case BNEP_FILTER_MULTI_ADDR_RSP:
222
/* Ignore these for now */
223
break;
224
225
case BNEP_FILTER_NET_TYPE_SET:
226
err = bnep_ctrl_set_netfilter(s, data, len);
227
break;
228
229
case BNEP_FILTER_MULTI_ADDR_SET:
230
err = bnep_ctrl_set_mcfilter(s, data, len);
231
break;
232
233
case BNEP_SETUP_CONN_REQ:
234
/* Successful response should be sent only once */
235
if (test_bit(BNEP_SETUP_RESPONSE, &s->flags) &&
236
!test_and_set_bit(BNEP_SETUP_RSP_SENT, &s->flags))
237
err = bnep_send_rsp(s, BNEP_SETUP_CONN_RSP,
238
BNEP_SUCCESS);
239
else
240
err = bnep_send_rsp(s, BNEP_SETUP_CONN_RSP,
241
BNEP_CONN_NOT_ALLOWED);
242
break;
243
244
default: {
245
u8 pkt[3];
246
pkt[0] = BNEP_CONTROL;
247
pkt[1] = BNEP_CMD_NOT_UNDERSTOOD;
248
pkt[2] = cmd;
249
err = bnep_send(s, pkt, sizeof(pkt));
250
}
251
break;
252
}
253
254
return err;
255
}
256
257
static int bnep_rx_extension(struct bnep_session *s, struct sk_buff *skb)
258
{
259
struct bnep_ext_hdr *h;
260
int err = 0;
261
262
do {
263
h = (void *) skb->data;
264
if (!skb_pull(skb, sizeof(*h))) {
265
err = -EILSEQ;
266
break;
267
}
268
269
BT_DBG("type 0x%x len %u", h->type, h->len);
270
271
switch (h->type & BNEP_TYPE_MASK) {
272
case BNEP_EXT_CONTROL:
273
bnep_rx_control(s, skb->data, skb->len);
274
break;
275
276
default:
277
/* Unknown extension, skip it. */
278
break;
279
}
280
281
if (!skb_pull(skb, h->len)) {
282
err = -EILSEQ;
283
break;
284
}
285
} while (!err && (h->type & BNEP_EXT_HEADER));
286
287
return err;
288
}
289
290
static u8 __bnep_rx_hlen[] = {
291
ETH_HLEN, /* BNEP_GENERAL */
292
0, /* BNEP_CONTROL */
293
2, /* BNEP_COMPRESSED */
294
ETH_ALEN + 2, /* BNEP_COMPRESSED_SRC_ONLY */
295
ETH_ALEN + 2 /* BNEP_COMPRESSED_DST_ONLY */
296
};
297
298
static int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
299
{
300
struct net_device *dev = s->dev;
301
struct sk_buff *nskb;
302
u8 type, ctrl_type;
303
304
dev->stats.rx_bytes += skb->len;
305
306
type = *(u8 *) skb->data;
307
skb_pull(skb, 1);
308
ctrl_type = *(u8 *)skb->data;
309
310
if ((type & BNEP_TYPE_MASK) >= sizeof(__bnep_rx_hlen))
311
goto badframe;
312
313
if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) {
314
if (bnep_rx_control(s, skb->data, skb->len) < 0) {
315
dev->stats.tx_errors++;
316
kfree_skb(skb);
317
return 0;
318
}
319
320
if (!(type & BNEP_EXT_HEADER)) {
321
kfree_skb(skb);
322
return 0;
323
}
324
325
/* Verify and pull ctrl message since it's already processed */
326
switch (ctrl_type) {
327
case BNEP_SETUP_CONN_REQ:
328
/* Pull: ctrl type (1 b), len (1 b), data (len bytes) */
329
if (!skb_pull(skb, 2 + *(u8 *)(skb->data + 1) * 2))
330
goto badframe;
331
break;
332
case BNEP_FILTER_MULTI_ADDR_SET:
333
case BNEP_FILTER_NET_TYPE_SET:
334
/* Pull: ctrl type (1 b), len (2 b), data (len bytes) */
335
if (!skb_pull(skb, 3 + *(u16 *)(skb->data + 1) * 2))
336
goto badframe;
337
break;
338
default:
339
kfree_skb(skb);
340
return 0;
341
}
342
} else {
343
skb_reset_mac_header(skb);
344
345
/* Verify and pull out header */
346
if (!skb_pull(skb, __bnep_rx_hlen[type & BNEP_TYPE_MASK]))
347
goto badframe;
348
349
s->eh.h_proto = get_unaligned((__be16 *) (skb->data - 2));
350
}
351
352
if (type & BNEP_EXT_HEADER) {
353
if (bnep_rx_extension(s, skb) < 0)
354
goto badframe;
355
}
356
357
/* Strip 802.1p header */
358
if (ntohs(s->eh.h_proto) == ETH_P_8021Q) {
359
if (!skb_pull(skb, 4))
360
goto badframe;
361
s->eh.h_proto = get_unaligned((__be16 *) (skb->data - 2));
362
}
363
364
/* We have to alloc new skb and copy data here :(. Because original skb
365
* may not be modified and because of the alignment requirements. */
366
nskb = alloc_skb(2 + ETH_HLEN + skb->len, GFP_KERNEL);
367
if (!nskb) {
368
dev->stats.rx_dropped++;
369
kfree_skb(skb);
370
return -ENOMEM;
371
}
372
skb_reserve(nskb, 2);
373
374
/* Decompress header and construct ether frame */
375
switch (type & BNEP_TYPE_MASK) {
376
case BNEP_COMPRESSED:
377
__skb_put_data(nskb, &s->eh, ETH_HLEN);
378
break;
379
380
case BNEP_COMPRESSED_SRC_ONLY:
381
__skb_put_data(nskb, s->eh.h_dest, ETH_ALEN);
382
__skb_put_data(nskb, skb_mac_header(skb), ETH_ALEN);
383
put_unaligned(s->eh.h_proto, (__be16 *) __skb_put(nskb, 2));
384
break;
385
386
case BNEP_COMPRESSED_DST_ONLY:
387
__skb_put_data(nskb, skb_mac_header(skb), ETH_ALEN);
388
__skb_put_data(nskb, s->eh.h_source, ETH_ALEN);
389
put_unaligned(s->eh.h_proto, (__be16 *)__skb_put(nskb, 2));
390
break;
391
392
case BNEP_GENERAL:
393
__skb_put_data(nskb, skb_mac_header(skb), ETH_ALEN * 2);
394
put_unaligned(s->eh.h_proto, (__be16 *) __skb_put(nskb, 2));
395
break;
396
}
397
398
skb_copy_from_linear_data(skb, __skb_put(nskb, skb->len), skb->len);
399
kfree_skb(skb);
400
401
dev->stats.rx_packets++;
402
nskb->ip_summed = CHECKSUM_NONE;
403
nskb->protocol = eth_type_trans(nskb, dev);
404
netif_rx(nskb);
405
return 0;
406
407
badframe:
408
dev->stats.rx_errors++;
409
kfree_skb(skb);
410
return 0;
411
}
412
413
static u8 __bnep_tx_types[] = {
414
BNEP_GENERAL,
415
BNEP_COMPRESSED_SRC_ONLY,
416
BNEP_COMPRESSED_DST_ONLY,
417
BNEP_COMPRESSED
418
};
419
420
static int bnep_tx_frame(struct bnep_session *s, struct sk_buff *skb)
421
{
422
struct ethhdr *eh = (void *) skb->data;
423
struct socket *sock = s->sock;
424
struct kvec iv[3];
425
int len = 0, il = 0;
426
u8 type = 0;
427
428
BT_DBG("skb %p dev %p type %u", skb, skb->dev, skb->pkt_type);
429
430
if (!skb->dev) {
431
/* Control frame sent by us */
432
goto send;
433
}
434
435
iv[il++] = (struct kvec) { &type, 1 };
436
len++;
437
438
if (compress_src && ether_addr_equal(eh->h_dest, s->eh.h_source))
439
type |= 0x01;
440
441
if (compress_dst && ether_addr_equal(eh->h_source, s->eh.h_dest))
442
type |= 0x02;
443
444
if (type)
445
skb_pull(skb, ETH_ALEN * 2);
446
447
type = __bnep_tx_types[type];
448
switch (type) {
449
case BNEP_COMPRESSED_SRC_ONLY:
450
iv[il++] = (struct kvec) { eh->h_source, ETH_ALEN };
451
len += ETH_ALEN;
452
break;
453
454
case BNEP_COMPRESSED_DST_ONLY:
455
iv[il++] = (struct kvec) { eh->h_dest, ETH_ALEN };
456
len += ETH_ALEN;
457
break;
458
}
459
460
send:
461
iv[il++] = (struct kvec) { skb->data, skb->len };
462
len += skb->len;
463
464
/* FIXME: linearize skb */
465
{
466
len = kernel_sendmsg(sock, &s->msg, iv, il, len);
467
}
468
kfree_skb(skb);
469
470
if (len > 0) {
471
s->dev->stats.tx_bytes += len;
472
s->dev->stats.tx_packets++;
473
return 0;
474
}
475
476
return len;
477
}
478
479
static int bnep_session(void *arg)
480
{
481
struct bnep_session *s = arg;
482
struct net_device *dev = s->dev;
483
struct sock *sk = s->sock->sk;
484
struct sk_buff *skb;
485
DEFINE_WAIT_FUNC(wait, woken_wake_function);
486
487
BT_DBG("");
488
489
set_user_nice(current, -15);
490
491
add_wait_queue(sk_sleep(sk), &wait);
492
while (1) {
493
if (atomic_read(&s->terminate))
494
break;
495
/* RX */
496
while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
497
skb_orphan(skb);
498
if (!skb_linearize(skb))
499
bnep_rx_frame(s, skb);
500
else
501
kfree_skb(skb);
502
}
503
504
if (sk->sk_state != BT_CONNECTED)
505
break;
506
507
/* TX */
508
while ((skb = skb_dequeue(&sk->sk_write_queue)))
509
if (bnep_tx_frame(s, skb))
510
break;
511
netif_wake_queue(dev);
512
513
/*
514
* wait_woken() performs the necessary memory barriers
515
* for us; see the header comment for this primitive.
516
*/
517
wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
518
}
519
remove_wait_queue(sk_sleep(sk), &wait);
520
521
/* Cleanup session */
522
down_write(&bnep_session_sem);
523
524
/* Delete network device */
525
unregister_netdev(dev);
526
527
/* Wakeup user-space polling for socket errors */
528
s->sock->sk->sk_err = EUNATCH;
529
530
wake_up_interruptible(sk_sleep(s->sock->sk));
531
532
/* Release the socket */
533
fput(s->sock->file);
534
535
__bnep_unlink_session(s);
536
537
up_write(&bnep_session_sem);
538
free_netdev(dev);
539
module_put_and_kthread_exit(0);
540
return 0;
541
}
542
543
static struct device *bnep_get_device(struct bnep_session *session)
544
{
545
struct l2cap_conn *conn = l2cap_pi(session->sock->sk)->chan->conn;
546
547
if (!conn || !conn->hcon)
548
return NULL;
549
550
return &conn->hcon->dev;
551
}
552
553
static const struct device_type bnep_type = {
554
.name = "bluetooth",
555
};
556
557
int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
558
{
559
u32 valid_flags = BIT(BNEP_SETUP_RESPONSE);
560
struct net_device *dev;
561
struct bnep_session *s, *ss;
562
u8 dst[ETH_ALEN], src[ETH_ALEN];
563
int err;
564
565
BT_DBG("");
566
567
if (!l2cap_is_socket(sock))
568
return -EBADFD;
569
570
if (req->flags & ~valid_flags)
571
return -EINVAL;
572
573
baswap((void *) dst, &l2cap_pi(sock->sk)->chan->dst);
574
baswap((void *) src, &l2cap_pi(sock->sk)->chan->src);
575
576
/* session struct allocated as private part of net_device */
577
dev = alloc_netdev(sizeof(struct bnep_session),
578
(*req->device) ? req->device : "bnep%d",
579
NET_NAME_UNKNOWN,
580
bnep_net_setup);
581
if (!dev)
582
return -ENOMEM;
583
584
down_write(&bnep_session_sem);
585
586
ss = __bnep_get_session(dst);
587
if (ss && ss->state == BT_CONNECTED) {
588
err = -EEXIST;
589
goto failed;
590
}
591
592
s = netdev_priv(dev);
593
594
/* This is rx header therefore addresses are swapped.
595
* ie. eh.h_dest is our local address. */
596
memcpy(s->eh.h_dest, &src, ETH_ALEN);
597
memcpy(s->eh.h_source, &dst, ETH_ALEN);
598
eth_hw_addr_set(dev, s->eh.h_dest);
599
600
s->dev = dev;
601
s->sock = sock;
602
s->role = req->role;
603
s->state = BT_CONNECTED;
604
s->flags = req->flags;
605
606
s->msg.msg_flags = MSG_NOSIGNAL;
607
608
#ifdef CONFIG_BT_BNEP_MC_FILTER
609
/* Set default mc filter to not filter out any mc addresses
610
* as defined in the BNEP specification (revision 0.95a)
611
* http://grouper.ieee.org/groups/802/15/Bluetooth/BNEP.pdf
612
*/
613
s->mc_filter = ~0LL;
614
#endif
615
616
#ifdef CONFIG_BT_BNEP_PROTO_FILTER
617
/* Set default protocol filter */
618
bnep_set_default_proto_filter(s);
619
#endif
620
621
SET_NETDEV_DEV(dev, bnep_get_device(s));
622
SET_NETDEV_DEVTYPE(dev, &bnep_type);
623
624
err = register_netdev(dev);
625
if (err)
626
goto failed;
627
628
__bnep_link_session(s);
629
630
__module_get(THIS_MODULE);
631
s->task = kthread_run(bnep_session, s, "kbnepd %s", dev->name);
632
if (IS_ERR(s->task)) {
633
/* Session thread start failed, gotta cleanup. */
634
module_put(THIS_MODULE);
635
unregister_netdev(dev);
636
__bnep_unlink_session(s);
637
err = PTR_ERR(s->task);
638
goto failed;
639
}
640
641
up_write(&bnep_session_sem);
642
strcpy(req->device, dev->name);
643
return 0;
644
645
failed:
646
up_write(&bnep_session_sem);
647
free_netdev(dev);
648
return err;
649
}
650
651
int bnep_del_connection(struct bnep_conndel_req *req)
652
{
653
u32 valid_flags = 0;
654
struct bnep_session *s;
655
int err = 0;
656
657
BT_DBG("");
658
659
if (req->flags & ~valid_flags)
660
return -EINVAL;
661
662
down_read(&bnep_session_sem);
663
664
s = __bnep_get_session(req->dst);
665
if (s) {
666
atomic_inc(&s->terminate);
667
wake_up_interruptible(sk_sleep(s->sock->sk));
668
} else
669
err = -ENOENT;
670
671
up_read(&bnep_session_sem);
672
return err;
673
}
674
675
static void __bnep_copy_ci(struct bnep_conninfo *ci, struct bnep_session *s)
676
{
677
u32 valid_flags = BIT(BNEP_SETUP_RESPONSE);
678
679
memset(ci, 0, sizeof(*ci));
680
memcpy(ci->dst, s->eh.h_source, ETH_ALEN);
681
strcpy(ci->device, s->dev->name);
682
ci->flags = s->flags & valid_flags;
683
ci->state = s->state;
684
ci->role = s->role;
685
}
686
687
int bnep_get_connlist(struct bnep_connlist_req *req)
688
{
689
struct bnep_session *s;
690
int err = 0, n = 0;
691
692
down_read(&bnep_session_sem);
693
694
list_for_each_entry(s, &bnep_session_list, list) {
695
struct bnep_conninfo ci;
696
697
__bnep_copy_ci(&ci, s);
698
699
if (copy_to_user(req->ci, &ci, sizeof(ci))) {
700
err = -EFAULT;
701
break;
702
}
703
704
if (++n >= req->cnum)
705
break;
706
707
req->ci++;
708
}
709
req->cnum = n;
710
711
up_read(&bnep_session_sem);
712
return err;
713
}
714
715
int bnep_get_conninfo(struct bnep_conninfo *ci)
716
{
717
struct bnep_session *s;
718
int err = 0;
719
720
down_read(&bnep_session_sem);
721
722
s = __bnep_get_session(ci->dst);
723
if (s)
724
__bnep_copy_ci(ci, s);
725
else
726
err = -ENOENT;
727
728
up_read(&bnep_session_sem);
729
return err;
730
}
731
732
static int __init bnep_init(void)
733
{
734
char flt[50] = "";
735
736
#ifdef CONFIG_BT_BNEP_PROTO_FILTER
737
strcat(flt, "protocol ");
738
#endif
739
740
#ifdef CONFIG_BT_BNEP_MC_FILTER
741
strcat(flt, "multicast");
742
#endif
743
744
BT_INFO("BNEP (Ethernet Emulation) ver %s", VERSION);
745
if (flt[0])
746
BT_INFO("BNEP filters: %s", flt);
747
748
return bnep_sock_init();
749
}
750
751
static void __exit bnep_exit(void)
752
{
753
bnep_sock_cleanup();
754
}
755
756
module_init(bnep_init);
757
module_exit(bnep_exit);
758
759
module_param(compress_src, bool, 0644);
760
MODULE_PARM_DESC(compress_src, "Compress sources headers");
761
762
module_param(compress_dst, bool, 0644);
763
MODULE_PARM_DESC(compress_dst, "Compress destination headers");
764
765
MODULE_AUTHOR("Marcel Holtmann <[email protected]>");
766
MODULE_DESCRIPTION("Bluetooth BNEP ver " VERSION);
767
MODULE_VERSION(VERSION);
768
MODULE_LICENSE("GPL");
769
MODULE_ALIAS("bt-proto-4");
770
771