blob: 155ff7406776f3790498f741972f48ec9bf1b5b9 [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>
Steve Mucklef132c6c2012-06-06 18:30:57 -070029#include <linux/interrupt.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090030#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031
32#include <linux/socket.h>
33#include <linux/netdevice.h>
34#include <linux/etherdevice.h>
35#include <linux/skbuff.h>
36#include <linux/wait.h>
37
38#include <asm/unaligned.h>
39
40#include <net/bluetooth/bluetooth.h>
41#include <net/bluetooth/hci_core.h>
42#include <net/bluetooth/l2cap.h>
43
44#include "bnep.h"
45
Linus Torvalds1da177e2005-04-16 15:20:36 -070046#define BNEP_TX_QUEUE_LEN 20
47
48static int bnep_net_open(struct net_device *dev)
49{
50 netif_start_queue(dev);
51 return 0;
52}
53
54static int bnep_net_close(struct net_device *dev)
55{
56 netif_stop_queue(dev);
57 return 0;
58}
59
Linus Torvalds1da177e2005-04-16 15:20:36 -070060static void bnep_net_set_mc_list(struct net_device *dev)
61{
62#ifdef CONFIG_BT_BNEP_MC_FILTER
Wang Chen524ad0a2008-11-12 23:39:10 -080063 struct bnep_session *s = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070064 struct sock *sk = s->sock->sk;
65 struct bnep_set_filter_req *r;
66 struct sk_buff *skb;
67 int size;
68
Jiri Pirko4cd24ea2010-02-08 04:30:35 +000069 BT_DBG("%s mc_count %d", dev->name, netdev_mc_count(dev));
Linus Torvalds1da177e2005-04-16 15:20:36 -070070
71 size = sizeof(*r) + (BNEP_MAX_MULTICAST_FILTERS + 1) * ETH_ALEN * 2;
72 skb = alloc_skb(size, GFP_ATOMIC);
73 if (!skb) {
74 BT_ERR("%s Multicast list allocation failed", dev->name);
75 return;
76 }
77
78 r = (void *) skb->data;
79 __skb_put(skb, sizeof(*r));
80
81 r->type = BNEP_CONTROL;
82 r->ctrl = BNEP_FILTER_MULTI_ADDR_SET;
83
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090084 if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070085 u8 start[ETH_ALEN] = { 0x01 };
86
87 /* Request all addresses */
88 memcpy(__skb_put(skb, ETH_ALEN), start, ETH_ALEN);
89 memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN);
90 r->len = htons(ETH_ALEN * 2);
91 } else {
Jiri Pirko22bedad2010-04-01 21:22:57 +000092 struct netdev_hw_addr *ha;
Linus Torvalds1da177e2005-04-16 15:20:36 -070093 int i, len = skb->len;
94
95 if (dev->flags & IFF_BROADCAST) {
96 memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN);
97 memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN);
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090098 }
99
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100 /* FIXME: We should group addresses here. */
101
Jiri Pirkoff6e2162010-03-01 05:09:14 +0000102 i = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +0000103 netdev_for_each_mc_addr(ha, dev) {
Jiri Pirkoff6e2162010-03-01 05:09:14 +0000104 if (i == BNEP_MAX_MULTICAST_FILTERS)
105 break;
Jiri Pirko22bedad2010-04-01 21:22:57 +0000106 memcpy(__skb_put(skb, ETH_ALEN), ha->addr, ETH_ALEN);
107 memcpy(__skb_put(skb, ETH_ALEN), ha->addr, ETH_ALEN);
Gustavo F. Padovan1a61a832010-06-18 14:24:00 +0000108
109 i++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 }
111 r->len = htons(skb->len - len);
112 }
113
114 skb_queue_tail(&sk->sk_write_queue, skb);
Eric Dumazetaa395142010-04-20 13:03:51 +0000115 wake_up_interruptible(sk_sleep(sk));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116#endif
117}
118
119static int bnep_net_set_mac_addr(struct net_device *dev, void *arg)
120{
121 BT_DBG("%s", dev->name);
122 return 0;
123}
124
125static void bnep_net_timeout(struct net_device *dev)
126{
127 BT_DBG("net_timeout");
128 netif_wake_queue(dev);
129}
130
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131#ifdef CONFIG_BT_BNEP_MC_FILTER
132static inline int bnep_net_mc_filter(struct sk_buff *skb, struct bnep_session *s)
133{
134 struct ethhdr *eh = (void *) skb->data;
135
136 if ((eh->h_dest[0] & 1) && !test_bit(bnep_mc_hash(eh->h_dest), (ulong *) &s->mc_filter))
137 return 1;
138 return 0;
139}
140#endif
141
142#ifdef CONFIG_BT_BNEP_PROTO_FILTER
143/* Determine ether protocol. Based on eth_type_trans. */
144static inline u16 bnep_net_eth_proto(struct sk_buff *skb)
145{
146 struct ethhdr *eh = (void *) skb->data;
Al Viroe41d2162006-11-08 00:27:36 -0800147 u16 proto = ntohs(eh->h_proto);
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900148
Al Viroe41d2162006-11-08 00:27:36 -0800149 if (proto >= 1536)
150 return proto;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900151
Al Viroe41d2162006-11-08 00:27:36 -0800152 if (get_unaligned((__be16 *) skb->data) == htons(0xFFFF))
153 return ETH_P_802_3;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900154
Al Viroe41d2162006-11-08 00:27:36 -0800155 return ETH_P_802_2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156}
157
158static inline int bnep_net_proto_filter(struct sk_buff *skb, struct bnep_session *s)
159{
160 u16 proto = bnep_net_eth_proto(skb);
161 struct bnep_proto_filter *f = s->proto_filter;
162 int i;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900163
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 for (i = 0; i < BNEP_MAX_PROTO_FILTERS && f[i].end; i++) {
165 if (proto >= f[i].start && proto <= f[i].end)
166 return 0;
167 }
168
169 BT_DBG("BNEP: filtered skb %p, proto 0x%.4x", skb, proto);
170 return 1;
171}
172#endif
173
Stephen Hemminger6fef4c02009-08-31 19:50:41 +0000174static netdev_tx_t bnep_net_xmit(struct sk_buff *skb,
175 struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176{
Wang Chen524ad0a2008-11-12 23:39:10 -0800177 struct bnep_session *s = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 struct sock *sk = s->sock->sk;
179
180 BT_DBG("skb %p, dev %p", skb, dev);
181
182#ifdef CONFIG_BT_BNEP_MC_FILTER
183 if (bnep_net_mc_filter(skb, s)) {
184 kfree_skb(skb);
Patrick McHardy6ed10652009-06-23 06:03:08 +0000185 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 }
187#endif
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900188
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189#ifdef CONFIG_BT_BNEP_PROTO_FILTER
190 if (bnep_net_proto_filter(skb, s)) {
191 kfree_skb(skb);
Patrick McHardy6ed10652009-06-23 06:03:08 +0000192 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 }
194#endif
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900195
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 /*
197 * We cannot send L2CAP packets from here as we are potentially in a bh.
198 * So we have to queue them and wake up session thread which is sleeping
Eric Dumazetaa395142010-04-20 13:03:51 +0000199 * on the sk_sleep(sk).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 */
201 dev->trans_start = jiffies;
202 skb_queue_tail(&sk->sk_write_queue, skb);
Eric Dumazetaa395142010-04-20 13:03:51 +0000203 wake_up_interruptible(sk_sleep(sk));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204
205 if (skb_queue_len(&sk->sk_write_queue) >= BNEP_TX_QUEUE_LEN) {
206 BT_DBG("tx queue is full");
207
208 /* Stop queuing.
209 * Session thread will do netif_wake_queue() */
210 netif_stop_queue(dev);
211 }
212
Patrick McHardy6ed10652009-06-23 06:03:08 +0000213 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214}
215
Stephen Hemmingerb4d7f0a2009-01-07 17:23:17 -0800216static const struct net_device_ops bnep_netdev_ops = {
217 .ndo_open = bnep_net_open,
218 .ndo_stop = bnep_net_close,
219 .ndo_start_xmit = bnep_net_xmit,
220 .ndo_validate_addr = eth_validate_addr,
Jiri Pirkoafc4b132011-08-16 06:29:01 +0000221 .ndo_set_rx_mode = bnep_net_set_mc_list,
Stephen Hemmingerb4d7f0a2009-01-07 17:23:17 -0800222 .ndo_set_mac_address = bnep_net_set_mac_addr,
223 .ndo_tx_timeout = bnep_net_timeout,
224 .ndo_change_mtu = eth_change_mtu,
225
226};
227
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228void bnep_net_setup(struct net_device *dev)
229{
230
231 memset(dev->broadcast, 0xff, ETH_ALEN);
232 dev->addr_len = ETH_ALEN;
233
234 ether_setup(dev);
Neil Horman550fd082011-07-26 06:05:38 +0000235 dev->priv_flags &= ~IFF_TX_SKB_SHARING;
Stephen Hemmingerb4d7f0a2009-01-07 17:23:17 -0800236 dev->netdev_ops = &bnep_netdev_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237
238 dev->watchdog_timeo = HZ * 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239}