diff options
author | Marcel Holtmann <marcel@holtmann.org> | 2009-02-09 03:18:02 -0500 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2009-02-27 00:14:42 -0500 |
commit | e1027a7c69700301d14db03d2e049ee60c4f92df (patch) | |
tree | d2dc9bc993deec30c8e9a797592458286e89e31b /net/bluetooth | |
parent | 435fef20acfc48f46476abad55b0cd3aa47b8365 (diff) |
Bluetooth: Request L2CAP fixed channel list if available
If the extended features mask indicates support for fixed channels,
request the list of available fixed channels. This also enables the
fixed channel features bit so remote implementations can request
information about it. Currently only the signal channel will be
listed.
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
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) { |