18e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   BNEP implementation for Linux Bluetooth stack (BlueZ).
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Copyright (C) 2001-2002 Inventel Systemes
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Written 2001-2002 by
596de0e252cedffad61b3cb5e05662c591898e69aJan Engelhardt	Clément Moreau <clement.moreau@inventel.fr>
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	David Libault  <david.libault@inventel.fr>
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   This program is free software; you can redistribute it and/or modify
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   it under the terms of the GNU General Public License version 2 as
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   published by the Free Software Foundation;
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
188e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
198e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
208e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
238e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
248e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   SOFTWARE IS DISCLAIMED.
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
29f4d7cd4a4c25cb4a5c30a675d4cc0052c93b925aSzymon Janc#include <linux/kthread.h>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/file.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/etherdevice.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/unaligned.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/bluetooth/bluetooth.h>
350a85b964e141a4b8db6eaf500ceace12f8f52f93Marcel Holtmann#include <net/bluetooth/hci_core.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "bnep.h"
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3928111eb2f5087c5aa5ec3697388f6c7d354b2ad8Marcel Holtmann#define VERSION "1.3"
4028111eb2f5087c5aa5ec3697388f6c7d354b2ad8Marcel Holtmann
41eb93992207dadb946a3b5cf4544957dc924a6f58Rusty Russellstatic bool compress_src = true;
42eb93992207dadb946a3b5cf4544957dc924a6f58Rusty Russellstatic bool compress_dst = true;
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic LIST_HEAD(bnep_session_list);
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DECLARE_RWSEM(bnep_session_sem);
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct bnep_session *__bnep_get_session(u8 *dst)
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct bnep_session *s;
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("");
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
538035ded466049ca2fe8c04564a0fa00f222abe3fLuiz Augusto von Dentz	list_for_each_entry(s, &bnep_session_list, list)
54c47fc9814ca15cc075f1f09e8c069b041f2ea397Joe Perches		if (ether_addr_equal(dst, s->eh.h_source))
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return s;
568035ded466049ca2fe8c04564a0fa00f222abe3fLuiz Augusto von Dentz
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __bnep_link_session(struct bnep_session *s)
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
628e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki	list_add(&s->list, &bnep_session_list);
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __bnep_unlink_session(struct bnep_session *s)
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_del(&s->list);
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int bnep_send(struct bnep_session *s, void *data, size_t len)
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct socket *sock = s->sock;
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct kvec iv = { data, len };
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return kernel_sendmsg(sock, &s->msg, &iv, 1, len);
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int bnep_send_rsp(struct bnep_session *s, u8 ctrl, u16 resp)
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct bnep_control_rsp rsp;
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rsp.type = BNEP_CONTROL;
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rsp.ctrl = ctrl;
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rsp.resp = htons(resp);
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return bnep_send(s, &rsp, sizeof(rsp));
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_BT_BNEP_PROTO_FILTER
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void bnep_set_default_proto_filter(struct bnep_session *s)
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* (IPv4, ARP)  */
91e41d21697326a38a0a871c515db88fa310177e24Al Viro	s->proto_filter[0].start = ETH_P_IP;
92e41d21697326a38a0a871c515db88fa310177e24Al Viro	s->proto_filter[0].end   = ETH_P_ARP;
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* (RARP, AppleTalk) */
94e41d21697326a38a0a871c515db88fa310177e24Al Viro	s->proto_filter[1].start = ETH_P_RARP;
95e41d21697326a38a0a871c515db88fa310177e24Al Viro	s->proto_filter[1].end   = ETH_P_AARP;
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* (IPX, IPv6) */
97e41d21697326a38a0a871c515db88fa310177e24Al Viro	s->proto_filter[2].start = ETH_P_IPX;
98e41d21697326a38a0a871c515db88fa310177e24Al Viro	s->proto_filter[2].end   = ETH_P_IPV6;
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1021bc5d4483a83349f143e2bbf23ec144cd7e21e89Al Virostatic int bnep_ctrl_set_netfilter(struct bnep_session *s, __be16 *data, int len)
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int n;
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (len < 2)
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EILSEQ;
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10983985319393973f280ca2a797047780a7955cf19Harvey Harrison	n = get_unaligned_be16(data);
1103aad75a128e2f2b8da31de1df4b9b9b4a8f65c66Szymon Janc	data++;
1113aad75a128e2f2b8da31de1df4b9b9b4a8f65c66Szymon Janc	len -= 2;
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (len < n)
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EILSEQ;
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("filter len %d", n);
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_BT_BNEP_PROTO_FILTER
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	n /= 4;
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (n <= BNEP_MAX_PROTO_FILTERS) {
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct bnep_proto_filter *f = s->proto_filter;
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int i;
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < n; i++) {
12583985319393973f280ca2a797047780a7955cf19Harvey Harrison			f[i].start = get_unaligned_be16(data++);
12683985319393973f280ca2a797047780a7955cf19Harvey Harrison			f[i].end   = get_unaligned_be16(data++);
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			BT_DBG("proto filter start %d end %d",
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				f[i].start, f[i].end);
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (i < BNEP_MAX_PROTO_FILTERS)
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			memset(f + i, 0, sizeof(*f));
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (n == 0)
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bnep_set_default_proto_filter(s);
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_SUCCESS);
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_LIMIT_REACHED);
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_UNSUPPORTED_REQ);
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len)
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int n;
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (len < 2)
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EILSEQ;
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15583985319393973f280ca2a797047780a7955cf19Harvey Harrison	n = get_unaligned_be16(data);
1563aad75a128e2f2b8da31de1df4b9b9b4a8f65c66Szymon Janc	data += 2;
1573aad75a128e2f2b8da31de1df4b9b9b4a8f65c66Szymon Janc	len -= 2;
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (len < n)
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EILSEQ;
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("filter len %d", n);
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_BT_BNEP_MC_FILTER
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	n /= (ETH_ALEN * 2);
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (n > 0) {
168a3d9bd4c00f13defd4c0fdcf8b47f8764a69e54dSzymon Janc		int i;
169a3d9bd4c00f13defd4c0fdcf8b47f8764a69e54dSzymon Janc
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		s->mc_filter = 0;
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Always send broadcast */
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_bit(bnep_mc_hash(s->dev->broadcast), (ulong *) &s->mc_filter);
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Add address ranges to the multicast hash */
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (; n > 0; n--) {
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			u8 a1[6], *a2;
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1793aad75a128e2f2b8da31de1df4b9b9b4a8f65c66Szymon Janc			memcpy(a1, data, ETH_ALEN);
1803aad75a128e2f2b8da31de1df4b9b9b4a8f65c66Szymon Janc			data += ETH_ALEN;
1813aad75a128e2f2b8da31de1df4b9b9b4a8f65c66Szymon Janc			a2 = data;
1823aad75a128e2f2b8da31de1df4b9b9b4a8f65c66Szymon Janc			data += ETH_ALEN;
1838e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki
1846ed93dc6427d14cdfe0b272cc0a9ee4685ce9ad7Andrei Emeltchenko			BT_DBG("mc filter %pMR -> %pMR", a1, a2);
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Iterate from a1 to a2 */
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			set_bit(bnep_mc_hash(a1), (ulong *) &s->mc_filter);
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			while (memcmp(a1, a2, 6) < 0 && s->mc_filter != ~0LL) {
189a3d9bd4c00f13defd4c0fdcf8b47f8764a69e54dSzymon Janc				/* Increment a1 */
190a3d9bd4c00f13defd4c0fdcf8b47f8764a69e54dSzymon Janc				i = 5;
191a3d9bd4c00f13defd4c0fdcf8b47f8764a69e54dSzymon Janc				while (i >= 0 && ++a1[i--] == 0)
192a3d9bd4c00f13defd4c0fdcf8b47f8764a69e54dSzymon Janc					;
193a3d9bd4c00f13defd4c0fdcf8b47f8764a69e54dSzymon Janc
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				set_bit(bnep_mc_hash(a1), (ulong *) &s->mc_filter);
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("mc filter hash 0x%llx", s->mc_filter);
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bnep_send_rsp(s, BNEP_FILTER_MULTI_ADDR_RSP, BNEP_SUCCESS);
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bnep_send_rsp(s, BNEP_FILTER_MULTI_ADDR_RSP, BNEP_FILTER_UNSUPPORTED_REQ);
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int bnep_rx_control(struct bnep_session *s, void *data, int len)
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8  cmd = *(u8 *)data;
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0;
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2133aad75a128e2f2b8da31de1df4b9b9b4a8f65c66Szymon Janc	data++;
2143aad75a128e2f2b8da31de1df4b9b9b4a8f65c66Szymon Janc	len--;
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case BNEP_CMD_NOT_UNDERSTOOD:
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case BNEP_SETUP_CONN_RSP:
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case BNEP_FILTER_NET_TYPE_RSP:
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case BNEP_FILTER_MULTI_ADDR_RSP:
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Ignore these for now */
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case BNEP_FILTER_NET_TYPE_SET:
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = bnep_ctrl_set_netfilter(s, data, len);
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case BNEP_FILTER_MULTI_ADDR_SET:
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = bnep_ctrl_set_mcfilter(s, data, len);
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
232cde9f807f003676862178a6f28b52c7d431511edVikram Kandukuri	case BNEP_SETUP_CONN_REQ:
233cde9f807f003676862178a6f28b52c7d431511edVikram Kandukuri		err = bnep_send_rsp(s, BNEP_SETUP_CONN_RSP, BNEP_CONN_NOT_ALLOWED);
234cde9f807f003676862178a6f28b52c7d431511edVikram Kandukuri		break;
235cde9f807f003676862178a6f28b52c7d431511edVikram Kandukuri
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default: {
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			u8 pkt[3];
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pkt[0] = BNEP_CONTROL;
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pkt[1] = BNEP_CMD_NOT_UNDERSTOOD;
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pkt[2] = cmd;
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bnep_send(s, pkt, sizeof(pkt));
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int bnep_rx_extension(struct bnep_session *s, struct sk_buff *skb)
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct bnep_ext_hdr *h;
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0;
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do {
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		h = (void *) skb->data;
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!skb_pull(skb, sizeof(*h))) {
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = -EILSEQ;
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		BT_DBG("type 0x%x len %d", h->type, h->len);
2628e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (h->type & BNEP_TYPE_MASK) {
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case BNEP_EXT_CONTROL:
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bnep_rx_control(s, skb->data, skb->len);
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Unknown extension, skip it. */
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!skb_pull(skb, h->len)) {
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = -EILSEQ;
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} while (!err && (h->type & BNEP_EXT_HEADER));
2788e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u8 __bnep_rx_hlen[] = {
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ETH_HLEN,     /* BNEP_GENERAL */
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0,            /* BNEP_CONTROL */
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	2,            /* BNEP_COMPRESSED */
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ETH_ALEN + 2, /* BNEP_COMPRESSED_SRC_ONLY */
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ETH_ALEN + 2  /* BNEP_COMPRESSED_DST_ONLY */
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2906039aa73a1323edc2d6d93a22505d4dc28f38e3fGustavo Padovanstatic int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev = s->dev;
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *nskb;
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 type;
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
296b4d7f0a46bc0e30514b1779caff0fce6e424c4b5Stephen Hemminger	dev->stats.rx_bytes += skb->len;
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2983aad75a128e2f2b8da31de1df4b9b9b4a8f65c66Szymon Janc	type = *(u8 *) skb->data;
2993aad75a128e2f2b8da31de1df4b9b9b4a8f65c66Szymon Janc	skb_pull(skb, 1);
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
301a3d9bd4c00f13defd4c0fdcf8b47f8764a69e54dSzymon Janc	if ((type & BNEP_TYPE_MASK) >= sizeof(__bnep_rx_hlen))
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto badframe;
3038e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) {
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bnep_rx_control(s, skb->data, skb->len);
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree_skb(skb);
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
310459a98ed881802dee55897441bc7f77af614368eArnaldo Carvalho de Melo	skb_reset_mac_header(skb);
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Verify and pull out header */
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!skb_pull(skb, __bnep_rx_hlen[type & BNEP_TYPE_MASK]))
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto badframe;
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3161bc5d4483a83349f143e2bbf23ec144cd7e21e89Al Viro	s->eh.h_proto = get_unaligned((__be16 *) (skb->data - 2));
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (type & BNEP_EXT_HEADER) {
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bnep_rx_extension(s, skb) < 0)
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto badframe;
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Strip 802.1p header */
324000092b0b4793caf831f6016fa69d25abba31e51Eldad Zack	if (ntohs(s->eh.h_proto) == ETH_P_8021Q) {
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!skb_pull(skb, 4))
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto badframe;
3271bc5d4483a83349f143e2bbf23ec144cd7e21e89Al Viro		s->eh.h_proto = get_unaligned((__be16 *) (skb->data - 2));
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3298e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We have to alloc new skb and copy data here :(. Because original skb
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * may not be modified and because of the alignment requirements. */
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nskb = alloc_skb(2 + ETH_HLEN + skb->len, GFP_KERNEL);
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!nskb) {
334b4d7f0a46bc0e30514b1779caff0fce6e424c4b5Stephen Hemminger		dev->stats.rx_dropped++;
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree_skb(skb);
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_reserve(nskb, 2);
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Decompress header and construct ether frame */
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (type & BNEP_TYPE_MASK) {
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case BNEP_COMPRESSED:
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy(__skb_put(nskb, ETH_HLEN), &s->eh, ETH_HLEN);
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3458e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case BNEP_COMPRESSED_SRC_ONLY:
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy(__skb_put(nskb, ETH_ALEN), s->eh.h_dest, ETH_ALEN);
34898e399f82ab3a6d863d1d4a7ea48925cc91c830eArnaldo Carvalho de Melo		memcpy(__skb_put(nskb, ETH_ALEN), skb_mac_header(skb), ETH_ALEN);
3491bc5d4483a83349f143e2bbf23ec144cd7e21e89Al Viro		put_unaligned(s->eh.h_proto, (__be16 *) __skb_put(nskb, 2));
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case BNEP_COMPRESSED_DST_ONLY:
35398e399f82ab3a6d863d1d4a7ea48925cc91c830eArnaldo Carvalho de Melo		memcpy(__skb_put(nskb, ETH_ALEN), skb_mac_header(skb),
3543aad75a128e2f2b8da31de1df4b9b9b4a8f65c66Szymon Janc								ETH_ALEN);
35598e399f82ab3a6d863d1d4a7ea48925cc91c830eArnaldo Carvalho de Melo		memcpy(__skb_put(nskb, ETH_ALEN + 2), s->eh.h_source,
3563aad75a128e2f2b8da31de1df4b9b9b4a8f65c66Szymon Janc								ETH_ALEN + 2);
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case BNEP_GENERAL:
36098e399f82ab3a6d863d1d4a7ea48925cc91c830eArnaldo Carvalho de Melo		memcpy(__skb_put(nskb, ETH_ALEN * 2), skb_mac_header(skb),
3613aad75a128e2f2b8da31de1df4b9b9b4a8f65c66Szymon Janc								ETH_ALEN * 2);
3621bc5d4483a83349f143e2bbf23ec144cd7e21e89Al Viro		put_unaligned(s->eh.h_proto, (__be16 *) __skb_put(nskb, 2));
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
366d626f62b11e00c16e81e4308ab93d3f13551812aArnaldo Carvalho de Melo	skb_copy_from_linear_data(skb, __skb_put(nskb, skb->len), skb->len);
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree_skb(skb);
3688e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki
369b4d7f0a46bc0e30514b1779caff0fce6e424c4b5Stephen Hemminger	dev->stats.rx_packets++;
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nskb->ip_summed = CHECKSUM_NONE;
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nskb->protocol  = eth_type_trans(nskb, dev);
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_rx_ni(nskb);
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsbadframe:
376b4d7f0a46bc0e30514b1779caff0fce6e424c4b5Stephen Hemminger	dev->stats.rx_errors++;
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree_skb(skb);
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u8 __bnep_tx_types[] = {
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BNEP_GENERAL,
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BNEP_COMPRESSED_SRC_ONLY,
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BNEP_COMPRESSED_DST_ONLY,
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BNEP_COMPRESSED
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3886039aa73a1323edc2d6d93a22505d4dc28f38e3fGustavo Padovanstatic int bnep_tx_frame(struct bnep_session *s, struct sk_buff *skb)
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ethhdr *eh = (void *) skb->data;
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct socket *sock = s->sock;
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct kvec iv[3];
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int len = 0, il = 0;
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 type = 0;
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("skb %p dev %p type %d", skb, skb->dev, skb->pkt_type);
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!skb->dev) {
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Control frame sent by us */
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto send;
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	iv[il++] = (struct kvec) { &type, 1 };
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len++;
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
406c47fc9814ca15cc075f1f09e8c069b041f2ea397Joe Perches	if (compress_src && ether_addr_equal(eh->h_dest, s->eh.h_source))
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type |= 0x01;
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
409c47fc9814ca15cc075f1f09e8c069b041f2ea397Joe Perches	if (compress_dst && ether_addr_equal(eh->h_source, s->eh.h_dest))
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type |= 0x02;
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (type)
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		skb_pull(skb, ETH_ALEN * 2);
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	type = __bnep_tx_types[type];
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (type) {
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case BNEP_COMPRESSED_SRC_ONLY:
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		iv[il++] = (struct kvec) { eh->h_source, ETH_ALEN };
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len += ETH_ALEN;
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4218e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case BNEP_COMPRESSED_DST_ONLY:
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		iv[il++] = (struct kvec) { eh->h_dest, ETH_ALEN };
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len += ETH_ALEN;
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssend:
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	iv[il++] = (struct kvec) { skb->data, skb->len };
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len += skb->len;
4318e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME: linearize skb */
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len = kernel_sendmsg(sock, &s->msg, iv, il, len);
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree_skb(skb);
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (len > 0) {
439b4d7f0a46bc0e30514b1779caff0fce6e424c4b5Stephen Hemminger		s->dev->stats.tx_bytes += len;
440b4d7f0a46bc0e30514b1779caff0fce6e424c4b5Stephen Hemminger		s->dev->stats.tx_packets++;
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return len;
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int bnep_session(void *arg)
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct bnep_session *s = arg;
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev = s->dev;
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sock *sk = s->sock->sk;
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wait_queue_t wait;
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("");
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_user_nice(current, -15);
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_waitqueue_entry(&wait, current);
460aa395145165cb06a0d0885221bbe0ce4a564391dEric Dumazet	add_wait_queue(sk_sleep(sk), &wait);
46138d57555616afcdad7381b02b523d494327494cdPeter Hurley	while (1) {
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_current_state(TASK_INTERRUPTIBLE);
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
464751c10a56802513a6b057c8cf1552cecc1c9afdePeter Hurley		if (atomic_read(&s->terminate))
46538d57555616afcdad7381b02b523d494327494cdPeter Hurley			break;
4663aad75a128e2f2b8da31de1df4b9b9b4a8f65c66Szymon Janc		/* RX */
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			skb_orphan(skb);
469449357200c5d73d80a9c42dee5dafed684b3cd17Mat Martineau			if (!skb_linearize(skb))
470449357200c5d73d80a9c42dee5dafed684b3cd17Mat Martineau				bnep_rx_frame(s, skb);
471449357200c5d73d80a9c42dee5dafed684b3cd17Mat Martineau			else
472449357200c5d73d80a9c42dee5dafed684b3cd17Mat Martineau				kfree_skb(skb);
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (sk->sk_state != BT_CONNECTED)
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
4778e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki
4783aad75a128e2f2b8da31de1df4b9b9b4a8f65c66Szymon Janc		/* TX */
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while ((skb = skb_dequeue(&sk->sk_write_queue)))
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (bnep_tx_frame(s, skb))
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		netif_wake_queue(dev);
4838e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		schedule();
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
48638d57555616afcdad7381b02b523d494327494cdPeter Hurley	__set_current_state(TASK_RUNNING);
487aa395145165cb06a0d0885221bbe0ce4a564391dEric Dumazet	remove_wait_queue(sk_sleep(sk), &wait);
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Cleanup session */
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	down_write(&bnep_session_sem);
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Delete network device */
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unregister_netdev(dev);
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
495ec8dab36e0738d3059980d144e34f16a26bbda7dMarcel Holtmann	/* Wakeup user-space polling for socket errors */
496ec8dab36e0738d3059980d144e34f16a26bbda7dMarcel Holtmann	s->sock->sk->sk_err = EUNATCH;
497ec8dab36e0738d3059980d144e34f16a26bbda7dMarcel Holtmann
498aa395145165cb06a0d0885221bbe0ce4a564391dEric Dumazet	wake_up_interruptible(sk_sleep(s->sock->sk));
499ec8dab36e0738d3059980d144e34f16a26bbda7dMarcel Holtmann
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Release the socket */
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fput(s->sock->file);
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__bnep_unlink_session(s);
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up_write(&bnep_session_sem);
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_netdev(dev);
5079b338c3dd12918f7f7df2b882f63f71e9efbcb41David Herrmann	module_put_and_exit(0);
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5110a85b964e141a4b8db6eaf500ceace12f8f52f93Marcel Holtmannstatic struct device *bnep_get_device(struct bnep_session *session)
5120a85b964e141a4b8db6eaf500ceace12f8f52f93Marcel Holtmann{
5130a85b964e141a4b8db6eaf500ceace12f8f52f93Marcel Holtmann	bdaddr_t *src = &bt_sk(session->sock->sk)->src;
5140a85b964e141a4b8db6eaf500ceace12f8f52f93Marcel Holtmann	bdaddr_t *dst = &bt_sk(session->sock->sk)->dst;
5150a85b964e141a4b8db6eaf500ceace12f8f52f93Marcel Holtmann	struct hci_dev *hdev;
5160a85b964e141a4b8db6eaf500ceace12f8f52f93Marcel Holtmann	struct hci_conn *conn;
5170a85b964e141a4b8db6eaf500ceace12f8f52f93Marcel Holtmann
5180a85b964e141a4b8db6eaf500ceace12f8f52f93Marcel Holtmann	hdev = hci_get_route(dst, src);
5190a85b964e141a4b8db6eaf500ceace12f8f52f93Marcel Holtmann	if (!hdev)
5200a85b964e141a4b8db6eaf500ceace12f8f52f93Marcel Holtmann		return NULL;
5210a85b964e141a4b8db6eaf500ceace12f8f52f93Marcel Holtmann
5220a85b964e141a4b8db6eaf500ceace12f8f52f93Marcel Holtmann	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
5230a85b964e141a4b8db6eaf500ceace12f8f52f93Marcel Holtmann
5240a85b964e141a4b8db6eaf500ceace12f8f52f93Marcel Holtmann	hci_dev_put(hdev);
5250a85b964e141a4b8db6eaf500ceace12f8f52f93Marcel Holtmann
526b2cfcd75df77b80d9cc3fa84190a350dfa79eb93Marcel Holtmann	return conn ? &conn->dev : NULL;
5270a85b964e141a4b8db6eaf500ceace12f8f52f93Marcel Holtmann}
5280a85b964e141a4b8db6eaf500ceace12f8f52f93Marcel Holtmann
529384912ed194e43c03ad1cdaa09b0b1e488c34d46Marcel Holtmannstatic struct device_type bnep_type = {
530384912ed194e43c03ad1cdaa09b0b1e488c34d46Marcel Holtmann	.name	= "bluetooth",
531384912ed194e43c03ad1cdaa09b0b1e488c34d46Marcel Holtmann};
532384912ed194e43c03ad1cdaa09b0b1e488c34d46Marcel Holtmann
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct bnep_session *s, *ss;
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 dst[ETH_ALEN], src[ETH_ALEN];
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("");
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	baswap((void *) dst, &bt_sk(sock->sk)->dst);
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	baswap((void *) src, &bt_sk(sock->sk)->src);
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* session struct allocated as private part of net_device */
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev = alloc_netdev(sizeof(struct bnep_session),
5473aad75a128e2f2b8da31de1df4b9b9b4a8f65c66Szymon Janc				(*req->device) ? req->device : "bnep%d",
5483aad75a128e2f2b8da31de1df4b9b9b4a8f65c66Szymon Janc				bnep_net_setup);
54967b52e554ba973947704fcb4fc284d7bab9ab931Tobias Klauser	if (!dev)
55067b52e554ba973947704fcb4fc284d7bab9ab931Tobias Klauser		return -ENOMEM;
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	down_write(&bnep_session_sem);
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ss = __bnep_get_session(dst);
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ss && ss->state == BT_CONNECTED) {
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -EEXIST;
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed;
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
560524ad0a79126efabf58d0a49eace6155ab5b4549Wang Chen	s = netdev_priv(dev);
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* This is rx header therefore addresses are swapped.
5633aad75a128e2f2b8da31de1df4b9b9b4a8f65c66Szymon Janc	 * ie. eh.h_dest is our local address. */
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(s->eh.h_dest,   &src, ETH_ALEN);
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(s->eh.h_source, &dst, ETH_ALEN);
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(dev->dev_addr, s->eh.h_dest, ETH_ALEN);
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5680a85b964e141a4b8db6eaf500ceace12f8f52f93Marcel Holtmann	s->dev   = dev;
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s->sock  = sock;
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s->role  = req->role;
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s->state = BT_CONNECTED;
5728e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s->msg.msg_flags = MSG_NOSIGNAL;
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_BT_BNEP_MC_FILTER
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set default mc filter */
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_bit(bnep_mc_hash(dev->broadcast), (ulong *) &s->mc_filter);
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_BT_BNEP_PROTO_FILTER
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set default protocol filter */
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bnep_set_default_proto_filter(s);
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5850a85b964e141a4b8db6eaf500ceace12f8f52f93Marcel Holtmann	SET_NETDEV_DEV(dev, bnep_get_device(s));
586384912ed194e43c03ad1cdaa09b0b1e488c34d46Marcel Holtmann	SET_NETDEV_DEVTYPE(dev, &bnep_type);
5870a85b964e141a4b8db6eaf500ceace12f8f52f93Marcel Holtmann
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = register_netdev(dev);
5893aad75a128e2f2b8da31de1df4b9b9b4a8f65c66Szymon Janc	if (err)
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed;
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__bnep_link_session(s);
5938e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki
5949b338c3dd12918f7f7df2b882f63f71e9efbcb41David Herrmann	__module_get(THIS_MODULE);
595f4d7cd4a4c25cb4a5c30a675d4cc0052c93b925aSzymon Janc	s->task = kthread_run(bnep_session, s, "kbnepd %s", dev->name);
596f4d7cd4a4c25cb4a5c30a675d4cc0052c93b925aSzymon Janc	if (IS_ERR(s->task)) {
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Session thread start failed, gotta cleanup. */
5989b338c3dd12918f7f7df2b882f63f71e9efbcb41David Herrmann		module_put(THIS_MODULE);
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unregister_netdev(dev);
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__bnep_unlink_session(s);
601f4d7cd4a4c25cb4a5c30a675d4cc0052c93b925aSzymon Janc		err = PTR_ERR(s->task);
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed;
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up_write(&bnep_session_sem);
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcpy(req->device, dev->name);
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfailed:
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up_write(&bnep_session_sem);
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_netdev(dev);
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint bnep_del_connection(struct bnep_conndel_req *req)
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct bnep_session *s;
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int  err = 0;
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("");
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	down_read(&bnep_session_sem);
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s = __bnep_get_session(req->dst);
625751c10a56802513a6b057c8cf1552cecc1c9afdePeter Hurley	if (s) {
626751c10a56802513a6b057c8cf1552cecc1c9afdePeter Hurley		atomic_inc(&s->terminate);
627751c10a56802513a6b057c8cf1552cecc1c9afdePeter Hurley		wake_up_process(s->task);
628751c10a56802513a6b057c8cf1552cecc1c9afdePeter Hurley	} else
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -ENOENT;
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up_read(&bnep_session_sem);
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __bnep_copy_ci(struct bnep_conninfo *ci, struct bnep_session *s)
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6375520d20f68310fc158dcbbecfd5eac5cdfc5a241Vasiliy Kulikov	memset(ci, 0, sizeof(*ci));
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(ci->dst, s->eh.h_source, ETH_ALEN);
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcpy(ci->device, s->dev->name);
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ci->flags = s->flags;
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ci->state = s->state;
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ci->role  = s->role;
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint bnep_get_connlist(struct bnep_connlist_req *req)
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6478035ded466049ca2fe8c04564a0fa00f222abe3fLuiz Augusto von Dentz	struct bnep_session *s;
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0, n = 0;
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	down_read(&bnep_session_sem);
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6528035ded466049ca2fe8c04564a0fa00f222abe3fLuiz Augusto von Dentz	list_for_each_entry(s, &bnep_session_list, list) {
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct bnep_conninfo ci;
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__bnep_copy_ci(&ci, s);
6568e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy_to_user(req->ci, &ci, sizeof(ci))) {
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = -EFAULT;
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (++n >= req->cnum)
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req->ci++;
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	req->cnum = n;
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up_read(&bnep_session_sem);
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint bnep_get_conninfo(struct bnep_conninfo *ci)
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct bnep_session *s;
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0;
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	down_read(&bnep_session_sem);
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s = __bnep_get_session(ci->dst);
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (s)
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__bnep_copy_ci(ci, s);
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -ENOENT;
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up_read(&bnep_session_sem);
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init bnep_init(void)
6918e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki{
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char flt[50] = "";
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_BT_BNEP_PROTO_FILTER
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcat(flt, "protocol ");
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_BT_BNEP_MC_FILTER
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcat(flt, "multicast");
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_INFO("BNEP (Ethernet Emulation) ver %s", VERSION);
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (flt[0])
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		BT_INFO("BNEP filters: %s", flt);
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bnep_sock_init();
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit bnep_exit(void)
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bnep_sock_cleanup();
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(bnep_init);
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(bnep_exit);
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
71828111eb2f5087c5aa5ec3697388f6c7d354b2ad8Marcel Holtmannmodule_param(compress_src, bool, 0644);
71928111eb2f5087c5aa5ec3697388f6c7d354b2ad8Marcel HoltmannMODULE_PARM_DESC(compress_src, "Compress sources headers");
72028111eb2f5087c5aa5ec3697388f6c7d354b2ad8Marcel Holtmann
72128111eb2f5087c5aa5ec3697388f6c7d354b2ad8Marcel Holtmannmodule_param(compress_dst, bool, 0644);
72228111eb2f5087c5aa5ec3697388f6c7d354b2ad8Marcel HoltmannMODULE_PARM_DESC(compress_dst, "Compress destination headers");
72328111eb2f5087c5aa5ec3697388f6c7d354b2ad8Marcel Holtmann
72463fbd24e5102eecfc9d049ed7f4be7f9a25f814fMarcel HoltmannMODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("Bluetooth BNEP ver " VERSION);
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_VERSION(VERSION);
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_ALIAS("bt-proto-4");
729