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