~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/bluetooth/bnep/core.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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/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         bnep_sock_init();
749         return 0;
750 }
751 
752 static void __exit bnep_exit(void)
753 {
754         bnep_sock_cleanup();
755 }
756 
757 module_init(bnep_init);
758 module_exit(bnep_exit);
759 
760 module_param(compress_src, bool, 0644);
761 MODULE_PARM_DESC(compress_src, "Compress sources headers");
762 
763 module_param(compress_dst, bool, 0644);
764 MODULE_PARM_DESC(compress_dst, "Compress destination headers");
765 
766 MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
767 MODULE_DESCRIPTION("Bluetooth BNEP ver " VERSION);
768 MODULE_VERSION(VERSION);
769 MODULE_LICENSE("GPL");
770 MODULE_ALIAS("bt-proto-4");
771 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php