aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/bluetooth/l2cap.h1
-rw-r--r--net/bluetooth/l2cap_core.c12
-rw-r--r--net/bluetooth/l2cap_sock.c8
3 files changed, 19 insertions, 2 deletions
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index cedda399f9c0..1558eccb19db 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -711,6 +711,7 @@ enum {
711 FLAG_DEFER_SETUP, 711 FLAG_DEFER_SETUP,
712 FLAG_LE_CONN_REQ_SENT, 712 FLAG_LE_CONN_REQ_SENT,
713 FLAG_PENDING_SECURITY, 713 FLAG_PENDING_SECURITY,
714 FLAG_HOLD_HCI_CONN,
714}; 715};
715 716
716enum { 717enum {
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 777c41dbfdbe..a6559225bb50 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -546,7 +546,10 @@ void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
546 546
547 l2cap_chan_hold(chan); 547 l2cap_chan_hold(chan);
548 548
549 hci_conn_hold(conn->hcon); 549 /* Only keep a reference for fixed channels if they requested it */
550 if (chan->chan_type != L2CAP_CHAN_FIXED ||
551 test_bit(FLAG_HOLD_HCI_CONN, &chan->flags))
552 hci_conn_hold(conn->hcon);
550 553
551 list_add(&chan->list, &conn->chan_l); 554 list_add(&chan->list, &conn->chan_l);
552} 555}
@@ -577,7 +580,12 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
577 580
578 chan->conn = NULL; 581 chan->conn = NULL;
579 582
580 if (chan->scid != L2CAP_CID_A2MP) 583 /* Reference was only held for non-fixed channels or
584 * fixed channels that explicitly requested it using the
585 * FLAG_HOLD_HCI_CONN flag.
586 */
587 if (chan->chan_type != L2CAP_CHAN_FIXED ||
588 test_bit(FLAG_HOLD_HCI_CONN, &chan->flags))
581 hci_conn_drop(conn->hcon); 589 hci_conn_drop(conn->hcon);
582 590
583 if (mgr && mgr->bredr_chan == chan) 591 if (mgr && mgr->bredr_chan == chan)
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index ed06f88e6f10..31f106e61ca2 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -146,6 +146,14 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
146 case L2CAP_CHAN_RAW: 146 case L2CAP_CHAN_RAW:
147 chan->sec_level = BT_SECURITY_SDP; 147 chan->sec_level = BT_SECURITY_SDP;
148 break; 148 break;
149 case L2CAP_CHAN_FIXED:
150 /* Fixed channels default to the L2CAP core not holding a
151 * hci_conn reference for them. For fixed channels mapping to
152 * L2CAP sockets we do want to hold a reference so set the
153 * appropriate flag to request it.
154 */
155 set_bit(FLAG_HOLD_HCI_CONN, &chan->flags);
156 break;
149 } 157 }
150 158
151 bacpy(&chan->src, &la.l2_bdaddr); 159 bacpy(&chan->src, &la.l2_bdaddr);