18e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   RFCOMM implementation for Linux Bluetooth stack (BlueZ).
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   This program is free software; you can redistribute it and/or modify
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   it under the terms of the GNU General Public License version 2 as
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   published by the Free Software Foundation;
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
148e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
158e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
168e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
198e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
208e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   SOFTWARE IS DISCLAIMED.
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * RFCOMM sockets.
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
288c520a59927a5600973782505dbb750d985057c4Gustavo Padovan#include <linux/export.h>
29aef7d97cc604309b66f6f45cce02cd734934cd4eMarcel Holtmann#include <linux/debugfs.h>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/bluetooth/bluetooth.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/bluetooth/hci_core.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/bluetooth/l2cap.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/bluetooth/rfcomm.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3690ddc4f0470427df306f308ad03db6b6b21644b8Eric Dumazetstatic const struct proto_ops rfcomm_sock_ops;
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct bt_sock_list rfcomm_sk_list = {
39d5fb2962c6157495e1365e4f30568ed3830d35a7Robert P. J. Day	.lock = __RW_LOCK_UNLOCKED(rfcomm_sk_list.lock)
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rfcomm_sock_close(struct sock *sk);
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rfcomm_sock_kill(struct sock *sk);
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ---- DLC callbacks ----
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * called under rfcomm_dlc_lock()
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rfcomm_sk_data_ready(struct rfcomm_dlc *d, struct sk_buff *skb)
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sock *sk = d->owner;
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!sk)
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_add(skb->len, &sk->sk_rmem_alloc);
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_queue_tail(&sk->sk_receive_queue, skb);
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sk->sk_data_ready(sk, skb->len);
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf)
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rfcomm_dlc_throttle(d);
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err)
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sock *sk = d->owner, *parent;
66fad003b6c8e3d944d4453fd569b0702ef1af82b3Gustavo Padovan	unsigned long flags;
67fad003b6c8e3d944d4453fd569b0702ef1af82b3Gustavo Padovan
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!sk)
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("dlc %p state %ld err %d", d, d->state, err);
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
73fad003b6c8e3d944d4453fd569b0702ef1af82b3Gustavo Padovan	local_irq_save(flags);
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bh_lock_sock(sk);
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err)
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sk->sk_err = err;
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sk->sk_state = d->state;
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	parent = bt_sk(sk)->parent;
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (parent) {
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (d->state == BT_CLOSED) {
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sock_set_flag(sk, SOCK_ZAPPED);
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bt_accept_unlink(sk);
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		parent->sk_data_ready(parent, 0);
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (d->state == BT_CONNECTED)
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rfcomm_session_getaddr(d->session, &bt_sk(sk)->src, NULL);
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sk->sk_state_change(sk);
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bh_unlock_sock(sk);
95fad003b6c8e3d944d4453fd569b0702ef1af82b3Gustavo Padovan	local_irq_restore(flags);
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (parent && sock_flag(sk, SOCK_ZAPPED)) {
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* We have to drop DLC lock here, otherwise
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * rfcomm_sock_destruct() will dead lock. */
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rfcomm_dlc_unlock(d);
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rfcomm_sock_kill(sk);
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rfcomm_dlc_lock(d);
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ---- Socket functions ---- */
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sock *__rfcomm_get_sock_by_addr(u8 channel, bdaddr_t *src)
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sock *sk = NULL;
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
111b67bfe0d42cac56c512dd5da4b1b347a23f4b70aSasha Levin	sk_for_each(sk, &rfcomm_sk_list.head) {
1128e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki		if (rfcomm_pi(sk)->channel == channel &&
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				!bacmp(&bt_sk(sk)->src, src))
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
117b67bfe0d42cac56c512dd5da4b1b347a23f4b70aSasha Levin	return sk ? sk : NULL;
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Find socket with channel and source bdaddr.
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns closest match.
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
123eeb366564be7c311b31c70821d18a43a8a57f9bcGustavo Padovanstatic struct sock *rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t *src)
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sock *sk = NULL, *sk1 = NULL;
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
127eeb366564be7c311b31c70821d18a43a8a57f9bcGustavo Padovan	read_lock(&rfcomm_sk_list.lock);
128eeb366564be7c311b31c70821d18a43a8a57f9bcGustavo Padovan
129b67bfe0d42cac56c512dd5da4b1b347a23f4b70aSasha Levin	sk_for_each(sk, &rfcomm_sk_list.head) {
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (state && sk->sk_state != state)
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (rfcomm_pi(sk)->channel == channel) {
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Exact match. */
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!bacmp(&bt_sk(sk)->src, src))
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Closest match */
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				sk1 = sk;
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	read_unlock(&rfcomm_sk_list.lock);
145eeb366564be7c311b31c70821d18a43a8a57f9bcGustavo Padovan
146b67bfe0d42cac56c512dd5da4b1b347a23f4b70aSasha Levin	return sk ? sk : sk1;
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rfcomm_sock_destruct(struct sock *sk)
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("sk %p dlc %p", sk, d);
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_queue_purge(&sk->sk_receive_queue);
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_queue_purge(&sk->sk_write_queue);
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rfcomm_dlc_lock(d);
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rfcomm_pi(sk)->dlc = NULL;
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Detach DLC if it's owned by this socket */
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (d->owner == sk)
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		d->owner = NULL;
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rfcomm_dlc_unlock(d);
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rfcomm_dlc_put(d);
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rfcomm_sock_cleanup_listen(struct sock *parent)
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sock *sk;
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("parent %p", parent);
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Close not yet accepted dlcs */
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while ((sk = bt_accept_dequeue(parent, NULL))) {
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rfcomm_sock_close(sk);
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rfcomm_sock_kill(sk);
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	parent->sk_state  = BT_CLOSED;
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sock_set_flag(parent, SOCK_ZAPPED);
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Kill socket (only if zapped and orphan)
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Must be called on unlocked socket.
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rfcomm_sock_kill(struct sock *sk)
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket)
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("sk %p state %d refcnt %d", sk, sk->sk_state, atomic_read(&sk->sk_refcnt));
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Kill poor orphan */
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bt_sock_unlink(&rfcomm_sk_list, sk);
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sock_set_flag(sk, SOCK_DEAD);
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sock_put(sk);
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __rfcomm_sock_close(struct sock *sk)
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket);
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (sk->sk_state) {
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case BT_LISTEN:
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rfcomm_sock_cleanup_listen(sk);
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case BT_CONNECT:
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case BT_CONNECT2:
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case BT_CONFIG:
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case BT_CONNECTED:
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rfcomm_dlc_close(d, 0);
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sock_set_flag(sk, SOCK_ZAPPED);
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Close socket.
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Must be called on unlocked socket.
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rfcomm_sock_close(struct sock *sk)
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lock_sock(sk);
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__rfcomm_sock_close(sk);
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_sock(sk);
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rfcomm_sock_init(struct sock *sk, struct sock *parent)
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rfcomm_pinfo *pi = rfcomm_pi(sk);
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("sk %p", sk);
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (parent) {
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sk->sk_type = parent->sk_type;
242c5daa683f2d3315cd766f550ef7d88bfca1671f4Gustavo Padovan		pi->dlc->defer_setup = test_bit(BT_SK_DEFER_SETUP,
243c5daa683f2d3315cd766f550ef7d88bfca1671f4Gustavo Padovan						&bt_sk(parent)->flags);
2449f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann
2459f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann		pi->sec_level = rfcomm_pi(parent)->sec_level;
2469f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann		pi->role_switch = rfcomm_pi(parent)->role_switch;
2476230c9b4f8957c8938ee4cf2d03166d3c2dc89dePaul Moore
2486230c9b4f8957c8938ee4cf2d03166d3c2dc89dePaul Moore		security_sk_clone(parent, sk);
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
250bb23c0ab824653be4aa7dfca15b07b3059717004Marcel Holtmann		pi->dlc->defer_setup = 0;
2519f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann
2529f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann		pi->sec_level = BT_SECURITY_LOW;
2539f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann		pi->role_switch = 0;
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2569f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann	pi->dlc->sec_level = pi->sec_level;
2579f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann	pi->dlc->role_switch = pi->role_switch;
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct proto rfcomm_proto = {
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name		= "RFCOMM",
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner		= THIS_MODULE,
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.obj_size	= sizeof(struct rfcomm_pinfo)
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2661b8d7ae42d02e483ad94035cca851e4f7fbecb40Eric W. Biedermanstatic struct sock *rfcomm_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio)
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rfcomm_dlc *d;
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sock *sk;
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2716257ff2177ff02d7f260a7a501876aa41cb9a9f6Pavel Emelyanov	sk = sk_alloc(net, PF_BLUETOOTH, prio, &rfcomm_proto);
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!sk)
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sock_init_data(sock, sk);
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	d = rfcomm_dlc_alloc(prio);
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!d) {
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sk_free(sk);
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	d->data_ready   = rfcomm_sk_data_ready;
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	d->state_change = rfcomm_sk_state_change;
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rfcomm_pi(sk)->dlc = d;
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	d->owner = sk;
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sk->sk_destruct = rfcomm_sock_destruct;
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sk->sk_sndtimeo = RFCOMM_CONN_TIMEOUT;
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29377db1980565626471a980f0d2d17299e4bd5e7a5Marcel Holtmann	sk->sk_sndbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
29477db1980565626471a980f0d2d17299e4bd5e7a5Marcel Holtmann	sk->sk_rcvbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sock_reset_flag(sk, SOCK_ZAPPED);
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sk->sk_protocol = proto;
29977db1980565626471a980f0d2d17299e4bd5e7a5Marcel Holtmann	sk->sk_state    = BT_OPEN;
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bt_sock_link(&rfcomm_sk_list, sk);
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("sk %p", sk);
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sk;
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3073f378b684453f2a028eda463ce383370545d9cc9Eric Parisstatic int rfcomm_sock_create(struct net *net, struct socket *sock,
3083f378b684453f2a028eda463ce383370545d9cc9Eric Paris			      int protocol, int kern)
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sock *sk;
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("sock %p", sock);
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sock->state = SS_UNCONNECTED;
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sock->type != SOCK_STREAM && sock->type != SOCK_RAW)
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ESOCKTNOSUPPORT;
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sock->ops = &rfcomm_sock_ops;
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3211b8d7ae42d02e483ad94035cca851e4f7fbecb40Eric W. Biederman	sk = rfcomm_sock_alloc(net, sock, protocol, GFP_ATOMIC);
32274da626a1098640ddc40c0e3481c0cd41e8ec1e9Marcel Holtmann	if (!sk)
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rfcomm_sock_init(sk, NULL);
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rfcomm_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sockaddr_rc *sa = (struct sockaddr_rc *) addr;
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sock *sk = sock->sk;
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0;
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3356ed93dc6427d14cdfe0b272cc0a9ee4685ce9ad7Andrei Emeltchenko	BT_DBG("sk %p %pMR", sk, &sa->rc_bdaddr);
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!addr || addr->sa_family != AF_BLUETOOTH)
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lock_sock(sk);
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sk->sk_state != BT_OPEN) {
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -EBADFD;
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto done;
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
347354d28d5f8546e115ebaae9311897f0bc4b6a8d4Marcel Holtmann	if (sk->sk_type != SOCK_STREAM) {
348354d28d5f8546e115ebaae9311897f0bc4b6a8d4Marcel Holtmann		err = -EINVAL;
349354d28d5f8546e115ebaae9311897f0bc4b6a8d4Marcel Holtmann		goto done;
350354d28d5f8546e115ebaae9311897f0bc4b6a8d4Marcel Holtmann	}
351354d28d5f8546e115ebaae9311897f0bc4b6a8d4Marcel Holtmann
35295ca83f42fb5f5bf789b514635f79242afe555d1Gustavo Padovan	write_lock(&rfcomm_sk_list.lock);
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sa->rc_channel && __rfcomm_get_sock_by_addr(sa->rc_channel, &sa->rc_bdaddr)) {
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -EADDRINUSE;
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Save source address */
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bacpy(&bt_sk(sk)->src, &sa->rc_bdaddr);
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rfcomm_pi(sk)->channel = sa->rc_channel;
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sk->sk_state = BT_BOUND;
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36395ca83f42fb5f5bf789b514635f79242afe555d1Gustavo Padovan	write_unlock(&rfcomm_sk_list.lock);
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdone:
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_sock(sk);
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sockaddr_rc *sa = (struct sockaddr_rc *) addr;
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sock *sk = sock->sk;
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0;
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("sk %p", sk);
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3796503d96168f891ffa3b70ae6c9698a1a722025a0Changli Gao	if (alen < sizeof(struct sockaddr_rc) ||
3806503d96168f891ffa3b70ae6c9698a1a722025a0Changli Gao	    addr->sa_family != AF_BLUETOOTH)
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
383354d28d5f8546e115ebaae9311897f0bc4b6a8d4Marcel Holtmann	lock_sock(sk);
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
385354d28d5f8546e115ebaae9311897f0bc4b6a8d4Marcel Holtmann	if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) {
386354d28d5f8546e115ebaae9311897f0bc4b6a8d4Marcel Holtmann		err = -EBADFD;
387354d28d5f8546e115ebaae9311897f0bc4b6a8d4Marcel Holtmann		goto done;
388354d28d5f8546e115ebaae9311897f0bc4b6a8d4Marcel Holtmann	}
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
390354d28d5f8546e115ebaae9311897f0bc4b6a8d4Marcel Holtmann	if (sk->sk_type != SOCK_STREAM) {
391354d28d5f8546e115ebaae9311897f0bc4b6a8d4Marcel Holtmann		err = -EINVAL;
392354d28d5f8546e115ebaae9311897f0bc4b6a8d4Marcel Holtmann		goto done;
393354d28d5f8546e115ebaae9311897f0bc4b6a8d4Marcel Holtmann	}
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sk->sk_state = BT_CONNECT;
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bacpy(&bt_sk(sk)->dst, &sa->rc_bdaddr);
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rfcomm_pi(sk)->channel = sa->rc_channel;
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3999f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann	d->sec_level = rfcomm_pi(sk)->sec_level;
4009f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann	d->role_switch = rfcomm_pi(sk)->role_switch;
40177db1980565626471a980f0d2d17299e4bd5e7a5Marcel Holtmann
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = rfcomm_dlc_open(d, &bt_sk(sk)->src, &sa->rc_bdaddr, sa->rc_channel);
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!err)
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = bt_sock_wait_state(sk, BT_CONNECTED,
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				sock_sndtimeo(sk, flags & O_NONBLOCK));
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
407354d28d5f8546e115ebaae9311897f0bc4b6a8d4Marcel Holtmanndone:
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_sock(sk);
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rfcomm_sock_listen(struct socket *sock, int backlog)
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sock *sk = sock->sk;
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0;
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("sk %p backlog %d", sk, backlog);
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lock_sock(sk);
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sk->sk_state != BT_BOUND) {
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -EBADFD;
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto done;
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
426354d28d5f8546e115ebaae9311897f0bc4b6a8d4Marcel Holtmann	if (sk->sk_type != SOCK_STREAM) {
427354d28d5f8546e115ebaae9311897f0bc4b6a8d4Marcel Holtmann		err = -EINVAL;
428354d28d5f8546e115ebaae9311897f0bc4b6a8d4Marcel Holtmann		goto done;
429354d28d5f8546e115ebaae9311897f0bc4b6a8d4Marcel Holtmann	}
430354d28d5f8546e115ebaae9311897f0bc4b6a8d4Marcel Holtmann
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!rfcomm_pi(sk)->channel) {
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bdaddr_t *src = &bt_sk(sk)->src;
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u8 channel;
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -EINVAL;
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43795ca83f42fb5f5bf789b514635f79242afe555d1Gustavo Padovan		write_lock(&rfcomm_sk_list.lock);
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (channel = 1; channel < 31; channel++)
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!__rfcomm_get_sock_by_addr(channel, src)) {
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rfcomm_pi(sk)->channel = channel;
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				err = 0;
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44695ca83f42fb5f5bf789b514635f79242afe555d1Gustavo Padovan		write_unlock(&rfcomm_sk_list.lock);
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (err < 0)
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sk->sk_max_ack_backlog = backlog;
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sk->sk_ack_backlog = 0;
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sk->sk_state = BT_LISTEN;
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdone:
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_sock(sk);
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int flags)
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DECLARE_WAITQUEUE(wait, current);
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sock *sk = sock->sk, *nsk;
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	long timeo;
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0;
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
468dc2a0e20fbc85a71c63aa4330b496fda33f6bf80Gustavo Padovan	lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
470354d28d5f8546e115ebaae9311897f0bc4b6a8d4Marcel Holtmann	if (sk->sk_type != SOCK_STREAM) {
471354d28d5f8546e115ebaae9311897f0bc4b6a8d4Marcel Holtmann		err = -EINVAL;
472354d28d5f8546e115ebaae9311897f0bc4b6a8d4Marcel Holtmann		goto done;
473354d28d5f8546e115ebaae9311897f0bc4b6a8d4Marcel Holtmann	}
474354d28d5f8546e115ebaae9311897f0bc4b6a8d4Marcel Holtmann
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("sk %p timeo %ld", sk, timeo);
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Wait for an incoming connection. (wake-one). */
480aa395145165cb06a0d0885221bbe0ce4a564391dEric Dumazet	add_wait_queue_exclusive(sk_sleep(sk), &wait);
481950e2d51e866623e4c360280aa63b85ab66d3403Peter Hurley	while (1) {
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_current_state(TASK_INTERRUPTIBLE);
483950e2d51e866623e4c360280aa63b85ab66d3403Peter Hurley
484950e2d51e866623e4c360280aa63b85ab66d3403Peter Hurley		if (sk->sk_state != BT_LISTEN) {
485950e2d51e866623e4c360280aa63b85ab66d3403Peter Hurley			err = -EBADFD;
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
489950e2d51e866623e4c360280aa63b85ab66d3403Peter Hurley		nsk = bt_accept_dequeue(sk, newsock);
490950e2d51e866623e4c360280aa63b85ab66d3403Peter Hurley		if (nsk)
491950e2d51e866623e4c360280aa63b85ab66d3403Peter Hurley			break;
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
493950e2d51e866623e4c360280aa63b85ab66d3403Peter Hurley		if (!timeo) {
494950e2d51e866623e4c360280aa63b85ab66d3403Peter Hurley			err = -EAGAIN;
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (signal_pending(current)) {
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = sock_intr_errno(timeo);
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
502950e2d51e866623e4c360280aa63b85ab66d3403Peter Hurley
503950e2d51e866623e4c360280aa63b85ab66d3403Peter Hurley		release_sock(sk);
504950e2d51e866623e4c360280aa63b85ab66d3403Peter Hurley		timeo = schedule_timeout(timeo);
505dc2a0e20fbc85a71c63aa4330b496fda33f6bf80Gustavo Padovan		lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
507950e2d51e866623e4c360280aa63b85ab66d3403Peter Hurley	__set_current_state(TASK_RUNNING);
508aa395145165cb06a0d0885221bbe0ce4a564391dEric Dumazet	remove_wait_queue(sk_sleep(sk), &wait);
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err)
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto done;
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	newsock->state = SS_CONNECTED;
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("new socket %p", nsk);
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdone:
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_sock(sk);
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rfcomm_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sockaddr_rc *sa = (struct sockaddr_rc *) addr;
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sock *sk = sock->sk;
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("sock %p, sk %p", sock, sk);
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5299344a972961d1a6d2c04d9008b13617bcb6ec2efMathias Krause	memset(sa, 0, sizeof(*sa));
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sa->rc_family  = AF_BLUETOOTH;
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sa->rc_channel = rfcomm_pi(sk)->channel;
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (peer)
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bacpy(&sa->rc_bdaddr, &bt_sk(sk)->dst);
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bacpy(&sa->rc_bdaddr, &bt_sk(sk)->src);
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*len = sizeof(struct sockaddr_rc);
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rfcomm_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       struct msghdr *msg, size_t len)
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sock *sk = sock->sk;
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int sent = 0;
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
549bb23c0ab824653be4aa7dfca15b07b3059717004Marcel Holtmann	if (test_bit(RFCOMM_DEFER_SETUP, &d->flags))
550bb23c0ab824653be4aa7dfca15b07b3059717004Marcel Holtmann		return -ENOTCONN;
551bb23c0ab824653be4aa7dfca15b07b3059717004Marcel Holtmann
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (msg->msg_flags & MSG_OOB)
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EOPNOTSUPP;
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sk->sk_shutdown & SEND_SHUTDOWN)
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EPIPE;
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("sock %p, sk %p", sock, sk);
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lock_sock(sk);
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (len) {
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size_t size = min_t(size_t, len, d->mtu);
5644d6a2188bd456969f52c03edf1988de90f08d9f5Marcel Holtmann		int err;
5658e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		skb = sock_alloc_send_skb(sk, size + RFCOMM_SKB_RESERVE,
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				msg->msg_flags & MSG_DONTWAIT, &err);
56891aa35a5aa3540223066bf6b51c935418c63a35dVictor Shcherbatyuk		if (!skb) {
56991aa35a5aa3540223066bf6b51c935418c63a35dVictor Shcherbatyuk			if (sent == 0)
57091aa35a5aa3540223066bf6b51c935418c63a35dVictor Shcherbatyuk				sent = err;
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
57291aa35a5aa3540223066bf6b51c935418c63a35dVictor Shcherbatyuk		}
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE);
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (err) {
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree_skb(skb);
5784d6a2188bd456969f52c03edf1988de90f08d9f5Marcel Holtmann			if (sent == 0)
5794d6a2188bd456969f52c03edf1988de90f08d9f5Marcel Holtmann				sent = err;
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
583262038fcb2a50e9b5553243452918fda08cdf83dLuiz Augusto von Dentz		skb->priority = sk->sk_priority;
584262038fcb2a50e9b5553243452918fda08cdf83dLuiz Augusto von Dentz
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = rfcomm_dlc_send(d, skb);
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (err < 0) {
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree_skb(skb);
5884d6a2188bd456969f52c03edf1988de90f08d9f5Marcel Holtmann			if (sent == 0)
5894d6a2188bd456969f52c03edf1988de90f08d9f5Marcel Holtmann				sent = err;
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sent += size;
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len  -= size;
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_sock(sk);
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5994d6a2188bd456969f52c03edf1988de90f08d9f5Marcel Holtmann	return sent;
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rfcomm_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       struct msghdr *msg, size_t size, int flags)
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sock *sk = sock->sk;
606bb23c0ab824653be4aa7dfca15b07b3059717004Marcel Holtmann	struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
6073d7d01dffec4a6757ed1e3182f01c7ef5caa2539Mat Martineau	int len;
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
609bb23c0ab824653be4aa7dfca15b07b3059717004Marcel Holtmann	if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
610bb23c0ab824653be4aa7dfca15b07b3059717004Marcel Holtmann		rfcomm_dlc_accept(d);
611e11e0455c0d7d3d62276a0c55d9dfbc16779d691Mathias Krause		msg->msg_namelen = 0;
612bb23c0ab824653be4aa7dfca15b07b3059717004Marcel Holtmann		return 0;
613bb23c0ab824653be4aa7dfca15b07b3059717004Marcel Holtmann	}
614bb23c0ab824653be4aa7dfca15b07b3059717004Marcel Holtmann
6153d7d01dffec4a6757ed1e3182f01c7ef5caa2539Mat Martineau	len = bt_sock_stream_recvmsg(iocb, sock, msg, size, flags);
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lock_sock(sk);
6183d7d01dffec4a6757ed1e3182f01c7ef5caa2539Mat Martineau	if (!(flags & MSG_PEEK) && len > 0)
6193d7d01dffec4a6757ed1e3182f01c7ef5caa2539Mat Martineau		atomic_sub(len, &sk->sk_rmem_alloc);
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (atomic_read(&sk->sk_rmem_alloc) <= (sk->sk_rcvbuf >> 2))
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rfcomm_dlc_unthrottle(rfcomm_pi(sk)->dlc);
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_sock(sk);
6243d7d01dffec4a6757ed1e3182f01c7ef5caa2539Mat Martineau
6253d7d01dffec4a6757ed1e3182f01c7ef5caa2539Mat Martineau	return len;
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
628b7058842c940ad2c08dd829b21e5c92ebe3b8758David S. Millerstatic int rfcomm_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, unsigned int optlen)
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sock *sk = sock->sk;
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0;
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 opt;
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("sk %p", sk);
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lock_sock(sk);
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (optname) {
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case RFCOMM_LM:
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (get_user(opt, (u32 __user *) optval)) {
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = -EFAULT;
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6459f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann		if (opt & RFCOMM_LM_AUTH)
6469f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann			rfcomm_pi(sk)->sec_level = BT_SECURITY_LOW;
6479f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann		if (opt & RFCOMM_LM_ENCRYPT)
6489f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann			rfcomm_pi(sk)->sec_level = BT_SECURITY_MEDIUM;
6499f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann		if (opt & RFCOMM_LM_SECURE)
6509f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann			rfcomm_pi(sk)->sec_level = BT_SECURITY_HIGH;
6519f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann
6529f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann		rfcomm_pi(sk)->role_switch = (opt & RFCOMM_LM_MASTER);
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -ENOPROTOOPT;
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_sock(sk);
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
664b7058842c940ad2c08dd829b21e5c92ebe3b8758David S. Millerstatic int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen)
665d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann{
666d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann	struct sock *sk = sock->sk;
6679f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann	struct bt_security sec;
668d0fad89da9801b3945d2ee7243ecbc75b3da6f09Stephen Boyd	int err = 0;
669d0fad89da9801b3945d2ee7243ecbc75b3da6f09Stephen Boyd	size_t len;
670bb23c0ab824653be4aa7dfca15b07b3059717004Marcel Holtmann	u32 opt;
671d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann
672d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann	BT_DBG("sk %p", sk);
673d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann
674d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann	if (level == SOL_RFCOMM)
675d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann		return rfcomm_sock_setsockopt_old(sock, optname, optval, optlen);
676d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann
6770588d94fd7e414367a7ae517569d2222441c255fMarcel Holtmann	if (level != SOL_BLUETOOTH)
6780588d94fd7e414367a7ae517569d2222441c255fMarcel Holtmann		return -ENOPROTOOPT;
6790588d94fd7e414367a7ae517569d2222441c255fMarcel Holtmann
680d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann	lock_sock(sk);
681d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann
682d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann	switch (optname) {
6839f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann	case BT_SECURITY:
6840588d94fd7e414367a7ae517569d2222441c255fMarcel Holtmann		if (sk->sk_type != SOCK_STREAM) {
6850588d94fd7e414367a7ae517569d2222441c255fMarcel Holtmann			err = -EINVAL;
6860588d94fd7e414367a7ae517569d2222441c255fMarcel Holtmann			break;
6870588d94fd7e414367a7ae517569d2222441c255fMarcel Holtmann		}
6880588d94fd7e414367a7ae517569d2222441c255fMarcel Holtmann
6899f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann		sec.level = BT_SECURITY_LOW;
6909f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann
6919f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann		len = min_t(unsigned int, sizeof(sec), optlen);
6929f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann		if (copy_from_user((char *) &sec, optval, len)) {
6939f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann			err = -EFAULT;
6949f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann			break;
6959f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann		}
6969f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann
6979f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann		if (sec.level > BT_SECURITY_HIGH) {
6989f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann			err = -EINVAL;
6999f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann			break;
7009f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann		}
7019f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann
7029f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann		rfcomm_pi(sk)->sec_level = sec.level;
7039f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann		break;
7049f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann
705bb23c0ab824653be4aa7dfca15b07b3059717004Marcel Holtmann	case BT_DEFER_SETUP:
706bb23c0ab824653be4aa7dfca15b07b3059717004Marcel Holtmann		if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
707bb23c0ab824653be4aa7dfca15b07b3059717004Marcel Holtmann			err = -EINVAL;
708bb23c0ab824653be4aa7dfca15b07b3059717004Marcel Holtmann			break;
709bb23c0ab824653be4aa7dfca15b07b3059717004Marcel Holtmann		}
710bb23c0ab824653be4aa7dfca15b07b3059717004Marcel Holtmann
711bb23c0ab824653be4aa7dfca15b07b3059717004Marcel Holtmann		if (get_user(opt, (u32 __user *) optval)) {
712bb23c0ab824653be4aa7dfca15b07b3059717004Marcel Holtmann			err = -EFAULT;
713bb23c0ab824653be4aa7dfca15b07b3059717004Marcel Holtmann			break;
714bb23c0ab824653be4aa7dfca15b07b3059717004Marcel Holtmann		}
715bb23c0ab824653be4aa7dfca15b07b3059717004Marcel Holtmann
716c5daa683f2d3315cd766f550ef7d88bfca1671f4Gustavo Padovan		if (opt)
717c5daa683f2d3315cd766f550ef7d88bfca1671f4Gustavo Padovan			set_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags);
718c5daa683f2d3315cd766f550ef7d88bfca1671f4Gustavo Padovan		else
719c5daa683f2d3315cd766f550ef7d88bfca1671f4Gustavo Padovan			clear_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags);
720c5daa683f2d3315cd766f550ef7d88bfca1671f4Gustavo Padovan
721bb23c0ab824653be4aa7dfca15b07b3059717004Marcel Holtmann		break;
722bb23c0ab824653be4aa7dfca15b07b3059717004Marcel Holtmann
723d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann	default:
724d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann		err = -ENOPROTOOPT;
725d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann		break;
726d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann	}
727d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann
728d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann	release_sock(sk);
729d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann	return err;
730d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann}
731d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann
732d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmannstatic int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen)
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sock *sk = sock->sk;
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rfcomm_conninfo cinfo;
7368c1d787be4b62d2d1b6f04953eca4bcf7c839d44Gustavo Padovan	struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int len, err = 0;
7389f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann	u32 opt;
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("sk %p", sk);
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (get_user(len, optlen))
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lock_sock(sk);
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (optname) {
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case RFCOMM_LM:
7499f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann		switch (rfcomm_pi(sk)->sec_level) {
7509f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann		case BT_SECURITY_LOW:
7519f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann			opt = RFCOMM_LM_AUTH;
7529f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann			break;
7539f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann		case BT_SECURITY_MEDIUM:
7549f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann			opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT;
7559f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann			break;
7569f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann		case BT_SECURITY_HIGH:
7579f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann			opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT |
7589f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann							RFCOMM_LM_SECURE;
7599f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann			break;
7609f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann		default:
7619f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann			opt = 0;
7629f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann			break;
7639f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann		}
7649f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann
7659f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann		if (rfcomm_pi(sk)->role_switch)
7669f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann			opt |= RFCOMM_LM_MASTER;
7679f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann
7689f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann		if (put_user(opt, (u32 __user *) optval))
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = -EFAULT;
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case RFCOMM_CONNINFO:
773bb23c0ab824653be4aa7dfca15b07b3059717004Marcel Holtmann		if (sk->sk_state != BT_CONNECTED &&
774bb23c0ab824653be4aa7dfca15b07b3059717004Marcel Holtmann					!rfcomm_pi(sk)->dlc->defer_setup) {
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = -ENOTCONN;
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7798d03e971cf403305217b8e62db3a2e5ad2d6263fFilip Palian		memset(&cinfo, 0, sizeof(cinfo));
7808c1d787be4b62d2d1b6f04953eca4bcf7c839d44Gustavo Padovan		cinfo.hci_handle = conn->hcon->handle;
7818c1d787be4b62d2d1b6f04953eca4bcf7c839d44Gustavo Padovan		memcpy(cinfo.dev_class, conn->hcon->dev_class, 3);
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len = min_t(unsigned int, len, sizeof(cinfo));
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy_to_user(optval, (char *) &cinfo, len))
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = -EFAULT;
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -ENOPROTOOPT;
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_sock(sk);
795d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann	return err;
796d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann}
797d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann
798d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmannstatic int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
799d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann{
800d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann	struct sock *sk = sock->sk;
8019f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann	struct bt_security sec;
802d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann	int len, err = 0;
803d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann
804d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann	BT_DBG("sk %p", sk);
805d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann
806d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann	if (level == SOL_RFCOMM)
807d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann		return rfcomm_sock_getsockopt_old(sock, optname, optval, optlen);
808d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann
8090588d94fd7e414367a7ae517569d2222441c255fMarcel Holtmann	if (level != SOL_BLUETOOTH)
8100588d94fd7e414367a7ae517569d2222441c255fMarcel Holtmann		return -ENOPROTOOPT;
8110588d94fd7e414367a7ae517569d2222441c255fMarcel Holtmann
812d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann	if (get_user(len, optlen))
813d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann		return -EFAULT;
814d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann
815d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann	lock_sock(sk);
816d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann
817d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann	switch (optname) {
8189f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann	case BT_SECURITY:
8190588d94fd7e414367a7ae517569d2222441c255fMarcel Holtmann		if (sk->sk_type != SOCK_STREAM) {
8200588d94fd7e414367a7ae517569d2222441c255fMarcel Holtmann			err = -EINVAL;
8210588d94fd7e414367a7ae517569d2222441c255fMarcel Holtmann			break;
8220588d94fd7e414367a7ae517569d2222441c255fMarcel Holtmann		}
8230588d94fd7e414367a7ae517569d2222441c255fMarcel Holtmann
8249f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann		sec.level = rfcomm_pi(sk)->sec_level;
8259ad2de43f1aee7e7274a4e0d41465489299e344bMathias Krause		sec.key_size = 0;
8269f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann
8279f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann		len = min_t(unsigned int, len, sizeof(sec));
8289f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann		if (copy_to_user(optval, (char *) &sec, len))
8299f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann			err = -EFAULT;
8309f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann
8319f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann		break;
8329f2c8a03fbb3048cf38b158f87aa0c3c09bca084Marcel Holtmann
833bb23c0ab824653be4aa7dfca15b07b3059717004Marcel Holtmann	case BT_DEFER_SETUP:
834bb23c0ab824653be4aa7dfca15b07b3059717004Marcel Holtmann		if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
835bb23c0ab824653be4aa7dfca15b07b3059717004Marcel Holtmann			err = -EINVAL;
836bb23c0ab824653be4aa7dfca15b07b3059717004Marcel Holtmann			break;
837bb23c0ab824653be4aa7dfca15b07b3059717004Marcel Holtmann		}
838bb23c0ab824653be4aa7dfca15b07b3059717004Marcel Holtmann
839c5daa683f2d3315cd766f550ef7d88bfca1671f4Gustavo Padovan		if (put_user(test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags),
840c5daa683f2d3315cd766f550ef7d88bfca1671f4Gustavo Padovan			     (u32 __user *) optval))
841bb23c0ab824653be4aa7dfca15b07b3059717004Marcel Holtmann			err = -EFAULT;
842bb23c0ab824653be4aa7dfca15b07b3059717004Marcel Holtmann
843bb23c0ab824653be4aa7dfca15b07b3059717004Marcel Holtmann		break;
844bb23c0ab824653be4aa7dfca15b07b3059717004Marcel Holtmann
845d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann	default:
846d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann		err = -ENOPROTOOPT;
847d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann		break;
848d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann	}
849d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann
850d58daf42d29a3a4a4d4be46cf47ceee096789680Marcel Holtmann	release_sock(sk);
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rfcomm_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
856e19caae7177fcc732ae1b47135e39f577352adb2David S. Miller	struct sock *sk __maybe_unused = sock->sk;
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
859e19caae7177fcc732ae1b47135e39f577352adb2David S. Miller	BT_DBG("sk %p cmd %x arg %lx", sk, cmd, arg);
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8613241ad820dbb172021e0268b5611031991431626Marcel Holtmann	err = bt_sock_ioctl(sock, cmd, arg);
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8633241ad820dbb172021e0268b5611031991431626Marcel Holtmann	if (err == -ENOIOCTLCMD) {
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_BT_RFCOMM_TTY
8653241ad820dbb172021e0268b5611031991431626Marcel Holtmann		lock_sock(sk);
8663241ad820dbb172021e0268b5611031991431626Marcel Holtmann		err = rfcomm_dev_ioctl(sk, cmd, (void __user *) arg);
8673241ad820dbb172021e0268b5611031991431626Marcel Holtmann		release_sock(sk);
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
8693241ad820dbb172021e0268b5611031991431626Marcel Holtmann		err = -EOPNOTSUPP;
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
8713241ad820dbb172021e0268b5611031991431626Marcel Holtmann	}
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rfcomm_sock_shutdown(struct socket *sock, int how)
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sock *sk = sock->sk;
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0;
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("sock %p, sk %p", sock, sk);
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
883285b4e90318dcf421a00b2ac3fe8ab713f3281e3Andrei Emeltchenko	if (!sk)
884285b4e90318dcf421a00b2ac3fe8ab713f3281e3Andrei Emeltchenko		return 0;
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lock_sock(sk);
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!sk->sk_shutdown) {
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sk->sk_shutdown = SHUTDOWN_MASK;
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__rfcomm_sock_close(sk);
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime)
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime);
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_sock(sk);
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rfcomm_sock_release(struct socket *sock)
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sock *sk = sock->sk;
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("sock %p, sk %p", sock, sk);
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!sk)
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = rfcomm_sock_shutdown(sock, 2);
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sock_orphan(sk);
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rfcomm_sock_kill(sk);
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9158e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki/* ---- RFCOMM core layer callbacks ----
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * called under rfcomm_lock()
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc **d)
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sock *sk, *parent;
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bdaddr_t src, dst;
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result = 0;
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("session %p channel %d", s, channel);
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rfcomm_session_getaddr(s, &src, &dst);
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Check if we have socket listening on channel */
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	parent = rfcomm_get_sock_by_channel(BT_LISTEN, channel, &src);
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!parent)
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
934eeb366564be7c311b31c70821d18a43a8a57f9bcGustavo Padovan	bh_lock_sock(parent);
935eeb366564be7c311b31c70821d18a43a8a57f9bcGustavo Padovan
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Check for backlog size */
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sk_acceptq_is_full(parent)) {
9388e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki		BT_DBG("backlog full %d", parent->sk_ack_backlog);
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto done;
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9423b1e0a655f8eba44ab1ee2a1068d169ccfb853b9YOSHIFUJI Hideaki	sk = rfcomm_sock_alloc(sock_net(parent), NULL, BTPROTO_RFCOMM, GFP_ATOMIC);
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!sk)
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto done;
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
946b5a30dda6598af216c070165ece6068f9f00f33aOctavian Purdila	bt_sock_reclassify_lock(sk, BTPROTO_RFCOMM);
947b5a30dda6598af216c070165ece6068f9f00f33aOctavian Purdila
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rfcomm_sock_init(sk, parent);
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bacpy(&bt_sk(sk)->src, &src);
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bacpy(&bt_sk(sk)->dst, &dst);
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rfcomm_pi(sk)->channel = channel;
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sk->sk_state = BT_CONFIG;
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bt_accept_enqueue(parent, sk);
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Accept connection and return socket DLC */
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*d = rfcomm_pi(sk)->dlc;
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = 1;
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdone:
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bh_unlock_sock(parent);
962bb23c0ab824653be4aa7dfca15b07b3059717004Marcel Holtmann
963c5daa683f2d3315cd766f550ef7d88bfca1671f4Gustavo Padovan	if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags))
964bb23c0ab824653be4aa7dfca15b07b3059717004Marcel Holtmann		parent->sk_state_change(parent);
965bb23c0ab824653be4aa7dfca15b07b3059717004Marcel Holtmann
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return result;
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
969aef7d97cc604309b66f6f45cce02cd734934cd4eMarcel Holtmannstatic int rfcomm_sock_debugfs_show(struct seq_file *f, void *p)
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sock *sk;
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
97395ca83f42fb5f5bf789b514635f79242afe555d1Gustavo Padovan	read_lock(&rfcomm_sk_list.lock);
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
975b67bfe0d42cac56c512dd5da4b1b347a23f4b70aSasha Levin	sk_for_each(sk, &rfcomm_sk_list.head) {
976fcb73338ed531dcc00cb17ca76fe3e05f774e4e9Andrei Emeltchenko		seq_printf(f, "%pMR %pMR %d %d\n",
977fcb73338ed531dcc00cb17ca76fe3e05f774e4e9Andrei Emeltchenko			   &bt_sk(sk)->src, &bt_sk(sk)->dst,
978fcb73338ed531dcc00cb17ca76fe3e05f774e4e9Andrei Emeltchenko			   sk->sk_state, rfcomm_pi(sk)->channel);
979be9d122730c878baafe11e70d1436faac229f2fcMarcel Holtmann	}
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
98195ca83f42fb5f5bf789b514635f79242afe555d1Gustavo Padovan	read_unlock(&rfcomm_sk_list.lock);
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
983aef7d97cc604309b66f6f45cce02cd734934cd4eMarcel Holtmann	return 0;
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
986aef7d97cc604309b66f6f45cce02cd734934cd4eMarcel Holtmannstatic int rfcomm_sock_debugfs_open(struct inode *inode, struct file *file)
987aef7d97cc604309b66f6f45cce02cd734934cd4eMarcel Holtmann{
988aef7d97cc604309b66f6f45cce02cd734934cd4eMarcel Holtmann	return single_open(file, rfcomm_sock_debugfs_show, inode->i_private);
989aef7d97cc604309b66f6f45cce02cd734934cd4eMarcel Holtmann}
990aef7d97cc604309b66f6f45cce02cd734934cd4eMarcel Holtmann
991aef7d97cc604309b66f6f45cce02cd734934cd4eMarcel Holtmannstatic const struct file_operations rfcomm_sock_debugfs_fops = {
992aef7d97cc604309b66f6f45cce02cd734934cd4eMarcel Holtmann	.open		= rfcomm_sock_debugfs_open,
993aef7d97cc604309b66f6f45cce02cd734934cd4eMarcel Holtmann	.read		= seq_read,
994aef7d97cc604309b66f6f45cce02cd734934cd4eMarcel Holtmann	.llseek		= seq_lseek,
995aef7d97cc604309b66f6f45cce02cd734934cd4eMarcel Holtmann	.release	= single_release,
996aef7d97cc604309b66f6f45cce02cd734934cd4eMarcel Holtmann};
997aef7d97cc604309b66f6f45cce02cd734934cd4eMarcel Holtmann
998aef7d97cc604309b66f6f45cce02cd734934cd4eMarcel Holtmannstatic struct dentry *rfcomm_sock_debugfs;
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
100090ddc4f0470427df306f308ad03db6b6b21644b8Eric Dumazetstatic const struct proto_ops rfcomm_sock_ops = {
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.family		= PF_BLUETOOTH,
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner		= THIS_MODULE,
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.release	= rfcomm_sock_release,
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.bind		= rfcomm_sock_bind,
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.connect	= rfcomm_sock_connect,
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.listen		= rfcomm_sock_listen,
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.accept		= rfcomm_sock_accept,
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.getname	= rfcomm_sock_getname,
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.sendmsg	= rfcomm_sock_sendmsg,
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.recvmsg	= rfcomm_sock_recvmsg,
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.shutdown	= rfcomm_sock_shutdown,
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.setsockopt	= rfcomm_sock_setsockopt,
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.getsockopt	= rfcomm_sock_getsockopt,
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.ioctl		= rfcomm_sock_ioctl,
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.poll		= bt_sock_poll,
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.socketpair	= sock_no_socketpair,
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.mmap		= sock_no_mmap
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1020ec1b4cf74c81bfd0fbe5bf62bafc86c45917e72fStephen Hemmingerstatic const struct net_proto_family rfcomm_sock_family_ops = {
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.family		= PF_BLUETOOTH,
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner		= THIS_MODULE,
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.create		= rfcomm_sock_create
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1026be9d122730c878baafe11e70d1436faac229f2fcMarcel Holtmannint __init rfcomm_init_sockets(void)
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = proto_register(&rfcomm_proto, 0);
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err < 0)
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return err;
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = bt_sock_register(BTPROTO_RFCOMM, &rfcomm_sock_family_ops);
1035c6f5df16a2710e64090078dfbaa86c54a27c0874Masatake YAMATO	if (err < 0) {
1036c6f5df16a2710e64090078dfbaa86c54a27c0874Masatake YAMATO		BT_ERR("RFCOMM socket layer registration failed");
1037c6f5df16a2710e64090078dfbaa86c54a27c0874Masatake YAMATO		goto error;
1038c6f5df16a2710e64090078dfbaa86c54a27c0874Masatake YAMATO	}
1039c6f5df16a2710e64090078dfbaa86c54a27c0874Masatake YAMATO
1040b03166152f6da91cec8b66837b309dd3923ea536Al Viro	err = bt_procfs_init(&init_net, "rfcomm", &rfcomm_sk_list, NULL);
1041c6f5df16a2710e64090078dfbaa86c54a27c0874Masatake YAMATO	if (err < 0) {
1042c6f5df16a2710e64090078dfbaa86c54a27c0874Masatake YAMATO		BT_ERR("Failed to create RFCOMM proc file");
1043c6f5df16a2710e64090078dfbaa86c54a27c0874Masatake YAMATO		bt_sock_unregister(BTPROTO_RFCOMM);
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto error;
1045c6f5df16a2710e64090078dfbaa86c54a27c0874Masatake YAMATO	}
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1047aef7d97cc604309b66f6f45cce02cd734934cd4eMarcel Holtmann	if (bt_debugfs) {
1048aef7d97cc604309b66f6f45cce02cd734934cd4eMarcel Holtmann		rfcomm_sock_debugfs = debugfs_create_file("rfcomm", 0444,
1049aef7d97cc604309b66f6f45cce02cd734934cd4eMarcel Holtmann				bt_debugfs, NULL, &rfcomm_sock_debugfs_fops);
1050aef7d97cc604309b66f6f45cce02cd734934cd4eMarcel Holtmann		if (!rfcomm_sock_debugfs)
1051aef7d97cc604309b66f6f45cce02cd734934cd4eMarcel Holtmann			BT_ERR("Failed to create RFCOMM debug file");
1052aef7d97cc604309b66f6f45cce02cd734934cd4eMarcel Holtmann	}
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_INFO("RFCOMM socket layer initialized");
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserror:
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	proto_unregister(&rfcomm_proto);
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10632f8362afcd2da8b313ec3cc04a50af19d3592972Gustavo Padovanvoid __exit rfcomm_cleanup_sockets(void)
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1065c6f5df16a2710e64090078dfbaa86c54a27c0874Masatake YAMATO	bt_procfs_cleanup(&init_net, "rfcomm");
1066c6f5df16a2710e64090078dfbaa86c54a27c0874Masatake YAMATO
1067aef7d97cc604309b66f6f45cce02cd734934cd4eMarcel Holtmann	debugfs_remove(rfcomm_sock_debugfs);
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10695e9d7f868f04106139a58212b860dcdc268ad3afDavid Herrmann	bt_sock_unregister(BTPROTO_RFCOMM);
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	proto_unregister(&rfcomm_proto);
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1073