xref: /openbmc/linux/net/bluetooth/bnep/netdev.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
1*1da177e4SLinus Torvalds /*
2*1da177e4SLinus Torvalds    BNEP implementation for Linux Bluetooth stack (BlueZ).
3*1da177e4SLinus Torvalds    Copyright (C) 2001-2002 Inventel Systemes
4*1da177e4SLinus Torvalds    Written 2001-2002 by
5*1da177e4SLinus Torvalds 	Cl�ment Moreau <clement.moreau@inventel.fr>
6*1da177e4SLinus Torvalds 	David Libault  <david.libault@inventel.fr>
7*1da177e4SLinus Torvalds 
8*1da177e4SLinus Torvalds    Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
9*1da177e4SLinus Torvalds 
10*1da177e4SLinus Torvalds    This program is free software; you can redistribute it and/or modify
11*1da177e4SLinus Torvalds    it under the terms of the GNU General Public License version 2 as
12*1da177e4SLinus Torvalds    published by the Free Software Foundation;
13*1da177e4SLinus Torvalds 
14*1da177e4SLinus Torvalds    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15*1da177e4SLinus Torvalds    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16*1da177e4SLinus Torvalds    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
17*1da177e4SLinus Torvalds    IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
18*1da177e4SLinus Torvalds    CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
19*1da177e4SLinus Torvalds    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20*1da177e4SLinus Torvalds    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
21*1da177e4SLinus Torvalds    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22*1da177e4SLinus Torvalds 
23*1da177e4SLinus Torvalds    ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
24*1da177e4SLinus Torvalds    COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
25*1da177e4SLinus Torvalds    SOFTWARE IS DISCLAIMED.
26*1da177e4SLinus Torvalds */
27*1da177e4SLinus Torvalds 
28*1da177e4SLinus Torvalds /*
29*1da177e4SLinus Torvalds  * $Id: netdev.c,v 1.8 2002/08/04 21:23:58 maxk Exp $
30*1da177e4SLinus Torvalds  */
31*1da177e4SLinus Torvalds 
32*1da177e4SLinus Torvalds #include <linux/config.h>
33*1da177e4SLinus Torvalds #include <linux/module.h>
34*1da177e4SLinus Torvalds 
35*1da177e4SLinus Torvalds #include <linux/socket.h>
36*1da177e4SLinus Torvalds #include <linux/netdevice.h>
37*1da177e4SLinus Torvalds #include <linux/etherdevice.h>
38*1da177e4SLinus Torvalds #include <linux/skbuff.h>
39*1da177e4SLinus Torvalds #include <linux/wait.h>
40*1da177e4SLinus Torvalds 
41*1da177e4SLinus Torvalds #include <asm/unaligned.h>
42*1da177e4SLinus Torvalds 
43*1da177e4SLinus Torvalds #include <net/bluetooth/bluetooth.h>
44*1da177e4SLinus Torvalds #include <net/bluetooth/hci_core.h>
45*1da177e4SLinus Torvalds #include <net/bluetooth/l2cap.h>
46*1da177e4SLinus Torvalds 
47*1da177e4SLinus Torvalds #include "bnep.h"
48*1da177e4SLinus Torvalds 
49*1da177e4SLinus Torvalds #ifndef CONFIG_BT_BNEP_DEBUG
50*1da177e4SLinus Torvalds #undef  BT_DBG
51*1da177e4SLinus Torvalds #define BT_DBG( A... )
52*1da177e4SLinus Torvalds #endif
53*1da177e4SLinus Torvalds 
54*1da177e4SLinus Torvalds #define BNEP_TX_QUEUE_LEN 20
55*1da177e4SLinus Torvalds 
56*1da177e4SLinus Torvalds static int bnep_net_open(struct net_device *dev)
57*1da177e4SLinus Torvalds {
58*1da177e4SLinus Torvalds 	netif_start_queue(dev);
59*1da177e4SLinus Torvalds 	return 0;
60*1da177e4SLinus Torvalds }
61*1da177e4SLinus Torvalds 
62*1da177e4SLinus Torvalds static int bnep_net_close(struct net_device *dev)
63*1da177e4SLinus Torvalds {
64*1da177e4SLinus Torvalds 	netif_stop_queue(dev);
65*1da177e4SLinus Torvalds 	return 0;
66*1da177e4SLinus Torvalds }
67*1da177e4SLinus Torvalds 
68*1da177e4SLinus Torvalds static struct net_device_stats *bnep_net_get_stats(struct net_device *dev)
69*1da177e4SLinus Torvalds {
70*1da177e4SLinus Torvalds 	struct bnep_session *s = dev->priv;
71*1da177e4SLinus Torvalds 	return &s->stats;
72*1da177e4SLinus Torvalds }
73*1da177e4SLinus Torvalds 
74*1da177e4SLinus Torvalds static void bnep_net_set_mc_list(struct net_device *dev)
75*1da177e4SLinus Torvalds {
76*1da177e4SLinus Torvalds #ifdef CONFIG_BT_BNEP_MC_FILTER
77*1da177e4SLinus Torvalds 	struct bnep_session *s = dev->priv;
78*1da177e4SLinus Torvalds 	struct sock *sk = s->sock->sk;
79*1da177e4SLinus Torvalds 	struct bnep_set_filter_req *r;
80*1da177e4SLinus Torvalds 	struct sk_buff *skb;
81*1da177e4SLinus Torvalds 	int size;
82*1da177e4SLinus Torvalds 
83*1da177e4SLinus Torvalds 	BT_DBG("%s mc_count %d", dev->name, dev->mc_count);
84*1da177e4SLinus Torvalds 
85*1da177e4SLinus Torvalds 	size = sizeof(*r) + (BNEP_MAX_MULTICAST_FILTERS + 1) * ETH_ALEN * 2;
86*1da177e4SLinus Torvalds 	skb  = alloc_skb(size, GFP_ATOMIC);
87*1da177e4SLinus Torvalds 	if (!skb) {
88*1da177e4SLinus Torvalds 		BT_ERR("%s Multicast list allocation failed", dev->name);
89*1da177e4SLinus Torvalds 		return;
90*1da177e4SLinus Torvalds 	}
91*1da177e4SLinus Torvalds 
92*1da177e4SLinus Torvalds 	r = (void *) skb->data;
93*1da177e4SLinus Torvalds 	__skb_put(skb, sizeof(*r));
94*1da177e4SLinus Torvalds 
95*1da177e4SLinus Torvalds 	r->type = BNEP_CONTROL;
96*1da177e4SLinus Torvalds 	r->ctrl = BNEP_FILTER_MULTI_ADDR_SET;
97*1da177e4SLinus Torvalds 
98*1da177e4SLinus Torvalds         if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) {
99*1da177e4SLinus Torvalds 		u8 start[ETH_ALEN] = { 0x01 };
100*1da177e4SLinus Torvalds 
101*1da177e4SLinus Torvalds 		/* Request all addresses */
102*1da177e4SLinus Torvalds 		memcpy(__skb_put(skb, ETH_ALEN), start, ETH_ALEN);
103*1da177e4SLinus Torvalds 		memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN);
104*1da177e4SLinus Torvalds 		r->len = htons(ETH_ALEN * 2);
105*1da177e4SLinus Torvalds 	} else {
106*1da177e4SLinus Torvalds                 struct dev_mc_list *dmi = dev->mc_list;
107*1da177e4SLinus Torvalds 		int i, len = skb->len;
108*1da177e4SLinus Torvalds 
109*1da177e4SLinus Torvalds 		if (dev->flags & IFF_BROADCAST) {
110*1da177e4SLinus Torvalds 			memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN);
111*1da177e4SLinus Torvalds 			memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN);
112*1da177e4SLinus Torvalds 		}
113*1da177e4SLinus Torvalds 
114*1da177e4SLinus Torvalds 		/* FIXME: We should group addresses here. */
115*1da177e4SLinus Torvalds 
116*1da177e4SLinus Torvalds 		for (i = 0; i < dev->mc_count && i < BNEP_MAX_MULTICAST_FILTERS; i++) {
117*1da177e4SLinus Torvalds 			memcpy(__skb_put(skb, ETH_ALEN), dmi->dmi_addr, ETH_ALEN);
118*1da177e4SLinus Torvalds 			memcpy(__skb_put(skb, ETH_ALEN), dmi->dmi_addr, ETH_ALEN);
119*1da177e4SLinus Torvalds 			dmi = dmi->next;
120*1da177e4SLinus Torvalds 		}
121*1da177e4SLinus Torvalds 		r->len = htons(skb->len - len);
122*1da177e4SLinus Torvalds 	}
123*1da177e4SLinus Torvalds 
124*1da177e4SLinus Torvalds 	skb_queue_tail(&sk->sk_write_queue, skb);
125*1da177e4SLinus Torvalds 	wake_up_interruptible(sk->sk_sleep);
126*1da177e4SLinus Torvalds #endif
127*1da177e4SLinus Torvalds }
128*1da177e4SLinus Torvalds 
129*1da177e4SLinus Torvalds static int bnep_net_set_mac_addr(struct net_device *dev, void *arg)
130*1da177e4SLinus Torvalds {
131*1da177e4SLinus Torvalds 	BT_DBG("%s", dev->name);
132*1da177e4SLinus Torvalds 	return 0;
133*1da177e4SLinus Torvalds }
134*1da177e4SLinus Torvalds 
135*1da177e4SLinus Torvalds static void bnep_net_timeout(struct net_device *dev)
136*1da177e4SLinus Torvalds {
137*1da177e4SLinus Torvalds 	BT_DBG("net_timeout");
138*1da177e4SLinus Torvalds 	netif_wake_queue(dev);
139*1da177e4SLinus Torvalds }
140*1da177e4SLinus Torvalds 
141*1da177e4SLinus Torvalds static int bnep_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
142*1da177e4SLinus Torvalds {
143*1da177e4SLinus Torvalds 	return -EINVAL;
144*1da177e4SLinus Torvalds }
145*1da177e4SLinus Torvalds 
146*1da177e4SLinus Torvalds #ifdef CONFIG_BT_BNEP_MC_FILTER
147*1da177e4SLinus Torvalds static inline int bnep_net_mc_filter(struct sk_buff *skb, struct bnep_session *s)
148*1da177e4SLinus Torvalds {
149*1da177e4SLinus Torvalds 	struct ethhdr *eh = (void *) skb->data;
150*1da177e4SLinus Torvalds 
151*1da177e4SLinus Torvalds 	if ((eh->h_dest[0] & 1) && !test_bit(bnep_mc_hash(eh->h_dest), (ulong *) &s->mc_filter))
152*1da177e4SLinus Torvalds 		return 1;
153*1da177e4SLinus Torvalds 	return 0;
154*1da177e4SLinus Torvalds }
155*1da177e4SLinus Torvalds #endif
156*1da177e4SLinus Torvalds 
157*1da177e4SLinus Torvalds #ifdef CONFIG_BT_BNEP_PROTO_FILTER
158*1da177e4SLinus Torvalds /* Determine ether protocol. Based on eth_type_trans. */
159*1da177e4SLinus Torvalds static inline u16 bnep_net_eth_proto(struct sk_buff *skb)
160*1da177e4SLinus Torvalds {
161*1da177e4SLinus Torvalds 	struct ethhdr *eh = (void *) skb->data;
162*1da177e4SLinus Torvalds 
163*1da177e4SLinus Torvalds 	if (ntohs(eh->h_proto) >= 1536)
164*1da177e4SLinus Torvalds 		return eh->h_proto;
165*1da177e4SLinus Torvalds 
166*1da177e4SLinus Torvalds 	if (get_unaligned((u16 *) skb->data) == 0xFFFF)
167*1da177e4SLinus Torvalds 		return htons(ETH_P_802_3);
168*1da177e4SLinus Torvalds 
169*1da177e4SLinus Torvalds 	return htons(ETH_P_802_2);
170*1da177e4SLinus Torvalds }
171*1da177e4SLinus Torvalds 
172*1da177e4SLinus Torvalds static inline int bnep_net_proto_filter(struct sk_buff *skb, struct bnep_session *s)
173*1da177e4SLinus Torvalds {
174*1da177e4SLinus Torvalds 	u16 proto = bnep_net_eth_proto(skb);
175*1da177e4SLinus Torvalds 	struct bnep_proto_filter *f = s->proto_filter;
176*1da177e4SLinus Torvalds 	int i;
177*1da177e4SLinus Torvalds 
178*1da177e4SLinus Torvalds 	for (i = 0; i < BNEP_MAX_PROTO_FILTERS && f[i].end; i++) {
179*1da177e4SLinus Torvalds 		if (proto >= f[i].start && proto <= f[i].end)
180*1da177e4SLinus Torvalds 			return 0;
181*1da177e4SLinus Torvalds 	}
182*1da177e4SLinus Torvalds 
183*1da177e4SLinus Torvalds 	BT_DBG("BNEP: filtered skb %p, proto 0x%.4x", skb, proto);
184*1da177e4SLinus Torvalds 	return 1;
185*1da177e4SLinus Torvalds }
186*1da177e4SLinus Torvalds #endif
187*1da177e4SLinus Torvalds 
188*1da177e4SLinus Torvalds static int bnep_net_xmit(struct sk_buff *skb, struct net_device *dev)
189*1da177e4SLinus Torvalds {
190*1da177e4SLinus Torvalds 	struct bnep_session *s = dev->priv;
191*1da177e4SLinus Torvalds 	struct sock *sk = s->sock->sk;
192*1da177e4SLinus Torvalds 
193*1da177e4SLinus Torvalds 	BT_DBG("skb %p, dev %p", skb, dev);
194*1da177e4SLinus Torvalds 
195*1da177e4SLinus Torvalds #ifdef CONFIG_BT_BNEP_MC_FILTER
196*1da177e4SLinus Torvalds 	if (bnep_net_mc_filter(skb, s)) {
197*1da177e4SLinus Torvalds 		kfree_skb(skb);
198*1da177e4SLinus Torvalds 		return 0;
199*1da177e4SLinus Torvalds 	}
200*1da177e4SLinus Torvalds #endif
201*1da177e4SLinus Torvalds 
202*1da177e4SLinus Torvalds #ifdef CONFIG_BT_BNEP_PROTO_FILTER
203*1da177e4SLinus Torvalds 	if (bnep_net_proto_filter(skb, s)) {
204*1da177e4SLinus Torvalds 		kfree_skb(skb);
205*1da177e4SLinus Torvalds 		return 0;
206*1da177e4SLinus Torvalds 	}
207*1da177e4SLinus Torvalds #endif
208*1da177e4SLinus Torvalds 
209*1da177e4SLinus Torvalds 	/*
210*1da177e4SLinus Torvalds 	 * We cannot send L2CAP packets from here as we are potentially in a bh.
211*1da177e4SLinus Torvalds 	 * So we have to queue them and wake up session thread which is sleeping
212*1da177e4SLinus Torvalds 	 * on the sk->sk_sleep.
213*1da177e4SLinus Torvalds 	 */
214*1da177e4SLinus Torvalds 	dev->trans_start = jiffies;
215*1da177e4SLinus Torvalds 	skb_queue_tail(&sk->sk_write_queue, skb);
216*1da177e4SLinus Torvalds 	wake_up_interruptible(sk->sk_sleep);
217*1da177e4SLinus Torvalds 
218*1da177e4SLinus Torvalds 	if (skb_queue_len(&sk->sk_write_queue) >= BNEP_TX_QUEUE_LEN) {
219*1da177e4SLinus Torvalds 		BT_DBG("tx queue is full");
220*1da177e4SLinus Torvalds 
221*1da177e4SLinus Torvalds 		/* Stop queuing.
222*1da177e4SLinus Torvalds 		 * Session thread will do netif_wake_queue() */
223*1da177e4SLinus Torvalds 		netif_stop_queue(dev);
224*1da177e4SLinus Torvalds 	}
225*1da177e4SLinus Torvalds 
226*1da177e4SLinus Torvalds 	return 0;
227*1da177e4SLinus Torvalds }
228*1da177e4SLinus Torvalds 
229*1da177e4SLinus Torvalds void bnep_net_setup(struct net_device *dev)
230*1da177e4SLinus Torvalds {
231*1da177e4SLinus Torvalds 
232*1da177e4SLinus Torvalds 	memset(dev->broadcast, 0xff, ETH_ALEN);
233*1da177e4SLinus Torvalds 	dev->addr_len = ETH_ALEN;
234*1da177e4SLinus Torvalds 
235*1da177e4SLinus Torvalds 	ether_setup(dev);
236*1da177e4SLinus Torvalds 
237*1da177e4SLinus Torvalds 	dev->open            = bnep_net_open;
238*1da177e4SLinus Torvalds 	dev->stop            = bnep_net_close;
239*1da177e4SLinus Torvalds 	dev->hard_start_xmit = bnep_net_xmit;
240*1da177e4SLinus Torvalds 	dev->get_stats       = bnep_net_get_stats;
241*1da177e4SLinus Torvalds 	dev->do_ioctl        = bnep_net_ioctl;
242*1da177e4SLinus Torvalds 	dev->set_mac_address = bnep_net_set_mac_addr;
243*1da177e4SLinus Torvalds 	dev->set_multicast_list = bnep_net_set_mc_list;
244*1da177e4SLinus Torvalds 
245*1da177e4SLinus Torvalds 	dev->watchdog_timeo  = HZ * 2;
246*1da177e4SLinus Torvalds 	dev->tx_timeout      = bnep_net_timeout;
247*1da177e4SLinus Torvalds }
248