aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/l2cap.c
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2008-07-14 14:13:44 -0400
committerMarcel Holtmann <marcel@holtmann.org>2008-07-14 14:13:44 -0400
commit79d554a6976a295aa9212172b218f29ca71c3b3d (patch)
tree430d106c1ebf194fcf208a145d32a2829ffca5a6 /net/bluetooth/l2cap.c
parentb7279469d66b55119784b8b9529c99c1955fe747 (diff)
[Bluetooth] Change retrieval of L2CAP features mask
Getting the remote L2CAP features mask is really important, but doing this as less intrusive as possible is tricky. To play nice with older systems and Bluetooth qualification testing, the features mask is now only retrieved in two specific cases and only once per lifetime of an ACL link. When trying to establish a L2CAP connection and the remote features mask is unknown, the L2CAP information request is sent when the ACL link goes into connected state. This applies only to outgoing connections and also only for the connection oriented channels. The second case is when a connection request has been received. In this case a connection response with the result pending and the information request will be send. After receiving an information response or if the timeout gets triggered, the normal connection setup process with security setup will be initiated. Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth/l2cap.c')
-rw-r--r--net/bluetooth/l2cap.c166
1 files changed, 118 insertions, 48 deletions
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 6e180d255505..2e3abdfbd69d 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -55,7 +55,7 @@
55#define BT_DBG(D...) 55#define BT_DBG(D...)
56#endif 56#endif
57 57
58#define VERSION "2.9" 58#define VERSION "2.10"
59 59
60static u32 l2cap_feat_mask = 0x0000; 60static u32 l2cap_feat_mask = 0x0000;
61 61
@@ -253,6 +253,21 @@ static void l2cap_chan_del(struct sock *sk, int err)
253 sk->sk_state_change(sk); 253 sk->sk_state_change(sk);
254} 254}
255 255
256/* Service level security */
257static inline int l2cap_check_link_mode(struct sock *sk)
258{
259 struct l2cap_conn *conn = l2cap_pi(sk)->conn;
260
261 if ((l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT) ||
262 (l2cap_pi(sk)->link_mode & L2CAP_LM_SECURE))
263 return hci_conn_encrypt(conn->hcon);
264
265 if (l2cap_pi(sk)->link_mode & L2CAP_LM_AUTH)
266 return hci_conn_auth(conn->hcon);
267
268 return 1;
269}
270
256static inline u8 l2cap_get_ident(struct l2cap_conn *conn) 271static inline u8 l2cap_get_ident(struct l2cap_conn *conn)
257{ 272{
258 u8 id; 273 u8 id;
@@ -287,6 +302,34 @@ static inline int l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16
287 return hci_send_acl(conn->hcon, skb, 0); 302 return hci_send_acl(conn->hcon, skb, 0);
288} 303}
289 304
305static void l2cap_do_start(struct sock *sk)
306{
307 struct l2cap_conn *conn = l2cap_pi(sk)->conn;
308
309 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
310 struct l2cap_conn_req req;
311 req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
312 req.psm = l2cap_pi(sk)->psm;
313
314 l2cap_pi(sk)->ident = l2cap_get_ident(conn);
315
316 l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
317 L2CAP_CONN_REQ, sizeof(req), &req);
318 } else {
319 struct l2cap_info_req req;
320 req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
321
322 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
323 conn->info_ident = l2cap_get_ident(conn);
324
325 mod_timer(&conn->info_timer, jiffies +
326 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
327
328 l2cap_send_cmd(conn, conn->info_ident,
329 L2CAP_INFO_REQ, sizeof(req), &req);
330 }
331}
332
290/* ---- L2CAP connections ---- */ 333/* ---- L2CAP connections ---- */
291static void l2cap_conn_start(struct l2cap_conn *conn) 334static void l2cap_conn_start(struct l2cap_conn *conn)
292{ 335{
@@ -301,16 +344,35 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
301 bh_lock_sock(sk); 344 bh_lock_sock(sk);
302 345
303 if (sk->sk_type != SOCK_SEQPACKET) { 346 if (sk->sk_type != SOCK_SEQPACKET) {
304 l2cap_sock_clear_timer(sk); 347 bh_unlock_sock(sk);
305 sk->sk_state = BT_CONNECTED; 348 continue;
306 sk->sk_state_change(sk); 349 }
307 } else if (sk->sk_state == BT_CONNECT) { 350
351 if (sk->sk_state == BT_CONNECT) {
308 struct l2cap_conn_req req; 352 struct l2cap_conn_req req;
309 l2cap_pi(sk)->ident = l2cap_get_ident(conn);
310 req.scid = cpu_to_le16(l2cap_pi(sk)->scid); 353 req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
311 req.psm = l2cap_pi(sk)->psm; 354 req.psm = l2cap_pi(sk)->psm;
355
356 l2cap_pi(sk)->ident = l2cap_get_ident(conn);
357
312 l2cap_send_cmd(conn, l2cap_pi(sk)->ident, 358 l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
313 L2CAP_CONN_REQ, sizeof(req), &req); 359 L2CAP_CONN_REQ, sizeof(req), &req);
360 } else if (sk->sk_state == BT_CONNECT2) {
361 struct l2cap_conn_rsp rsp;
362 rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid);
363 rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
364
365 if (l2cap_check_link_mode(sk)) {
366 sk->sk_state = BT_CONFIG;
367 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
368 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
369 } else {
370 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
371 rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
372 }
373
374 l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
375 L2CAP_CONN_RSP, sizeof(rsp), &rsp);
314 } 376 }
315 377
316 bh_unlock_sock(sk); 378 bh_unlock_sock(sk);
@@ -321,22 +383,27 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
321 383
322static void l2cap_conn_ready(struct l2cap_conn *conn) 384static void l2cap_conn_ready(struct l2cap_conn *conn)
323{ 385{
324 BT_DBG("conn %p", conn); 386 struct l2cap_chan_list *l = &conn->chan_list;
387 struct sock *sk;
325 388
326 if (conn->chan_list.head || !hlist_empty(&l2cap_sk_list.head)) { 389 BT_DBG("conn %p", conn);
327 struct l2cap_info_req req;
328 390
329 req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK); 391 read_lock(&l->lock);
330 392
331 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT; 393 for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
332 conn->info_ident = l2cap_get_ident(conn); 394 bh_lock_sock(sk);
333 395
334 mod_timer(&conn->info_timer, 396 if (sk->sk_type != SOCK_SEQPACKET) {
335 jiffies + msecs_to_jiffies(L2CAP_INFO_TIMEOUT)); 397 l2cap_sock_clear_timer(sk);
398 sk->sk_state = BT_CONNECTED;
399 sk->sk_state_change(sk);
400 } else if (sk->sk_state == BT_CONNECT)
401 l2cap_do_start(sk);
336 402
337 l2cap_send_cmd(conn, conn->info_ident, 403 bh_unlock_sock(sk);
338 L2CAP_INFO_REQ, sizeof(req), &req);
339 } 404 }
405
406 read_unlock(&l->lock);
340} 407}
341 408
342/* Notify sockets that we cannot guaranty reliability anymore */ 409/* Notify sockets that we cannot guaranty reliability anymore */
@@ -729,22 +796,11 @@ static int l2cap_do_connect(struct sock *sk)
729 l2cap_sock_set_timer(sk, sk->sk_sndtimeo); 796 l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
730 797
731 if (hcon->state == BT_CONNECTED) { 798 if (hcon->state == BT_CONNECTED) {
732 if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)) { 799 if (sk->sk_type != SOCK_SEQPACKET) {
733 l2cap_conn_ready(conn);
734 goto done;
735 }
736
737 if (sk->sk_type == SOCK_SEQPACKET) {
738 struct l2cap_conn_req req;
739 l2cap_pi(sk)->ident = l2cap_get_ident(conn);
740 req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
741 req.psm = l2cap_pi(sk)->psm;
742 l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
743 L2CAP_CONN_REQ, sizeof(req), &req);
744 } else {
745 l2cap_sock_clear_timer(sk); 800 l2cap_sock_clear_timer(sk);
746 sk->sk_state = BT_CONNECTED; 801 sk->sk_state = BT_CONNECTED;
747 } 802 } else
803 l2cap_do_start(sk);
748 } 804 }
749 805
750done: 806done:
@@ -1477,7 +1533,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
1477 struct l2cap_conn_req *req = (struct l2cap_conn_req *) data; 1533 struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
1478 struct l2cap_conn_rsp rsp; 1534 struct l2cap_conn_rsp rsp;
1479 struct sock *sk, *parent; 1535 struct sock *sk, *parent;
1480 int result = 0, status = 0; 1536 int result, status = 0;
1481 1537
1482 u16 dcid = 0, scid = __le16_to_cpu(req->scid); 1538 u16 dcid = 0, scid = __le16_to_cpu(req->scid);
1483 __le16 psm = req->psm; 1539 __le16 psm = req->psm;
@@ -1526,25 +1582,24 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
1526 1582
1527 l2cap_sock_set_timer(sk, sk->sk_sndtimeo); 1583 l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
1528 1584
1529 /* Service level security */
1530 result = L2CAP_CR_PEND;
1531 status = L2CAP_CS_AUTHEN_PEND;
1532 sk->sk_state = BT_CONNECT2;
1533 l2cap_pi(sk)->ident = cmd->ident; 1585 l2cap_pi(sk)->ident = cmd->ident;
1534 1586
1535 if ((l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT) || 1587 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
1536 (l2cap_pi(sk)->link_mode & L2CAP_LM_SECURE)) { 1588 if (l2cap_check_link_mode(sk)) {
1537 if (!hci_conn_encrypt(conn->hcon)) 1589 sk->sk_state = BT_CONFIG;
1538 goto done; 1590 result = L2CAP_CR_SUCCESS;
1539 } else if (l2cap_pi(sk)->link_mode & L2CAP_LM_AUTH) { 1591 status = L2CAP_CS_NO_INFO;
1540 if (!hci_conn_auth(conn->hcon)) 1592 } else {
1541 goto done; 1593 sk->sk_state = BT_CONNECT2;
1594 result = L2CAP_CR_PEND;
1595 status = L2CAP_CS_AUTHEN_PEND;
1596 }
1597 } else {
1598 sk->sk_state = BT_CONNECT2;
1599 result = L2CAP_CR_PEND;
1600 status = L2CAP_CS_NO_INFO;
1542 } 1601 }
1543 1602
1544 sk->sk_state = BT_CONFIG;
1545 result = status = 0;
1546
1547done:
1548 write_unlock_bh(&list->lock); 1603 write_unlock_bh(&list->lock);
1549 1604
1550response: 1605response:
@@ -1556,6 +1611,21 @@ sendresp:
1556 rsp.result = cpu_to_le16(result); 1611 rsp.result = cpu_to_le16(result);
1557 rsp.status = cpu_to_le16(status); 1612 rsp.status = cpu_to_le16(status);
1558 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp); 1613 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
1614
1615 if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) {
1616 struct l2cap_info_req info;
1617 info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
1618
1619 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
1620 conn->info_ident = l2cap_get_ident(conn);
1621
1622 mod_timer(&conn->info_timer, jiffies +
1623 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
1624
1625 l2cap_send_cmd(conn, conn->info_ident,
1626 L2CAP_INFO_REQ, sizeof(info), &info);
1627 }
1628
1559 return 0; 1629 return 0;
1560} 1630}
1561 1631
@@ -1664,9 +1734,9 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
1664 } 1734 }
1665 1735
1666 if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)) { 1736 if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)) {
1667 u8 req[64]; 1737 u8 buf[64];
1668 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, 1738 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
1669 l2cap_build_conf_req(sk, req), req); 1739 l2cap_build_conf_req(sk, buf), buf);
1670 } 1740 }
1671 1741
1672unlock: 1742unlock: