Hi Marcel, On Sun, Jun 21, 2009 at 4:04 PM, Marcel Holtmann<marcel@xxxxxxxxxxxx> wrote: > stupid specification. It is just bloody stupid that we have to cleanup > someone else's stuff that we haven't initiated in the first place :( > > diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c > index 374536e..864c3c4 100644 > --- a/net/bluetooth/rfcomm/core.c > +++ b/net/bluetooth/rfcomm/core.c > @@ -466,6 +466,11 @@ static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err) > > skb_queue_purge(&d->tx_queue); > rfcomm_dlc_unlink(d); > + > + /* Specification demands to cleanup after remote > + * initiated session when closing last DLC */ > + if (list_empty(&s->dlcs)) > + rfcomm_session_put(s); > } As your patch seems to trigger DISC 0 in both sides when the remote stack cope with DM I would suggest introducing a timer_list to rfcomm_session so we can give some time to remote stack to take down dlci 0 clean it up otherwise. @@ -244,6 +246,33 @@ static inline int rfcomm_check_security(struct rfcomm_dlc *d) auth_type); } +static void rfcomm_session_timeout(unsigned long arg) +{ + struct rfcomm_session *s = (void *) arg; + + BT_DBG("session %p state %ld", s, s->state); + + set_bit(RFCOMM_TIMED_OUT, &s->flags); + rfcomm_session_put(s); + rfcomm_schedule(RFCOMM_SCHED_TIMEO); +} + +static void rfcomm_session_set_timer(struct rfcomm_session *s, long timeout) +{ + BT_DBG("session %p state %ld timeout %ld", s, s->state, timeout); + + if (!mod_timer(&s->timer, jiffies + timeout)) + rfcomm_session_hold(s); +} + +static void rfcomm_session_clear_timer(struct rfcomm_session *s) +{ + BT_DBG("session %p state %ld", s, s->state); + + if (timer_pending(&s->timer) && del_timer(&s->timer)) + rfcomm_session_put(s); +} + /* ---- RFCOMM DLCs ---- */ static void rfcomm_dlc_timeout(unsigned long arg) { @@ -320,6 +349,7 @@ static void rfcomm_dlc_link(struct rfcomm_session *s, struct rfcomm_dlc *d) rfcomm_session_hold(s); + rfcomm_session_clear_timer(s); rfcomm_dlc_hold(d); list_add(&d->list, &s->dlcs); d->session = s; @@ -335,6 +365,9 @@ static void rfcomm_dlc_unlink(struct rfcomm_dlc *d) d->session = NULL; rfcomm_dlc_put(d); + if (list_empty(&s->dlcs)) + rfcomm_session_set_timer(s, RFCOMM_DISC_TIMEOUT); + rfcomm_session_put(s); } @@ -454,6 +487,7 @@ static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err) rfcomm_schedule(RFCOMM_SCHED_AUTH); break; } + /* Fall through */ default: @@ -567,6 +601,8 @@ static struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state) BT_DBG("session %p sock %p", s, sock); + setup_timer(&s->timer, rfcomm_session_timeout, (unsigned long)s); + INIT_LIST_HEAD(&s->dlcs); s->state = state; s->sock = sock; @@ -639,6 +675,7 @@ static void rfcomm_session_close(struct rfcomm_session *s, int err) __rfcomm_dlc_close(d, err); } + rfcomm_session_clear_timer(s); rfcomm_session_put(s); } @@ -1774,6 +1811,7 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s) rfcomm_send_dm(s, d->dlci); else d->state = BT_CLOSED; + __rfcomm_dlc_close(d, ECONNREFUSED); continue; } @@ -1879,6 +1917,11 @@ static inline void rfcomm_process_sessions(void) struct rfcomm_session *s; s = list_entry(p, struct rfcomm_session, list); + if (test_bit(RFCOMM_TIMED_OUT, &s->flags)) { + rfcomm_session_put(s); + continue; + } + if (s->state == BT_LISTEN) { rfcomm_accept_connection(s); continue; -- Luiz Augusto von Dentz Engenheiro de Computação -- To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html