Commit 08c30aca authored by Dean Jenkins's avatar Dean Jenkins Committed by Gustavo Padovan

Bluetooth: Remove RFCOMM session refcnt

Previous commits have improved the handling of the RFCOMM session
timer and the RFCOMM session pointers such that freed RFCOMM
session structures should no longer be erroneously accessed. The
RFCOMM session refcnt now has no purpose and will be deleted by
this commit.

Note that the RFCOMM session is now deleted as soon as the
RFCOMM control channel link is no longer required. This makes the
lifetime of the RFCOMM session deterministic and absolute.
Previously with the refcnt, there was uncertainty about when
the session structure would be deleted because the relative
refcnt prevented the session structure from being deleted at will.

It was noted that the refcnt could malfunction under very heavy
real-time processor loading in embedded SMP environments. This
could cause premature RFCOMM session deletion or double session
deletion that could result in kernel crashes. Removal of the
refcnt prevents this issue.

There are 4 connection / disconnection RFCOMM session scenarios:
host initiated control link ---> host disconnected control link
host initiated ctrl link ---> remote device disconnected ctrl link
remote device initiated ctrl link ---> host disconnected ctrl link
remote device initiated ctrl link ---> remote device disc'ed ctrl link

The control channel connection procedures are independent of the
disconnection procedures. Strangely, the RFCOMM session refcnt was
applying special treatment so erroneously combining connection and
disconnection events. This commit fixes this issue by removing
some session code that used the "initiator" member of the session
structure that was intended for use with the data channels.
Signed-off-by: default avatarDean Jenkins <Dean_Jenkins@mentor.com>
Acked-by: default avatarMarcel Holtmann <marcel@holtmann.org>
Signed-off-by: default avatarGustavo Padovan <gustavo.padovan@collabora.co.uk>
parent 8ff52f7d
...@@ -158,7 +158,6 @@ struct rfcomm_session { ...@@ -158,7 +158,6 @@ struct rfcomm_session {
struct timer_list timer; struct timer_list timer;
unsigned long state; unsigned long state;
unsigned long flags; unsigned long flags;
atomic_t refcnt;
int initiator; int initiator;
/* Default DLC parameters */ /* Default DLC parameters */
...@@ -276,12 +275,6 @@ static inline void rfcomm_dlc_unthrottle(struct rfcomm_dlc *d) ...@@ -276,12 +275,6 @@ static inline void rfcomm_dlc_unthrottle(struct rfcomm_dlc *d)
void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src,
bdaddr_t *dst); bdaddr_t *dst);
static inline void rfcomm_session_hold(struct rfcomm_session *s)
{
if (s)
atomic_inc(&s->refcnt);
}
/* ---- RFCOMM sockets ---- */ /* ---- RFCOMM sockets ---- */
struct sockaddr_rc { struct sockaddr_rc {
sa_family_t rc_family; sa_family_t rc_family;
......
...@@ -108,14 +108,6 @@ static void rfcomm_schedule(void) ...@@ -108,14 +108,6 @@ static void rfcomm_schedule(void)
wake_up_process(rfcomm_thread); wake_up_process(rfcomm_thread);
} }
static struct rfcomm_session *rfcomm_session_put(struct rfcomm_session *s)
{
if (s && atomic_dec_and_test(&s->refcnt))
s = rfcomm_session_del(s);
return s;
}
/* ---- RFCOMM FCS computation ---- */ /* ---- RFCOMM FCS computation ---- */
/* reversed, 8-bit, poly=0x07 */ /* reversed, 8-bit, poly=0x07 */
...@@ -251,16 +243,14 @@ static void rfcomm_session_set_timer(struct rfcomm_session *s, long timeout) ...@@ -251,16 +243,14 @@ static void rfcomm_session_set_timer(struct rfcomm_session *s, long timeout)
{ {
BT_DBG("session %p state %ld timeout %ld", s, s->state, timeout); BT_DBG("session %p state %ld timeout %ld", s, s->state, timeout);
if (!mod_timer(&s->timer, jiffies + timeout)) mod_timer(&s->timer, jiffies + timeout);
rfcomm_session_hold(s);
} }
static void rfcomm_session_clear_timer(struct rfcomm_session *s) static void rfcomm_session_clear_timer(struct rfcomm_session *s)
{ {
BT_DBG("session %p state %ld", s, s->state); BT_DBG("session %p state %ld", s, s->state);
if (del_timer_sync(&s->timer)) del_timer_sync(&s->timer);
rfcomm_session_put(s);
} }
/* ---- RFCOMM DLCs ---- */ /* ---- RFCOMM DLCs ---- */
...@@ -338,8 +328,6 @@ static void rfcomm_dlc_link(struct rfcomm_session *s, struct rfcomm_dlc *d) ...@@ -338,8 +328,6 @@ static void rfcomm_dlc_link(struct rfcomm_session *s, struct rfcomm_dlc *d)
{ {
BT_DBG("dlc %p session %p", d, s); BT_DBG("dlc %p session %p", d, s);
rfcomm_session_hold(s);
rfcomm_session_clear_timer(s); rfcomm_session_clear_timer(s);
rfcomm_dlc_hold(d); rfcomm_dlc_hold(d);
list_add(&d->list, &s->dlcs); list_add(&d->list, &s->dlcs);
...@@ -358,8 +346,6 @@ static void rfcomm_dlc_unlink(struct rfcomm_dlc *d) ...@@ -358,8 +346,6 @@ static void rfcomm_dlc_unlink(struct rfcomm_dlc *d)
if (list_empty(&s->dlcs)) if (list_empty(&s->dlcs))
rfcomm_session_set_timer(s, RFCOMM_IDLE_TIMEOUT); rfcomm_session_set_timer(s, RFCOMM_IDLE_TIMEOUT);
rfcomm_session_put(s);
} }
static struct rfcomm_dlc *rfcomm_dlc_get(struct rfcomm_session *s, u8 dlci) static struct rfcomm_dlc *rfcomm_dlc_get(struct rfcomm_session *s, u8 dlci)
...@@ -678,8 +664,6 @@ static struct rfcomm_session *rfcomm_session_close(struct rfcomm_session *s, ...@@ -678,8 +664,6 @@ static struct rfcomm_session *rfcomm_session_close(struct rfcomm_session *s,
BT_DBG("session %p state %ld err %d", s, s->state, err); BT_DBG("session %p state %ld err %d", s, s->state, err);
rfcomm_session_hold(s);
s->state = BT_CLOSED; s->state = BT_CLOSED;
/* Close all dlcs */ /* Close all dlcs */
...@@ -690,7 +674,7 @@ static struct rfcomm_session *rfcomm_session_close(struct rfcomm_session *s, ...@@ -690,7 +674,7 @@ static struct rfcomm_session *rfcomm_session_close(struct rfcomm_session *s,
} }
rfcomm_session_clear_timer(s); rfcomm_session_clear_timer(s);
return rfcomm_session_put(s); return rfcomm_session_del(s);
} }
static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src,
...@@ -1884,13 +1868,8 @@ static struct rfcomm_session *rfcomm_process_rx(struct rfcomm_session *s) ...@@ -1884,13 +1868,8 @@ static struct rfcomm_session *rfcomm_process_rx(struct rfcomm_session *s)
kfree_skb(skb); kfree_skb(skb);
} }
if (s && (sk->sk_state == BT_CLOSED)) { if (s && (sk->sk_state == BT_CLOSED))
if (!s->initiator)
s = rfcomm_session_put(s);
if (s)
s = rfcomm_session_close(s, sk->sk_err); s = rfcomm_session_close(s, sk->sk_err);
}
return s; return s;
} }
...@@ -1917,8 +1896,6 @@ static void rfcomm_accept_connection(struct rfcomm_session *s) ...@@ -1917,8 +1896,6 @@ static void rfcomm_accept_connection(struct rfcomm_session *s)
s = rfcomm_session_add(nsock, BT_OPEN); s = rfcomm_session_add(nsock, BT_OPEN);
if (s) { if (s) {
rfcomm_session_hold(s);
/* We should adjust MTU on incoming sessions. /* We should adjust MTU on incoming sessions.
* L2CAP MTU minus UIH header and FCS. */ * L2CAP MTU minus UIH header and FCS. */
s->mtu = min(l2cap_pi(nsock->sk)->chan->omtu, s->mtu = min(l2cap_pi(nsock->sk)->chan->omtu,
...@@ -1967,7 +1944,6 @@ static void rfcomm_process_sessions(void) ...@@ -1967,7 +1944,6 @@ static void rfcomm_process_sessions(void)
if (test_and_clear_bit(RFCOMM_TIMED_OUT, &s->flags)) { if (test_and_clear_bit(RFCOMM_TIMED_OUT, &s->flags)) {
s->state = BT_DISCONN; s->state = BT_DISCONN;
rfcomm_send_disc(s, 0); rfcomm_send_disc(s, 0);
rfcomm_session_put(s);
continue; continue;
} }
...@@ -1976,8 +1952,6 @@ static void rfcomm_process_sessions(void) ...@@ -1976,8 +1952,6 @@ static void rfcomm_process_sessions(void)
continue; continue;
} }
rfcomm_session_hold(s);
switch (s->state) { switch (s->state) {
case BT_BOUND: case BT_BOUND:
s = rfcomm_check_connection(s); s = rfcomm_check_connection(s);
...@@ -1990,8 +1964,6 @@ static void rfcomm_process_sessions(void) ...@@ -1990,8 +1964,6 @@ static void rfcomm_process_sessions(void)
if (s) if (s)
rfcomm_process_dlcs(s); rfcomm_process_dlcs(s);
rfcomm_session_put(s);
} }
rfcomm_unlock(); rfcomm_unlock();
...@@ -2041,7 +2013,6 @@ static int rfcomm_add_listener(bdaddr_t *ba) ...@@ -2041,7 +2013,6 @@ static int rfcomm_add_listener(bdaddr_t *ba)
if (!s) if (!s)
goto failed; goto failed;
rfcomm_session_hold(s);
return 0; return 0;
failed: failed:
sock_release(sock); sock_release(sock);
...@@ -2099,8 +2070,6 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt) ...@@ -2099,8 +2070,6 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
if (!s) if (!s)
return; return;
rfcomm_session_hold(s);
list_for_each_safe(p, n, &s->dlcs) { list_for_each_safe(p, n, &s->dlcs) {
d = list_entry(p, struct rfcomm_dlc, list); d = list_entry(p, struct rfcomm_dlc, list);
...@@ -2132,8 +2101,6 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt) ...@@ -2132,8 +2101,6 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
set_bit(RFCOMM_AUTH_REJECT, &d->flags); set_bit(RFCOMM_AUTH_REJECT, &d->flags);
} }
rfcomm_session_put(s);
rfcomm_schedule(); rfcomm_schedule();
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment