aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/l2cap.c
diff options
context:
space:
mode:
authorGustavo F. Padovan <padovan@profusion.mobi>2010-06-07 19:54:45 -0400
committerMarcel Holtmann <marcel@holtmann.org>2010-07-21 13:39:09 -0400
commitcf6c2c0b9f47ee3cd12684b905725c8376d52135 (patch)
tree0564fbf6b00891c810d8b91dbdb33c3e97ce1ce4 /net/bluetooth/l2cap.c
parent2ba13ed678775195e8255b4e503c59d48b615bd8 (diff)
Bluetooth: Disconnect early if mode is not supported
When mode is mandatory we shall not send connect request and report this to the userspace as well. Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth/l2cap.c')
-rw-r--r--net/bluetooth/l2cap.c56
1 files changed, 40 insertions, 16 deletions
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 2fb45c481762..6a33d269389e 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -456,6 +456,22 @@ static void l2cap_do_start(struct sock *sk)
456 } 456 }
457} 457}
458 458
459static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
460{
461 u32 local_feat_mask = l2cap_feat_mask;
462 if (enable_ertm)
463 local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING;
464
465 switch (mode) {
466 case L2CAP_MODE_ERTM:
467 return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask;
468 case L2CAP_MODE_STREAMING:
469 return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask;
470 default:
471 return 0x00;
472 }
473}
474
459static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int err) 475static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int err)
460{ 476{
461 struct l2cap_disconn_req req; 477 struct l2cap_disconn_req req;
@@ -484,10 +500,13 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int
484static void l2cap_conn_start(struct l2cap_conn *conn) 500static void l2cap_conn_start(struct l2cap_conn *conn)
485{ 501{
486 struct l2cap_chan_list *l = &conn->chan_list; 502 struct l2cap_chan_list *l = &conn->chan_list;
503 struct sock_del_list del, *tmp1, *tmp2;
487 struct sock *sk; 504 struct sock *sk;
488 505
489 BT_DBG("conn %p", conn); 506 BT_DBG("conn %p", conn);
490 507
508 INIT_LIST_HEAD(&del.list);
509
491 read_lock(&l->lock); 510 read_lock(&l->lock);
492 511
493 for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { 512 for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
@@ -503,6 +522,19 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
503 if (l2cap_check_security(sk) && 522 if (l2cap_check_security(sk) &&
504 __l2cap_no_conn_pending(sk)) { 523 __l2cap_no_conn_pending(sk)) {
505 struct l2cap_conn_req req; 524 struct l2cap_conn_req req;
525
526 if (!l2cap_mode_supported(l2cap_pi(sk)->mode,
527 conn->feat_mask)
528 && l2cap_pi(sk)->conf_state &
529 L2CAP_CONF_STATE2_DEVICE) {
530 tmp1 = kzalloc(sizeof(struct srej_list),
531 GFP_ATOMIC);
532 tmp1->sk = sk;
533 list_add_tail(&tmp1->list, &del.list);
534 bh_unlock_sock(sk);
535 continue;
536 }
537
506 req.scid = cpu_to_le16(l2cap_pi(sk)->scid); 538 req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
507 req.psm = l2cap_pi(sk)->psm; 539 req.psm = l2cap_pi(sk)->psm;
508 540
@@ -542,6 +574,14 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
542 } 574 }
543 575
544 read_unlock(&l->lock); 576 read_unlock(&l->lock);
577
578 list_for_each_entry_safe(tmp1, tmp2, &del.list, list) {
579 bh_lock_sock(tmp1->sk);
580 __l2cap_sock_close(tmp1->sk, ECONNRESET);
581 bh_unlock_sock(tmp1->sk);
582 list_del(&tmp1->list);
583 kfree(tmp1);
584 }
545} 585}
546 586
547static void l2cap_conn_ready(struct l2cap_conn *conn) 587static void l2cap_conn_ready(struct l2cap_conn *conn)
@@ -2429,22 +2469,6 @@ static inline void l2cap_ertm_init(struct sock *sk)
2429 INIT_WORK(&l2cap_pi(sk)->busy_work, l2cap_busy_work); 2469 INIT_WORK(&l2cap_pi(sk)->busy_work, l2cap_busy_work);
2430} 2470}
2431 2471
2432static int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
2433{
2434 u32 local_feat_mask = l2cap_feat_mask;
2435 if (enable_ertm)
2436 local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING;
2437
2438 switch (mode) {
2439 case L2CAP_MODE_ERTM:
2440 return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask;
2441 case L2CAP_MODE_STREAMING:
2442 return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask;
2443 default:
2444 return 0x00;
2445 }
2446}
2447
2448static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask) 2472static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
2449{ 2473{
2450 switch (mode) { 2474 switch (mode) {