patch-2.4.10 linux/net/bluetooth/l2cap_core.c
Next file: linux/net/bluetooth/l2cap_proc.c
Previous file: linux/net/bluetooth/hci_sock.c
Back to the patch index
Back to the overall index
- Lines: 893
- Date:
Fri Sep 7 09:28:38 2001
- Orig file:
v2.4.9/linux/net/bluetooth/l2cap_core.c
- Orig date:
Tue Jul 3 17:08:22 2001
diff -u --recursive --new-file v2.4.9/linux/net/bluetooth/l2cap_core.c linux/net/bluetooth/l2cap_core.c
@@ -25,8 +25,9 @@
/*
* BlueZ L2CAP core and sockets.
*
- * $Id: l2cap_core.c,v 1.1 2001/06/01 08:12:11 davem Exp $
+ * $Id: l2cap_core.c,v 1.19 2001/08/03 04:19:50 maxk Exp $
*/
+#define VERSION "1.1"
#include <linux/config.h>
#include <linux/module.h>
@@ -36,7 +37,7 @@
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/sched.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/fcntl.h>
#include <linux/init.h>
@@ -73,7 +74,7 @@
static int l2cap_conn_del(struct l2cap_conn *conn, int err);
-static __inline__ void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent);
+static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent);
static void l2cap_chan_del(struct sock *sk, int err);
static int l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len);
@@ -176,7 +177,7 @@
}
/* ----- L2CAP timers ------ */
-static void l2cap_timeout(unsigned long arg)
+static void l2cap_sock_timeout(unsigned long arg)
{
struct sock *sk = (struct sock *) arg;
@@ -199,7 +200,7 @@
sock_put(sk);
}
-static void l2cap_set_timer(struct sock *sk, long timeout)
+static void l2cap_sock_set_timer(struct sock *sk, long timeout)
{
DBG("sock %p state %d timeout %ld", sk, sk->state, timeout);
@@ -207,7 +208,7 @@
sock_hold(sk);
}
-static void l2cap_clear_timer(struct sock *sk)
+static void l2cap_sock_clear_timer(struct sock *sk)
{
DBG("sock %p state %d", sk, sk->state);
@@ -215,13 +216,47 @@
__sock_put(sk);
}
-static void l2cap_init_timer(struct sock *sk)
+static void l2cap_sock_init_timer(struct sock *sk)
{
init_timer(&sk->timer);
- sk->timer.function = l2cap_timeout;
+ sk->timer.function = l2cap_sock_timeout;
sk->timer.data = (unsigned long)sk;
}
+static void l2cap_conn_timeout(unsigned long arg)
+{
+ struct l2cap_conn *conn = (void *)arg;
+
+ DBG("conn %p state %d", conn, conn->state);
+
+ if (conn->state == BT_CONNECTED) {
+ hci_disconnect(conn->hconn, 0x13);
+ }
+
+ return;
+}
+
+static void l2cap_conn_set_timer(struct l2cap_conn *conn, long timeout)
+{
+ DBG("conn %p state %d timeout %ld", conn, conn->state, timeout);
+
+ mod_timer(&conn->timer, jiffies + timeout);
+}
+
+static void l2cap_conn_clear_timer(struct l2cap_conn *conn)
+{
+ DBG("conn %p state %d", conn, conn->state);
+
+ del_timer(&conn->timer);
+}
+
+static void l2cap_conn_init_timer(struct l2cap_conn *conn)
+{
+ init_timer(&conn->timer);
+ conn->timer.function = l2cap_conn_timeout;
+ conn->timer.data = (unsigned long)conn;
+}
+
/* -------- L2CAP connections --------- */
/* Add new connection to the interface.
* Interface must be locked
@@ -244,6 +279,8 @@
spin_lock_init(&conn->lock);
conn->chan_list.lock = RW_LOCK_UNLOCKED;
+ l2cap_conn_init_timer(conn);
+
__l2cap_conn_link(iff, conn);
DBG("%s -> %s, %p", batostr(src), batostr(dst), conn);
@@ -262,17 +299,18 @@
DBG("conn %p, state %d, err %d", conn, conn->state, err);
+ l2cap_conn_clear_timer(conn);
__l2cap_conn_unlink(conn->iff, conn);
conn->state = BT_CLOSED;
if (conn->rx_skb)
- bluez_skb_free(conn->rx_skb);
+ kfree_skb(conn->rx_skb);
/* Kill channels */
while ((sk = conn->chan_list.head)) {
bh_lock_sock(sk);
- l2cap_clear_timer(sk);
+ l2cap_sock_clear_timer(sk);
l2cap_chan_del(sk, err);
bh_unlock_sock(sk);
@@ -285,11 +323,11 @@
return 0;
}
-static __inline__ struct l2cap_conn *l2cap_get_conn_by_addr(struct l2cap_iff *iff, bdaddr_t *dst)
+static inline struct l2cap_conn *l2cap_get_conn_by_addr(struct l2cap_iff *iff, bdaddr_t *dst)
{
struct list_head *p;
- list_for_each(p, &iff->conn_list){
+ list_for_each(p, &iff->conn_list) {
struct l2cap_conn *c;
c = list_entry(p, struct l2cap_conn, list);
@@ -337,7 +375,7 @@
l2cap_chan_add(conn, sk, NULL);
sk->state = BT_CONNECT;
- l2cap_set_timer(sk, sk->sndtimeo);
+ l2cap_sock_set_timer(sk, sk->sndtimeo);
switch (conn->state) {
case BT_CONNECTED:
@@ -347,8 +385,8 @@
req.psm = l2cap_pi(sk)->psm;
l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req);
} else {
+ l2cap_sock_clear_timer(sk);
sk->state = BT_CONNECTED;
- l2cap_clear_timer(sk);
}
break;
@@ -364,7 +402,6 @@
done:
read_unlock_bh(&l2cap_rt_lock);
-
return err;
}
@@ -425,7 +462,7 @@
struct l2cap_accept_q *q = &l2cap_pi(parent)->accept_q;
struct sock *sk;
- for (sk = q->head; sk; sk = l2cap_pi(sk)->next_q){
+ for (sk = q->head; sk; sk = l2cap_pi(sk)->next_q) {
if (!state || sk->state == state) {
l2cap_accept_unlink(sk);
break;
@@ -490,8 +527,8 @@
{
DBG("sk %p", sk);
- bluez_skb_queue_purge(&sk->receive_queue);
- bluez_skb_queue_purge(&sk->write_queue);
+ skb_queue_purge(&sk->receive_queue);
+ skb_queue_purge(&sk->write_queue);
MOD_DEC_USE_COUNT;
}
@@ -533,6 +570,8 @@
{
struct l2cap_conn *conn;
+ l2cap_sock_clear_timer(sk);
+
lock_sock(sk);
conn = l2cap_pi(sk)->conn;
@@ -555,7 +594,7 @@
req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req);
- l2cap_set_timer(sk, sk->sndtimeo);
+ l2cap_sock_set_timer(sk, sk->sndtimeo);
} else {
l2cap_chan_del(sk, ECONNRESET);
}
@@ -614,7 +653,7 @@
sk->protocol = proto;
sk->state = BT_OPEN;
- l2cap_init_timer(sk);
+ l2cap_sock_init_timer(sk);
bluez_sock_link(&l2cap_sk_list, sk);
@@ -689,6 +728,8 @@
long timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
int err = 0;
+ DBG("sk %p", sk);
+
add_wait_queue(sk->sleep, &wait);
current->state = TASK_INTERRUPTIBLE;
@@ -951,7 +992,6 @@
};
release_sock(sk);
-
return err;
}
@@ -959,11 +999,14 @@
{
struct sock *sk = sock->sk;
struct l2cap_options opts;
- int len;
+ struct l2cap_conninfo cinfo;
+ int len, err = 0;
if (get_user(len, optlen))
return -EFAULT;
+ lock_sock(sk);
+
switch (optname) {
case L2CAP_OPTIONS:
opts.imtu = l2cap_pi(sk)->imtu;
@@ -972,16 +1015,63 @@
len = MIN(len, sizeof(opts));
if (copy_to_user(optval, (char *)&opts, len))
- return -EFAULT;
+ err = -EFAULT;
+
+ break;
+
+ case L2CAP_CONNINFO:
+ if (sk->state != BT_CONNECTED) {
+ err = -ENOTCONN;
+ break;
+ }
+
+ cinfo.hci_handle = l2cap_pi(sk)->conn->hconn->handle;
+
+ len = MIN(len, sizeof(cinfo));
+ if (copy_to_user(optval, (char *)&cinfo, len))
+ err = -EFAULT;
break;
default:
- return -ENOPROTOOPT;
+ err = -ENOPROTOOPT;
break;
};
- return 0;
+ release_sock(sk);
+ return err;
+}
+
+static unsigned int l2cap_sock_poll(struct file * file, struct socket *sock, poll_table *wait)
+{
+ struct sock *sk = sock->sk;
+ struct l2cap_accept_q *aq;
+ unsigned int mask;
+
+ DBG("sock %p, sk %p", sock, sk);
+
+ poll_wait(file, sk->sleep, wait);
+ mask = 0;
+
+ if (sk->err || !skb_queue_empty(&sk->error_queue))
+ mask |= POLLERR;
+
+ if (sk->shutdown == SHUTDOWN_MASK)
+ mask |= POLLHUP;
+
+ aq = &l2cap_pi(sk)->accept_q;
+ if (!skb_queue_empty(&sk->receive_queue) || aq->head || (sk->shutdown & RCV_SHUTDOWN))
+ mask |= POLLIN | POLLRDNORM;
+
+ if (sk->state == BT_CLOSED)
+ mask |= POLLHUP;
+
+ if (sock_writeable(sk))
+ mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
+ else
+ set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
+
+ return mask;
}
static int l2cap_sock_release(struct socket *sock)
@@ -1013,7 +1103,7 @@
return s;
}
-static __inline__ struct sock *l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, __u16 cid)
+static inline struct sock *l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, __u16 cid)
{
struct sock *s;
@@ -1035,7 +1125,7 @@
return s;
}
-static __inline__ struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid)
+static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid)
{
struct sock *s;
@@ -1058,7 +1148,7 @@
return s;
}
-static __inline__ struct sock *l2cap_get_chan_by_ident(struct l2cap_chan_list *l, __u8 ident)
+static inline struct sock *l2cap_get_chan_by_ident(struct l2cap_chan_list *l, __u8 ident)
{
struct sock *s;
@@ -1081,7 +1171,7 @@
return 0;
}
-static __inline__ void __l2cap_chan_link(struct l2cap_chan_list *l, struct sock *sk)
+static inline void __l2cap_chan_link(struct l2cap_chan_list *l, struct sock *sk)
{
sock_hold(sk);
@@ -1093,7 +1183,7 @@
l->head = sk;
}
-static __inline__ void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk)
+static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk)
{
struct sock *next = l2cap_pi(sk)->next_c, *prev = l2cap_pi(sk)->prev_c;
@@ -1116,6 +1206,8 @@
DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid);
+ l2cap_conn_clear_timer(conn);
+
atomic_inc(&conn->refcnt);
l2cap_pi(sk)->conn = conn;
@@ -1135,7 +1227,7 @@
l2cap_accept_queue(parent, sk);
}
-static __inline__ void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
+static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
{
struct l2cap_chan_list *l = &conn->chan_list;
@@ -1144,7 +1236,8 @@
write_unlock(&l->lock);
}
-/* Delete channel. Must be called on the locked socket. */
+/* Delete channel.
+ * Must be called on the locked socket. */
static void l2cap_chan_del(struct sock *sk, int err)
{
struct l2cap_conn *conn;
@@ -1162,16 +1255,21 @@
bh_unlock_sock(parent);
}
- if (conn) {
+ if (conn) {
+ long timeout;
+
/* Unlink from channel list */
l2cap_chan_unlink(&conn->chan_list, sk);
l2cap_pi(sk)->conn = NULL;
- if (conn->out &&
- conn->state == BT_CONNECTED &&
- atomic_dec_and_test(&conn->refcnt)) {
- /* Disconnect baseband */
- hci_disconnect(conn->hconn, 0x13);
+ if (conn->out)
+ timeout = L2CAP_DISCONN_TIMEOUT;
+ else
+ timeout = L2CAP_CONN_IDLE_TIMEOUT;
+
+ if (atomic_dec_and_test(&conn->refcnt) && conn->state == BT_CONNECTED) {
+ /* Schedule Baseband disconnect */
+ l2cap_conn_set_timer(conn, timeout);
}
}
@@ -1197,14 +1295,14 @@
if (sk->type != SOCK_SEQPACKET) {
sk->state = BT_CONNECTED;
sk->state_change(sk);
- l2cap_clear_timer(sk);
+ l2cap_sock_clear_timer(sk);
} else if (sk->state == BT_CONNECT) {
l2cap_conn_req req;
req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
req.psm = l2cap_pi(sk)->psm;
l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req);
- l2cap_set_timer(sk, sk->sndtimeo);
+ l2cap_sock_set_timer(sk, sk->sndtimeo);
}
bh_unlock_sock(sk);
@@ -1220,7 +1318,7 @@
DBG("sk %p, parent %p", sk, parent);
l2cap_pi(sk)->conf_state = 0;
- l2cap_clear_timer(sk);
+ l2cap_sock_clear_timer(sk);
if (!parent) {
/* Outgoing channel.
@@ -1232,7 +1330,7 @@
/* Incomming channel.
* Wake up socket sleeping on accept.
*/
- parent->state_change(parent);
+ parent->data_ready(parent, 1);
}
}
@@ -1254,7 +1352,7 @@
if (skb->sk == sk)
continue;
- if (!(nskb = bluez_skb_clone(skb, GFP_ATOMIC)))
+ if (!(nskb = skb_clone(skb, GFP_ATOMIC)))
continue;
skb_queue_tail(&sk->receive_queue, nskb);
@@ -1266,17 +1364,18 @@
static int l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len)
{
struct l2cap_conn *conn = l2cap_pi(sk)->conn;
- struct l2cap_iff *iff = conn->iff;
- struct sk_buff *skb, *frag;
+ struct sk_buff *skb, **frag;
int err, size, count, sent=0;
- l2cap_hdr * lh;
+ l2cap_hdr *lh;
/* Check outgoing MTU */
if (len > l2cap_pi(sk)->omtu)
return -EINVAL;
+ DBG("sk %p len %d", sk, len);
+
/* First fragment (with L2CAP header) */
- count = MIN(iff->mtu - L2CAP_HDR_SIZE, len);
+ count = MIN(conn->iff->mtu - L2CAP_HDR_SIZE, len);
size = L2CAP_HDR_SIZE + count;
if (!(skb = bluez_skb_send_alloc(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)))
return err;
@@ -1295,21 +1394,23 @@
len -= count;
/* Continuation fragments (no L2CAP header) */
+ frag = &skb_shinfo(skb)->frag_list;
while (len) {
- count = MIN(iff->mtu, len);
+ count = MIN(conn->iff->mtu, len);
- if (!(frag = bluez_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err)))
+ *frag = bluez_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
+ if (!*frag)
goto fail;
-
- bluez_skb_add_frag(skb, frag);
-
- if (memcpy_fromiovec(skb_put(frag, count), msg->msg_iov, count)) {
+
+ if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count)) {
err = -EFAULT;
goto fail;
}
sent += count;
len -= count;
+
+ frag = &(*frag)->next;
}
if ((err = hci_send_acl(conn->hconn, skb, 0)) < 0)
@@ -1318,12 +1419,12 @@
return sent;
fail:
- bluez_skb_free(skb);
-
+ kfree_skb(skb);
return err;
}
+
/* --------- L2CAP signalling commands --------- */
-static __inline__ __u8 l2cap_get_ident(struct l2cap_conn *conn)
+static inline __u8 l2cap_get_ident(struct l2cap_conn *conn)
{
__u8 id;
@@ -1344,7 +1445,7 @@
return id;
}
-static __inline__ struct sk_buff *l2cap_build_cmd(__u8 code, __u8 ident, __u16 len, void *data)
+static inline struct sk_buff *l2cap_build_cmd(__u8 code, __u8 ident, __u16 len, void *data)
{
struct sk_buff *skb;
l2cap_cmd_hdr *cmd;
@@ -1382,7 +1483,6 @@
ident = l2cap_get_ident(conn);
if (!(skb = l2cap_build_cmd(code, ident, len, data)))
return -ENOMEM;
- skb->dev = (void *) conn->iff->hdev;
return hci_send_acl(conn->hconn, skb, 0);
}
@@ -1394,13 +1494,10 @@
if (!(skb = l2cap_build_cmd(code, ident, len, data)))
return -ENOMEM;
-
- skb->dev = (void *) conn->iff->hdev;
-
return hci_send_acl(conn->hconn, skb, 0);
}
-static __inline__ int l2cap_get_conf_opt(__u8 **ptr, __u8 *type, __u32 *val)
+static inline int l2cap_get_conf_opt(__u8 **ptr, __u8 *type, __u32 *val)
{
l2cap_conf_opt *opt = (l2cap_conf_opt *) (*ptr);
int len;
@@ -1433,9 +1530,9 @@
return len;
}
-static __inline__ void l2cap_parse_conf_req(struct sock *sk, char *data, int len)
+static inline void l2cap_parse_conf_req(struct sock *sk, char *data, int len)
{
- __u8 type; __u32 val;
+ __u8 type, hint; __u32 val;
__u8 *ptr = data;
DBG("sk %p len %d", sk, len);
@@ -1443,6 +1540,9 @@
while (len >= L2CAP_CONF_OPT_SIZE) {
len -= l2cap_get_conf_opt(&ptr, &type, &val);
+ hint = type & 0x80;
+ type &= 0x7f;
+
switch (type) {
case L2CAP_CONF_MTU:
l2cap_pi(sk)->conf_mtu = val;
@@ -1454,11 +1554,18 @@
case L2CAP_CONF_QOS:
break;
+
+ default:
+ if (hint)
+ break;
+
+ /* FIXME: Reject unknon option */
+ break;
};
}
}
-static __inline__ void l2cap_add_conf_opt(__u8 **ptr, __u8 type, __u8 len, __u32 val)
+static inline void l2cap_add_conf_opt(__u8 **ptr, __u8 type, __u8 len, __u32 val)
{
register l2cap_conf_opt *opt = (l2cap_conf_opt *) (*ptr);
@@ -1540,7 +1647,7 @@
return ptr - data;
}
-static __inline__ int l2cap_connect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
+static inline int l2cap_connect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
{
struct l2cap_chan_list *list = &conn->chan_list;
l2cap_conn_req *req = (l2cap_conn_req *) data;
@@ -1605,7 +1712,7 @@
return 0;
}
-static __inline__ int l2cap_connect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
+static inline int l2cap_connect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
{
l2cap_conn_rsp *rsp = (l2cap_conn_rsp *) data;
__u16 scid, dcid, result, status;
@@ -1626,8 +1733,9 @@
if (!result) {
char req[64];
- l2cap_pi(sk)->dcid = dcid;
sk->state = BT_CONFIG;
+ l2cap_pi(sk)->dcid = dcid;
+ l2cap_pi(sk)->conf_state |= CONF_REQ_SENT;
l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req);
} else {
@@ -1638,7 +1746,7 @@
return 0;
}
-static __inline__ int l2cap_config_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
+static inline int l2cap_config_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
{
l2cap_conf_req * req = (l2cap_conf_req *) data;
__u16 dcid, flags;
@@ -1671,12 +1779,12 @@
goto unlock;
/* Output config done */
- l2cap_pi(sk)->conf_state |= CONF_OUTPUT;
+ l2cap_pi(sk)->conf_state |= CONF_OUTPUT_DONE;
- if (l2cap_pi(sk)->conf_state == CONF_DONE) {
+ if (l2cap_pi(sk)->conf_state & CONF_INPUT_DONE) {
sk->state = BT_CONNECTED;
l2cap_chan_ready(sk);
- } else {
+ } else if (!(l2cap_pi(sk)->conf_state & CONF_REQ_SENT)) {
char req[64];
l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req);
}
@@ -1687,7 +1795,7 @@
return 0;
}
-static __inline__ int l2cap_config_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
+static inline int l2cap_config_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
{
l2cap_conf_rsp *rsp = (l2cap_conf_rsp *)data;
__u16 scid, flags, result;
@@ -1705,11 +1813,6 @@
bh_lock_sock(sk);
- if (sk->state != BT_CONFIG) {
- err = -EINVAL;
- goto done;
- }
-
if (result) {
l2cap_disconn_req req;
@@ -1722,7 +1825,7 @@
req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req);
- l2cap_set_timer(sk, sk->sndtimeo);
+ l2cap_sock_set_timer(sk, sk->sndtimeo);
goto done;
}
@@ -1730,9 +1833,9 @@
goto done;
/* Input config done */
- l2cap_pi(sk)->conf_state |= CONF_INPUT;
+ l2cap_pi(sk)->conf_state |= CONF_INPUT_DONE;
- if (l2cap_pi(sk)->conf_state == CONF_DONE) {
+ if (l2cap_pi(sk)->conf_state & CONF_OUTPUT_DONE) {
sk->state = BT_CONNECTED;
l2cap_chan_ready(sk);
}
@@ -1743,7 +1846,7 @@
return err;
}
-static __inline__ int l2cap_disconnect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
+static inline int l2cap_disconnect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
{
l2cap_disconn_req *req = (l2cap_disconn_req *) data;
l2cap_disconn_rsp rsp;
@@ -1773,7 +1876,7 @@
return 0;
}
-static __inline__ int l2cap_disconnect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
+static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
{
l2cap_disconn_rsp *rsp = (l2cap_disconn_rsp *) data;
__u16 dcid, scid;
@@ -1788,7 +1891,7 @@
return -ENOENT;
bh_lock_sock(sk);
- l2cap_clear_timer(sk);
+ l2cap_sock_clear_timer(sk);
l2cap_chan_del(sk, ECONNABORTED);
bh_unlock_sock(sk);
@@ -1797,7 +1900,7 @@
return 0;
}
-static __inline__ void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
+static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
{
__u8 *data = skb->data;
int len = skb->len;
@@ -1809,7 +1912,7 @@
data += L2CAP_CMD_HDR_SIZE;
len -= L2CAP_CMD_HDR_SIZE;
- cmd.len = le16_to_cpu(cmd.len);
+ cmd.len = __le16_to_cpu(cmd.len);
DBG("code 0x%2.2x len %d id 0x%2.2x", cmd.code, cmd.len, cmd.ident);
@@ -1869,7 +1972,7 @@
DBG("error %d", err);
/* FIXME: Map err to a valid reason. */
- rej.reason = cpu_to_le16(0);
+ rej.reason = __cpu_to_le16(0);
l2cap_send_rsp(conn, cmd.ident, L2CAP_COMMAND_REJ, L2CAP_CMD_REJ_SIZE, &rej);
}
@@ -1877,10 +1980,10 @@
len -= cmd.len;
}
- bluez_skb_free(skb);
+ kfree_skb(skb);
}
-static __inline__ int l2cap_data_channel(struct l2cap_conn *conn, __u16 cid, struct sk_buff *skb)
+static inline int l2cap_data_channel(struct l2cap_conn *conn, __u16 cid, struct sk_buff *skb)
{
struct sock *sk;
@@ -1903,7 +2006,7 @@
return 0;
drop:
- bluez_skb_free(skb);
+ kfree_skb(skb);
return 0;
}
@@ -1914,8 +2017,8 @@
__u16 cid, len;
skb_pull(skb, L2CAP_HDR_SIZE);
- cid = le16_to_cpu(lh->cid);
- len = le16_to_cpu(lh->len);
+ cid = __le16_to_cpu(lh->cid);
+ len = __le16_to_cpu(lh->len);
DBG("len %d, cid 0x%4.4x", len, cid);
@@ -2008,10 +2111,10 @@
goto done;
}
- conn->state = BT_CONNECTED;
conn->hconn = hconn;
-
hconn->l2cap_data = (void *)conn;
+
+ conn->state = BT_CONNECTED;
}
done:
@@ -2044,7 +2147,7 @@
struct l2cap_conn *conn = hconn->l2cap_data;
if (!conn) {
- ERR("unknown connection");
+ ERR("unknown connection %p", hconn);
goto drop;
}
@@ -2054,8 +2157,14 @@
int flen, tlen, size;
l2cap_hdr *lh;
+ if (conn->rx_len) {
+ ERR("Unexpected start frame (len %d)", skb->len);
+ kfree_skb(conn->rx_skb); conn->rx_skb = NULL;
+ conn->rx_len = 0;
+ }
+
if (skb->len < L2CAP_HDR_SIZE) {
- DBG("Corrupted L2CAP frame %d", skb->len);
+ ERR("Frame is too small (len %d)", skb->len);
goto drop;
}
@@ -2082,12 +2191,14 @@
} else {
DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
- /* Check length */
+ if (!conn->rx_len) {
+ ERR("Unexpected continuation frame (len %d)", skb->len);
+ goto drop;
+ }
+
if (skb->len > conn->rx_len) {
- if (conn->rx_skb) {
- bluez_skb_free(conn->rx_skb);
- conn->rx_skb = NULL;
- }
+ ERR("Fragment is too large (len %d)", skb->len);
+ kfree_skb(conn->rx_skb); conn->rx_skb = NULL;
goto drop;
}
@@ -2098,13 +2209,11 @@
/* Complete frame received */
l2cap_recv_frame(conn, conn->rx_skb);
conn->rx_skb = NULL;
- conn->rx_len = 0;
}
}
drop:
- bluez_skb_free(skb);
-
+ kfree_skb(skb);
return 0;
}
@@ -2118,7 +2227,7 @@
getname: l2cap_sock_getname,
sendmsg: l2cap_sock_sendmsg,
recvmsg: l2cap_sock_recvmsg,
- poll: datagram_poll,
+ poll: l2cap_sock_poll,
socketpair: sock_no_socketpair,
ioctl: sock_no_ioctl,
shutdown: sock_no_shutdown,
@@ -2148,7 +2257,7 @@
int __init l2cap_init(void)
{
INF("BlueZ L2CAP ver %s Copyright (C) 2000,2001 Qualcomm Inc",
- BLUEZ_VER);
+ VERSION);
INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
if (bluez_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops)) {
@@ -2200,3 +2309,6 @@
module_init(l2cap_init);
module_exit(l2cap_cleanup);
+
+MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
+MODULE_DESCRIPTION("BlueZ L2CAP ver " VERSION);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)