blob: 0ee6f6d9d93e153eaa20c7f11f70d3de6fb18b1a [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:
234 err = bnep_send_rsp(s, BNEP_SETUP_CONN_RSP, BNEP_CONN_NOT_ALLOWED);
235 break;
236
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 default: {
238 u8 pkt[3];
239 pkt[0] = BNEP_CONTROL;
240 pkt[1] = BNEP_CMD_NOT_UNDERSTOOD;
241 pkt[2] = cmd;
Grzegorz Kolodziejczyke0fdbab2015-04-03 12:14:52 +0200242 err = bnep_send(s, pkt, sizeof(pkt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 }
244 break;
245 }
246
247 return err;
248}
249
250static int bnep_rx_extension(struct bnep_session *s, struct sk_buff *skb)
251{
252 struct bnep_ext_hdr *h;
253 int err = 0;
254
255 do {
256 h = (void *) skb->data;
257 if (!skb_pull(skb, sizeof(*h))) {
258 err = -EILSEQ;
259 break;
260 }
261
262 BT_DBG("type 0x%x len %d", h->type, h->len);
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900263
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 switch (h->type & BNEP_TYPE_MASK) {
265 case BNEP_EXT_CONTROL:
266 bnep_rx_control(s, skb->data, skb->len);
267 break;
268
269 default:
270 /* Unknown extension, skip it. */
271 break;
272 }
273
274 if (!skb_pull(skb, h->len)) {
275 err = -EILSEQ;
276 break;
277 }
278 } while (!err && (h->type & BNEP_EXT_HEADER));
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900279
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 return err;
281}
282
283static u8 __bnep_rx_hlen[] = {
284 ETH_HLEN, /* BNEP_GENERAL */
285 0, /* BNEP_CONTROL */
286 2, /* BNEP_COMPRESSED */
287 ETH_ALEN + 2, /* BNEP_COMPRESSED_SRC_ONLY */
288 ETH_ALEN + 2 /* BNEP_COMPRESSED_DST_ONLY */
289};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290
Gustavo Padovan6039aa72012-05-23 04:04:18 -0300291static int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292{
293 struct net_device *dev = s->dev;
294 struct sk_buff *nskb;
Grzegorz Kolodziejczykbf8b9a92015-04-03 12:14:54 +0200295 u8 type, ctrl_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296
Stephen Hemmingerb4d7f0a2009-01-07 17:23:17 -0800297 dev->stats.rx_bytes += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298
Szymon Janc3aad75a2011-03-21 14:19:58 +0100299 type = *(u8 *) skb->data;
300 skb_pull(skb, 1);
Grzegorz Kolodziejczykbf8b9a92015-04-03 12:14:54 +0200301 ctrl_type = *(u8 *)skb->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302
Szymon Janca3d9bd42011-03-21 14:19:57 +0100303 if ((type & BNEP_TYPE_MASK) >= sizeof(__bnep_rx_hlen))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 goto badframe;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900305
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) {
Grzegorz Kolodziejczykbf8b9a92015-04-03 12:14:54 +0200307 if (bnep_rx_control(s, skb->data, skb->len) < 0) {
308 dev->stats.tx_errors++;
309 kfree_skb(skb);
310 return 0;
311 }
312
313 if (!(type & BNEP_EXT_HEADER)) {
314 kfree_skb(skb);
315 return 0;
316 }
317
318 /* Verify and pull ctrl message since it's already processed */
319 switch (ctrl_type) {
320 case BNEP_SETUP_CONN_REQ:
321 /* Pull: ctrl type (1 b), len (1 b), data (len bytes) */
322 if (!skb_pull(skb, 2 + *(u8 *)(skb->data + 1) * 2))
323 goto badframe;
324 break;
325 case BNEP_FILTER_MULTI_ADDR_SET:
326 case BNEP_FILTER_NET_TYPE_SET:
327 /* Pull: ctrl type (1 b), len (2 b), data (len bytes) */
328 if (!skb_pull(skb, 3 + *(u16 *)(skb->data + 1) * 2))
329 goto badframe;
330 break;
331 default:
332 kfree_skb(skb);
333 return 0;
334 }
335 } else {
336 skb_reset_mac_header(skb);
337
338 /* Verify and pull out header */
339 if (!skb_pull(skb, __bnep_rx_hlen[type & BNEP_TYPE_MASK]))
340 goto badframe;
341
342 s->eh.h_proto = get_unaligned((__be16 *) (skb->data - 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 }
344
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 if (type & BNEP_EXT_HEADER) {
346 if (bnep_rx_extension(s, skb) < 0)
347 goto badframe;
348 }
349
350 /* Strip 802.1p header */
Eldad Zack000092b2012-05-08 00:09:35 +0200351 if (ntohs(s->eh.h_proto) == ETH_P_8021Q) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 if (!skb_pull(skb, 4))
353 goto badframe;
Al Viro1bc5d442006-11-08 00:27:57 -0800354 s->eh.h_proto = get_unaligned((__be16 *) (skb->data - 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 }
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900356
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 /* We have to alloc new skb and copy data here :(. Because original skb
358 * may not be modified and because of the alignment requirements. */
359 nskb = alloc_skb(2 + ETH_HLEN + skb->len, GFP_KERNEL);
360 if (!nskb) {
Stephen Hemmingerb4d7f0a2009-01-07 17:23:17 -0800361 dev->stats.rx_dropped++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 kfree_skb(skb);
363 return -ENOMEM;
364 }
365 skb_reserve(nskb, 2);
366
367 /* Decompress header and construct ether frame */
368 switch (type & BNEP_TYPE_MASK) {
369 case BNEP_COMPRESSED:
370 memcpy(__skb_put(nskb, ETH_HLEN), &s->eh, ETH_HLEN);
371 break;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900372
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 case BNEP_COMPRESSED_SRC_ONLY:
374 memcpy(__skb_put(nskb, ETH_ALEN), s->eh.h_dest, ETH_ALEN);
Arnaldo Carvalho de Melo98e399f2007-03-19 15:33:04 -0700375 memcpy(__skb_put(nskb, ETH_ALEN), skb_mac_header(skb), ETH_ALEN);
Al Viro1bc5d442006-11-08 00:27:57 -0800376 put_unaligned(s->eh.h_proto, (__be16 *) __skb_put(nskb, 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 break;
378
379 case BNEP_COMPRESSED_DST_ONLY:
Arnaldo Carvalho de Melo98e399f2007-03-19 15:33:04 -0700380 memcpy(__skb_put(nskb, ETH_ALEN), skb_mac_header(skb),
Szymon Janc3aad75a2011-03-21 14:19:58 +0100381 ETH_ALEN);
Arnaldo Carvalho de Melo98e399f2007-03-19 15:33:04 -0700382 memcpy(__skb_put(nskb, ETH_ALEN + 2), s->eh.h_source,
Szymon Janc3aad75a2011-03-21 14:19:58 +0100383 ETH_ALEN + 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 break;
385
386 case BNEP_GENERAL:
Arnaldo Carvalho de Melo98e399f2007-03-19 15:33:04 -0700387 memcpy(__skb_put(nskb, ETH_ALEN * 2), skb_mac_header(skb),
Szymon Janc3aad75a2011-03-21 14:19:58 +0100388 ETH_ALEN * 2);
Al Viro1bc5d442006-11-08 00:27:57 -0800389 put_unaligned(s->eh.h_proto, (__be16 *) __skb_put(nskb, 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 break;
391 }
392
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -0300393 skb_copy_from_linear_data(skb, __skb_put(nskb, skb->len), skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 kfree_skb(skb);
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900395
Stephen Hemmingerb4d7f0a2009-01-07 17:23:17 -0800396 dev->stats.rx_packets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 nskb->ip_summed = CHECKSUM_NONE;
398 nskb->protocol = eth_type_trans(nskb, dev);
399 netif_rx_ni(nskb);
400 return 0;
401
402badframe:
Stephen Hemmingerb4d7f0a2009-01-07 17:23:17 -0800403 dev->stats.rx_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 kfree_skb(skb);
405 return 0;
406}
407
408static u8 __bnep_tx_types[] = {
409 BNEP_GENERAL,
410 BNEP_COMPRESSED_SRC_ONLY,
411 BNEP_COMPRESSED_DST_ONLY,
412 BNEP_COMPRESSED
413};
414
Gustavo Padovan6039aa72012-05-23 04:04:18 -0300415static int bnep_tx_frame(struct bnep_session *s, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416{
417 struct ethhdr *eh = (void *) skb->data;
418 struct socket *sock = s->sock;
419 struct kvec iv[3];
420 int len = 0, il = 0;
421 u8 type = 0;
422
423 BT_DBG("skb %p dev %p type %d", skb, skb->dev, skb->pkt_type);
424
425 if (!skb->dev) {
426 /* Control frame sent by us */
427 goto send;
428 }
429
430 iv[il++] = (struct kvec) { &type, 1 };
431 len++;
432
Joe Perchesc47fc982012-05-08 18:56:51 +0000433 if (compress_src && ether_addr_equal(eh->h_dest, s->eh.h_source))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 type |= 0x01;
435
Joe Perchesc47fc982012-05-08 18:56:51 +0000436 if (compress_dst && ether_addr_equal(eh->h_source, s->eh.h_dest))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 type |= 0x02;
438
439 if (type)
440 skb_pull(skb, ETH_ALEN * 2);
441
442 type = __bnep_tx_types[type];
443 switch (type) {
444 case BNEP_COMPRESSED_SRC_ONLY:
445 iv[il++] = (struct kvec) { eh->h_source, ETH_ALEN };
446 len += ETH_ALEN;
447 break;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900448
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 case BNEP_COMPRESSED_DST_ONLY:
450 iv[il++] = (struct kvec) { eh->h_dest, ETH_ALEN };
451 len += ETH_ALEN;
452 break;
453 }
454
455send:
456 iv[il++] = (struct kvec) { skb->data, skb->len };
457 len += skb->len;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900458
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 /* FIXME: linearize skb */
460 {
461 len = kernel_sendmsg(sock, &s->msg, iv, il, len);
462 }
463 kfree_skb(skb);
464
465 if (len > 0) {
Stephen Hemmingerb4d7f0a2009-01-07 17:23:17 -0800466 s->dev->stats.tx_bytes += len;
467 s->dev->stats.tx_packets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 return 0;
469 }
470
471 return len;
472}
473
474static int bnep_session(void *arg)
475{
476 struct bnep_session *s = arg;
477 struct net_device *dev = s->dev;
478 struct sock *sk = s->sock->sk;
479 struct sk_buff *skb;
480 wait_queue_t wait;
481
482 BT_DBG("");
483
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 set_user_nice(current, -15);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485
486 init_waitqueue_entry(&wait, current);
Eric Dumazetaa395142010-04-20 13:03:51 +0000487 add_wait_queue(sk_sleep(sk), &wait);
Peter Hurley38d57552011-07-24 00:11:07 -0400488 while (1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 set_current_state(TASK_INTERRUPTIBLE);
490
Peter Hurley751c10a2011-08-05 10:41:35 -0400491 if (atomic_read(&s->terminate))
Peter Hurley38d57552011-07-24 00:11:07 -0400492 break;
Szymon Janc3aad75a2011-03-21 14:19:58 +0100493 /* RX */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
495 skb_orphan(skb);
Mat Martineau44935722011-07-22 14:53:58 -0700496 if (!skb_linearize(skb))
497 bnep_rx_frame(s, skb);
498 else
499 kfree_skb(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 }
501
502 if (sk->sk_state != BT_CONNECTED)
503 break;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900504
Szymon Janc3aad75a2011-03-21 14:19:58 +0100505 /* TX */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 while ((skb = skb_dequeue(&sk->sk_write_queue)))
507 if (bnep_tx_frame(s, skb))
508 break;
509 netif_wake_queue(dev);
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900510
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 schedule();
512 }
Peter Hurley38d57552011-07-24 00:11:07 -0400513 __set_current_state(TASK_RUNNING);
Eric Dumazetaa395142010-04-20 13:03:51 +0000514 remove_wait_queue(sk_sleep(sk), &wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515
516 /* Cleanup session */
517 down_write(&bnep_session_sem);
518
519 /* Delete network device */
520 unregister_netdev(dev);
521
Marcel Holtmannec8dab32008-07-14 20:13:53 +0200522 /* Wakeup user-space polling for socket errors */
523 s->sock->sk->sk_err = EUNATCH;
524
Eric Dumazetaa395142010-04-20 13:03:51 +0000525 wake_up_interruptible(sk_sleep(s->sock->sk));
Marcel Holtmannec8dab32008-07-14 20:13:53 +0200526
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 /* Release the socket */
528 fput(s->sock->file);
529
530 __bnep_unlink_session(s);
531
532 up_write(&bnep_session_sem);
533 free_netdev(dev);
David Herrmann9b338c32011-11-19 13:23:33 +0100534 module_put_and_exit(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 return 0;
536}
537
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200538static struct device *bnep_get_device(struct bnep_session *session)
539{
Johan Hedberg88d90772015-02-03 10:01:13 +0200540 struct l2cap_conn *conn = l2cap_pi(session->sock->sk)->chan->conn;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200541
Johan Hedberg88d90772015-02-03 10:01:13 +0200542 if (!conn || !conn->hcon)
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200543 return NULL;
544
Johan Hedberg88d90772015-02-03 10:01:13 +0200545 return &conn->hcon->dev;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200546}
547
Marcel Holtmann384912e2009-08-31 21:08:19 +0000548static struct device_type bnep_type = {
549 .name = "bluetooth",
550};
551
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
553{
Marcel Holtmann0151e422015-04-01 13:51:54 -0700554 u32 valid_flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 struct net_device *dev;
556 struct bnep_session *s, *ss;
557 u8 dst[ETH_ALEN], src[ETH_ALEN];
558 int err;
559
560 BT_DBG("");
561
Al Viro71bb99a2014-12-19 06:20:59 +0000562 if (!l2cap_is_socket(sock))
563 return -EBADFD;
564
Marcel Holtmann0151e422015-04-01 13:51:54 -0700565 if (req->flags & ~valid_flags)
566 return -EINVAL;
567
Marcel Holtmann65f53e92013-10-13 09:49:57 -0700568 baswap((void *) dst, &l2cap_pi(sock->sk)->chan->dst);
569 baswap((void *) src, &l2cap_pi(sock->sk)->chan->src);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570
571 /* session struct allocated as private part of net_device */
572 dev = alloc_netdev(sizeof(struct bnep_session),
Tom Gundersenc835a672014-07-14 16:37:24 +0200573 (*req->device) ? req->device : "bnep%d",
574 NET_NAME_UNKNOWN,
575 bnep_net_setup);
Tobias Klauser67b52e52006-03-21 23:53:16 -0800576 if (!dev)
577 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 down_write(&bnep_session_sem);
580
581 ss = __bnep_get_session(dst);
582 if (ss && ss->state == BT_CONNECTED) {
583 err = -EEXIST;
584 goto failed;
585 }
586
Wang Chen524ad0a2008-11-12 23:39:10 -0800587 s = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588
589 /* This is rx header therefore addresses are swapped.
Szymon Janc3aad75a2011-03-21 14:19:58 +0100590 * ie. eh.h_dest is our local address. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 memcpy(s->eh.h_dest, &src, ETH_ALEN);
592 memcpy(s->eh.h_source, &dst, ETH_ALEN);
593 memcpy(dev->dev_addr, s->eh.h_dest, ETH_ALEN);
594
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200595 s->dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 s->sock = sock;
597 s->role = req->role;
598 s->state = BT_CONNECTED;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900599
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 s->msg.msg_flags = MSG_NOSIGNAL;
601
602#ifdef CONFIG_BT_BNEP_MC_FILTER
603 /* Set default mc filter */
604 set_bit(bnep_mc_hash(dev->broadcast), (ulong *) &s->mc_filter);
605#endif
606
607#ifdef CONFIG_BT_BNEP_PROTO_FILTER
608 /* Set default protocol filter */
609 bnep_set_default_proto_filter(s);
610#endif
611
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200612 SET_NETDEV_DEV(dev, bnep_get_device(s));
Marcel Holtmann384912e2009-08-31 21:08:19 +0000613 SET_NETDEV_DEVTYPE(dev, &bnep_type);
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200614
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 err = register_netdev(dev);
Szymon Janc3aad75a2011-03-21 14:19:58 +0100616 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618
619 __bnep_link_session(s);
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900620
David Herrmann9b338c32011-11-19 13:23:33 +0100621 __module_get(THIS_MODULE);
Szymon Jancf4d7cd42011-03-21 14:20:00 +0100622 s->task = kthread_run(bnep_session, s, "kbnepd %s", dev->name);
623 if (IS_ERR(s->task)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 /* Session thread start failed, gotta cleanup. */
David Herrmann9b338c32011-11-19 13:23:33 +0100625 module_put(THIS_MODULE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 unregister_netdev(dev);
627 __bnep_unlink_session(s);
Szymon Jancf4d7cd42011-03-21 14:20:00 +0100628 err = PTR_ERR(s->task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 goto failed;
630 }
631
632 up_write(&bnep_session_sem);
633 strcpy(req->device, dev->name);
634 return 0;
635
636failed:
637 up_write(&bnep_session_sem);
638 free_netdev(dev);
639 return err;
640}
641
642int bnep_del_connection(struct bnep_conndel_req *req)
643{
Marcel Holtmann0151e422015-04-01 13:51:54 -0700644 u32 valid_flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 struct bnep_session *s;
646 int err = 0;
647
648 BT_DBG("");
649
Marcel Holtmann0151e422015-04-01 13:51:54 -0700650 if (req->flags & ~valid_flags)
651 return -EINVAL;
652
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 down_read(&bnep_session_sem);
654
655 s = __bnep_get_session(req->dst);
Peter Hurley751c10a2011-08-05 10:41:35 -0400656 if (s) {
657 atomic_inc(&s->terminate);
658 wake_up_process(s->task);
659 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 err = -ENOENT;
661
662 up_read(&bnep_session_sem);
663 return err;
664}
665
666static void __bnep_copy_ci(struct bnep_conninfo *ci, struct bnep_session *s)
667{
Marcel Holtmann0151e422015-04-01 13:51:54 -0700668 u32 valid_flags = 0;
669
Vasiliy Kulikov5520d202010-10-30 18:26:21 +0400670 memset(ci, 0, sizeof(*ci));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 memcpy(ci->dst, s->eh.h_source, ETH_ALEN);
672 strcpy(ci->device, s->dev->name);
Marcel Holtmann0151e422015-04-01 13:51:54 -0700673 ci->flags = s->flags & valid_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 ci->state = s->state;
675 ci->role = s->role;
676}
677
678int bnep_get_connlist(struct bnep_connlist_req *req)
679{
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200680 struct bnep_session *s;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 int err = 0, n = 0;
682
683 down_read(&bnep_session_sem);
684
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200685 list_for_each_entry(s, &bnep_session_list, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 struct bnep_conninfo ci;
687
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 __bnep_copy_ci(&ci, s);
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900689
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 if (copy_to_user(req->ci, &ci, sizeof(ci))) {
691 err = -EFAULT;
692 break;
693 }
694
695 if (++n >= req->cnum)
696 break;
697
698 req->ci++;
699 }
700 req->cnum = n;
701
702 up_read(&bnep_session_sem);
703 return err;
704}
705
706int bnep_get_conninfo(struct bnep_conninfo *ci)
707{
708 struct bnep_session *s;
709 int err = 0;
710
711 down_read(&bnep_session_sem);
712
713 s = __bnep_get_session(ci->dst);
714 if (s)
715 __bnep_copy_ci(ci, s);
716 else
717 err = -ENOENT;
718
719 up_read(&bnep_session_sem);
720 return err;
721}
722
723static int __init bnep_init(void)
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900724{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 char flt[50] = "";
726
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727#ifdef CONFIG_BT_BNEP_PROTO_FILTER
728 strcat(flt, "protocol ");
729#endif
730
731#ifdef CONFIG_BT_BNEP_MC_FILTER
732 strcat(flt, "multicast");
733#endif
734
735 BT_INFO("BNEP (Ethernet Emulation) ver %s", VERSION);
736 if (flt[0])
737 BT_INFO("BNEP filters: %s", flt);
738
739 bnep_sock_init();
740 return 0;
741}
742
743static void __exit bnep_exit(void)
744{
745 bnep_sock_cleanup();
746}
747
748module_init(bnep_init);
749module_exit(bnep_exit);
750
Marcel Holtmann28111eb2008-08-07 22:26:54 +0200751module_param(compress_src, bool, 0644);
752MODULE_PARM_DESC(compress_src, "Compress sources headers");
753
754module_param(compress_dst, bool, 0644);
755MODULE_PARM_DESC(compress_dst, "Compress destination headers");
756
Marcel Holtmann63fbd242008-08-18 13:23:53 +0200757MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758MODULE_DESCRIPTION("Bluetooth BNEP ver " VERSION);
759MODULE_VERSION(VERSION);
760MODULE_LICENSE("GPL");
761MODULE_ALIAS("bt-proto-4");