* $Id: sock.c,v 1.24 2002/10/03 01:00:34 maxk Exp $
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/kernel.h>
-#include <linux/major.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/socket.h>
#include <linux/skbuff.h>
#include <linux/list.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
+#include <linux/device.h>
#include <net/sock.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/l2cap.h>
#include <net/bluetooth/rfcomm.h>
#ifndef CONFIG_BT_RFCOMM_DEBUG
#define BT_DBG(D...)
#endif
-static struct proto_ops rfcomm_sock_ops;
+static const struct proto_ops rfcomm_sock_ops;
static struct bt_sock_list rfcomm_sk_list = {
.lock = RW_LOCK_UNLOCKED
parent = bt_sk(sk)->parent;
if (parent) {
if (d->state == BT_CLOSED) {
- sk->sk_zapped = 1;
+ sock_set_flag(sk, SOCK_ZAPPED);
bt_accept_unlink(sk);
}
parent->sk_data_ready(parent, 0);
bh_unlock_sock(sk);
- if (parent && sk->sk_zapped)
+ if (parent && sock_flag(sk, SOCK_ZAPPED)) {
+ /* We have to drop DLC lock here, otherwise
+ * rfcomm_sock_destruct() will dead lock. */
+ rfcomm_dlc_unlock(d);
rfcomm_sock_kill(sk);
+ rfcomm_dlc_lock(d);
+ }
}
/* ---- Socket functions ---- */
rfcomm_dlc_lock(d);
rfcomm_pi(sk)->dlc = NULL;
-
+
/* Detach DLC if it's owned by this socket */
if (d->owner == sk)
d->owner = NULL;
rfcomm_dlc_unlock(d);
rfcomm_dlc_put(d);
-
- if (sk->sk_protinfo)
- kfree(sk->sk_protinfo);
}
static void rfcomm_sock_cleanup_listen(struct sock *parent)
}
parent->sk_state = BT_CLOSED;
- parent->sk_zapped = 1;
+ sock_set_flag(parent, SOCK_ZAPPED);
}
/* Kill socket (only if zapped and orphan)
*/
static void rfcomm_sock_kill(struct sock *sk)
{
- if (!sk->sk_zapped || sk->sk_socket)
+ if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket)
return;
BT_DBG("sk %p state %d refcnt %d", sk, sk->sk_state, atomic_read(&sk->sk_refcnt));
rfcomm_dlc_close(d, 0);
default:
- sk->sk_zapped = 1;
+ sock_set_flag(sk, SOCK_ZAPPED);
break;
}
}
static void rfcomm_sock_init(struct sock *sk, struct sock *parent)
{
+ struct rfcomm_pinfo *pi = rfcomm_pi(sk);
+
BT_DBG("sk %p", sk);
- if (parent)
+ if (parent) {
sk->sk_type = parent->sk_type;
+ pi->link_mode = rfcomm_pi(parent)->link_mode;
+ } else {
+ pi->link_mode = 0;
+ }
+
+ pi->dlc->link_mode = pi->link_mode;
}
-static struct sock *rfcomm_sock_alloc(struct socket *sock, int proto, int prio)
+static struct proto rfcomm_proto = {
+ .name = "RFCOMM",
+ .owner = THIS_MODULE,
+ .obj_size = sizeof(struct rfcomm_pinfo)
+};
+
+static struct sock *rfcomm_sock_alloc(struct socket *sock, int proto, gfp_t prio)
{
struct rfcomm_dlc *d;
struct sock *sk;
- sk = bt_sock_alloc(sock, BTPROTO_RFCOMM, sizeof(struct rfcomm_pinfo), prio);
+ sk = sk_alloc(PF_BLUETOOTH, prio, &rfcomm_proto, 1);
if (!sk)
return NULL;
- sk_set_owner(sk, THIS_MODULE);
+ sock_init_data(sock, sk);
+ INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
d = rfcomm_dlc_alloc(prio);
if (!d) {
sk_free(sk);
return NULL;
}
+
d->data_ready = rfcomm_sk_data_ready;
d->state_change = rfcomm_sk_state_change;
sk->sk_sndbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
sk->sk_rcvbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
+ sock_reset_flag(sk, SOCK_ZAPPED);
+
sk->sk_protocol = proto;
- sk->sk_state = BT_OPEN;
+ sk->sk_state = BT_OPEN;
bt_sock_link(&rfcomm_sk_list, sk);
sock->ops = &rfcomm_sock_ops;
- if (!(sk = rfcomm_sock_alloc(sock, protocol, GFP_KERNEL)))
+ sk = rfcomm_sock_alloc(sock, protocol, GFP_ATOMIC);
+ if (!sk)
return -ENOMEM;
rfcomm_sock_init(sk, NULL);
goto done;
}
+ if (sk->sk_type != SOCK_STREAM) {
+ err = -EINVAL;
+ goto done;
+ }
+
write_lock_bh(&rfcomm_sk_list.lock);
if (sa->rc_channel && __rfcomm_get_sock_by_addr(sa->rc_channel, &sa->rc_bdaddr)) {
if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_rc))
return -EINVAL;
- if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND)
- return -EBADFD;
+ lock_sock(sk);
- if (sk->sk_type != SOCK_STREAM)
- return -EINVAL;
+ if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) {
+ err = -EBADFD;
+ goto done;
+ }
- lock_sock(sk);
+ if (sk->sk_type != SOCK_STREAM) {
+ err = -EINVAL;
+ goto done;
+ }
sk->sk_state = BT_CONNECT;
bacpy(&bt_sk(sk)->dst, &sa->rc_bdaddr);
err = bt_sock_wait_state(sk, BT_CONNECTED,
sock_sndtimeo(sk, flags & O_NONBLOCK));
+done:
release_sock(sk);
return err;
}
-int rfcomm_sock_listen(struct socket *sock, int backlog)
+static int rfcomm_sock_listen(struct socket *sock, int backlog)
{
struct sock *sk = sock->sk;
int err = 0;
goto done;
}
+ if (sk->sk_type != SOCK_STREAM) {
+ err = -EINVAL;
+ goto done;
+ }
+
if (!rfcomm_pi(sk)->channel) {
bdaddr_t *src = &bt_sk(sk)->src;
u8 channel;
return err;
}
-int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int flags)
+static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int flags)
{
DECLARE_WAITQUEUE(wait, current);
struct sock *sk = sock->sk, *nsk;
goto done;
}
+ if (sk->sk_type != SOCK_STREAM) {
+ err = -EINVAL;
+ goto done;
+ }
+
timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
BT_DBG("sk %p timeo %ld", sk, timeo);
struct sock *sk = sock->sk;
struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
struct sk_buff *skb;
- int err;
int sent = 0;
if (msg->msg_flags & MSG_OOB)
while (len) {
size_t size = min_t(size_t, len, d->mtu);
+ int err;
skb = sock_alloc_send_skb(sk, size + RFCOMM_SKB_RESERVE,
msg->msg_flags & MSG_DONTWAIT, &err);
err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
if (err) {
kfree_skb(skb);
- sent = err;
+ if (sent == 0)
+ sent = err;
break;
}
err = rfcomm_dlc_send(d, skb);
if (err < 0) {
kfree_skb(skb);
+ if (sent == 0)
+ sent = err;
break;
}
release_sock(sk);
- return sent ? sent : err;
+ return sent;
}
static long rfcomm_sock_data_wait(struct sock *sk, long timeo)
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
- if (skb_queue_len(&sk->sk_receive_queue) || sk->sk_err || (sk->sk_shutdown & RCV_SHUTDOWN) ||
- signal_pending(current) || !timeo)
+ if (!skb_queue_empty(&sk->sk_receive_queue) ||
+ sk->sk_err ||
+ (sk->sk_shutdown & RCV_SHUTDOWN) ||
+ signal_pending(current) ||
+ !timeo)
break;
set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
{
struct sock *sk = sock->sk;
int err = 0;
+ u32 opt;
BT_DBG("sk %p", sk);
lock_sock(sk);
switch (optname) {
+ case RFCOMM_LM:
+ if (get_user(opt, (u32 __user *) optval)) {
+ err = -EFAULT;
+ break;
+ }
+
+ rfcomm_pi(sk)->link_mode = opt;
+ break;
+
default:
err = -ENOPROTOOPT;
break;
static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
{
struct sock *sk = sock->sk;
- int len, err = 0;
+ struct sock *l2cap_sk;
+ struct rfcomm_conninfo cinfo;
+ int len, err = 0;
BT_DBG("sk %p", sk);
lock_sock(sk);
switch (optname) {
+ case RFCOMM_LM:
+ if (put_user(rfcomm_pi(sk)->link_mode, (u32 __user *) optval))
+ err = -EFAULT;
+ break;
+
+ case RFCOMM_CONNINFO:
+ if (sk->sk_state != BT_CONNECTED) {
+ err = -ENOTCONN;
+ break;
+ }
+
+ l2cap_sk = rfcomm_pi(sk)->dlc->session->sock->sk;
+
+ cinfo.hci_handle = l2cap_pi(l2cap_sk)->conn->hcon->handle;
+ memcpy(cinfo.dev_class, l2cap_pi(l2cap_sk)->conn->hcon->dev_class, 3);
+
+ len = min_t(unsigned int, len, sizeof(cinfo));
+ if (copy_to_user(optval, (char *) &cinfo, len))
+ err = -EFAULT;
+
+ break;
+
default:
err = -ENOPROTOOPT;
break;
- };
+ }
release_sock(sk);
return err;
return 0;
/* Check for backlog size */
- if (parent->sk_ack_backlog > parent->sk_max_ack_backlog) {
+ if (sk_acceptq_is_full(parent)) {
BT_DBG("backlog full %d", parent->sk_ack_backlog);
goto done;
}
return result;
}
-/* ---- Proc fs support ---- */
-#ifdef CONFIG_PROC_FS
-static void *rfcomm_seq_start(struct seq_file *seq, loff_t *pos)
+static ssize_t rfcomm_sock_sysfs_show(struct class *dev, char *buf)
{
struct sock *sk;
struct hlist_node *node;
- loff_t l = *pos;
+ char *str = buf;
read_lock_bh(&rfcomm_sk_list.lock);
- sk_for_each(sk, node, &rfcomm_sk_list.head)
- if (!l--)
- return sk;
- return NULL;
-}
-
-static void *rfcomm_seq_next(struct seq_file *seq, void *e, loff_t *pos)
-{
- struct sock *sk = e;
- (*pos)++;
- return sk_next(sk);
-}
+ sk_for_each(sk, node, &rfcomm_sk_list.head) {
+ str += sprintf(str, "%s %s %d %d\n",
+ batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst),
+ sk->sk_state, rfcomm_pi(sk)->channel);
+ }
-static void rfcomm_seq_stop(struct seq_file *seq, void *e)
-{
read_unlock_bh(&rfcomm_sk_list.lock);
-}
-
-static int rfcomm_seq_show(struct seq_file *seq, void *e)
-{
- struct sock *sk = e;
- seq_printf(seq, "%s %s %d %d\n",
- batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst),
- sk->sk_state, rfcomm_pi(sk)->channel);
- return 0;
-}
-
-static struct seq_operations rfcomm_seq_ops = {
- .start = rfcomm_seq_start,
- .next = rfcomm_seq_next,
- .stop = rfcomm_seq_stop,
- .show = rfcomm_seq_show
-};
-
-static int rfcomm_seq_open(struct inode *inode, struct file *file)
-{
- return seq_open(file, &rfcomm_seq_ops);
-}
-
-static struct file_operations rfcomm_seq_fops = {
- .owner = THIS_MODULE,
- .open = rfcomm_seq_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release,
-};
-
-static int __init rfcomm_sock_proc_init(void)
-{
- struct proc_dir_entry *p = create_proc_entry("sock", S_IRUGO, proc_bt_rfcomm);
- if (!p)
- return -ENOMEM;
- p->proc_fops = &rfcomm_seq_fops;
- return 0;
-}
-
-static void __exit rfcomm_sock_proc_cleanup(void)
-{
- remove_proc_entry("sock", proc_bt_rfcomm);
-}
-
-#else /* CONFIG_PROC_FS */
-static int __init rfcomm_sock_proc_init(void)
-{
- return 0;
+ return (str - buf);
}
-static void __exit rfcomm_sock_proc_cleanup(void)
-{
- return;
-}
-#endif /* CONFIG_PROC_FS */
+static CLASS_ATTR(rfcomm, S_IRUGO, rfcomm_sock_sysfs_show, NULL);
-static struct proto_ops rfcomm_sock_ops = {
+static const struct proto_ops rfcomm_sock_ops = {
.family = PF_BLUETOOTH,
.owner = THIS_MODULE,
.release = rfcomm_sock_release,
.create = rfcomm_sock_create
};
-int __init rfcomm_init_sockets(void)
+int __init rfcomm_init_sockets(void)
{
int err;
- if ((err = bt_sock_register(BTPROTO_RFCOMM, &rfcomm_sock_family_ops))) {
- BT_ERR("RFCOMM socket layer registration failed. %d", err);
+ err = proto_register(&rfcomm_proto, 0);
+ if (err < 0)
return err;
- }
- rfcomm_sock_proc_init();
+ err = bt_sock_register(BTPROTO_RFCOMM, &rfcomm_sock_family_ops);
+ if (err < 0)
+ goto error;
+
+ if (class_create_file(bt_class, &class_attr_rfcomm) < 0)
+ BT_ERR("Failed to create RFCOMM info file");
BT_INFO("RFCOMM socket layer initialized");
+
return 0;
+
+error:
+ BT_ERR("RFCOMM socket layer registration failed");
+ proto_unregister(&rfcomm_proto);
+ return err;
}
void __exit rfcomm_cleanup_sockets(void)
{
- int err;
+ class_remove_file(bt_class, &class_attr_rfcomm);
- rfcomm_sock_proc_cleanup();
+ if (bt_sock_unregister(BTPROTO_RFCOMM) < 0)
+ BT_ERR("RFCOMM socket layer unregistration failed");
- /* Unregister socket, protocol and notifier */
- if ((err = bt_sock_unregister(BTPROTO_RFCOMM)))
- BT_ERR("RFCOMM socket layer unregistration failed. %d", err);
+ proto_unregister(&rfcomm_proto);
}