diff options
Diffstat (limited to 'net/bluetooth')
-rw-r--r-- | net/bluetooth/l2cap.c | 40 |
1 files changed, 31 insertions, 9 deletions
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 | ||
55 | static u32 l2cap_feat_mask = 0x0000; | 55 | static u32 l2cap_feat_mask = 0x0080; |
56 | static u8 l2cap_fixed_chan[8] = { 0x02, }; | ||
56 | 57 | ||
57 | static const struct proto_ops l2cap_sock_ops; | 58 | static 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) { |