blob: fbf251fef70fe89d61a3533bbb7a6b3e18429c01 [file] [log] [blame]
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 BNEP implementation for Linux Bluetooth stack (BlueZ).
3 Copyright (C) 2001-2002 Inventel Systemes
4 Written 2001-2002 by
Jan Engelhardt96de0e22007-10-19 23:21:04 +02005 Clément Moreau <clement.moreau@inventel.fr>
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 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
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090018 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
Linus Torvalds1da177e2005-04-16 15:20:36 -070021 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090023 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
24 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
Linus Torvalds1da177e2005-04-16 15:20:36 -070025 SOFTWARE IS DISCLAIMED.
26*/
27
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <linux/module.h>
Szymon Jancf4d7cd42011-03-21 14:20:00 +010029#include <linux/kthread.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/file.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <linux/etherdevice.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <asm/unaligned.h>
33
34#include <net/bluetooth/bluetooth.h>
Marcel Holtmann65f53e92013-10-13 09:49:57 -070035#include <net/bluetooth/l2cap.h>
Marcel Holtmann0a85b962006-07-06 13:09:02 +020036#include <net/bluetooth/hci_core.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037
38#include "bnep.h"
39
Marcel Holtmann28111eb2008-08-07 22:26:54 +020040#define VERSION "1.3"
41
Rusty Russelleb939922011-12-19 14:08:01 +000042static bool compress_src = true;
43static bool compress_dst = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -070044
45static LIST_HEAD(bnep_session_list);
46static DECLARE_RWSEM(bnep_session_sem);
47
48static struct bnep_session *__bnep_get_session(u8 *dst)
49{
50 struct bnep_session *s;
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
52 BT_DBG("");
53
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +020054 list_for_each_entry(s, &bnep_session_list, list)
Joe Perchesc47fc982012-05-08 18:56:51 +000055 if (ether_addr_equal(dst, s->eh.h_source))
Linus Torvalds1da177e2005-04-16 15:20:36 -070056 return s;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +020057
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 return NULL;
59}
60
61static void __bnep_link_session(struct bnep_session *s)
62{
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090063 list_add(&s->list, &bnep_session_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -070064}
65
66static void __bnep_unlink_session(struct bnep_session *s)
67{
68 list_del(&s->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -070069}
70
71static 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
79static 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
89static inline void bnep_set_default_proto_filter(struct bnep_session *s)
90{
91 /* (IPv4, ARP) */
Al Viroe41d2162006-11-08 00:27:36 -080092 s->proto_filter[0].start = ETH_P_IP;
93 s->proto_filter[0].end = ETH_P_ARP;
Linus Torvalds1da177e2005-04-16 15:20:36 -070094 /* (RARP, AppleTalk) */
Al Viroe41d2162006-11-08 00:27:36 -080095 s->proto_filter[1].start = ETH_P_RARP;
96 s->proto_filter[1].end = ETH_P_AARP;
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 /* (IPX, IPv6) */
Al Viroe41d2162006-11-08 00:27:36 -080098 s->proto_filter[2].start = ETH_P_IPX;
99 s->proto_filter[2].end = ETH_P_IPV6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100}
101#endif
102
Al Viro1bc5d442006-11-08 00:27:57 -0800103static int bnep_ctrl_set_netfilter(struct bnep_session *s, __be16 *data, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104{
105 int n;
106
107 if (len < 2)
108 return -EILSEQ;
109
Harvey Harrison83985312008-05-02 16:25:46 -0700110 n = get_unaligned_be16(data);
Szymon Janc3aad75a2011-03-21 14:19:58 +0100111 data++;
112 len -= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113
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++) {
Harvey Harrison83985312008-05-02 16:25:46 -0700126 f[i].start = get_unaligned_be16(data++);
127 f[i].end = get_unaligned_be16(data++);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128
129 BT_DBG("proto filter start %d end %d",
130 f[i].start, f[i].end);
131 }
132
133 if (i < BNEP_MAX_PROTO_FILTERS)
134 memset(f + i, 0, sizeof(*f));
135
136 if (n == 0)
137 bnep_set_default_proto_filter(s);
138
139 bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_SUCCESS);
140 } else {
141 bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_LIMIT_REACHED);
142 }
143#else
144 bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_UNSUPPORTED_REQ);
145#endif
146 return 0;
147}
148
149static 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
Harvey Harrison83985312008-05-02 16:25:46 -0700156 n = get_unaligned_be16(data);
Szymon Janc3aad75a2011-03-21 14:19:58 +0100157 data += 2;
158 len -= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159
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) {
Szymon Janca3d9bd42011-03-21 14:19:57 +0100169 int i;
170
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 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
Szymon Janc3aad75a2011-03-21 14:19:58 +0100180 memcpy(a1, data, ETH_ALEN);
181 data += ETH_ALEN;
182 a2 = data;
183 data += ETH_ALEN;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900184
Andrei Emeltchenko6ed93dc2012-09-25 12:49:43 +0300185 BT_DBG("mc filter %pMR -> %pMR", a1, a2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 /* 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) {
Szymon Janca3d9bd42011-03-21 14:19:57 +0100190 /* Increment a1 */
191 i = 5;
192 while (i >= 0 && ++a1[i--] == 0)
193 ;
194
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 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
209static int bnep_rx_control(struct bnep_session *s, void *data, int len)
210{
211 u8 cmd = *(u8 *)data;
212 int err = 0;
213
Szymon Janc3aad75a2011-03-21 14:19:58 +0100214 data++;
215 len--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216
217 switch (cmd) {
218 case BNEP_CMD_NOT_UNDERSTOOD:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 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
Vikram Kandukuricde9f802009-12-03 15:12:51 +0530233 case BNEP_SETUP_CONN_REQ:
Grzegorz Kolodziejczyk836a0612015-04-03 12:14:55 +0200234 /* 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);
Vikram Kandukuricde9f802009-12-03 15:12:51 +0530242 break;
243
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 default: {
245 u8 pkt[3];
246 pkt[0] = BNEP_CONTROL;
247 pkt[1] = BNEP_CMD_NOT_UNDERSTOOD;
248 pkt[2] = cmd;
Grzegorz Kolodziejczyke0fdbab2015-04-03 12:14:52 +0200249 err = bnep_send(s, pkt, sizeof(pkt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 }
251 break;
252 }
253
254 return err;
255}
256
257static 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 %d", h->type, h->len);
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900270
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 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));
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900286
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 return err;
288}
289
290static 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};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297
Gustavo Padovan6039aa72012-05-23 04:04:18 -0300298static int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299{
300 struct net_device *dev = s->dev;
301 struct sk_buff *nskb;
Grzegorz Kolodziejczykbf8b9a92015-04-03 12:14:54 +0200302 u8 type, ctrl_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303
Stephen Hemmingerb4d7f0a2009-01-07 17:23:17 -0800304 dev->stats.rx_bytes += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305
Szymon Janc3aad75a2011-03-21 14:19:58 +0100306 type = *(u8 *) skb->data;
307 skb_pull(skb, 1);
Grzegorz Kolodziejczykbf8b9a92015-04-03 12:14:54 +0200308 ctrl_type = *(u8 *)skb->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309
Szymon Janca3d9bd42011-03-21 14:19:57 +0100310 if ((type & BNEP_TYPE_MASK) >= sizeof(__bnep_rx_hlen))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 goto badframe;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900312
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) {
Grzegorz Kolodziejczykbf8b9a92015-04-03 12:14:54 +0200314 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));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 }
351
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 if (type & BNEP_EXT_HEADER) {
353 if (bnep_rx_extension(s, skb) < 0)
354 goto badframe;
355 }
356
357 /* Strip 802.1p header */
Eldad Zack000092b2012-05-08 00:09:35 +0200358 if (ntohs(s->eh.h_proto) == ETH_P_8021Q) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 if (!skb_pull(skb, 4))
360 goto badframe;
Al Viro1bc5d442006-11-08 00:27:57 -0800361 s->eh.h_proto = get_unaligned((__be16 *) (skb->data - 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 }
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900363
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 /* 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) {
Stephen Hemmingerb4d7f0a2009-01-07 17:23:17 -0800368 dev->stats.rx_dropped++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 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 memcpy(__skb_put(nskb, ETH_HLEN), &s->eh, ETH_HLEN);
378 break;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900379
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 case BNEP_COMPRESSED_SRC_ONLY:
381 memcpy(__skb_put(nskb, ETH_ALEN), s->eh.h_dest, ETH_ALEN);
Arnaldo Carvalho de Melo98e399f2007-03-19 15:33:04 -0700382 memcpy(__skb_put(nskb, ETH_ALEN), skb_mac_header(skb), ETH_ALEN);
Al Viro1bc5d442006-11-08 00:27:57 -0800383 put_unaligned(s->eh.h_proto, (__be16 *) __skb_put(nskb, 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 break;
385
386 case BNEP_COMPRESSED_DST_ONLY:
Arnaldo Carvalho de Melo98e399f2007-03-19 15:33:04 -0700387 memcpy(__skb_put(nskb, ETH_ALEN), skb_mac_header(skb),
Szymon Janc3aad75a2011-03-21 14:19:58 +0100388 ETH_ALEN);
Arnaldo Carvalho de Melo98e399f2007-03-19 15:33:04 -0700389 memcpy(__skb_put(nskb, ETH_ALEN + 2), s->eh.h_source,
Szymon Janc3aad75a2011-03-21 14:19:58 +0100390 ETH_ALEN + 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 break;
392
393 case BNEP_GENERAL:
Arnaldo Carvalho de Melo98e399f2007-03-19 15:33:04 -0700394 memcpy(__skb_put(nskb, ETH_ALEN * 2), skb_mac_header(skb),
Szymon Janc3aad75a2011-03-21 14:19:58 +0100395 ETH_ALEN * 2);
Al Viro1bc5d442006-11-08 00:27:57 -0800396 put_unaligned(s->eh.h_proto, (__be16 *) __skb_put(nskb, 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 break;
398 }
399
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -0300400 skb_copy_from_linear_data(skb, __skb_put(nskb, skb->len), skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 kfree_skb(skb);
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900402
Stephen Hemmingerb4d7f0a2009-01-07 17:23:17 -0800403 dev->stats.rx_packets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 nskb->ip_summed = CHECKSUM_NONE;
405 nskb->protocol = eth_type_trans(nskb, dev);
406 netif_rx_ni(nskb);
407 return 0;
408
409badframe:
Stephen Hemmingerb4d7f0a2009-01-07 17:23:17 -0800410 dev->stats.rx_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 kfree_skb(skb);
412 return 0;
413}
414
415static u8 __bnep_tx_types[] = {
416 BNEP_GENERAL,
417 BNEP_COMPRESSED_SRC_ONLY,
418 BNEP_COMPRESSED_DST_ONLY,
419 BNEP_COMPRESSED
420};
421
Gustavo Padovan6039aa72012-05-23 04:04:18 -0300422static int bnep_tx_frame(struct bnep_session *s, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423{
424 struct ethhdr *eh = (void *) skb->data;
425 struct socket *sock = s->sock;
426 struct kvec iv[3];
427 int len = 0, il = 0;
428 u8 type = 0;
429
430 BT_DBG("skb %p dev %p type %d", skb, skb->dev, skb->pkt_type);
431
432 if (!skb->dev) {
433 /* Control frame sent by us */
434 goto send;
435 }
436
437 iv[il++] = (struct kvec) { &type, 1 };
438 len++;
439
Joe Perchesc47fc982012-05-08 18:56:51 +0000440 if (compress_src && ether_addr_equal(eh->h_dest, s->eh.h_source))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 type |= 0x01;
442
Joe Perchesc47fc982012-05-08 18:56:51 +0000443 if (compress_dst && ether_addr_equal(eh->h_source, s->eh.h_dest))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 type |= 0x02;
445
446 if (type)
447 skb_pull(skb, ETH_ALEN * 2);
448
449 type = __bnep_tx_types[type];
450 switch (type) {
451 case BNEP_COMPRESSED_SRC_ONLY:
452 iv[il++] = (struct kvec) { eh->h_source, ETH_ALEN };
453 len += ETH_ALEN;
454 break;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900455
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 case BNEP_COMPRESSED_DST_ONLY:
457 iv[il++] = (struct kvec) { eh->h_dest, ETH_ALEN };
458 len += ETH_ALEN;
459 break;
460 }
461
462send:
463 iv[il++] = (struct kvec) { skb->data, skb->len };
464 len += skb->len;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900465
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 /* FIXME: linearize skb */
467 {
468 len = kernel_sendmsg(sock, &s->msg, iv, il, len);
469 }
470 kfree_skb(skb);
471
472 if (len > 0) {
Stephen Hemmingerb4d7f0a2009-01-07 17:23:17 -0800473 s->dev->stats.tx_bytes += len;
474 s->dev->stats.tx_packets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 return 0;
476 }
477
478 return len;
479}
480
481static int bnep_session(void *arg)
482{
483 struct bnep_session *s = arg;
484 struct net_device *dev = s->dev;
485 struct sock *sk = s->sock->sk;
486 struct sk_buff *skb;
487 wait_queue_t wait;
488
489 BT_DBG("");
490
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 set_user_nice(current, -15);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492
493 init_waitqueue_entry(&wait, current);
Eric Dumazetaa395142010-04-20 13:03:51 +0000494 add_wait_queue(sk_sleep(sk), &wait);
Peter Hurley38d57552011-07-24 00:11:07 -0400495 while (1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 set_current_state(TASK_INTERRUPTIBLE);
497
Peter Hurley751c10a2011-08-05 10:41:35 -0400498 if (atomic_read(&s->terminate))
Peter Hurley38d57552011-07-24 00:11:07 -0400499 break;
Szymon Janc3aad75a2011-03-21 14:19:58 +0100500 /* RX */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
502 skb_orphan(skb);
Mat Martineau44935722011-07-22 14:53:58 -0700503 if (!skb_linearize(skb))
504 bnep_rx_frame(s, skb);
505 else
506 kfree_skb(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 }
508
509 if (sk->sk_state != BT_CONNECTED)
510 break;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900511
Szymon Janc3aad75a2011-03-21 14:19:58 +0100512 /* TX */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 while ((skb = skb_dequeue(&sk->sk_write_queue)))
514 if (bnep_tx_frame(s, skb))
515 break;
516 netif_wake_queue(dev);
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900517
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 schedule();
519 }
Peter Hurley38d57552011-07-24 00:11:07 -0400520 __set_current_state(TASK_RUNNING);
Eric Dumazetaa395142010-04-20 13:03:51 +0000521 remove_wait_queue(sk_sleep(sk), &wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522
523 /* Cleanup session */
524 down_write(&bnep_session_sem);
525
526 /* Delete network device */
527 unregister_netdev(dev);
528
Marcel Holtmannec8dab32008-07-14 20:13:53 +0200529 /* Wakeup user-space polling for socket errors */
530 s->sock->sk->sk_err = EUNATCH;
531
Eric Dumazetaa395142010-04-20 13:03:51 +0000532 wake_up_interruptible(sk_sleep(s->sock->sk));
Marcel Holtmannec8dab32008-07-14 20:13:53 +0200533
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 /* Release the socket */
535 fput(s->sock->file);
536
537 __bnep_unlink_session(s);
538
539 up_write(&bnep_session_sem);
540 free_netdev(dev);
David Herrmann9b338c32011-11-19 13:23:33 +0100541 module_put_and_exit(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 return 0;
543}
544
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200545static struct device *bnep_get_device(struct bnep_session *session)
546{
Johan Hedberg88d90772015-02-03 10:01:13 +0200547 struct l2cap_conn *conn = l2cap_pi(session->sock->sk)->chan->conn;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200548
Johan Hedberg88d90772015-02-03 10:01:13 +0200549 if (!conn || !conn->hcon)
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200550 return NULL;
551
Johan Hedberg88d90772015-02-03 10:01:13 +0200552 return &conn->hcon->dev;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200553}
554
Marcel Holtmann384912e2009-08-31 21:08:19 +0000555static struct device_type bnep_type = {
556 .name = "bluetooth",
557};
558
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
560{
Grzegorz Kolodziejczyk836a0612015-04-03 12:14:55 +0200561 u32 valid_flags = BIT(BNEP_SETUP_RESPONSE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 struct net_device *dev;
563 struct bnep_session *s, *ss;
564 u8 dst[ETH_ALEN], src[ETH_ALEN];
565 int err;
566
567 BT_DBG("");
568
Al Viro71bb99a2014-12-19 06:20:59 +0000569 if (!l2cap_is_socket(sock))
570 return -EBADFD;
571
Marcel Holtmann0151e422015-04-01 13:51:54 -0700572 if (req->flags & ~valid_flags)
573 return -EINVAL;
574
Marcel Holtmann65f53e92013-10-13 09:49:57 -0700575 baswap((void *) dst, &l2cap_pi(sock->sk)->chan->dst);
576 baswap((void *) src, &l2cap_pi(sock->sk)->chan->src);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577
578 /* session struct allocated as private part of net_device */
579 dev = alloc_netdev(sizeof(struct bnep_session),
Tom Gundersenc835a672014-07-14 16:37:24 +0200580 (*req->device) ? req->device : "bnep%d",
581 NET_NAME_UNKNOWN,
582 bnep_net_setup);
Tobias Klauser67b52e52006-03-21 23:53:16 -0800583 if (!dev)
584 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 down_write(&bnep_session_sem);
587
588 ss = __bnep_get_session(dst);
589 if (ss && ss->state == BT_CONNECTED) {
590 err = -EEXIST;
591 goto failed;
592 }
593
Wang Chen524ad0a2008-11-12 23:39:10 -0800594 s = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595
596 /* This is rx header therefore addresses are swapped.
Szymon Janc3aad75a2011-03-21 14:19:58 +0100597 * ie. eh.h_dest is our local address. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 memcpy(s->eh.h_dest, &src, ETH_ALEN);
599 memcpy(s->eh.h_source, &dst, ETH_ALEN);
600 memcpy(dev->dev_addr, s->eh.h_dest, ETH_ALEN);
601
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200602 s->dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 s->sock = sock;
604 s->role = req->role;
605 s->state = BT_CONNECTED;
Grzegorz Kolodziejczyk836a0612015-04-03 12:14:55 +0200606 s->flags = req->flags;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900607
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 s->msg.msg_flags = MSG_NOSIGNAL;
609
610#ifdef CONFIG_BT_BNEP_MC_FILTER
Danny Schweizer4ada1282015-12-11 10:04:54 +0100611 /* Set default mc filter to not filter out any mc addresses
612 * as defined in the BNEP specification (revision 0.95a)
613 * http://grouper.ieee.org/groups/802/15/Bluetooth/BNEP.pdf
614 */
615 s->mc_filter = ~0LL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616#endif
617
618#ifdef CONFIG_BT_BNEP_PROTO_FILTER
619 /* Set default protocol filter */
620 bnep_set_default_proto_filter(s);
621#endif
622
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200623 SET_NETDEV_DEV(dev, bnep_get_device(s));
Marcel Holtmann384912e2009-08-31 21:08:19 +0000624 SET_NETDEV_DEVTYPE(dev, &bnep_type);
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200625
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 err = register_netdev(dev);
Szymon Janc3aad75a2011-03-21 14:19:58 +0100627 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629
630 __bnep_link_session(s);
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900631
David Herrmann9b338c32011-11-19 13:23:33 +0100632 __module_get(THIS_MODULE);
Szymon Jancf4d7cd42011-03-21 14:20:00 +0100633 s->task = kthread_run(bnep_session, s, "kbnepd %s", dev->name);
634 if (IS_ERR(s->task)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 /* Session thread start failed, gotta cleanup. */
David Herrmann9b338c32011-11-19 13:23:33 +0100636 module_put(THIS_MODULE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 unregister_netdev(dev);
638 __bnep_unlink_session(s);
Szymon Jancf4d7cd42011-03-21 14:20:00 +0100639 err = PTR_ERR(s->task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 goto failed;
641 }
642
643 up_write(&bnep_session_sem);
644 strcpy(req->device, dev->name);
645 return 0;
646
647failed:
648 up_write(&bnep_session_sem);
649 free_netdev(dev);
650 return err;
651}
652
653int bnep_del_connection(struct bnep_conndel_req *req)
654{
Marcel Holtmann0151e422015-04-01 13:51:54 -0700655 u32 valid_flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 struct bnep_session *s;
657 int err = 0;
658
659 BT_DBG("");
660
Marcel Holtmann0151e422015-04-01 13:51:54 -0700661 if (req->flags & ~valid_flags)
662 return -EINVAL;
663
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 down_read(&bnep_session_sem);
665
666 s = __bnep_get_session(req->dst);
Peter Hurley751c10a2011-08-05 10:41:35 -0400667 if (s) {
668 atomic_inc(&s->terminate);
669 wake_up_process(s->task);
670 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 err = -ENOENT;
672
673 up_read(&bnep_session_sem);
674 return err;
675}
676
677static void __bnep_copy_ci(struct bnep_conninfo *ci, struct bnep_session *s)
678{
Grzegorz Kolodziejczyk836a0612015-04-03 12:14:55 +0200679 u32 valid_flags = BIT(BNEP_SETUP_RESPONSE);
Marcel Holtmann0151e422015-04-01 13:51:54 -0700680
Vasiliy Kulikov5520d202010-10-30 18:26:21 +0400681 memset(ci, 0, sizeof(*ci));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 memcpy(ci->dst, s->eh.h_source, ETH_ALEN);
683 strcpy(ci->device, s->dev->name);
Marcel Holtmann0151e422015-04-01 13:51:54 -0700684 ci->flags = s->flags & valid_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 ci->state = s->state;
686 ci->role = s->role;
687}
688
689int bnep_get_connlist(struct bnep_connlist_req *req)
690{
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200691 struct bnep_session *s;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 int err = 0, n = 0;
693
694 down_read(&bnep_session_sem);
695
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200696 list_for_each_entry(s, &bnep_session_list, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 struct bnep_conninfo ci;
698
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 __bnep_copy_ci(&ci, s);
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900700
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 if (copy_to_user(req->ci, &ci, sizeof(ci))) {
702 err = -EFAULT;
703 break;
704 }
705
706 if (++n >= req->cnum)
707 break;
708
709 req->ci++;
710 }
711 req->cnum = n;
712
713 up_read(&bnep_session_sem);
714 return err;
715}
716
717int bnep_get_conninfo(struct bnep_conninfo *ci)
718{
719 struct bnep_session *s;
720 int err = 0;
721
722 down_read(&bnep_session_sem);
723
724 s = __bnep_get_session(ci->dst);
725 if (s)
726 __bnep_copy_ci(ci, s);
727 else
728 err = -ENOENT;
729
730 up_read(&bnep_session_sem);
731 return err;
732}
733
734static int __init bnep_init(void)
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900735{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 char flt[50] = "";
737
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738#ifdef CONFIG_BT_BNEP_PROTO_FILTER
739 strcat(flt, "protocol ");
740#endif
741
742#ifdef CONFIG_BT_BNEP_MC_FILTER
743 strcat(flt, "multicast");
744#endif
745
746 BT_INFO("BNEP (Ethernet Emulation) ver %s", VERSION);
747 if (flt[0])
748 BT_INFO("BNEP filters: %s", flt);
749
750 bnep_sock_init();
751 return 0;
752}
753
754static void __exit bnep_exit(void)
755{
756 bnep_sock_cleanup();
757}
758
759module_init(bnep_init);
760module_exit(bnep_exit);
761
Marcel Holtmann28111eb2008-08-07 22:26:54 +0200762module_param(compress_src, bool, 0644);
763MODULE_PARM_DESC(compress_src, "Compress sources headers");
764
765module_param(compress_dst, bool, 0644);
766MODULE_PARM_DESC(compress_dst, "Compress destination headers");
767
Marcel Holtmann63fbd242008-08-18 13:23:53 +0200768MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769MODULE_DESCRIPTION("Bluetooth BNEP ver " VERSION);
770MODULE_VERSION(VERSION);
771MODULE_LICENSE("GPL");
772MODULE_ALIAS("bt-proto-4");