|
@@ -244,6 +244,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 +347,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 +363,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_IDLE_TIMEOUT);
|
|
|
+
|
|
|
rfcomm_session_put(s);
|
|
|
}
|
|
|
|
|
@@ -567,6 +598,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;
|
|
@@ -598,6 +631,7 @@ static void rfcomm_session_del(struct rfcomm_session *s)
|
|
|
if (state == BT_CONNECTED)
|
|
|
rfcomm_send_disc(s, 0);
|
|
|
|
|
|
+ rfcomm_session_clear_timer(s);
|
|
|
sock_release(s->sock);
|
|
|
kfree(s);
|
|
|
|
|
@@ -639,6 +673,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);
|
|
|
}
|
|
|
|
|
@@ -1879,6 +1914,12 @@ static inline void rfcomm_process_sessions(void)
|
|
|
struct rfcomm_session *s;
|
|
|
s = list_entry(p, struct rfcomm_session, list);
|
|
|
|
|
|
+ if (test_and_clear_bit(RFCOMM_TIMED_OUT, &s->flags)) {
|
|
|
+ s->state = BT_DISCONN;
|
|
|
+ rfcomm_send_disc(s, 0);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
if (s->state == BT_LISTEN) {
|
|
|
rfcomm_accept_connection(s);
|
|
|
continue;
|