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