blob: 7b3965861013c4ed85f818efaff54336a3dc84fe [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:
yuan linyude77b962017-06-18 22:48:17 +0800377 __skb_put_data(nskb, &s->eh, ETH_HLEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 break;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900379
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 case BNEP_COMPRESSED_SRC_ONLY:
yuan linyude77b962017-06-18 22:48:17 +0800381 __skb_put_data(nskb, s->eh.h_dest, ETH_ALEN);
382 __skb_put_data(nskb, 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:
yuan linyude77b962017-06-18 22:48:17 +0800387 __skb_put_data(nskb, skb_mac_header(skb), ETH_ALEN);
388 __skb_put_data(nskb, s->eh.h_source, ETH_ALEN + 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 break;
390
391 case BNEP_GENERAL:
yuan linyude77b962017-06-18 22:48:17 +0800392 __skb_put_data(nskb, skb_mac_header(skb), ETH_ALEN * 2);
Al Viro1bc5d442006-11-08 00:27:57 -0800393 put_unaligned(s->eh.h_proto, (__be16 *) __skb_put(nskb, 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 break;
395 }
396
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -0300397 skb_copy_from_linear_data(skb, __skb_put(nskb, skb->len), skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 kfree_skb(skb);
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900399
Stephen Hemmingerb4d7f0a2009-01-07 17:23:17 -0800400 dev->stats.rx_packets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 nskb->ip_summed = CHECKSUM_NONE;
402 nskb->protocol = eth_type_trans(nskb, dev);
403 netif_rx_ni(nskb);
404 return 0;
405
406badframe:
Stephen Hemmingerb4d7f0a2009-01-07 17:23:17 -0800407 dev->stats.rx_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 kfree_skb(skb);
409 return 0;
410}
411
412static u8 __bnep_tx_types[] = {
413 BNEP_GENERAL,
414 BNEP_COMPRESSED_SRC_ONLY,
415 BNEP_COMPRESSED_DST_ONLY,
416 BNEP_COMPRESSED
417};
418
Gustavo Padovan6039aa72012-05-23 04:04:18 -0300419static int bnep_tx_frame(struct bnep_session *s, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420{
421 struct ethhdr *eh = (void *) skb->data;
422 struct socket *sock = s->sock;
423 struct kvec iv[3];
424 int len = 0, il = 0;
425 u8 type = 0;
426
427 BT_DBG("skb %p dev %p type %d", skb, skb->dev, skb->pkt_type);
428
429 if (!skb->dev) {
430 /* Control frame sent by us */
431 goto send;
432 }
433
434 iv[il++] = (struct kvec) { &type, 1 };
435 len++;
436
Joe Perchesc47fc982012-05-08 18:56:51 +0000437 if (compress_src && ether_addr_equal(eh->h_dest, s->eh.h_source))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 type |= 0x01;
439
Joe Perchesc47fc982012-05-08 18:56:51 +0000440 if (compress_dst && ether_addr_equal(eh->h_source, s->eh.h_dest))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 type |= 0x02;
442
443 if (type)
444 skb_pull(skb, ETH_ALEN * 2);
445
446 type = __bnep_tx_types[type];
447 switch (type) {
448 case BNEP_COMPRESSED_SRC_ONLY:
449 iv[il++] = (struct kvec) { eh->h_source, ETH_ALEN };
450 len += ETH_ALEN;
451 break;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900452
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 case BNEP_COMPRESSED_DST_ONLY:
454 iv[il++] = (struct kvec) { eh->h_dest, ETH_ALEN };
455 len += ETH_ALEN;
456 break;
457 }
458
459send:
460 iv[il++] = (struct kvec) { skb->data, skb->len };
461 len += skb->len;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900462
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 /* FIXME: linearize skb */
464 {
465 len = kernel_sendmsg(sock, &s->msg, iv, il, len);
466 }
467 kfree_skb(skb);
468
469 if (len > 0) {
Stephen Hemmingerb4d7f0a2009-01-07 17:23:17 -0800470 s->dev->stats.tx_bytes += len;
471 s->dev->stats.tx_packets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 return 0;
473 }
474
475 return len;
476}
477
478static int bnep_session(void *arg)
479{
480 struct bnep_session *s = arg;
481 struct net_device *dev = s->dev;
482 struct sock *sk = s->sock->sk;
483 struct sk_buff *skb;
Jeffy Chen25717382017-06-27 17:34:42 +0800484 DEFINE_WAIT_FUNC(wait, woken_wake_function);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485
486 BT_DBG("");
487
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 set_user_nice(current, -15);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489
Eric Dumazetaa395142010-04-20 13:03:51 +0000490 add_wait_queue(sk_sleep(sk), &wait);
Peter Hurley38d57552011-07-24 00:11:07 -0400491 while (1) {
Jeffy Chen25717382017-06-27 17:34:42 +0800492 /* Ensure session->terminate is updated */
493 smp_mb__before_atomic();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494
Peter Hurley751c10a2011-08-05 10:41:35 -0400495 if (atomic_read(&s->terminate))
Peter Hurley38d57552011-07-24 00:11:07 -0400496 break;
Szymon Janc3aad75a2011-03-21 14:19:58 +0100497 /* RX */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
499 skb_orphan(skb);
Mat Martineau44935722011-07-22 14:53:58 -0700500 if (!skb_linearize(skb))
501 bnep_rx_frame(s, skb);
502 else
503 kfree_skb(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 }
505
506 if (sk->sk_state != BT_CONNECTED)
507 break;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900508
Szymon Janc3aad75a2011-03-21 14:19:58 +0100509 /* TX */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 while ((skb = skb_dequeue(&sk->sk_write_queue)))
511 if (bnep_tx_frame(s, skb))
512 break;
513 netif_wake_queue(dev);
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900514
Jeffy Chen25717382017-06-27 17:34:42 +0800515 wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 }
Eric Dumazetaa395142010-04-20 13:03:51 +0000517 remove_wait_queue(sk_sleep(sk), &wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518
519 /* Cleanup session */
520 down_write(&bnep_session_sem);
521
522 /* Delete network device */
523 unregister_netdev(dev);
524
Marcel Holtmannec8dab32008-07-14 20:13:53 +0200525 /* Wakeup user-space polling for socket errors */
526 s->sock->sk->sk_err = EUNATCH;
527
Eric Dumazetaa395142010-04-20 13:03:51 +0000528 wake_up_interruptible(sk_sleep(s->sock->sk));
Marcel Holtmannec8dab32008-07-14 20:13:53 +0200529
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 /* Release the socket */
531 fput(s->sock->file);
532
533 __bnep_unlink_session(s);
534
535 up_write(&bnep_session_sem);
536 free_netdev(dev);
David Herrmann9b338c32011-11-19 13:23:33 +0100537 module_put_and_exit(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 return 0;
539}
540
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200541static struct device *bnep_get_device(struct bnep_session *session)
542{
Johan Hedberg88d90772015-02-03 10:01:13 +0200543 struct l2cap_conn *conn = l2cap_pi(session->sock->sk)->chan->conn;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200544
Johan Hedberg88d90772015-02-03 10:01:13 +0200545 if (!conn || !conn->hcon)
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200546 return NULL;
547
Johan Hedberg88d90772015-02-03 10:01:13 +0200548 return &conn->hcon->dev;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200549}
550
Marcel Holtmann384912e2009-08-31 21:08:19 +0000551static struct device_type bnep_type = {
552 .name = "bluetooth",
553};
554
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
556{
Grzegorz Kolodziejczyk836a0612015-04-03 12:14:55 +0200557 u32 valid_flags = BIT(BNEP_SETUP_RESPONSE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 struct net_device *dev;
559 struct bnep_session *s, *ss;
560 u8 dst[ETH_ALEN], src[ETH_ALEN];
561 int err;
562
563 BT_DBG("");
564
Al Viro71bb99a2014-12-19 06:20:59 +0000565 if (!l2cap_is_socket(sock))
566 return -EBADFD;
567
Marcel Holtmann0151e422015-04-01 13:51:54 -0700568 if (req->flags & ~valid_flags)
569 return -EINVAL;
570
Marcel Holtmann65f53e92013-10-13 09:49:57 -0700571 baswap((void *) dst, &l2cap_pi(sock->sk)->chan->dst);
572 baswap((void *) src, &l2cap_pi(sock->sk)->chan->src);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573
574 /* session struct allocated as private part of net_device */
575 dev = alloc_netdev(sizeof(struct bnep_session),
Tom Gundersenc835a672014-07-14 16:37:24 +0200576 (*req->device) ? req->device : "bnep%d",
577 NET_NAME_UNKNOWN,
578 bnep_net_setup);
Tobias Klauser67b52e52006-03-21 23:53:16 -0800579 if (!dev)
580 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 down_write(&bnep_session_sem);
583
584 ss = __bnep_get_session(dst);
585 if (ss && ss->state == BT_CONNECTED) {
586 err = -EEXIST;
587 goto failed;
588 }
589
Wang Chen524ad0a2008-11-12 23:39:10 -0800590 s = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591
592 /* This is rx header therefore addresses are swapped.
Szymon Janc3aad75a2011-03-21 14:19:58 +0100593 * ie. eh.h_dest is our local address. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 memcpy(s->eh.h_dest, &src, ETH_ALEN);
595 memcpy(s->eh.h_source, &dst, ETH_ALEN);
596 memcpy(dev->dev_addr, s->eh.h_dest, ETH_ALEN);
597
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200598 s->dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 s->sock = sock;
600 s->role = req->role;
601 s->state = BT_CONNECTED;
Grzegorz Kolodziejczyk836a0612015-04-03 12:14:55 +0200602 s->flags = req->flags;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900603
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 s->msg.msg_flags = MSG_NOSIGNAL;
605
606#ifdef CONFIG_BT_BNEP_MC_FILTER
Danny Schweizer4ada1282015-12-11 10:04:54 +0100607 /* Set default mc filter to not filter out any mc addresses
608 * as defined in the BNEP specification (revision 0.95a)
609 * http://grouper.ieee.org/groups/802/15/Bluetooth/BNEP.pdf
610 */
611 s->mc_filter = ~0LL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612#endif
613
614#ifdef CONFIG_BT_BNEP_PROTO_FILTER
615 /* Set default protocol filter */
616 bnep_set_default_proto_filter(s);
617#endif
618
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200619 SET_NETDEV_DEV(dev, bnep_get_device(s));
Marcel Holtmann384912e2009-08-31 21:08:19 +0000620 SET_NETDEV_DEVTYPE(dev, &bnep_type);
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200621
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 err = register_netdev(dev);
Szymon Janc3aad75a2011-03-21 14:19:58 +0100623 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625
626 __bnep_link_session(s);
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900627
David Herrmann9b338c32011-11-19 13:23:33 +0100628 __module_get(THIS_MODULE);
Szymon Jancf4d7cd42011-03-21 14:20:00 +0100629 s->task = kthread_run(bnep_session, s, "kbnepd %s", dev->name);
630 if (IS_ERR(s->task)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 /* Session thread start failed, gotta cleanup. */
David Herrmann9b338c32011-11-19 13:23:33 +0100632 module_put(THIS_MODULE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 unregister_netdev(dev);
634 __bnep_unlink_session(s);
Szymon Jancf4d7cd42011-03-21 14:20:00 +0100635 err = PTR_ERR(s->task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 goto failed;
637 }
638
639 up_write(&bnep_session_sem);
640 strcpy(req->device, dev->name);
641 return 0;
642
643failed:
644 up_write(&bnep_session_sem);
645 free_netdev(dev);
646 return err;
647}
648
649int bnep_del_connection(struct bnep_conndel_req *req)
650{
Marcel Holtmann0151e422015-04-01 13:51:54 -0700651 u32 valid_flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 struct bnep_session *s;
653 int err = 0;
654
655 BT_DBG("");
656
Marcel Holtmann0151e422015-04-01 13:51:54 -0700657 if (req->flags & ~valid_flags)
658 return -EINVAL;
659
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 down_read(&bnep_session_sem);
661
662 s = __bnep_get_session(req->dst);
Peter Hurley751c10a2011-08-05 10:41:35 -0400663 if (s) {
664 atomic_inc(&s->terminate);
Jeffy Chen25717382017-06-27 17:34:42 +0800665 wake_up_interruptible(sk_sleep(s->sock->sk));
Peter Hurley751c10a2011-08-05 10:41:35 -0400666 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 err = -ENOENT;
668
669 up_read(&bnep_session_sem);
670 return err;
671}
672
673static void __bnep_copy_ci(struct bnep_conninfo *ci, struct bnep_session *s)
674{
Grzegorz Kolodziejczyk836a0612015-04-03 12:14:55 +0200675 u32 valid_flags = BIT(BNEP_SETUP_RESPONSE);
Marcel Holtmann0151e422015-04-01 13:51:54 -0700676
Vasiliy Kulikov5520d202010-10-30 18:26:21 +0400677 memset(ci, 0, sizeof(*ci));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 memcpy(ci->dst, s->eh.h_source, ETH_ALEN);
679 strcpy(ci->device, s->dev->name);
Marcel Holtmann0151e422015-04-01 13:51:54 -0700680 ci->flags = s->flags & valid_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 ci->state = s->state;
682 ci->role = s->role;
683}
684
685int bnep_get_connlist(struct bnep_connlist_req *req)
686{
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200687 struct bnep_session *s;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 int err = 0, n = 0;
689
690 down_read(&bnep_session_sem);
691
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200692 list_for_each_entry(s, &bnep_session_list, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 struct bnep_conninfo ci;
694
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 __bnep_copy_ci(&ci, s);
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900696
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 if (copy_to_user(req->ci, &ci, sizeof(ci))) {
698 err = -EFAULT;
699 break;
700 }
701
702 if (++n >= req->cnum)
703 break;
704
705 req->ci++;
706 }
707 req->cnum = n;
708
709 up_read(&bnep_session_sem);
710 return err;
711}
712
713int bnep_get_conninfo(struct bnep_conninfo *ci)
714{
715 struct bnep_session *s;
716 int err = 0;
717
718 down_read(&bnep_session_sem);
719
720 s = __bnep_get_session(ci->dst);
721 if (s)
722 __bnep_copy_ci(ci, s);
723 else
724 err = -ENOENT;
725
726 up_read(&bnep_session_sem);
727 return err;
728}
729
730static int __init bnep_init(void)
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900731{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 char flt[50] = "";
733
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734#ifdef CONFIG_BT_BNEP_PROTO_FILTER
735 strcat(flt, "protocol ");
736#endif
737
738#ifdef CONFIG_BT_BNEP_MC_FILTER
739 strcat(flt, "multicast");
740#endif
741
742 BT_INFO("BNEP (Ethernet Emulation) ver %s", VERSION);
743 if (flt[0])
744 BT_INFO("BNEP filters: %s", flt);
745
746 bnep_sock_init();
747 return 0;
748}
749
750static void __exit bnep_exit(void)
751{
752 bnep_sock_cleanup();
753}
754
755module_init(bnep_init);
756module_exit(bnep_exit);
757
Marcel Holtmann28111eb2008-08-07 22:26:54 +0200758module_param(compress_src, bool, 0644);
759MODULE_PARM_DESC(compress_src, "Compress sources headers");
760
761module_param(compress_dst, bool, 0644);
762MODULE_PARM_DESC(compress_dst, "Compress destination headers");
763
Marcel Holtmann63fbd242008-08-18 13:23:53 +0200764MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765MODULE_DESCRIPTION("Bluetooth BNEP ver " VERSION);
766MODULE_VERSION(VERSION);
767MODULE_LICENSE("GPL");
768MODULE_ALIAS("bt-proto-4");