• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/net/bluetooth/bnep/
1/*
2   BNEP implementation for Linux Bluetooth stack (BlueZ).
3   Copyright (C) 2001-2002 Inventel Systemes
4   Written 2001-2002 by
5	Cl��ment Moreau <clement.moreau@inventel.fr>
6	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
18   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
21   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
23   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
24   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
25   SOFTWARE IS DISCLAIMED.
26*/
27
28#include <linux/module.h>
29#include <linux/slab.h>
30
31#include <linux/socket.h>
32#include <linux/netdevice.h>
33#include <linux/etherdevice.h>
34#include <linux/skbuff.h>
35#include <linux/wait.h>
36
37#include <asm/unaligned.h>
38
39#include <net/bluetooth/bluetooth.h>
40#include <net/bluetooth/hci_core.h>
41#include <net/bluetooth/l2cap.h>
42
43#include "bnep.h"
44
45#define BNEP_TX_QUEUE_LEN 20
46
47static int bnep_net_open(struct net_device *dev)
48{
49	netif_start_queue(dev);
50	return 0;
51}
52
53static int bnep_net_close(struct net_device *dev)
54{
55	netif_stop_queue(dev);
56	return 0;
57}
58
59static void bnep_net_set_mc_list(struct net_device *dev)
60{
61#ifdef CONFIG_BT_BNEP_MC_FILTER
62	struct bnep_session *s = netdev_priv(dev);
63	struct sock *sk = s->sock->sk;
64	struct bnep_set_filter_req *r;
65	struct sk_buff *skb;
66	int size;
67
68	BT_DBG("%s mc_count %d", dev->name, netdev_mc_count(dev));
69
70	size = sizeof(*r) + (BNEP_MAX_MULTICAST_FILTERS + 1) * ETH_ALEN * 2;
71	skb  = alloc_skb(size, GFP_ATOMIC);
72	if (!skb) {
73		BT_ERR("%s Multicast list allocation failed", dev->name);
74		return;
75	}
76
77	r = (void *) skb->data;
78	__skb_put(skb, sizeof(*r));
79
80	r->type = BNEP_CONTROL;
81	r->ctrl = BNEP_FILTER_MULTI_ADDR_SET;
82
83	if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) {
84		u8 start[ETH_ALEN] = { 0x01 };
85
86		/* Request all addresses */
87		memcpy(__skb_put(skb, ETH_ALEN), start, ETH_ALEN);
88		memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN);
89		r->len = htons(ETH_ALEN * 2);
90	} else {
91		struct netdev_hw_addr *ha;
92		int i, len = skb->len;
93
94		if (dev->flags & IFF_BROADCAST) {
95			memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN);
96			memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN);
97		}
98
99
100		i = 0;
101		netdev_for_each_mc_addr(ha, dev) {
102			if (i == BNEP_MAX_MULTICAST_FILTERS)
103				break;
104			memcpy(__skb_put(skb, ETH_ALEN), ha->addr, ETH_ALEN);
105			memcpy(__skb_put(skb, ETH_ALEN), ha->addr, ETH_ALEN);
106
107			i++;
108		}
109		r->len = htons(skb->len - len);
110	}
111
112	skb_queue_tail(&sk->sk_write_queue, skb);
113	wake_up_interruptible(sk_sleep(sk));
114#endif
115}
116
117static int bnep_net_set_mac_addr(struct net_device *dev, void *arg)
118{
119	BT_DBG("%s", dev->name);
120	return 0;
121}
122
123static void bnep_net_timeout(struct net_device *dev)
124{
125	BT_DBG("net_timeout");
126	netif_wake_queue(dev);
127}
128
129#ifdef CONFIG_BT_BNEP_MC_FILTER
130static inline int bnep_net_mc_filter(struct sk_buff *skb, struct bnep_session *s)
131{
132	struct ethhdr *eh = (void *) skb->data;
133
134	if ((eh->h_dest[0] & 1) && !test_bit(bnep_mc_hash(eh->h_dest), (ulong *) &s->mc_filter))
135		return 1;
136	return 0;
137}
138#endif
139
140#ifdef CONFIG_BT_BNEP_PROTO_FILTER
141/* Determine ether protocol. Based on eth_type_trans. */
142static inline u16 bnep_net_eth_proto(struct sk_buff *skb)
143{
144	struct ethhdr *eh = (void *) skb->data;
145	u16 proto = ntohs(eh->h_proto);
146
147	if (proto >= 1536)
148		return proto;
149
150	if (get_unaligned((__be16 *) skb->data) == htons(0xFFFF))
151		return ETH_P_802_3;
152
153	return ETH_P_802_2;
154}
155
156static inline int bnep_net_proto_filter(struct sk_buff *skb, struct bnep_session *s)
157{
158	u16 proto = bnep_net_eth_proto(skb);
159	struct bnep_proto_filter *f = s->proto_filter;
160	int i;
161
162	for (i = 0; i < BNEP_MAX_PROTO_FILTERS && f[i].end; i++) {
163		if (proto >= f[i].start && proto <= f[i].end)
164			return 0;
165	}
166
167	BT_DBG("BNEP: filtered skb %p, proto 0x%.4x", skb, proto);
168	return 1;
169}
170#endif
171
172static netdev_tx_t bnep_net_xmit(struct sk_buff *skb,
173				 struct net_device *dev)
174{
175	struct bnep_session *s = netdev_priv(dev);
176	struct sock *sk = s->sock->sk;
177
178	BT_DBG("skb %p, dev %p", skb, dev);
179
180#ifdef CONFIG_BT_BNEP_MC_FILTER
181	if (bnep_net_mc_filter(skb, s)) {
182		kfree_skb(skb);
183		return NETDEV_TX_OK;
184	}
185#endif
186
187#ifdef CONFIG_BT_BNEP_PROTO_FILTER
188	if (bnep_net_proto_filter(skb, s)) {
189		kfree_skb(skb);
190		return NETDEV_TX_OK;
191	}
192#endif
193
194	/*
195	 * We cannot send L2CAP packets from here as we are potentially in a bh.
196	 * So we have to queue them and wake up session thread which is sleeping
197	 * on the sk_sleep(sk).
198	 */
199	dev->trans_start = jiffies;
200	skb_queue_tail(&sk->sk_write_queue, skb);
201	wake_up_interruptible(sk_sleep(sk));
202
203	if (skb_queue_len(&sk->sk_write_queue) >= BNEP_TX_QUEUE_LEN) {
204		BT_DBG("tx queue is full");
205
206		/* Stop queuing.
207		 * Session thread will do netif_wake_queue() */
208		netif_stop_queue(dev);
209	}
210
211	return NETDEV_TX_OK;
212}
213
214static const struct net_device_ops bnep_netdev_ops = {
215	.ndo_open            = bnep_net_open,
216	.ndo_stop            = bnep_net_close,
217	.ndo_start_xmit	     = bnep_net_xmit,
218	.ndo_validate_addr   = eth_validate_addr,
219	.ndo_set_multicast_list = bnep_net_set_mc_list,
220	.ndo_set_mac_address = bnep_net_set_mac_addr,
221	.ndo_tx_timeout      = bnep_net_timeout,
222	.ndo_change_mtu	     = eth_change_mtu,
223
224};
225
226void bnep_net_setup(struct net_device *dev)
227{
228
229	memset(dev->broadcast, 0xff, ETH_ALEN);
230	dev->addr_len = ETH_ALEN;
231
232	ether_setup(dev);
233	dev->netdev_ops = &bnep_netdev_ops;
234
235	dev->watchdog_timeo  = HZ * 2;
236}
237