aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/l2cap.c
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2009-02-09 03:18:02 -0500
committerMarcel Holtmann <marcel@holtmann.org>2009-02-27 00:14:42 -0500
commite1027a7c69700301d14db03d2e049ee60c4f92df (patch)
treed2dc9bc993deec30c8e9a797592458286e89e31b /net/bluetooth/l2cap.c
parent435fef20acfc48f46476abad55b0cd3aa47b8365 (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/l2cap.c')
-rw-r--r--net/bluetooth/l2cap.c40
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
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) {