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