Fix dangling callout problem in the Bluetooth L2CAP code that leads to

panic. The panic happens when outgoing L2CAP connection descriptor is
deleted with the L2CAP command(s) pending in the queue. In this case when
the last L2CAP command is deleted (due to cleanup) and reference counter
for the L2CAP connection goes down to zero the auto disconnect timeout
is incorrectly set. pjd gets credit for tracking this down and committing
bandaid.

Reported by:	Jonatan B <onatan at gmail dot com>
MFC after:	3 days
This commit is contained in:
Maksim Yevmenkin 2005-08-31 18:13:23 +00:00
parent 7b7b9810bd
commit 82e1becc5f
3 changed files with 14 additions and 5 deletions

View File

@ -623,6 +623,7 @@ typedef struct {
#define NG_L2CAP_CON_OUTGOING (1 << 2) /* outgoing connection */
#define NG_L2CAP_CON_LP_TIMO (1 << 3) /* LP timeout */
#define NG_L2CAP_CON_AUTO_DISCON_TIMO (1 << 4) /* auto discon. timeout */
#define NG_L2CAP_CON_DYING (1 << 5) /* connection is dying */
typedef struct {
u_int8_t state; /* connection state */

View File

@ -226,6 +226,9 @@ ng_l2cap_con_fail(ng_l2cap_con_p con, u_int16_t result)
"%s: %s - ACL connection failed, result=%d\n",
__func__, NG_NODE_NAME(l2cap->node), result);
/* Connection is dying */
con->flags |= NG_L2CAP_CON_DYING;
/* Clean command queue */
while (!TAILQ_EMPTY(&con->cmd_list)) {
cmd = TAILQ_FIRST(&con->cmd_list);

View File

@ -182,12 +182,14 @@ ng_l2cap_con_unref(ng_l2cap_con_p con)
* 2) connection is in OPEN state
* 3) it is an outgoing connection
* 4) disconnect timeout > 0
* 5) connection is not dying
*/
if ((con->refcnt == 0) &&
(con->state == NG_L2CAP_CON_OPEN) &&
(con->flags & NG_L2CAP_CON_OUTGOING) &&
(con->l2cap->discon_timo > 0))
(con->l2cap->discon_timo > 0) &&
((con->flags & NG_L2CAP_CON_DYING) == 0))
ng_l2cap_discon_timeout(con);
} /* ng_l2cap_con_unref */
@ -273,11 +275,14 @@ ng_l2cap_free_con(ng_l2cap_con_p con)
ng_l2cap_free_cmd(cmd);
}
if (con->flags & (NG_L2CAP_CON_AUTO_DISCON_TIMO|NG_L2CAP_CON_LP_TIMO))
panic(
"%s: %s - timeout pending! state=%d, flags=%#x\n",
__func__, NG_NODE_NAME(con->l2cap->node),
con->state, con->flags);
LIST_REMOVE(con, next);
if (con->flags & NG_L2CAP_CON_AUTO_DISCON_TIMO)
ng_l2cap_discon_untimeout(con);
if (con->flags & NG_L2CAP_CON_LP_TIMO)
ng_l2cap_lp_untimeout(con);
bzero(con, sizeof(*con));
FREE(con, M_NETGRAPH_L2CAP);
} /* ng_l2cap_free_con */