11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds BNEP implementation for Linux Bluetooth stack (BlueZ).
31da177e4SLinus Torvalds Copyright (C) 2001-2002 Inventel Systemes
41da177e4SLinus Torvalds Written 2001-2002 by
596de0e25SJan Engelhardt Clément Moreau <clement.moreau@inventel.fr>
61da177e4SLinus Torvalds David Libault <david.libault@inventel.fr>
71da177e4SLinus Torvalds
81da177e4SLinus Torvalds Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
91da177e4SLinus Torvalds
101da177e4SLinus Torvalds This program is free software; you can redistribute it and/or modify
111da177e4SLinus Torvalds it under the terms of the GNU General Public License version 2 as
121da177e4SLinus Torvalds published by the Free Software Foundation;
131da177e4SLinus Torvalds
141da177e4SLinus Torvalds THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
151da177e4SLinus Torvalds OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
161da177e4SLinus Torvalds FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
171da177e4SLinus Torvalds IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
181da177e4SLinus Torvalds CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
191da177e4SLinus Torvalds WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
201da177e4SLinus Torvalds ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
211da177e4SLinus Torvalds OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
221da177e4SLinus Torvalds
231da177e4SLinus Torvalds ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
241da177e4SLinus Torvalds COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
251da177e4SLinus Torvalds SOFTWARE IS DISCLAIMED.
261da177e4SLinus Torvalds */
271da177e4SLinus Torvalds
281da177e4SLinus Torvalds #include <linux/module.h>
29f4d7cd4aSSzymon Janc #include <linux/kthread.h>
301da177e4SLinus Torvalds #include <linux/file.h>
311da177e4SLinus Torvalds #include <linux/etherdevice.h>
321da177e4SLinus Torvalds #include <asm/unaligned.h>
331da177e4SLinus Torvalds
341da177e4SLinus Torvalds #include <net/bluetooth/bluetooth.h>
3565f53e98SMarcel Holtmann #include <net/bluetooth/l2cap.h>
360a85b964SMarcel Holtmann #include <net/bluetooth/hci_core.h>
371da177e4SLinus Torvalds
381da177e4SLinus Torvalds #include "bnep.h"
391da177e4SLinus Torvalds
4028111eb2SMarcel Holtmann #define VERSION "1.3"
4128111eb2SMarcel Holtmann
42eb939922SRusty Russell static bool compress_src = true;
43eb939922SRusty Russell static bool compress_dst = true;
441da177e4SLinus Torvalds
451da177e4SLinus Torvalds static LIST_HEAD(bnep_session_list);
461da177e4SLinus Torvalds static DECLARE_RWSEM(bnep_session_sem);
471da177e4SLinus Torvalds
__bnep_get_session(u8 * dst)481da177e4SLinus Torvalds static struct bnep_session *__bnep_get_session(u8 *dst)
491da177e4SLinus Torvalds {
501da177e4SLinus Torvalds struct bnep_session *s;
511da177e4SLinus Torvalds
521da177e4SLinus Torvalds BT_DBG("");
531da177e4SLinus Torvalds
548035ded4SLuiz Augusto von Dentz list_for_each_entry(s, &bnep_session_list, list)
55c47fc981SJoe Perches if (ether_addr_equal(dst, s->eh.h_source))
561da177e4SLinus Torvalds return s;
578035ded4SLuiz Augusto von Dentz
581da177e4SLinus Torvalds return NULL;
591da177e4SLinus Torvalds }
601da177e4SLinus Torvalds
__bnep_link_session(struct bnep_session * s)611da177e4SLinus Torvalds static void __bnep_link_session(struct bnep_session *s)
621da177e4SLinus Torvalds {
631da177e4SLinus Torvalds list_add(&s->list, &bnep_session_list);
641da177e4SLinus Torvalds }
651da177e4SLinus Torvalds
__bnep_unlink_session(struct bnep_session * s)661da177e4SLinus Torvalds static void __bnep_unlink_session(struct bnep_session *s)
671da177e4SLinus Torvalds {
681da177e4SLinus Torvalds list_del(&s->list);
691da177e4SLinus Torvalds }
701da177e4SLinus Torvalds
bnep_send(struct bnep_session * s,void * data,size_t len)711da177e4SLinus Torvalds static int bnep_send(struct bnep_session *s, void *data, size_t len)
721da177e4SLinus Torvalds {
731da177e4SLinus Torvalds struct socket *sock = s->sock;
741da177e4SLinus Torvalds struct kvec iv = { data, len };
751da177e4SLinus Torvalds
761da177e4SLinus Torvalds return kernel_sendmsg(sock, &s->msg, &iv, 1, len);
771da177e4SLinus Torvalds }
781da177e4SLinus Torvalds
bnep_send_rsp(struct bnep_session * s,u8 ctrl,u16 resp)791da177e4SLinus Torvalds static int bnep_send_rsp(struct bnep_session *s, u8 ctrl, u16 resp)
801da177e4SLinus Torvalds {
811da177e4SLinus Torvalds struct bnep_control_rsp rsp;
821da177e4SLinus Torvalds rsp.type = BNEP_CONTROL;
831da177e4SLinus Torvalds rsp.ctrl = ctrl;
841da177e4SLinus Torvalds rsp.resp = htons(resp);
851da177e4SLinus Torvalds return bnep_send(s, &rsp, sizeof(rsp));
861da177e4SLinus Torvalds }
871da177e4SLinus Torvalds
881da177e4SLinus Torvalds #ifdef CONFIG_BT_BNEP_PROTO_FILTER
bnep_set_default_proto_filter(struct bnep_session * s)891da177e4SLinus Torvalds static inline void bnep_set_default_proto_filter(struct bnep_session *s)
901da177e4SLinus Torvalds {
911da177e4SLinus Torvalds /* (IPv4, ARP) */
92e41d2169SAl Viro s->proto_filter[0].start = ETH_P_IP;
93e41d2169SAl Viro s->proto_filter[0].end = ETH_P_ARP;
941da177e4SLinus Torvalds /* (RARP, AppleTalk) */
95e41d2169SAl Viro s->proto_filter[1].start = ETH_P_RARP;
96e41d2169SAl Viro s->proto_filter[1].end = ETH_P_AARP;
971da177e4SLinus Torvalds /* (IPX, IPv6) */
98e41d2169SAl Viro s->proto_filter[2].start = ETH_P_IPX;
99e41d2169SAl Viro s->proto_filter[2].end = ETH_P_IPV6;
1001da177e4SLinus Torvalds }
1011da177e4SLinus Torvalds #endif
1021da177e4SLinus Torvalds
bnep_ctrl_set_netfilter(struct bnep_session * s,__be16 * data,int len)1031bc5d448SAl Viro static int bnep_ctrl_set_netfilter(struct bnep_session *s, __be16 *data, int len)
1041da177e4SLinus Torvalds {
1051da177e4SLinus Torvalds int n;
1061da177e4SLinus Torvalds
1071da177e4SLinus Torvalds if (len < 2)
1081da177e4SLinus Torvalds return -EILSEQ;
1091da177e4SLinus Torvalds
11083985319SHarvey Harrison n = get_unaligned_be16(data);
1113aad75a1SSzymon Janc data++;
1123aad75a1SSzymon Janc len -= 2;
1131da177e4SLinus Torvalds
1141da177e4SLinus Torvalds if (len < n)
1151da177e4SLinus Torvalds return -EILSEQ;
1161da177e4SLinus Torvalds
1171da177e4SLinus Torvalds BT_DBG("filter len %d", n);
1181da177e4SLinus Torvalds
1191da177e4SLinus Torvalds #ifdef CONFIG_BT_BNEP_PROTO_FILTER
1201da177e4SLinus Torvalds n /= 4;
1211da177e4SLinus Torvalds if (n <= BNEP_MAX_PROTO_FILTERS) {
1221da177e4SLinus Torvalds struct bnep_proto_filter *f = s->proto_filter;
1231da177e4SLinus Torvalds int i;
1241da177e4SLinus Torvalds
1251da177e4SLinus Torvalds for (i = 0; i < n; i++) {
12683985319SHarvey Harrison f[i].start = get_unaligned_be16(data++);
12783985319SHarvey Harrison f[i].end = get_unaligned_be16(data++);
1281da177e4SLinus Torvalds
1298c8ca05dSKai Ye BT_DBG("proto filter start %u end %u",
1301da177e4SLinus Torvalds f[i].start, f[i].end);
1311da177e4SLinus Torvalds }
1321da177e4SLinus Torvalds
1331da177e4SLinus Torvalds if (i < BNEP_MAX_PROTO_FILTERS)
1341da177e4SLinus Torvalds memset(f + i, 0, sizeof(*f));
1351da177e4SLinus Torvalds
1361da177e4SLinus Torvalds if (n == 0)
1371da177e4SLinus Torvalds bnep_set_default_proto_filter(s);
1381da177e4SLinus Torvalds
1391da177e4SLinus Torvalds bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_SUCCESS);
1401da177e4SLinus Torvalds } else {
1411da177e4SLinus Torvalds bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_LIMIT_REACHED);
1421da177e4SLinus Torvalds }
1431da177e4SLinus Torvalds #else
1441da177e4SLinus Torvalds bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_UNSUPPORTED_REQ);
1451da177e4SLinus Torvalds #endif
1461da177e4SLinus Torvalds return 0;
1471da177e4SLinus Torvalds }
1481da177e4SLinus Torvalds
bnep_ctrl_set_mcfilter(struct bnep_session * s,u8 * data,int len)1491da177e4SLinus Torvalds static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len)
1501da177e4SLinus Torvalds {
1511da177e4SLinus Torvalds int n;
1521da177e4SLinus Torvalds
1531da177e4SLinus Torvalds if (len < 2)
1541da177e4SLinus Torvalds return -EILSEQ;
1551da177e4SLinus Torvalds
15683985319SHarvey Harrison n = get_unaligned_be16(data);
1573aad75a1SSzymon Janc data += 2;
1583aad75a1SSzymon Janc len -= 2;
1591da177e4SLinus Torvalds
1601da177e4SLinus Torvalds if (len < n)
1611da177e4SLinus Torvalds return -EILSEQ;
1621da177e4SLinus Torvalds
1631da177e4SLinus Torvalds BT_DBG("filter len %d", n);
1641da177e4SLinus Torvalds
1651da177e4SLinus Torvalds #ifdef CONFIG_BT_BNEP_MC_FILTER
1661da177e4SLinus Torvalds n /= (ETH_ALEN * 2);
1671da177e4SLinus Torvalds
1681da177e4SLinus Torvalds if (n > 0) {
169a3d9bd4cSSzymon Janc int i;
170a3d9bd4cSSzymon Janc
1711da177e4SLinus Torvalds s->mc_filter = 0;
1721da177e4SLinus Torvalds
1731da177e4SLinus Torvalds /* Always send broadcast */
1741da177e4SLinus Torvalds set_bit(bnep_mc_hash(s->dev->broadcast), (ulong *) &s->mc_filter);
1751da177e4SLinus Torvalds
1761da177e4SLinus Torvalds /* Add address ranges to the multicast hash */
1771da177e4SLinus Torvalds for (; n > 0; n--) {
1781da177e4SLinus Torvalds u8 a1[6], *a2;
1791da177e4SLinus Torvalds
1803aad75a1SSzymon Janc memcpy(a1, data, ETH_ALEN);
1813aad75a1SSzymon Janc data += ETH_ALEN;
1823aad75a1SSzymon Janc a2 = data;
1833aad75a1SSzymon Janc data += ETH_ALEN;
1841da177e4SLinus Torvalds
1856ed93dc6SAndrei Emeltchenko BT_DBG("mc filter %pMR -> %pMR", a1, a2);
1861da177e4SLinus Torvalds
1871da177e4SLinus Torvalds /* Iterate from a1 to a2 */
1881da177e4SLinus Torvalds set_bit(bnep_mc_hash(a1), (ulong *) &s->mc_filter);
1891da177e4SLinus Torvalds while (memcmp(a1, a2, 6) < 0 && s->mc_filter != ~0LL) {
190a3d9bd4cSSzymon Janc /* Increment a1 */
191a3d9bd4cSSzymon Janc i = 5;
192a3d9bd4cSSzymon Janc while (i >= 0 && ++a1[i--] == 0)
193a3d9bd4cSSzymon Janc ;
194a3d9bd4cSSzymon Janc
1951da177e4SLinus Torvalds set_bit(bnep_mc_hash(a1), (ulong *) &s->mc_filter);
1961da177e4SLinus Torvalds }
1971da177e4SLinus Torvalds }
1981da177e4SLinus Torvalds }
1991da177e4SLinus Torvalds
2001da177e4SLinus Torvalds BT_DBG("mc filter hash 0x%llx", s->mc_filter);
2011da177e4SLinus Torvalds
2021da177e4SLinus Torvalds bnep_send_rsp(s, BNEP_FILTER_MULTI_ADDR_RSP, BNEP_SUCCESS);
2031da177e4SLinus Torvalds #else
2041da177e4SLinus Torvalds bnep_send_rsp(s, BNEP_FILTER_MULTI_ADDR_RSP, BNEP_FILTER_UNSUPPORTED_REQ);
2051da177e4SLinus Torvalds #endif
2061da177e4SLinus Torvalds return 0;
2071da177e4SLinus Torvalds }
2081da177e4SLinus Torvalds
bnep_rx_control(struct bnep_session * s,void * data,int len)2091da177e4SLinus Torvalds static int bnep_rx_control(struct bnep_session *s, void *data, int len)
2101da177e4SLinus Torvalds {
2111da177e4SLinus Torvalds u8 cmd = *(u8 *)data;
2121da177e4SLinus Torvalds int err = 0;
2131da177e4SLinus Torvalds
2143aad75a1SSzymon Janc data++;
2153aad75a1SSzymon Janc len--;
2161da177e4SLinus Torvalds
2171da177e4SLinus Torvalds switch (cmd) {
2181da177e4SLinus Torvalds case BNEP_CMD_NOT_UNDERSTOOD:
2191da177e4SLinus Torvalds case BNEP_SETUP_CONN_RSP:
2201da177e4SLinus Torvalds case BNEP_FILTER_NET_TYPE_RSP:
2211da177e4SLinus Torvalds case BNEP_FILTER_MULTI_ADDR_RSP:
2221da177e4SLinus Torvalds /* Ignore these for now */
2231da177e4SLinus Torvalds break;
2241da177e4SLinus Torvalds
2251da177e4SLinus Torvalds case BNEP_FILTER_NET_TYPE_SET:
2261da177e4SLinus Torvalds err = bnep_ctrl_set_netfilter(s, data, len);
2271da177e4SLinus Torvalds break;
2281da177e4SLinus Torvalds
2291da177e4SLinus Torvalds case BNEP_FILTER_MULTI_ADDR_SET:
2301da177e4SLinus Torvalds err = bnep_ctrl_set_mcfilter(s, data, len);
2311da177e4SLinus Torvalds break;
2321da177e4SLinus Torvalds
233cde9f807SVikram Kandukuri case BNEP_SETUP_CONN_REQ:
234836a061bSGrzegorz Kolodziejczyk /* Successful response should be sent only once */
235836a061bSGrzegorz Kolodziejczyk if (test_bit(BNEP_SETUP_RESPONSE, &s->flags) &&
236836a061bSGrzegorz Kolodziejczyk !test_and_set_bit(BNEP_SETUP_RSP_SENT, &s->flags))
237836a061bSGrzegorz Kolodziejczyk err = bnep_send_rsp(s, BNEP_SETUP_CONN_RSP,
238836a061bSGrzegorz Kolodziejczyk BNEP_SUCCESS);
239836a061bSGrzegorz Kolodziejczyk else
240836a061bSGrzegorz Kolodziejczyk err = bnep_send_rsp(s, BNEP_SETUP_CONN_RSP,
241836a061bSGrzegorz Kolodziejczyk BNEP_CONN_NOT_ALLOWED);
242cde9f807SVikram Kandukuri break;
243cde9f807SVikram Kandukuri
2441da177e4SLinus Torvalds default: {
2451da177e4SLinus Torvalds u8 pkt[3];
2461da177e4SLinus Torvalds pkt[0] = BNEP_CONTROL;
2471da177e4SLinus Torvalds pkt[1] = BNEP_CMD_NOT_UNDERSTOOD;
2481da177e4SLinus Torvalds pkt[2] = cmd;
249e0fdbab1SGrzegorz Kolodziejczyk err = bnep_send(s, pkt, sizeof(pkt));
2501da177e4SLinus Torvalds }
2511da177e4SLinus Torvalds break;
2521da177e4SLinus Torvalds }
2531da177e4SLinus Torvalds
2541da177e4SLinus Torvalds return err;
2551da177e4SLinus Torvalds }
2561da177e4SLinus Torvalds
bnep_rx_extension(struct bnep_session * s,struct sk_buff * skb)2571da177e4SLinus Torvalds static int bnep_rx_extension(struct bnep_session *s, struct sk_buff *skb)
2581da177e4SLinus Torvalds {
2591da177e4SLinus Torvalds struct bnep_ext_hdr *h;
2601da177e4SLinus Torvalds int err = 0;
2611da177e4SLinus Torvalds
2621da177e4SLinus Torvalds do {
2631da177e4SLinus Torvalds h = (void *) skb->data;
2641da177e4SLinus Torvalds if (!skb_pull(skb, sizeof(*h))) {
2651da177e4SLinus Torvalds err = -EILSEQ;
2661da177e4SLinus Torvalds break;
2671da177e4SLinus Torvalds }
2681da177e4SLinus Torvalds
2698c8ca05dSKai Ye BT_DBG("type 0x%x len %u", h->type, h->len);
2701da177e4SLinus Torvalds
2711da177e4SLinus Torvalds switch (h->type & BNEP_TYPE_MASK) {
2721da177e4SLinus Torvalds case BNEP_EXT_CONTROL:
2731da177e4SLinus Torvalds bnep_rx_control(s, skb->data, skb->len);
2741da177e4SLinus Torvalds break;
2751da177e4SLinus Torvalds
2761da177e4SLinus Torvalds default:
2771da177e4SLinus Torvalds /* Unknown extension, skip it. */
2781da177e4SLinus Torvalds break;
2791da177e4SLinus Torvalds }
2801da177e4SLinus Torvalds
2811da177e4SLinus Torvalds if (!skb_pull(skb, h->len)) {
2821da177e4SLinus Torvalds err = -EILSEQ;
2831da177e4SLinus Torvalds break;
2841da177e4SLinus Torvalds }
2851da177e4SLinus Torvalds } while (!err && (h->type & BNEP_EXT_HEADER));
2861da177e4SLinus Torvalds
2871da177e4SLinus Torvalds return err;
2881da177e4SLinus Torvalds }
2891da177e4SLinus Torvalds
2901da177e4SLinus Torvalds static u8 __bnep_rx_hlen[] = {
2911da177e4SLinus Torvalds ETH_HLEN, /* BNEP_GENERAL */
2921da177e4SLinus Torvalds 0, /* BNEP_CONTROL */
2931da177e4SLinus Torvalds 2, /* BNEP_COMPRESSED */
2941da177e4SLinus Torvalds ETH_ALEN + 2, /* BNEP_COMPRESSED_SRC_ONLY */
2951da177e4SLinus Torvalds ETH_ALEN + 2 /* BNEP_COMPRESSED_DST_ONLY */
2961da177e4SLinus Torvalds };
2971da177e4SLinus Torvalds
bnep_rx_frame(struct bnep_session * s,struct sk_buff * skb)2986039aa73SGustavo Padovan static int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
2991da177e4SLinus Torvalds {
3001da177e4SLinus Torvalds struct net_device *dev = s->dev;
3011da177e4SLinus Torvalds struct sk_buff *nskb;
302bf8b9a9cSGrzegorz Kolodziejczyk u8 type, ctrl_type;
3031da177e4SLinus Torvalds
304b4d7f0a4SStephen Hemminger dev->stats.rx_bytes += skb->len;
3051da177e4SLinus Torvalds
3063aad75a1SSzymon Janc type = *(u8 *) skb->data;
3073aad75a1SSzymon Janc skb_pull(skb, 1);
308bf8b9a9cSGrzegorz Kolodziejczyk ctrl_type = *(u8 *)skb->data;
3091da177e4SLinus Torvalds
310a3d9bd4cSSzymon Janc if ((type & BNEP_TYPE_MASK) >= sizeof(__bnep_rx_hlen))
3111da177e4SLinus Torvalds goto badframe;
3121da177e4SLinus Torvalds
3131da177e4SLinus Torvalds if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) {
314bf8b9a9cSGrzegorz Kolodziejczyk if (bnep_rx_control(s, skb->data, skb->len) < 0) {
315bf8b9a9cSGrzegorz Kolodziejczyk dev->stats.tx_errors++;
3161da177e4SLinus Torvalds kfree_skb(skb);
3171da177e4SLinus Torvalds return 0;
3181da177e4SLinus Torvalds }
3191da177e4SLinus Torvalds
320bf8b9a9cSGrzegorz Kolodziejczyk if (!(type & BNEP_EXT_HEADER)) {
321bf8b9a9cSGrzegorz Kolodziejczyk kfree_skb(skb);
322bf8b9a9cSGrzegorz Kolodziejczyk return 0;
323bf8b9a9cSGrzegorz Kolodziejczyk }
324bf8b9a9cSGrzegorz Kolodziejczyk
325bf8b9a9cSGrzegorz Kolodziejczyk /* Verify and pull ctrl message since it's already processed */
326bf8b9a9cSGrzegorz Kolodziejczyk switch (ctrl_type) {
327bf8b9a9cSGrzegorz Kolodziejczyk case BNEP_SETUP_CONN_REQ:
328bf8b9a9cSGrzegorz Kolodziejczyk /* Pull: ctrl type (1 b), len (1 b), data (len bytes) */
329bf8b9a9cSGrzegorz Kolodziejczyk if (!skb_pull(skb, 2 + *(u8 *)(skb->data + 1) * 2))
330bf8b9a9cSGrzegorz Kolodziejczyk goto badframe;
331bf8b9a9cSGrzegorz Kolodziejczyk break;
332bf8b9a9cSGrzegorz Kolodziejczyk case BNEP_FILTER_MULTI_ADDR_SET:
333bf8b9a9cSGrzegorz Kolodziejczyk case BNEP_FILTER_NET_TYPE_SET:
334bf8b9a9cSGrzegorz Kolodziejczyk /* Pull: ctrl type (1 b), len (2 b), data (len bytes) */
335bf8b9a9cSGrzegorz Kolodziejczyk if (!skb_pull(skb, 3 + *(u16 *)(skb->data + 1) * 2))
336bf8b9a9cSGrzegorz Kolodziejczyk goto badframe;
337bf8b9a9cSGrzegorz Kolodziejczyk break;
338bf8b9a9cSGrzegorz Kolodziejczyk default:
339bf8b9a9cSGrzegorz Kolodziejczyk kfree_skb(skb);
340bf8b9a9cSGrzegorz Kolodziejczyk return 0;
341bf8b9a9cSGrzegorz Kolodziejczyk }
342bf8b9a9cSGrzegorz Kolodziejczyk } else {
343459a98edSArnaldo Carvalho de Melo skb_reset_mac_header(skb);
3441da177e4SLinus Torvalds
3451da177e4SLinus Torvalds /* Verify and pull out header */
3461da177e4SLinus Torvalds if (!skb_pull(skb, __bnep_rx_hlen[type & BNEP_TYPE_MASK]))
3471da177e4SLinus Torvalds goto badframe;
3481da177e4SLinus Torvalds
3491bc5d448SAl Viro s->eh.h_proto = get_unaligned((__be16 *) (skb->data - 2));
350bf8b9a9cSGrzegorz Kolodziejczyk }
3511da177e4SLinus Torvalds
3521da177e4SLinus Torvalds if (type & BNEP_EXT_HEADER) {
3531da177e4SLinus Torvalds if (bnep_rx_extension(s, skb) < 0)
3541da177e4SLinus Torvalds goto badframe;
3551da177e4SLinus Torvalds }
3561da177e4SLinus Torvalds
3571da177e4SLinus Torvalds /* Strip 802.1p header */
358000092b0SEldad Zack if (ntohs(s->eh.h_proto) == ETH_P_8021Q) {
3591da177e4SLinus Torvalds if (!skb_pull(skb, 4))
3601da177e4SLinus Torvalds goto badframe;
3611bc5d448SAl Viro s->eh.h_proto = get_unaligned((__be16 *) (skb->data - 2));
3621da177e4SLinus Torvalds }
3631da177e4SLinus Torvalds
3641da177e4SLinus Torvalds /* We have to alloc new skb and copy data here :(. Because original skb
3651da177e4SLinus Torvalds * may not be modified and because of the alignment requirements. */
3661da177e4SLinus Torvalds nskb = alloc_skb(2 + ETH_HLEN + skb->len, GFP_KERNEL);
3671da177e4SLinus Torvalds if (!nskb) {
368b4d7f0a4SStephen Hemminger dev->stats.rx_dropped++;
3691da177e4SLinus Torvalds kfree_skb(skb);
3701da177e4SLinus Torvalds return -ENOMEM;
3711da177e4SLinus Torvalds }
3721da177e4SLinus Torvalds skb_reserve(nskb, 2);
3731da177e4SLinus Torvalds
3741da177e4SLinus Torvalds /* Decompress header and construct ether frame */
3751da177e4SLinus Torvalds switch (type & BNEP_TYPE_MASK) {
3761da177e4SLinus Torvalds case BNEP_COMPRESSED:
377de77b966Syuan linyu __skb_put_data(nskb, &s->eh, ETH_HLEN);
3781da177e4SLinus Torvalds break;
3791da177e4SLinus Torvalds
3801da177e4SLinus Torvalds case BNEP_COMPRESSED_SRC_ONLY:
381de77b966Syuan linyu __skb_put_data(nskb, s->eh.h_dest, ETH_ALEN);
382de77b966Syuan linyu __skb_put_data(nskb, skb_mac_header(skb), ETH_ALEN);
3831bc5d448SAl Viro put_unaligned(s->eh.h_proto, (__be16 *) __skb_put(nskb, 2));
3841da177e4SLinus Torvalds break;
3851da177e4SLinus Torvalds
3861da177e4SLinus Torvalds case BNEP_COMPRESSED_DST_ONLY:
387de77b966Syuan linyu __skb_put_data(nskb, skb_mac_header(skb), ETH_ALEN);
3887ff15407SLuiz Augusto von Dentz __skb_put_data(nskb, s->eh.h_source, ETH_ALEN);
3897ff15407SLuiz Augusto von Dentz put_unaligned(s->eh.h_proto, (__be16 *)__skb_put(nskb, 2));
3901da177e4SLinus Torvalds break;
3911da177e4SLinus Torvalds
3921da177e4SLinus Torvalds case BNEP_GENERAL:
393de77b966Syuan linyu __skb_put_data(nskb, skb_mac_header(skb), ETH_ALEN * 2);
3941bc5d448SAl Viro put_unaligned(s->eh.h_proto, (__be16 *) __skb_put(nskb, 2));
3951da177e4SLinus Torvalds break;
3961da177e4SLinus Torvalds }
3971da177e4SLinus Torvalds
398d626f62bSArnaldo Carvalho de Melo skb_copy_from_linear_data(skb, __skb_put(nskb, skb->len), skb->len);
3991da177e4SLinus Torvalds kfree_skb(skb);
4001da177e4SLinus Torvalds
401b4d7f0a4SStephen Hemminger dev->stats.rx_packets++;
4021da177e4SLinus Torvalds nskb->ip_summed = CHECKSUM_NONE;
4031da177e4SLinus Torvalds nskb->protocol = eth_type_trans(nskb, dev);
404d33d0dc9SSebastian Andrzej Siewior netif_rx(nskb);
4051da177e4SLinus Torvalds return 0;
4061da177e4SLinus Torvalds
4071da177e4SLinus Torvalds badframe:
408b4d7f0a4SStephen Hemminger dev->stats.rx_errors++;
4091da177e4SLinus Torvalds kfree_skb(skb);
4101da177e4SLinus Torvalds return 0;
4111da177e4SLinus Torvalds }
4121da177e4SLinus Torvalds
4131da177e4SLinus Torvalds static u8 __bnep_tx_types[] = {
4141da177e4SLinus Torvalds BNEP_GENERAL,
4151da177e4SLinus Torvalds BNEP_COMPRESSED_SRC_ONLY,
4161da177e4SLinus Torvalds BNEP_COMPRESSED_DST_ONLY,
4171da177e4SLinus Torvalds BNEP_COMPRESSED
4181da177e4SLinus Torvalds };
4191da177e4SLinus Torvalds
bnep_tx_frame(struct bnep_session * s,struct sk_buff * skb)4206039aa73SGustavo Padovan static int bnep_tx_frame(struct bnep_session *s, struct sk_buff *skb)
4211da177e4SLinus Torvalds {
4221da177e4SLinus Torvalds struct ethhdr *eh = (void *) skb->data;
4231da177e4SLinus Torvalds struct socket *sock = s->sock;
4241da177e4SLinus Torvalds struct kvec iv[3];
4251da177e4SLinus Torvalds int len = 0, il = 0;
4261da177e4SLinus Torvalds u8 type = 0;
4271da177e4SLinus Torvalds
4288c8ca05dSKai Ye BT_DBG("skb %p dev %p type %u", skb, skb->dev, skb->pkt_type);
4291da177e4SLinus Torvalds
4301da177e4SLinus Torvalds if (!skb->dev) {
4311da177e4SLinus Torvalds /* Control frame sent by us */
4321da177e4SLinus Torvalds goto send;
4331da177e4SLinus Torvalds }
4341da177e4SLinus Torvalds
4351da177e4SLinus Torvalds iv[il++] = (struct kvec) { &type, 1 };
4361da177e4SLinus Torvalds len++;
4371da177e4SLinus Torvalds
438c47fc981SJoe Perches if (compress_src && ether_addr_equal(eh->h_dest, s->eh.h_source))
4391da177e4SLinus Torvalds type |= 0x01;
4401da177e4SLinus Torvalds
441c47fc981SJoe Perches if (compress_dst && ether_addr_equal(eh->h_source, s->eh.h_dest))
4421da177e4SLinus Torvalds type |= 0x02;
4431da177e4SLinus Torvalds
4441da177e4SLinus Torvalds if (type)
4451da177e4SLinus Torvalds skb_pull(skb, ETH_ALEN * 2);
4461da177e4SLinus Torvalds
4471da177e4SLinus Torvalds type = __bnep_tx_types[type];
4481da177e4SLinus Torvalds switch (type) {
4491da177e4SLinus Torvalds case BNEP_COMPRESSED_SRC_ONLY:
4501da177e4SLinus Torvalds iv[il++] = (struct kvec) { eh->h_source, ETH_ALEN };
4511da177e4SLinus Torvalds len += ETH_ALEN;
4521da177e4SLinus Torvalds break;
4531da177e4SLinus Torvalds
4541da177e4SLinus Torvalds case BNEP_COMPRESSED_DST_ONLY:
4551da177e4SLinus Torvalds iv[il++] = (struct kvec) { eh->h_dest, ETH_ALEN };
4561da177e4SLinus Torvalds len += ETH_ALEN;
4571da177e4SLinus Torvalds break;
4581da177e4SLinus Torvalds }
4591da177e4SLinus Torvalds
4601da177e4SLinus Torvalds send:
4611da177e4SLinus Torvalds iv[il++] = (struct kvec) { skb->data, skb->len };
4621da177e4SLinus Torvalds len += skb->len;
4631da177e4SLinus Torvalds
4641da177e4SLinus Torvalds /* FIXME: linearize skb */
4651da177e4SLinus Torvalds {
4661da177e4SLinus Torvalds len = kernel_sendmsg(sock, &s->msg, iv, il, len);
4671da177e4SLinus Torvalds }
4681da177e4SLinus Torvalds kfree_skb(skb);
4691da177e4SLinus Torvalds
4701da177e4SLinus Torvalds if (len > 0) {
471b4d7f0a4SStephen Hemminger s->dev->stats.tx_bytes += len;
472b4d7f0a4SStephen Hemminger s->dev->stats.tx_packets++;
4731da177e4SLinus Torvalds return 0;
4741da177e4SLinus Torvalds }
4751da177e4SLinus Torvalds
4761da177e4SLinus Torvalds return len;
4771da177e4SLinus Torvalds }
4781da177e4SLinus Torvalds
bnep_session(void * arg)4791da177e4SLinus Torvalds static int bnep_session(void *arg)
4801da177e4SLinus Torvalds {
4811da177e4SLinus Torvalds struct bnep_session *s = arg;
4821da177e4SLinus Torvalds struct net_device *dev = s->dev;
4831da177e4SLinus Torvalds struct sock *sk = s->sock->sk;
4841da177e4SLinus Torvalds struct sk_buff *skb;
48525717382SJeffy Chen DEFINE_WAIT_FUNC(wait, woken_wake_function);
4861da177e4SLinus Torvalds
4871da177e4SLinus Torvalds BT_DBG("");
4881da177e4SLinus Torvalds
4891da177e4SLinus Torvalds set_user_nice(current, -15);
4901da177e4SLinus Torvalds
491aa395145SEric Dumazet add_wait_queue(sk_sleep(sk), &wait);
49238d57555SPeter Hurley while (1) {
493751c10a5SPeter Hurley if (atomic_read(&s->terminate))
49438d57555SPeter Hurley break;
4953aad75a1SSzymon Janc /* RX */
4961da177e4SLinus Torvalds while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
4971da177e4SLinus Torvalds skb_orphan(skb);
49844935720SMat Martineau if (!skb_linearize(skb))
4991da177e4SLinus Torvalds bnep_rx_frame(s, skb);
50044935720SMat Martineau else
50144935720SMat Martineau kfree_skb(skb);
5021da177e4SLinus Torvalds }
5031da177e4SLinus Torvalds
5041da177e4SLinus Torvalds if (sk->sk_state != BT_CONNECTED)
5051da177e4SLinus Torvalds break;
5061da177e4SLinus Torvalds
5073aad75a1SSzymon Janc /* TX */
5081da177e4SLinus Torvalds while ((skb = skb_dequeue(&sk->sk_write_queue)))
5091da177e4SLinus Torvalds if (bnep_tx_frame(s, skb))
5101da177e4SLinus Torvalds break;
5111da177e4SLinus Torvalds netif_wake_queue(dev);
5121da177e4SLinus Torvalds
5135aac4937SAndrea Parri /*
5145aac4937SAndrea Parri * wait_woken() performs the necessary memory barriers
5155aac4937SAndrea Parri * for us; see the header comment for this primitive.
5165aac4937SAndrea Parri */
51725717382SJeffy Chen wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
5181da177e4SLinus Torvalds }
519aa395145SEric Dumazet remove_wait_queue(sk_sleep(sk), &wait);
5201da177e4SLinus Torvalds
5211da177e4SLinus Torvalds /* Cleanup session */
5221da177e4SLinus Torvalds down_write(&bnep_session_sem);
5231da177e4SLinus Torvalds
5241da177e4SLinus Torvalds /* Delete network device */
5251da177e4SLinus Torvalds unregister_netdev(dev);
5261da177e4SLinus Torvalds
527ec8dab36SMarcel Holtmann /* Wakeup user-space polling for socket errors */
528ec8dab36SMarcel Holtmann s->sock->sk->sk_err = EUNATCH;
529ec8dab36SMarcel Holtmann
530aa395145SEric Dumazet wake_up_interruptible(sk_sleep(s->sock->sk));
531ec8dab36SMarcel Holtmann
5321da177e4SLinus Torvalds /* Release the socket */
5331da177e4SLinus Torvalds fput(s->sock->file);
5341da177e4SLinus Torvalds
5351da177e4SLinus Torvalds __bnep_unlink_session(s);
5361da177e4SLinus Torvalds
5371da177e4SLinus Torvalds up_write(&bnep_session_sem);
5381da177e4SLinus Torvalds free_netdev(dev);
539ca3574bdSEric W. Biederman module_put_and_kthread_exit(0);
5401da177e4SLinus Torvalds return 0;
5411da177e4SLinus Torvalds }
5421da177e4SLinus Torvalds
bnep_get_device(struct bnep_session * session)5430a85b964SMarcel Holtmann static struct device *bnep_get_device(struct bnep_session *session)
5440a85b964SMarcel Holtmann {
54588d9077cSJohan Hedberg struct l2cap_conn *conn = l2cap_pi(session->sock->sk)->chan->conn;
5460a85b964SMarcel Holtmann
54788d9077cSJohan Hedberg if (!conn || !conn->hcon)
5480a85b964SMarcel Holtmann return NULL;
5490a85b964SMarcel Holtmann
55088d9077cSJohan Hedberg return &conn->hcon->dev;
5510a85b964SMarcel Holtmann }
5520a85b964SMarcel Holtmann
553384912edSMarcel Holtmann static struct device_type bnep_type = {
554384912edSMarcel Holtmann .name = "bluetooth",
555384912edSMarcel Holtmann };
556384912edSMarcel Holtmann
bnep_add_connection(struct bnep_connadd_req * req,struct socket * sock)5571da177e4SLinus Torvalds int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
5581da177e4SLinus Torvalds {
559836a061bSGrzegorz Kolodziejczyk u32 valid_flags = BIT(BNEP_SETUP_RESPONSE);
5601da177e4SLinus Torvalds struct net_device *dev;
5611da177e4SLinus Torvalds struct bnep_session *s, *ss;
5621da177e4SLinus Torvalds u8 dst[ETH_ALEN], src[ETH_ALEN];
5631da177e4SLinus Torvalds int err;
5641da177e4SLinus Torvalds
5651da177e4SLinus Torvalds BT_DBG("");
5661da177e4SLinus Torvalds
56771bb99a0SAl Viro if (!l2cap_is_socket(sock))
56871bb99a0SAl Viro return -EBADFD;
56971bb99a0SAl Viro
5700151e426SMarcel Holtmann if (req->flags & ~valid_flags)
5710151e426SMarcel Holtmann return -EINVAL;
5720151e426SMarcel Holtmann
57365f53e98SMarcel Holtmann baswap((void *) dst, &l2cap_pi(sock->sk)->chan->dst);
57465f53e98SMarcel Holtmann baswap((void *) src, &l2cap_pi(sock->sk)->chan->src);
5751da177e4SLinus Torvalds
5761da177e4SLinus Torvalds /* session struct allocated as private part of net_device */
5771da177e4SLinus Torvalds dev = alloc_netdev(sizeof(struct bnep_session),
5781da177e4SLinus Torvalds (*req->device) ? req->device : "bnep%d",
579c835a677STom Gundersen NET_NAME_UNKNOWN,
5801da177e4SLinus Torvalds bnep_net_setup);
5811da177e4SLinus Torvalds if (!dev)
58267b52e55STobias Klauser return -ENOMEM;
5831da177e4SLinus Torvalds
5841da177e4SLinus Torvalds down_write(&bnep_session_sem);
5851da177e4SLinus Torvalds
5861da177e4SLinus Torvalds ss = __bnep_get_session(dst);
5871da177e4SLinus Torvalds if (ss && ss->state == BT_CONNECTED) {
5881da177e4SLinus Torvalds err = -EEXIST;
5891da177e4SLinus Torvalds goto failed;
5901da177e4SLinus Torvalds }
5911da177e4SLinus Torvalds
592524ad0a7SWang Chen s = netdev_priv(dev);
5931da177e4SLinus Torvalds
5941da177e4SLinus Torvalds /* This is rx header therefore addresses are swapped.
5953aad75a1SSzymon Janc * ie. eh.h_dest is our local address. */
5961da177e4SLinus Torvalds memcpy(s->eh.h_dest, &src, ETH_ALEN);
5971da177e4SLinus Torvalds memcpy(s->eh.h_source, &dst, ETH_ALEN);
59808c181f0SJakub Kicinski eth_hw_addr_set(dev, s->eh.h_dest);
5991da177e4SLinus Torvalds
6001da177e4SLinus Torvalds s->dev = dev;
6011da177e4SLinus Torvalds s->sock = sock;
6021da177e4SLinus Torvalds s->role = req->role;
6031da177e4SLinus Torvalds s->state = BT_CONNECTED;
604836a061bSGrzegorz Kolodziejczyk s->flags = req->flags;
6051da177e4SLinus Torvalds
6061da177e4SLinus Torvalds s->msg.msg_flags = MSG_NOSIGNAL;
6071da177e4SLinus Torvalds
6081da177e4SLinus Torvalds #ifdef CONFIG_BT_BNEP_MC_FILTER
6094ada1282SDanny Schweizer /* Set default mc filter to not filter out any mc addresses
6104ada1282SDanny Schweizer * as defined in the BNEP specification (revision 0.95a)
6114ada1282SDanny Schweizer * http://grouper.ieee.org/groups/802/15/Bluetooth/BNEP.pdf
6124ada1282SDanny Schweizer */
6134ada1282SDanny Schweizer s->mc_filter = ~0LL;
6141da177e4SLinus Torvalds #endif
6151da177e4SLinus Torvalds
6161da177e4SLinus Torvalds #ifdef CONFIG_BT_BNEP_PROTO_FILTER
6171da177e4SLinus Torvalds /* Set default protocol filter */
6181da177e4SLinus Torvalds bnep_set_default_proto_filter(s);
6191da177e4SLinus Torvalds #endif
6201da177e4SLinus Torvalds
6210a85b964SMarcel Holtmann SET_NETDEV_DEV(dev, bnep_get_device(s));
622384912edSMarcel Holtmann SET_NETDEV_DEVTYPE(dev, &bnep_type);
6230a85b964SMarcel Holtmann
6241da177e4SLinus Torvalds err = register_netdev(dev);
6253aad75a1SSzymon Janc if (err)
6261da177e4SLinus Torvalds goto failed;
6271da177e4SLinus Torvalds
6281da177e4SLinus Torvalds __bnep_link_session(s);
6291da177e4SLinus Torvalds
6309b338c3dSDavid Herrmann __module_get(THIS_MODULE);
631f4d7cd4aSSzymon Janc s->task = kthread_run(bnep_session, s, "kbnepd %s", dev->name);
632f4d7cd4aSSzymon Janc if (IS_ERR(s->task)) {
6331da177e4SLinus Torvalds /* Session thread start failed, gotta cleanup. */
6349b338c3dSDavid Herrmann module_put(THIS_MODULE);
6351da177e4SLinus Torvalds unregister_netdev(dev);
6361da177e4SLinus Torvalds __bnep_unlink_session(s);
637f4d7cd4aSSzymon Janc err = PTR_ERR(s->task);
6381da177e4SLinus Torvalds goto failed;
6391da177e4SLinus Torvalds }
6401da177e4SLinus Torvalds
6411da177e4SLinus Torvalds up_write(&bnep_session_sem);
6421da177e4SLinus Torvalds strcpy(req->device, dev->name);
6431da177e4SLinus Torvalds return 0;
6441da177e4SLinus Torvalds
6451da177e4SLinus Torvalds failed:
6461da177e4SLinus Torvalds up_write(&bnep_session_sem);
6471da177e4SLinus Torvalds free_netdev(dev);
6481da177e4SLinus Torvalds return err;
6491da177e4SLinus Torvalds }
6501da177e4SLinus Torvalds
bnep_del_connection(struct bnep_conndel_req * req)6511da177e4SLinus Torvalds int bnep_del_connection(struct bnep_conndel_req *req)
6521da177e4SLinus Torvalds {
6530151e426SMarcel Holtmann u32 valid_flags = 0;
6541da177e4SLinus Torvalds struct bnep_session *s;
6551da177e4SLinus Torvalds int err = 0;
6561da177e4SLinus Torvalds
6571da177e4SLinus Torvalds BT_DBG("");
6581da177e4SLinus Torvalds
6590151e426SMarcel Holtmann if (req->flags & ~valid_flags)
6600151e426SMarcel Holtmann return -EINVAL;
6610151e426SMarcel Holtmann
6621da177e4SLinus Torvalds down_read(&bnep_session_sem);
6631da177e4SLinus Torvalds
6641da177e4SLinus Torvalds s = __bnep_get_session(req->dst);
665751c10a5SPeter Hurley if (s) {
666751c10a5SPeter Hurley atomic_inc(&s->terminate);
66725717382SJeffy Chen wake_up_interruptible(sk_sleep(s->sock->sk));
668751c10a5SPeter Hurley } else
6691da177e4SLinus Torvalds err = -ENOENT;
6701da177e4SLinus Torvalds
6711da177e4SLinus Torvalds up_read(&bnep_session_sem);
6721da177e4SLinus Torvalds return err;
6731da177e4SLinus Torvalds }
6741da177e4SLinus Torvalds
__bnep_copy_ci(struct bnep_conninfo * ci,struct bnep_session * s)6751da177e4SLinus Torvalds static void __bnep_copy_ci(struct bnep_conninfo *ci, struct bnep_session *s)
6761da177e4SLinus Torvalds {
677836a061bSGrzegorz Kolodziejczyk u32 valid_flags = BIT(BNEP_SETUP_RESPONSE);
6780151e426SMarcel Holtmann
6795520d20fSVasiliy Kulikov memset(ci, 0, sizeof(*ci));
6801da177e4SLinus Torvalds memcpy(ci->dst, s->eh.h_source, ETH_ALEN);
6811da177e4SLinus Torvalds strcpy(ci->device, s->dev->name);
6820151e426SMarcel Holtmann ci->flags = s->flags & valid_flags;
6831da177e4SLinus Torvalds ci->state = s->state;
6841da177e4SLinus Torvalds ci->role = s->role;
6851da177e4SLinus Torvalds }
6861da177e4SLinus Torvalds
bnep_get_connlist(struct bnep_connlist_req * req)6871da177e4SLinus Torvalds int bnep_get_connlist(struct bnep_connlist_req *req)
6881da177e4SLinus Torvalds {
6898035ded4SLuiz Augusto von Dentz struct bnep_session *s;
6901da177e4SLinus Torvalds int err = 0, n = 0;
6911da177e4SLinus Torvalds
6921da177e4SLinus Torvalds down_read(&bnep_session_sem);
6931da177e4SLinus Torvalds
6948035ded4SLuiz Augusto von Dentz list_for_each_entry(s, &bnep_session_list, list) {
6951da177e4SLinus Torvalds struct bnep_conninfo ci;
6961da177e4SLinus Torvalds
6971da177e4SLinus Torvalds __bnep_copy_ci(&ci, s);
6981da177e4SLinus Torvalds
6991da177e4SLinus Torvalds if (copy_to_user(req->ci, &ci, sizeof(ci))) {
7001da177e4SLinus Torvalds err = -EFAULT;
7011da177e4SLinus Torvalds break;
7021da177e4SLinus Torvalds }
7031da177e4SLinus Torvalds
7041da177e4SLinus Torvalds if (++n >= req->cnum)
7051da177e4SLinus Torvalds break;
7061da177e4SLinus Torvalds
7071da177e4SLinus Torvalds req->ci++;
7081da177e4SLinus Torvalds }
7091da177e4SLinus Torvalds req->cnum = n;
7101da177e4SLinus Torvalds
7111da177e4SLinus Torvalds up_read(&bnep_session_sem);
7121da177e4SLinus Torvalds return err;
7131da177e4SLinus Torvalds }
7141da177e4SLinus Torvalds
bnep_get_conninfo(struct bnep_conninfo * ci)7151da177e4SLinus Torvalds int bnep_get_conninfo(struct bnep_conninfo *ci)
7161da177e4SLinus Torvalds {
7171da177e4SLinus Torvalds struct bnep_session *s;
7181da177e4SLinus Torvalds int err = 0;
7191da177e4SLinus Torvalds
7201da177e4SLinus Torvalds down_read(&bnep_session_sem);
7211da177e4SLinus Torvalds
7221da177e4SLinus Torvalds s = __bnep_get_session(ci->dst);
7231da177e4SLinus Torvalds if (s)
7241da177e4SLinus Torvalds __bnep_copy_ci(ci, s);
7251da177e4SLinus Torvalds else
7261da177e4SLinus Torvalds err = -ENOENT;
7271da177e4SLinus Torvalds
7281da177e4SLinus Torvalds up_read(&bnep_session_sem);
7291da177e4SLinus Torvalds return err;
7301da177e4SLinus Torvalds }
7311da177e4SLinus Torvalds
bnep_init(void)7321da177e4SLinus Torvalds static int __init bnep_init(void)
7331da177e4SLinus Torvalds {
7341da177e4SLinus Torvalds char flt[50] = "";
7351da177e4SLinus Torvalds
7361da177e4SLinus Torvalds #ifdef CONFIG_BT_BNEP_PROTO_FILTER
7371da177e4SLinus Torvalds strcat(flt, "protocol ");
7381da177e4SLinus Torvalds #endif
7391da177e4SLinus Torvalds
7401da177e4SLinus Torvalds #ifdef CONFIG_BT_BNEP_MC_FILTER
7411da177e4SLinus Torvalds strcat(flt, "multicast");
7421da177e4SLinus Torvalds #endif
7431da177e4SLinus Torvalds
7441da177e4SLinus Torvalds BT_INFO("BNEP (Ethernet Emulation) ver %s", VERSION);
7451da177e4SLinus Torvalds if (flt[0])
7461da177e4SLinus Torvalds BT_INFO("BNEP filters: %s", flt);
7471da177e4SLinus Torvalds
748*d10cd7bfSYe Bin return bnep_sock_init();
7491da177e4SLinus Torvalds }
7501da177e4SLinus Torvalds
bnep_exit(void)7511da177e4SLinus Torvalds static void __exit bnep_exit(void)
7521da177e4SLinus Torvalds {
7531da177e4SLinus Torvalds bnep_sock_cleanup();
7541da177e4SLinus Torvalds }
7551da177e4SLinus Torvalds
7561da177e4SLinus Torvalds module_init(bnep_init);
7571da177e4SLinus Torvalds module_exit(bnep_exit);
7581da177e4SLinus Torvalds
75928111eb2SMarcel Holtmann module_param(compress_src, bool, 0644);
76028111eb2SMarcel Holtmann MODULE_PARM_DESC(compress_src, "Compress sources headers");
76128111eb2SMarcel Holtmann
76228111eb2SMarcel Holtmann module_param(compress_dst, bool, 0644);
76328111eb2SMarcel Holtmann MODULE_PARM_DESC(compress_dst, "Compress destination headers");
76428111eb2SMarcel Holtmann
76563fbd24eSMarcel Holtmann MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
7661da177e4SLinus Torvalds MODULE_DESCRIPTION("Bluetooth BNEP ver " VERSION);
7671da177e4SLinus Torvalds MODULE_VERSION(VERSION);
7681da177e4SLinus Torvalds MODULE_LICENSE("GPL");
7691da177e4SLinus Torvalds MODULE_ALIAS("bt-proto-4");
770