aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/bluetooth/l2cap.h1
-rw-r--r--net/bluetooth/l2cap.c40
2 files changed, 32 insertions, 9 deletions
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 4781d285b2e9..abfec8847718 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -185,6 +185,7 @@ struct l2cap_info_rsp {
185/* info type */ 185/* info type */
186#define L2CAP_IT_CL_MTU 0x0001 186#define L2CAP_IT_CL_MTU 0x0001
187#define L2CAP_IT_FEAT_MASK 0x0002 187#define L2CAP_IT_FEAT_MASK 0x0002
188#define L2CAP_IT_FIXED_CHAN 0x0003
188 189
189/* info result */ 190/* info result */
190#define L2CAP_IR_SUCCESS 0x0000 191#define L2CAP_IR_SUCCESS 0x0000
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 88340d24d11d..985366c36f48 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -50,9 +50,10 @@
50#include <net/bluetooth/hci_core.h> 50#include <net/bluetooth/hci_core.h>
51#include <net/bluetooth/l2cap.h> 51#include <net/bluetooth/l2cap.h>
52 52
53#define VERSION "2.12" 53#define VERSION "2.13"
54 54
55static u32 l2cap_feat_mask = 0x0000; 55static u32 l2cap_feat_mask = 0x0080;
56static u8 l2cap_fixed_chan[8] = { 0x02, };
56 57
57static const struct proto_ops l2cap_sock_ops; 58static const struct proto_ops l2cap_sock_ops;
58 59
@@ -456,9 +457,8 @@ static void l2cap_info_timeout(unsigned long arg)
456{ 457{
457 struct l2cap_conn *conn = (void *) arg; 458 struct l2cap_conn *conn = (void *) arg;
458 459
459 conn->info_ident = 0;
460
461 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; 460 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
461 conn->info_ident = 0;
462 462
463 l2cap_conn_start(conn); 463 l2cap_conn_start(conn);
464} 464}
@@ -1793,10 +1793,10 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hd
1793 1793
1794 if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) && 1794 if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
1795 cmd->ident == conn->info_ident) { 1795 cmd->ident == conn->info_ident) {
1796 conn->info_ident = 0;
1797 del_timer(&conn->info_timer); 1796 del_timer(&conn->info_timer);
1798 1797
1799 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; 1798 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
1799 conn->info_ident = 0;
1800 1800
1801 l2cap_conn_start(conn); 1801 l2cap_conn_start(conn);
1802 } 1802 }
@@ -2165,6 +2165,14 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cm
2165 put_unaligned(cpu_to_le32(l2cap_feat_mask), (__le32 *) rsp->data); 2165 put_unaligned(cpu_to_le32(l2cap_feat_mask), (__le32 *) rsp->data);
2166 l2cap_send_cmd(conn, cmd->ident, 2166 l2cap_send_cmd(conn, cmd->ident,
2167 L2CAP_INFO_RSP, sizeof(buf), buf); 2167 L2CAP_INFO_RSP, sizeof(buf), buf);
2168 } else if (type == L2CAP_IT_FIXED_CHAN) {
2169 u8 buf[12];
2170 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
2171 rsp->type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
2172 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
2173 memcpy(buf + 4, l2cap_fixed_chan, 8);
2174 l2cap_send_cmd(conn, cmd->ident,
2175 L2CAP_INFO_RSP, sizeof(buf), buf);
2168 } else { 2176 } else {
2169 struct l2cap_info_rsp rsp; 2177 struct l2cap_info_rsp rsp;
2170 rsp.type = cpu_to_le16(type); 2178 rsp.type = cpu_to_le16(type);
@@ -2186,14 +2194,28 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
2186 2194
2187 BT_DBG("type 0x%4.4x result 0x%2.2x", type, result); 2195 BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
2188 2196
2189 conn->info_ident = 0;
2190
2191 del_timer(&conn->info_timer); 2197 del_timer(&conn->info_timer);
2192 2198
2193 if (type == L2CAP_IT_FEAT_MASK) { 2199 if (type == L2CAP_IT_FEAT_MASK) {
2194 conn->feat_mask = get_unaligned_le32(rsp->data); 2200 conn->feat_mask = get_unaligned_le32(rsp->data);
2195 2201
2202 if (conn->feat_mask & 0x0080) {
2203 struct l2cap_info_req req;
2204 req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
2205
2206 conn->info_ident = l2cap_get_ident(conn);
2207
2208 l2cap_send_cmd(conn, conn->info_ident,
2209 L2CAP_INFO_REQ, sizeof(req), &req);
2210 } else {
2211 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
2212 conn->info_ident = 0;
2213
2214 l2cap_conn_start(conn);
2215 }
2216 } else if (type == L2CAP_IT_FIXED_CHAN) {
2196 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; 2217 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
2218 conn->info_ident = 0;
2197 2219
2198 l2cap_conn_start(conn); 2220 l2cap_conn_start(conn);
2199 } 2221 }
@@ -2589,7 +2611,7 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
2589 goto drop; 2611 goto drop;
2590 2612
2591 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len), 2613 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
2592 skb->len); 2614 skb->len);
2593 conn->rx_len = len - skb->len; 2615 conn->rx_len = len - skb->len;
2594 } else { 2616 } else {
2595 BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len); 2617 BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
@@ -2611,7 +2633,7 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
2611 } 2633 }
2612 2634
2613 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len), 2635 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
2614 skb->len); 2636 skb->len);
2615 conn->rx_len -= skb->len; 2637 conn->rx_len -= skb->len;
2616 2638
2617 if (!conn->rx_len) { 2639 if (!conn->rx_len) {