From d57b0e8b8990419b7b7ae0dda5cc4452720b3c7c Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Tue, 11 Oct 2011 14:04:31 +0300 Subject: Bluetooth: convert flushable variable to flag in l2cap chan flushable variable inside l2cap_chan is a logical one and can be easily converted to flag. Added flags in l2cap_chan structure. Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo F. Padovan --- net/bluetooth/l2cap_sock.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'net/bluetooth/l2cap_sock.c') diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 61f1f623091..99782cb4f0b 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -446,7 +446,8 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch break; case BT_FLUSHABLE: - if (put_user(chan->flushable, (u32 __user *) optval)) + if (put_user(test_bit(FLAG_FLUSHABLE, &chan->flags), + (u32 __user *) optval)) err = -EFAULT; break; @@ -655,7 +656,10 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch } } - chan->flushable = opt; + if (opt) + set_bit(FLAG_FLUSHABLE, &chan->flags); + else + clear_bit(FLAG_FLUSHABLE, &chan->flags); break; case BT_POWER: @@ -931,7 +935,7 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) chan->sec_level = pchan->sec_level; chan->role_switch = pchan->role_switch; chan->force_reliable = pchan->force_reliable; - chan->flushable = pchan->flushable; + chan->flags = pchan->flags; chan->force_active = pchan->force_active; } else { @@ -962,7 +966,7 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) chan->sec_level = BT_SECURITY_LOW; chan->role_switch = 0; chan->force_reliable = 0; - chan->flushable = BT_FLUSHABLE_OFF; + chan->flags = 0; chan->force_active = BT_POWER_FORCE_ACTIVE_ON; } -- cgit v1.2.3-70-g09d2 From ecf61bdba845b5e77cf1d5e8620ef54abcfa50ef Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Tue, 11 Oct 2011 14:04:32 +0300 Subject: Bluetooth: convert force_reliable variable to flag in l2cap chan force_reliable variable inside l2cap_chan is a logical one and can be easily converted to flag Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/l2cap.h | 2 +- net/bluetooth/l2cap_core.c | 2 +- net/bluetooth/l2cap_sock.c | 10 ++++++---- 3 files changed, 8 insertions(+), 6 deletions(-) (limited to 'net/bluetooth/l2cap_sock.c') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 0fe5d59b71a..6c0d247de94 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -325,7 +325,6 @@ struct l2cap_chan { __u8 sec_level; __u8 role_switch; - __u8 force_reliable; __u8 force_active; __u8 ident; @@ -465,6 +464,7 @@ enum { /* Definitions for flags in l2cap_chan */ enum { + FLAG_FORCE_RELIABLE, FLAG_FLUSHABLE, }; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index b21ecfffcaa..57e4b2cf7b6 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -948,7 +948,7 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err) list_for_each_entry(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; - if (chan->force_reliable) + if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags)) sk->sk_err = err; } diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 99782cb4f0b..405d736131e 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -359,7 +359,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us if (chan->role_switch) opt |= L2CAP_LM_MASTER; - if (chan->force_reliable) + if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags)) opt |= L2CAP_LM_RELIABLE; if (put_user(opt, (u32 __user *) optval)) @@ -550,7 +550,11 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us chan->sec_level = BT_SECURITY_HIGH; chan->role_switch = (opt & L2CAP_LM_MASTER); - chan->force_reliable = (opt & L2CAP_LM_RELIABLE); + + if (opt & L2CAP_LM_RELIABLE) + set_bit(FLAG_FORCE_RELIABLE, &chan->flags); + else + clear_bit(FLAG_FORCE_RELIABLE, &chan->flags); break; default: @@ -934,7 +938,6 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) chan->tx_win = pchan->tx_win; chan->sec_level = pchan->sec_level; chan->role_switch = pchan->role_switch; - chan->force_reliable = pchan->force_reliable; chan->flags = pchan->flags; chan->force_active = pchan->force_active; } else { @@ -965,7 +968,6 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) chan->tx_win = L2CAP_DEFAULT_TX_WINDOW; chan->sec_level = BT_SECURITY_LOW; chan->role_switch = 0; - chan->force_reliable = 0; chan->flags = 0; chan->force_active = BT_POWER_FORCE_ACTIVE_ON; -- cgit v1.2.3-70-g09d2 From 15770b1ab9747de47604da3494e187056b120aff Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Tue, 11 Oct 2011 14:04:33 +0300 Subject: Bluetooth: convert force_active variable to flag in l2cap chan force_active variable inside l2cap_chan is a logical one and can be easily converted to flag Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/l2cap.h | 2 +- net/bluetooth/l2cap_core.c | 4 ++-- net/bluetooth/l2cap_sock.c | 12 +++++++----- 3 files changed, 10 insertions(+), 8 deletions(-) (limited to 'net/bluetooth/l2cap_sock.c') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 6c0d247de94..440e7b86c01 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -325,7 +325,6 @@ struct l2cap_chan { __u8 sec_level; __u8 role_switch; - __u8 force_active; __u8 ident; @@ -464,6 +463,7 @@ enum { /* Definitions for flags in l2cap_chan */ enum { + FLAG_FORCE_ACTIVE, FLAG_FORCE_RELIABLE, FLAG_FLUSHABLE, }; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 57e4b2cf7b6..aeeacf8076d 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -605,7 +605,7 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control) else flags = ACL_START; - bt_cb(skb)->force_active = chan->force_active; + bt_cb(skb)->force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags); hci_send_acl(chan->conn->hcon, skb, flags); } @@ -1259,7 +1259,7 @@ static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb) else flags = ACL_START; - bt_cb(skb)->force_active = chan->force_active; + bt_cb(skb)->force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags); hci_send_acl(hcon, skb, flags); } diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 405d736131e..bf196c67ecb 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -459,7 +459,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch break; } - pwr.force_active = chan->force_active; + pwr.force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags); len = min_t(unsigned int, len, sizeof(pwr)); if (copy_to_user(optval, (char *) &pwr, len)) @@ -680,7 +680,11 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch err = -EFAULT; break; } - chan->force_active = pwr.force_active; + + if (pwr.force_active) + set_bit(FLAG_FORCE_ACTIVE, &chan->flags); + else + clear_bit(FLAG_FORCE_ACTIVE, &chan->flags); break; default: @@ -939,7 +943,6 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) chan->sec_level = pchan->sec_level; chan->role_switch = pchan->role_switch; chan->flags = pchan->flags; - chan->force_active = pchan->force_active; } else { switch (sk->sk_type) { @@ -969,8 +972,7 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) chan->sec_level = BT_SECURITY_LOW; chan->role_switch = 0; chan->flags = 0; - chan->force_active = BT_POWER_FORCE_ACTIVE_ON; - + set_bit(FLAG_FORCE_ACTIVE, &chan->flags); } /* Default config options */ -- cgit v1.2.3-70-g09d2 From 43bd0f32d5cf6593e420b26e2c1c41dc371a47d7 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Tue, 11 Oct 2011 14:04:34 +0300 Subject: Bluetooth: convert role_switch variable to flag in l2cap chan role_switch variable inside l2cap_chan is a logical one and can be easily converted to flag Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/l2cap.h | 2 +- net/bluetooth/l2cap_core.c | 4 ++-- net/bluetooth/l2cap_sock.c | 9 +++++---- 3 files changed, 8 insertions(+), 7 deletions(-) (limited to 'net/bluetooth/l2cap_sock.c') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 440e7b86c01..aea083c1524 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -324,7 +324,6 @@ struct l2cap_chan { __le16 sport; __u8 sec_level; - __u8 role_switch; __u8 ident; @@ -463,6 +462,7 @@ enum { /* Definitions for flags in l2cap_chan */ enum { + FLAG_ROLE_SWITCH, FLAG_FORCE_ACTIVE, FLAG_FORCE_RELIABLE, FLAG_FLUSHABLE, diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index aeeacf8076d..18a08c59f08 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -3938,12 +3938,12 @@ static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) { lm1 |= HCI_LM_ACCEPT; - if (c->role_switch) + if (test_bit(FLAG_ROLE_SWITCH, &c->flags)) lm1 |= HCI_LM_MASTER; exact++; } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) { lm2 |= HCI_LM_ACCEPT; - if (c->role_switch) + if (test_bit(FLAG_ROLE_SWITCH, &c->flags)) lm2 |= HCI_LM_MASTER; } } diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index bf196c67ecb..48ad8ba492a 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -356,7 +356,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us break; } - if (chan->role_switch) + if (test_bit(FLAG_ROLE_SWITCH, &chan->flags)) opt |= L2CAP_LM_MASTER; if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags)) @@ -549,7 +549,10 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us if (opt & L2CAP_LM_SECURE) chan->sec_level = BT_SECURITY_HIGH; - chan->role_switch = (opt & L2CAP_LM_MASTER); + if (opt & L2CAP_LM_MASTER) + set_bit(FLAG_ROLE_SWITCH, &chan->flags); + else + clear_bit(FLAG_ROLE_SWITCH, &chan->flags); if (opt & L2CAP_LM_RELIABLE) set_bit(FLAG_FORCE_RELIABLE, &chan->flags); @@ -941,7 +944,6 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) chan->max_tx = pchan->max_tx; chan->tx_win = pchan->tx_win; chan->sec_level = pchan->sec_level; - chan->role_switch = pchan->role_switch; chan->flags = pchan->flags; } else { @@ -970,7 +972,6 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) chan->fcs = L2CAP_FCS_CRC16; chan->tx_win = L2CAP_DEFAULT_TX_WINDOW; chan->sec_level = BT_SECURITY_LOW; - chan->role_switch = 0; chan->flags = 0; set_bit(FLAG_FORCE_ACTIVE, &chan->flags); } -- cgit v1.2.3-70-g09d2 From 6327eb980d2ff0c96363b81cb0ce580165cb81b8 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Tue, 11 Oct 2011 13:37:42 +0300 Subject: Bluetooth: EWS: extended window size option support Adds support for extended window size (EWS) config option. We enable EWS feature in L2CAP Info RSP when hs enabled. EWS option is included in L2CAP Config Req if tx_win (which is set via socket) bigger then standard default value (63) && hs enabled && remote side supports EWS feature. Using EWS selects extended control field in L2CAP. Code partly based on Qualcomm and Atheros patches sent upstream a year ago. Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/l2cap.h | 8 +++++-- net/bluetooth/l2cap_core.c | 51 ++++++++++++++++++++++++++++++++++++++++--- net/bluetooth/l2cap_sock.c | 8 +++---- 3 files changed, 58 insertions(+), 9 deletions(-) (limited to 'net/bluetooth/l2cap_sock.c') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 08ad40bb5a4..51998ff6b8c 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -32,6 +32,7 @@ #define L2CAP_DEFAULT_MIN_MTU 48 #define L2CAP_DEFAULT_FLUSH_TO 0xffff #define L2CAP_DEFAULT_TX_WINDOW 63 +#define L2CAP_DEFAULT_EXT_WINDOW 0x3FFF #define L2CAP_DEFAULT_MAX_TX 3 #define L2CAP_DEFAULT_RETRANS_TO 2000 /* 2 seconds */ #define L2CAP_DEFAULT_MONITOR_TO 12000 /* 12 seconds */ @@ -233,6 +234,7 @@ struct l2cap_conf_opt { #define L2CAP_CONF_QOS 0x03 #define L2CAP_CONF_RFC 0x04 #define L2CAP_CONF_FCS 0x05 +#define L2CAP_CONF_EWS 0x07 #define L2CAP_CONF_MAX_SIZE 22 @@ -333,7 +335,7 @@ struct l2cap_chan { __u8 fcs; - __u8 tx_win; + __u16 tx_win; __u8 max_tx; __u16 retrans_timeout; __u16 monitor_timeout; @@ -357,7 +359,7 @@ struct l2cap_chan { struct sk_buff *sdu; struct sk_buff *sdu_last_frag; - __u8 remote_tx_win; + __u16 remote_tx_win; __u8 remote_max_tx; __u16 remote_mps; @@ -442,6 +444,7 @@ enum { CONF_CONNECT_PEND, CONF_NO_FCS_RECV, CONF_STATE2_DEVICE, + CONF_EWS_RECV, }; #define L2CAP_CONF_MAX_CONF_REQ 2 @@ -465,6 +468,7 @@ enum { FLAG_FORCE_ACTIVE, FLAG_FORCE_RELIABLE, FLAG_FLUSHABLE, + FLAG_EXT_CTRL, }; #define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t)) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 18a08c59f08..6e343126f38 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1898,6 +1898,22 @@ static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask) } } +static inline bool __l2cap_ews_supported(struct l2cap_chan *chan) +{ + return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_WINDOW; +} + +static inline void l2cap_txwin_setup(struct l2cap_chan *chan) +{ + if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW && + __l2cap_ews_supported(chan)) + /* use extended control field */ + set_bit(FLAG_EXT_CTRL, &chan->flags); + else + chan->tx_win = min_t(u16, chan->tx_win, + L2CAP_DEFAULT_TX_WINDOW); +} + static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data) { struct l2cap_conf_req *req = data; @@ -1944,7 +1960,6 @@ done: case L2CAP_MODE_ERTM: rfc.mode = L2CAP_MODE_ERTM; - rfc.txwin_size = chan->tx_win; rfc.max_transmit = chan->max_tx; rfc.retrans_timeout = 0; rfc.monitor_timeout = 0; @@ -1952,6 +1967,11 @@ done: if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10) rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10); + l2cap_txwin_setup(chan); + + rfc.txwin_size = min_t(u16, chan->tx_win, + L2CAP_DEFAULT_TX_WINDOW); + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), (unsigned long) &rfc); @@ -1963,6 +1983,10 @@ done: chan->fcs = L2CAP_FCS_NONE; l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs); } + + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) + l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2, + chan->tx_win); break; case L2CAP_MODE_STREAMING: @@ -2038,6 +2062,15 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data) break; + case L2CAP_CONF_EWS: + if (!enable_hs) + return -ECONNREFUSED; + + set_bit(FLAG_EXT_CTRL, &chan->flags); + set_bit(CONF_EWS_RECV, &chan->conf_state); + chan->remote_tx_win = val; + break; + default: if (hint) break; @@ -2098,7 +2131,11 @@ done: break; case L2CAP_MODE_ERTM: - chan->remote_tx_win = rfc.txwin_size; + if (!test_bit(CONF_EWS_RECV, &chan->conf_state)) + chan->remote_tx_win = rfc.txwin_size; + else + rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW; + chan->remote_max_tx = rfc.max_transmit; if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10) @@ -2190,6 +2227,13 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), (unsigned long) &rfc); break; + + case L2CAP_CONF_EWS: + chan->tx_win = min_t(u16, val, + L2CAP_DEFAULT_EXT_WINDOW); + l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, + 2, chan->tx_win); + break; } } @@ -2785,7 +2829,8 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cm feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING | L2CAP_FEAT_FCS; if (enable_hs) - feat_mask |= L2CAP_FEAT_EXT_FLOW; + feat_mask |= L2CAP_FEAT_EXT_FLOW + | L2CAP_FEAT_EXT_WINDOW; put_unaligned_le32(feat_mask, rsp->data); l2cap_send_cmd(conn, cmd->ident, diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 48ad8ba492a..836d12e66a3 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -331,7 +331,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us opts.mode = chan->mode; opts.fcs = chan->fcs; opts.max_tx = chan->max_tx; - opts.txwin_size = (__u16)chan->tx_win; + opts.txwin_size = chan->tx_win; len = min_t(unsigned int, len, sizeof(opts)); if (copy_to_user(optval, (char *) &opts, len)) @@ -501,7 +501,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us opts.mode = chan->mode; opts.fcs = chan->fcs; opts.max_tx = chan->max_tx; - opts.txwin_size = (__u16)chan->tx_win; + opts.txwin_size = chan->tx_win; len = min_t(unsigned int, sizeof(opts), optlen); if (copy_from_user((char *) &opts, optval, len)) { @@ -509,7 +509,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us break; } - if (opts.txwin_size > L2CAP_DEFAULT_TX_WINDOW) { + if (opts.txwin_size > L2CAP_DEFAULT_EXT_WINDOW) { err = -EINVAL; break; } @@ -533,7 +533,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us chan->omtu = opts.omtu; chan->fcs = opts.fcs; chan->max_tx = opts.max_tx; - chan->tx_win = (__u8)opts.txwin_size; + chan->tx_win = opts.txwin_size; break; case L2CAP_LM: -- cgit v1.2.3-70-g09d2 From 5e59b791c3561e2fbb4aee17df3505ad25c16b7a Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Tue, 1 Nov 2011 10:58:57 +0200 Subject: Bluetooth: set skbuffer priority based on L2CAP socket priority This uses SO_PRIORITY to set the skbuffer priority field Signed-off-by: Luiz Augusto von Dentz Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/hci_core.h | 3 +++ include/net/bluetooth/l2cap.h | 3 ++- net/bluetooth/l2cap_core.c | 27 ++++++++++++++++++++------- net/bluetooth/l2cap_sock.c | 2 +- 4 files changed, 26 insertions(+), 9 deletions(-) (limited to 'net/bluetooth/l2cap_sock.c') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 967e18f72a3..9285a650949 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -32,6 +32,9 @@ #define HCI_PROTO_L2CAP 0 #define HCI_PROTO_SCO 1 +/* HCI priority */ +#define HCI_PRIO_MAX 7 + /* HCI Core structures */ struct inquiry_data { bdaddr_t bdaddr; diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 38a56158116..c10bf1db0ab 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -747,7 +747,8 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk); void l2cap_chan_close(struct l2cap_chan *chan, int reason); void l2cap_chan_destroy(struct l2cap_chan *chan); int l2cap_chan_connect(struct l2cap_chan *chan); -int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len); +int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, + u32 priority); void l2cap_chan_busy(struct l2cap_chan *chan, int busy); #endif /* __L2CAP_H */ diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 76210cd6d3e..ac2c41ada0f 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -564,6 +564,7 @@ static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, flags = ACL_START; bt_cb(skb)->force_active = BT_POWER_FORCE_ACTIVE_ON; + skb->priority = HCI_PRIO_MAX; hci_send_acl(conn->hcon, skb, flags); } @@ -1265,7 +1266,8 @@ static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb) struct hci_conn *hcon = chan->conn->hcon; u16 flags; - BT_DBG("chan %p, skb %p len %d", chan, skb, skb->len); + BT_DBG("chan %p, skb %p len %d priority %u", chan, skb, skb->len, + skb->priority); if (!test_bit(FLAG_FLUSHABLE, &chan->flags) && lmp_no_flush_capable(hcon->hdev)) @@ -1483,6 +1485,8 @@ static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, in if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count)) return -EFAULT; + (*frag)->priority = skb->priority; + sent += count; len -= count; @@ -1492,7 +1496,9 @@ static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, in return sent; } -static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) +static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, + struct msghdr *msg, size_t len, + u32 priority) { struct sock *sk = chan->sk; struct l2cap_conn *conn = chan->conn; @@ -1500,7 +1506,7 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE; struct l2cap_hdr *lh; - BT_DBG("sk %p len %d", sk, (int)len); + BT_DBG("sk %p len %d priority %u", sk, (int)len, priority); count = min_t(unsigned int, (conn->mtu - hlen), len); skb = bt_skb_send_alloc(sk, count + hlen, @@ -1508,6 +1514,8 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct if (!skb) return ERR_PTR(err); + skb->priority = priority; + /* Create L2CAP header */ lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); lh->cid = cpu_to_le16(chan->dcid); @@ -1522,7 +1530,9 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct return skb; } -static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) +static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, + struct msghdr *msg, size_t len, + u32 priority) { struct sock *sk = chan->sk; struct l2cap_conn *conn = chan->conn; @@ -1538,6 +1548,8 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct ms if (!skb) return ERR_PTR(err); + skb->priority = priority; + /* Create L2CAP header */ lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); lh->cid = cpu_to_le16(chan->dcid); @@ -1651,7 +1663,8 @@ static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, si return size; } -int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len) +int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, + u32 priority) { struct sk_buff *skb; u32 control; @@ -1659,7 +1672,7 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len) /* Connectionless channel */ if (chan->chan_type == L2CAP_CHAN_CONN_LESS) { - skb = l2cap_create_connless_pdu(chan, msg, len); + skb = l2cap_create_connless_pdu(chan, msg, len, priority); if (IS_ERR(skb)) return PTR_ERR(skb); @@ -1674,7 +1687,7 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len) return -EMSGSIZE; /* Create a basic PDU */ - skb = l2cap_create_basic_pdu(chan, msg, len); + skb = l2cap_create_basic_pdu(chan, msg, len, priority); if (IS_ERR(skb)) return PTR_ERR(skb); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 836d12e66a3..646aefc4f1d 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -721,7 +721,7 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms return -ENOTCONN; } - err = l2cap_chan_send(chan, msg, len); + err = l2cap_chan_send(chan, msg, len, sk->sk_priority); release_sock(sk); return err; -- cgit v1.2.3-70-g09d2 From 6b3c7104677a731cf6d3638e09d9d6c530b9bc25 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Wed, 2 Nov 2011 09:57:10 +0200 Subject: Bluetooth: Initialize tx_win_max for fixed channel tx_win_max is initialized during L2CAP configuration phase. For fixed channels (e.g. A2MP) we want to have it initialized when channel is created. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- net/bluetooth/l2cap_sock.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net/bluetooth/l2cap_sock.c') diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 646aefc4f1d..9ed6501d90f 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -943,6 +943,7 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) chan->fcs = pchan->fcs; chan->max_tx = pchan->max_tx; chan->tx_win = pchan->tx_win; + chan->tx_win_max = pchan->tx_win_max; chan->sec_level = pchan->sec_level; chan->flags = pchan->flags; } else { @@ -971,6 +972,7 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) chan->max_tx = L2CAP_DEFAULT_MAX_TX; chan->fcs = L2CAP_FCS_CRC16; chan->tx_win = L2CAP_DEFAULT_TX_WINDOW; + chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW; chan->sec_level = BT_SECURITY_LOW; chan->flags = 0; set_bit(FLAG_FORCE_ACTIVE, &chan->flags); -- cgit v1.2.3-70-g09d2 From 2ea664822af6705574dfbbf8c77fc7d75a94e9b3 Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Wed, 2 Nov 2011 16:18:30 -0700 Subject: Bluetooth: Add channel policy to getsockopt/setsockopt Each channel has a policy to require BR/EDR (the default), prefer BR/EDR, or prefer AMP. Check for valid policy value and L2CAP mode. Signed-off-by: Mat Martineau Acked-by: Marcel Holtmann Acked-by: Andrei Emeltchenko Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/l2cap.h | 1 + net/bluetooth/l2cap_sock.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) (limited to 'net/bluetooth/l2cap_sock.c') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 1a62573dbd6..9c7d06e6b98 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -367,6 +367,7 @@ struct l2cap_chan { __u16 flush_to; __u8 mode; __u8 chan_type; + __u8 chan_policy; __le16 sport; diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 9ed6501d90f..664762e89ec 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -467,6 +467,16 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch break; + case BT_CHANNEL_POLICY: + if (!enable_hs) { + err = -ENOPROTOOPT; + break; + } + + if (put_user(chan->chan_policy, (u32 __user *) optval)) + err = -EFAULT; + break; + default: err = -ENOPROTOOPT; break; @@ -690,6 +700,31 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch clear_bit(FLAG_FORCE_ACTIVE, &chan->flags); break; + case BT_CHANNEL_POLICY: + if (!enable_hs) { + err = -ENOPROTOOPT; + break; + } + + if (get_user(opt, (u32 __user *) optval)) { + err = -EFAULT; + break; + } + + if (opt > BT_CHANNEL_POLICY_AMP_PREFERRED) { + err = -EINVAL; + break; + } + + if (chan->mode != L2CAP_MODE_ERTM && + chan->mode != L2CAP_MODE_STREAMING) { + err = -EOPNOTSUPP; + break; + } + + chan->chan_policy = (u8) opt; + break; + default: err = -ENOPROTOOPT; break; -- cgit v1.2.3-70-g09d2 From 0bee1d60cbad24288c75573511356d450c1fd45a Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 5 Nov 2011 19:58:31 -0200 Subject: Bluetooth: Allow L2CAP to increase the security level Some incomming connections needs to increase the security level by requesting encryption for example (HID keyboard case). This change allows the userspace to change it through setsockopt with defer_setup enabled. Signed-off-by: Gustavo F. Padovan --- net/bluetooth/l2cap_sock.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'net/bluetooth/l2cap_sock.c') diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 567b585d980..b85e3906b3a 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -625,8 +625,13 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch chan->sec_level = sec.level; + if (!chan->conn) + break; + conn = chan->conn; - if (conn && chan->scid == L2CAP_CID_LE_DATA) { + + /*change security for LE channels */ + if (chan->scid == L2CAP_CID_LE_DATA) { if (!conn->hcon->out) { err = -EINVAL; break; @@ -634,9 +639,14 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch if (smp_conn_security(conn, sec.level)) break; - - err = 0; sk->sk_state = BT_CONFIG; + + /* or for ACL link, under defer_setup time */ + } else if (sk->sk_state == BT_CONNECT2 && + bt_sk(sk)->defer_setup) { + err = l2cap_chan_check_security(chan); + } else { + err = -EINVAL; } break; -- cgit v1.2.3-70-g09d2 From f9c3123b5a7c9585902927b14983e6635aca00c6 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 9 Dec 2011 04:40:10 -0200 Subject: Bluetooth: Use chan instead of l2cap_pi macro Signed-off-by: Gustavo F. Padovan --- net/bluetooth/l2cap_sock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth/l2cap_sock.c') diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index b85e3906b3a..fbdc8b38d9e 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -176,7 +176,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al chan->psm = la.l2_psm; chan->dcid = la.l2_cid; - err = l2cap_chan_connect(l2cap_pi(sk)->chan); + err = l2cap_chan_connect(chan); if (err) goto done; -- cgit v1.2.3-70-g09d2 From 03a001948166d966d0d580cddb8ae3a23f8b795b Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 9 Dec 2011 04:48:17 -0200 Subject: Bluetooth: invert locking order in connect path This move some checking code that was in l2cap_sock_connect() to l2cap_chan_connect(). Thus we can invert the lock calls, i.e., call lock_sock() before hci_dev_lock() to avoid a deadlock scenario. Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/l2cap.h | 3 ++- net/bluetooth/l2cap_core.c | 58 ++++++++++++++++++++++++++++++++++++++-- net/bluetooth/l2cap_sock.c | 61 +++---------------------------------------- 3 files changed, 61 insertions(+), 61 deletions(-) (limited to 'net/bluetooth/l2cap_sock.c') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index f79137476cb..c0d168adf9b 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -806,7 +806,8 @@ int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid); struct l2cap_chan *l2cap_chan_create(struct sock *sk); void l2cap_chan_close(struct l2cap_chan *chan, int reason); void l2cap_chan_destroy(struct l2cap_chan *chan); -int l2cap_chan_connect(struct l2cap_chan *chan); +inline int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, + bdaddr_t *dst); int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u32 priority); void l2cap_chan_busy(struct l2cap_chan *chan, int busy); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index a78cdf7236d..d6165199fc8 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1144,11 +1144,10 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr return c1; } -int l2cap_chan_connect(struct l2cap_chan *chan) +inline int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst) { struct sock *sk = chan->sk; 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; @@ -1164,6 +1163,61 @@ int l2cap_chan_connect(struct l2cap_chan *chan) hci_dev_lock(hdev); + lock_sock(sk); + + /* PSM must be odd and lsb of upper byte must be 0 */ + if ((__le16_to_cpu(psm) & 0x0101) != 0x0001 && !cid && + chan->chan_type != L2CAP_CHAN_RAW) { + err = -EINVAL; + goto done; + } + + if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && !(psm || cid)) { + err = -EINVAL; + goto done; + } + + switch (chan->mode) { + case L2CAP_MODE_BASIC: + break; + case L2CAP_MODE_ERTM: + case L2CAP_MODE_STREAMING: + if (!disable_ertm) + break; + /* fall through */ + default: + err = -ENOTSUPP; + goto done; + } + + switch (sk->sk_state) { + case BT_CONNECT: + case BT_CONNECT2: + case BT_CONFIG: + /* Already connecting */ + err = 0; + goto done; + + case BT_CONNECTED: + /* Already connected */ + err = -EISCONN; + goto done; + + case BT_OPEN: + case BT_BOUND: + /* Can connect */ + break; + + default: + err = -EBADFD; + goto done; + } + + /* Set destination address and psm */ + bacpy(&bt_sk(sk)->dst, src); + chan->psm = psm; + chan->dcid = cid; + auth_type = l2cap_get_auth_type(chan); if (chan->dcid == L2CAP_CID_LE_DATA) diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index fbdc8b38d9e..6c7d4323e79 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -121,70 +121,15 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al if (la.l2_cid && la.l2_psm) return -EINVAL; - lock_sock(sk); - - if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED - && !(la.l2_psm || la.l2_cid)) { - err = -EINVAL; - goto done; - } - - switch (chan->mode) { - case L2CAP_MODE_BASIC: - break; - case L2CAP_MODE_ERTM: - case L2CAP_MODE_STREAMING: - if (!disable_ertm) - break; - /* fall through */ - default: - err = -ENOTSUPP; - goto done; - } - - switch (sk->sk_state) { - case BT_CONNECT: - case BT_CONNECT2: - case BT_CONFIG: - /* Already connecting */ - goto wait; - - case BT_CONNECTED: - /* Already connected */ - err = -EISCONN; - goto done; - - case BT_OPEN: - case BT_BOUND: - /* Can connect */ - break; - - default: - err = -EBADFD; - goto done; - } - - /* PSM must be odd and lsb of upper byte must be 0 */ - if ((__le16_to_cpu(la.l2_psm) & 0x0101) != 0x0001 && !la.l2_cid && - chan->chan_type != L2CAP_CHAN_RAW) { - err = -EINVAL; - goto done; - } - - /* Set destination address and psm */ - bacpy(&bt_sk(sk)->dst, &la.l2_bdaddr); - chan->psm = la.l2_psm; - chan->dcid = la.l2_cid; - - err = l2cap_chan_connect(chan); + err = l2cap_chan_connect(chan, la.l2_psm, la.l2_cid, &la.l2_bdaddr); if (err) goto done; -wait: err = bt_sock_wait_state(sk, BT_CONNECTED, sock_sndtimeo(sk, flags & O_NONBLOCK)); done: - release_sock(sk); + if (sock_owned_by_user(sk)) + release_sock(sk); return err; } -- cgit v1.2.3-70-g09d2 From 590051de5ce54f7ae02997ed0a2532f08c7b7866 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sun, 18 Dec 2011 13:39:33 -0200 Subject: Bluetooth: Add ProFUSION's copyright Add ProFUSION's copyright to some files I've been touching recently. Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_core.c | 1 + net/bluetooth/l2cap_core.c | 1 + net/bluetooth/l2cap_sock.c | 1 + 3 files changed, 3 insertions(+) (limited to 'net/bluetooth/l2cap_sock.c') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index b250685d59a..82d1d9e6b7c 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1,6 +1,7 @@ /* BlueZ - Bluetooth protocol stack for Linux Copyright (C) 2000-2001 Qualcomm Incorporated + Copyright (C) 2011 ProFUSION Embedded Systems Written 2000,2001 by Maxim Krasnyansky diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index a1766adee39..ea36d1dea76 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -3,6 +3,7 @@ Copyright (C) 2000-2001 Qualcomm Incorporated Copyright (C) 2009-2010 Gustavo F. Padovan Copyright (C) 2010 Google Inc. + Copyright (C) 2011 ProFUSION Embedded Systems Written 2000,2001 by Maxim Krasnyansky diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 6c7d4323e79..5e0976670b9 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -3,6 +3,7 @@ Copyright (C) 2000-2001 Qualcomm Incorporated Copyright (C) 2009-2010 Gustavo F. Padovan Copyright (C) 2010 Google Inc. + Copyright (C) 2011 ProFUSION Embedded Systems Written 2000,2001 by Maxim Krasnyansky -- cgit v1.2.3-70-g09d2