SOFTWARE IS DISCLAIMED.
*/
-/*
- * Bluetooth L2CAP core and sockets.
- *
- * $Id: l2cap.c,v 1.15 2002/09/09 01:14:52 maxk Exp $
- */
-#define VERSION "2.1"
+/* Bluetooth L2CAP core and sockets. */
#include <linux/config.h>
#include <linux/module.h>
#ifndef CONFIG_BT_L2CAP_DEBUG
#undef BT_DBG
-#define BT_DBG( A... )
+#define BT_DBG(D...)
#endif
+#define VERSION "2.2"
+
static struct proto_ops l2cap_sock_ops;
struct bt_sock_list l2cap_sk_list = {
hcon->l2cap_data = conn;
conn->hcon = hcon;
-
+
conn->mtu = hcon->hdev->acl_mtu;
conn->src = &hcon->hdev->bdaddr;
conn->dst = &hcon->dst;
-
+
spin_lock_init(&conn->lock);
conn->chan_list.lock = RW_LOCK_UNLOCKED;
if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_DGRAM && sock->type != SOCK_RAW)
return -ESOCKTNOSUPPORT;
-
+
if (sock->type == SOCK_RAW && !capable(CAP_NET_RAW))
return -EPERM;
-
+
sock->ops = &l2cap_sock_ops;
sk = l2cap_sock_alloc(sock, protocol, GFP_KERNEL);
}
write_lock_bh(&l2cap_sk_list.lock);
+
if (la->l2_psm && __l2cap_get_sock_by_addr(la->l2_psm, &la->l2_bdaddr)) {
err = -EADDRINUSE;
} else {
l2cap_pi(sk)->sport = la->l2_psm;
sk->sk_state = BT_BOUND;
}
+
write_unlock_bh(&l2cap_sk_list.lock);
done:
bdaddr_t *src = &bt_sk(sk)->src;
bdaddr_t *dst = &bt_sk(sk)->dst;
struct l2cap_conn *conn;
- struct hci_conn *hcon;
- struct hci_dev *hdev;
+ struct hci_conn *hcon;
+ struct hci_dev *hdev;
int err = 0;
BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), l2cap_pi(sk)->psm);
}
if (!l2cap_pi(sk)->psm) {
+ bdaddr_t *src = &bt_sk(sk)->src;
+ u16 psm;
+
err = -EINVAL;
- goto done;
+
+ write_lock_bh(&l2cap_sk_list.lock);
+
+ for (psm = 0x1001; psm < 0x1100; psm += 2)
+ if (!__l2cap_get_sock_by_addr(psm, src)) {
+ l2cap_pi(sk)->psm = htobs(psm);
+ l2cap_pi(sk)->sport = htobs(psm);
+ err = 0;
+ break;
+ }
+
+ write_unlock_bh(&l2cap_sk_list.lock);
+
+ if (err < 0)
+ goto done;
}
sk->sk_max_ack_backlog = backlog;
return err;
}
-static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
+static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen)
{
struct sock *sk = sock->sk;
struct l2cap_options opts;
break;
case L2CAP_LM:
- if (get_user(opt, (u32 *)optval)) {
+ if (get_user(opt, (u32 __user *)optval)) {
err = -EFAULT;
break;
}
return err;
}
-static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
+static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
{
struct sock *sk = sock->sk;
struct l2cap_options opts;
break;
case L2CAP_LM:
- if (put_user(l2cap_pi(sk)->link_mode, (u32 *)optval))
+ if (put_user(l2cap_pi(sk)->link_mode, (u32 __user *)optval))
err = -EFAULT;
break;
BT_DBG("sock %p, sk %p", sock, sk);
- if (!sk) return 0;
+ if (!sk)
+ return 0;
lock_sock(sk);
if (!sk->sk_shutdown) {
BT_DBG("sock %p, sk %p", sock, sk);
- if (!sk) return 0;
+ if (!sk)
+ return 0;
err = l2cap_sock_shutdown(sock, 2);
sk->sk_state = BT_CLOSED;
sk->sk_zapped = 1;
-
+
if (err)
sk->sk_err = err;
len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
count = min_t(unsigned int, conn->mtu, len);
-
+
skb = bt_skb_alloc(count, GFP_ATOMIC);
if (!skb)
return NULL;
}
len -= skb->len;
-
+
/* Continuation fragments (no L2CAP header) */
frag = &skb_shinfo(skb)->frag_list;
while (len) {
*frag = bt_skb_alloc(count, GFP_ATOMIC);
if (!*frag)
goto fail;
-
+
memcpy(skb_put(*frag, count), data, count);
len -= count;
data += count;
-
+
frag = &(*frag)->next;
}
case L2CAP_CONF_QOS:
break;
-
+
default:
if (hint)
break;
int result = 0;
/* Configure output options and let the other side know
- * which ones we don't like.
- */
+ * which ones we don't like. */
if (pi->conf_mtu < pi->omtu) {
l2cap_add_conf_opt(ptr, L2CAP_CONF_MTU, 2, pi->omtu);
result = L2CAP_CONF_UNACCEPT;
case L2CAP_CONF_UNACCEPT:
if (++l2cap_pi(sk)->conf_retry < L2CAP_CONF_MAX_RETRIES) {
char req[128];
- /*
- It does not make sense to adjust L2CAP parameters
- that are currently defined in the spec. We simply
- resend config request that we sent earlier. It is
- stupid :) but it helps qualification testing
- which expects at least some response from us.
- */
+ /* It does not make sense to adjust L2CAP parameters
+ * that are currently defined in the spec. We simply
+ * resend config request that we sent earlier. It is
+ * stupid, but it helps qualification testing which
+ * expects at least some response from us. */
l2cap_send_req(conn, L2CAP_CONF_REQ,
l2cap_build_conf_req(sk, req), req);
goto done;
l2cap_send_rsp(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
sk->sk_shutdown = SHUTDOWN_MASK;
-
+
l2cap_chan_del(sk, ECONNRESET);
bh_unlock_sock(sk);
if (l2cap_pi(sk)->imtu < skb->len)
goto drop;
- /* If socket recv buffers overflows we drop data here
- * which is *bad* because L2CAP has to be reliable.
- * But we don't have any other choice. L2CAP doesn't
- * provide flow control mechanism */
-
+ /* If socket recv buffers overflows we drop data here
+ * which is *bad* because L2CAP has to be reliable.
+ * But we don't have any other choice. L2CAP doesn't
+ * provide flow control mechanism */
+
if (!sock_queue_rcv_skb(sk, skb))
goto done;
skb_pull(skb, 2);
l2cap_conless_channel(conn, psm, skb);
break;
-
+
default:
l2cap_data_channel(conn, cid, skb);
break;
l2cap_conn_ready(conn);
} else
l2cap_conn_del(hcon, bt_err(status));
-
+
return 0;
}
struct l2cap_conn_rsp rsp;
struct sock *sk;
int result;
-
+
if (!(conn = hcon->l2cap_data))
return 0;
l = &conn->chan_list;
struct l2cap_conn_rsp rsp;
struct sock *sk;
int result;
-
+
if (!(conn = hcon->l2cap_data))
return 0;
l = &conn->chan_list;
}
static struct seq_operations l2cap_seq_ops = {
- .start = l2cap_seq_start,
- .next = l2cap_seq_next,
- .stop = l2cap_seq_stop,
- .show = l2cap_seq_show
+ .start = l2cap_seq_start,
+ .next = l2cap_seq_next,
+ .stop = l2cap_seq_stop,
+ .show = l2cap_seq_show
};
static int l2cap_seq_open(struct inode *inode, struct file *file)
}
static struct file_operations l2cap_seq_fops = {
- .owner = THIS_MODULE,
- .open = l2cap_seq_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release,
+ .owner = THIS_MODULE,
+ .open = l2cap_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
};
-static int __init l2cap_proc_init(void)
+static int __init l2cap_proc_init(void)
{
- struct proc_dir_entry *p = create_proc_entry("l2cap", S_IRUGO, proc_bt);
- if (!p)
- return -ENOMEM;
+ struct proc_dir_entry *p = create_proc_entry("l2cap", S_IRUGO, proc_bt);
+ if (!p)
+ return -ENOMEM;
p->owner = THIS_MODULE;
- p->proc_fops = &l2cap_seq_fops;
- return 0;
+ p->proc_fops = &l2cap_seq_fops;
+ return 0;
}
static void __exit l2cap_proc_cleanup(void)
{
- remove_proc_entry("l2cap", proc_bt);
+ remove_proc_entry("l2cap", proc_bt);
}
#else /* CONFIG_PROC_FS */
-static int __init l2cap_proc_init(void)
+static int __init l2cap_proc_init(void)
{
- return 0;
+ return 0;
}
static void __exit l2cap_proc_cleanup(void)
{
- return;
+ return;
}
#endif /* CONFIG_PROC_FS */
static struct proto_ops l2cap_sock_ops = {
- .family = PF_BLUETOOTH,
- .owner = THIS_MODULE,
- .release = l2cap_sock_release,
- .bind = l2cap_sock_bind,
- .connect = l2cap_sock_connect,
- .listen = l2cap_sock_listen,
- .accept = l2cap_sock_accept,
- .getname = l2cap_sock_getname,
- .sendmsg = l2cap_sock_sendmsg,
- .recvmsg = bt_sock_recvmsg,
- .poll = bt_sock_poll,
- .mmap = sock_no_mmap,
- .socketpair = sock_no_socketpair,
- .ioctl = sock_no_ioctl,
- .shutdown = l2cap_sock_shutdown,
- .setsockopt = l2cap_sock_setsockopt,
- .getsockopt = l2cap_sock_getsockopt
+ .family = PF_BLUETOOTH,
+ .owner = THIS_MODULE,
+ .release = l2cap_sock_release,
+ .bind = l2cap_sock_bind,
+ .connect = l2cap_sock_connect,
+ .listen = l2cap_sock_listen,
+ .accept = l2cap_sock_accept,
+ .getname = l2cap_sock_getname,
+ .sendmsg = l2cap_sock_sendmsg,
+ .recvmsg = bt_sock_recvmsg,
+ .poll = bt_sock_poll,
+ .mmap = sock_no_mmap,
+ .socketpair = sock_no_socketpair,
+ .ioctl = sock_no_ioctl,
+ .shutdown = l2cap_sock_shutdown,
+ .setsockopt = l2cap_sock_setsockopt,
+ .getsockopt = l2cap_sock_getsockopt
};
static struct net_proto_family l2cap_sock_family_ops = {
- .family = PF_BLUETOOTH,
- .create = l2cap_sock_create,
- .owner = THIS_MODULE,
+ .family = PF_BLUETOOTH,
+ .owner = THIS_MODULE,
+ .create = l2cap_sock_create,
};
static struct hci_proto l2cap_hci_proto = {
- .name = "L2CAP",
- .id = HCI_PROTO_L2CAP,
- .connect_ind = l2cap_connect_ind,
- .connect_cfm = l2cap_connect_cfm,
- .disconn_ind = l2cap_disconn_ind,
- .auth_cfm = l2cap_auth_cfm,
- .encrypt_cfm = l2cap_encrypt_cfm,
- .recv_acldata = l2cap_recv_acldata
+ .name = "L2CAP",
+ .id = HCI_PROTO_L2CAP,
+ .connect_ind = l2cap_connect_ind,
+ .connect_cfm = l2cap_connect_cfm,
+ .disconn_ind = l2cap_disconn_ind,
+ .auth_cfm = l2cap_auth_cfm,
+ .encrypt_cfm = l2cap_encrypt_cfm,
+ .recv_acldata = l2cap_recv_acldata
};
static int __init l2cap_init(void)
}
l2cap_proc_init();
-
+
BT_INFO("L2CAP ver %s", VERSION);
BT_INFO("L2CAP socket layer initialized");
void l2cap_load(void)
{
- /* Dummy function to trigger automatic L2CAP module loading by
- other modules that use L2CAP sockets but don not use any other
- symbols from it. */
+ /* Dummy function to trigger automatic L2CAP module loading by
+ * other modules that use L2CAP sockets but don not use any othe
+ * symbols from it. */
return;
}
EXPORT_SYMBOL(l2cap_load);