blob: 4d6b94d7ce5f778a2ac8d634d936acececc2b643 [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 Padovan6039aa732012-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 Padovan6039aa732012-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;
Jeffy Chen242cea22017-06-27 17:34:42 +0800487 DEFINE_WAIT_FUNC(wait, woken_wake_function);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488
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
Eric Dumazetaa395142010-04-20 13:03:51 +0000493 add_wait_queue(sk_sleep(sk), &wait);
Peter Hurley38d57552011-07-24 00:11:07 -0400494 while (1) {
Jeffy Chen242cea22017-06-27 17:34:42 +0800495 /* Ensure session->terminate is updated */
496 smp_mb__before_atomic();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497
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
Jeffy Chen242cea22017-06-27 17:34:42 +0800518 wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 }
Eric Dumazetaa395142010-04-20 13:03:51 +0000520 remove_wait_queue(sk_sleep(sk), &wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521
522 /* Cleanup session */
523 down_write(&bnep_session_sem);
524
525 /* Delete network device */
526 unregister_netdev(dev);
527
Marcel Holtmannec8dab32008-07-14 20:13:53 +0200528 /* Wakeup user-space polling for socket errors */
529 s->sock->sk->sk_err = EUNATCH;
530
Eric Dumazetaa395142010-04-20 13:03:51 +0000531 wake_up_interruptible(sk_sleep(s->sock->sk));
Marcel Holtmannec8dab32008-07-14 20:13:53 +0200532
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 /* Release the socket */
534 fput(s->sock->file);
535
536 __bnep_unlink_session(s);
537
538 up_write(&bnep_session_sem);
539 free_netdev(dev);
David Herrmann9b338c32011-11-19 13:23:33 +0100540 module_put_and_exit(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 return 0;
542}
543
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200544static struct device *bnep_get_device(struct bnep_session *session)
545{
Johan Hedberg88d90772015-02-03 10:01:13 +0200546 struct l2cap_conn *conn = l2cap_pi(session->sock->sk)->chan->conn;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200547
Johan Hedberg88d90772015-02-03 10:01:13 +0200548 if (!conn || !conn->hcon)
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200549 return NULL;
550
Johan Hedberg88d90772015-02-03 10:01:13 +0200551 return &conn->hcon->dev;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200552}
553
Marcel Holtmann384912e2009-08-31 21:08:19 +0000554static struct device_type bnep_type = {
555 .name = "bluetooth",
556};
557
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
559{
Grzegorz Kolodziejczyk836a0612015-04-03 12:14:55 +0200560 u32 valid_flags = BIT(BNEP_SETUP_RESPONSE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 struct net_device *dev;
562 struct bnep_session *s, *ss;
563 u8 dst[ETH_ALEN], src[ETH_ALEN];
564 int err;
565
566 BT_DBG("");
567
Al Viro71bb99a2014-12-19 06:20:59 +0000568 if (!l2cap_is_socket(sock))
569 return -EBADFD;
570
Marcel Holtmann0151e422015-04-01 13:51:54 -0700571 if (req->flags & ~valid_flags)
572 return -EINVAL;
573
Marcel Holtmann65f53e92013-10-13 09:49:57 -0700574 baswap((void *) dst, &l2cap_pi(sock->sk)->chan->dst);
575 baswap((void *) src, &l2cap_pi(sock->sk)->chan->src);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576
577 /* session struct allocated as private part of net_device */
578 dev = alloc_netdev(sizeof(struct bnep_session),
Tom Gundersenc835a672014-07-14 16:37:24 +0200579 (*req->device) ? req->device : "bnep%d",
580 NET_NAME_UNKNOWN,
581 bnep_net_setup);
Tobias Klauser67b52e52006-03-21 23:53:16 -0800582 if (!dev)
583 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 down_write(&bnep_session_sem);
586
587 ss = __bnep_get_session(dst);
588 if (ss && ss->state == BT_CONNECTED) {
589 err = -EEXIST;
590 goto failed;
591 }
592
Wang Chen524ad0a2008-11-12 23:39:10 -0800593 s = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594
595 /* This is rx header therefore addresses are swapped.
Szymon Janc3aad75a2011-03-21 14:19:58 +0100596 * ie. eh.h_dest is our local address. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 memcpy(s->eh.h_dest, &src, ETH_ALEN);
598 memcpy(s->eh.h_source, &dst, ETH_ALEN);
599 memcpy(dev->dev_addr, s->eh.h_dest, ETH_ALEN);
600
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200601 s->dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 s->sock = sock;
603 s->role = req->role;
604 s->state = BT_CONNECTED;
Grzegorz Kolodziejczyk836a0612015-04-03 12:14:55 +0200605 s->flags = req->flags;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900606
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 s->msg.msg_flags = MSG_NOSIGNAL;
608
609#ifdef CONFIG_BT_BNEP_MC_FILTER
Danny Schweizer4ada1282015-12-11 10:04:54 +0100610 /* Set default mc filter to not filter out any mc addresses
611 * as defined in the BNEP specification (revision 0.95a)
612 * http://grouper.ieee.org/groups/802/15/Bluetooth/BNEP.pdf
613 */
614 s->mc_filter = ~0LL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615#endif
616
617#ifdef CONFIG_BT_BNEP_PROTO_FILTER
618 /* Set default protocol filter */
619 bnep_set_default_proto_filter(s);
620#endif
621
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200622 SET_NETDEV_DEV(dev, bnep_get_device(s));
Marcel Holtmann384912e2009-08-31 21:08:19 +0000623 SET_NETDEV_DEVTYPE(dev, &bnep_type);
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200624
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 err = register_netdev(dev);
Szymon Janc3aad75a2011-03-21 14:19:58 +0100626 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628
629 __bnep_link_session(s);
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900630
David Herrmann9b338c32011-11-19 13:23:33 +0100631 __module_get(THIS_MODULE);
Szymon Jancf4d7cd42011-03-21 14:20:00 +0100632 s->task = kthread_run(bnep_session, s, "kbnepd %s", dev->name);
633 if (IS_ERR(s->task)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 /* Session thread start failed, gotta cleanup. */
David Herrmann9b338c32011-11-19 13:23:33 +0100635 module_put(THIS_MODULE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 unregister_netdev(dev);
637 __bnep_unlink_session(s);
Szymon Jancf4d7cd42011-03-21 14:20:00 +0100638 err = PTR_ERR(s->task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 goto failed;
640 }
641
642 up_write(&bnep_session_sem);
643 strcpy(req->device, dev->name);
644 return 0;
645
646failed:
647 up_write(&bnep_session_sem);
648 free_netdev(dev);
649 return err;
650}
651
652int bnep_del_connection(struct bnep_conndel_req *req)
653{
Marcel Holtmann0151e422015-04-01 13:51:54 -0700654 u32 valid_flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 struct bnep_session *s;
656 int err = 0;
657
658 BT_DBG("");
659
Marcel Holtmann0151e422015-04-01 13:51:54 -0700660 if (req->flags & ~valid_flags)
661 return -EINVAL;
662
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 down_read(&bnep_session_sem);
664
665 s = __bnep_get_session(req->dst);
Peter Hurley751c10a2011-08-05 10:41:35 -0400666 if (s) {
667 atomic_inc(&s->terminate);
Jeffy Chen242cea22017-06-27 17:34:42 +0800668 wake_up_interruptible(sk_sleep(s->sock->sk));
Peter Hurley751c10a2011-08-05 10:41:35 -0400669 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 err = -ENOENT;
671
672 up_read(&bnep_session_sem);
673 return err;
674}
675
676static void __bnep_copy_ci(struct bnep_conninfo *ci, struct bnep_session *s)
677{
Grzegorz Kolodziejczyk836a0612015-04-03 12:14:55 +0200678 u32 valid_flags = BIT(BNEP_SETUP_RESPONSE);
Marcel Holtmann0151e422015-04-01 13:51:54 -0700679
Vasiliy Kulikov5520d202010-10-30 18:26:21 +0400680 memset(ci, 0, sizeof(*ci));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 memcpy(ci->dst, s->eh.h_source, ETH_ALEN);
682 strcpy(ci->device, s->dev->name);
Marcel Holtmann0151e422015-04-01 13:51:54 -0700683 ci->flags = s->flags & valid_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 ci->state = s->state;
685 ci->role = s->role;
686}
687
688int bnep_get_connlist(struct bnep_connlist_req *req)
689{
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200690 struct bnep_session *s;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 int err = 0, n = 0;
692
693 down_read(&bnep_session_sem);
694
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200695 list_for_each_entry(s, &bnep_session_list, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 struct bnep_conninfo ci;
697
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 __bnep_copy_ci(&ci, s);
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900699
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 if (copy_to_user(req->ci, &ci, sizeof(ci))) {
701 err = -EFAULT;
702 break;
703 }
704
705 if (++n >= req->cnum)
706 break;
707
708 req->ci++;
709 }
710 req->cnum = n;
711
712 up_read(&bnep_session_sem);
713 return err;
714}
715
716int bnep_get_conninfo(struct bnep_conninfo *ci)
717{
718 struct bnep_session *s;
719 int err = 0;
720
721 down_read(&bnep_session_sem);
722
723 s = __bnep_get_session(ci->dst);
724 if (s)
725 __bnep_copy_ci(ci, s);
726 else
727 err = -ENOENT;
728
729 up_read(&bnep_session_sem);
730 return err;
731}
732
733static int __init bnep_init(void)
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900734{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 char flt[50] = "";
736
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737#ifdef CONFIG_BT_BNEP_PROTO_FILTER
738 strcat(flt, "protocol ");
739#endif
740
741#ifdef CONFIG_BT_BNEP_MC_FILTER
742 strcat(flt, "multicast");
743#endif
744
745 BT_INFO("BNEP (Ethernet Emulation) ver %s", VERSION);
746 if (flt[0])
747 BT_INFO("BNEP filters: %s", flt);
748
749 bnep_sock_init();
750 return 0;
751}
752
753static void __exit bnep_exit(void)
754{
755 bnep_sock_cleanup();
756}
757
758module_init(bnep_init);
759module_exit(bnep_exit);
760
Marcel Holtmann28111eb2008-08-07 22:26:54 +0200761module_param(compress_src, bool, 0644);
762MODULE_PARM_DESC(compress_src, "Compress sources headers");
763
764module_param(compress_dst, bool, 0644);
765MODULE_PARM_DESC(compress_dst, "Compress destination headers");
766
Marcel Holtmann63fbd242008-08-18 13:23:53 +0200767MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768MODULE_DESCRIPTION("Bluetooth BNEP ver " VERSION);
769MODULE_VERSION(VERSION);
770MODULE_LICENSE("GPL");
771MODULE_ALIAS("bt-proto-4");