mISDN: L2 timeouts need to be queued as L2 event

To be full preemptiv safe, we cannot handle a L2 timeout in the timer
context itself, we should do all actions via the D-channel thread.

Signed-off-by: Karsten Keil <kkeil@linux-pingi.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Karsten Keil 2012-05-04 04:15:32 +00:00 committed by David S. Miller
parent 7ed80fe45d
commit 8423e6b212
3 changed files with 69 additions and 9 deletions

View File

@ -58,6 +58,8 @@ enum {
EV_L1_DEACTIVATE,
EV_L2_T200,
EV_L2_T203,
EV_L2_T200I,
EV_L2_T203I,
EV_L2_SET_OWN_BUSY,
EV_L2_CLEAR_OWN_BUSY,
EV_L2_FRAME_ERROR,
@ -86,6 +88,8 @@ static char *strL2Event[] =
"EV_L1_DEACTIVATE",
"EV_L2_T200",
"EV_L2_T203",
"EV_L2_T200I",
"EV_L2_T203I",
"EV_L2_SET_OWN_BUSY",
"EV_L2_CLEAR_OWN_BUSY",
"EV_L2_FRAME_ERROR",
@ -276,6 +280,31 @@ ph_data_confirm(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb) {
return ret;
}
static void
l2_timeout(struct FsmInst *fi, int event, void *arg)
{
struct layer2 *l2 = fi->userdata;
struct sk_buff *skb;
struct mISDNhead *hh;
skb = mI_alloc_skb(0, GFP_ATOMIC);
if (!skb) {
printk(KERN_WARNING "L2(%d,%d) nr:%x timer %s lost - no skb\n",
l2->sapi, l2->tei, l2->ch.nr, event == EV_L2_T200 ?
"T200" : "T203");
return;
}
hh = mISDN_HEAD_P(skb);
hh->prim = event == EV_L2_T200 ? DL_TIMER200_IND : DL_TIMER203_IND;
hh->id = l2->ch.nr;
if (*debug & DEBUG_TIMER)
printk(KERN_DEBUG "L2(%d,%d) nr:%x timer %s expired\n",
l2->sapi, l2->tei, l2->ch.nr, event == EV_L2_T200 ?
"T200" : "T203");
if (l2->ch.st)
l2->ch.st->own.recv(&l2->ch.st->own, skb);
}
static int
l2mgr(struct layer2 *l2, u_int prim, void *arg) {
long c = (long)arg;
@ -1814,11 +1843,16 @@ static struct FsmNode L2FnList[] =
{ST_L2_8, EV_L2_SUPER, l2_st8_got_super},
{ST_L2_7, EV_L2_I, l2_got_iframe},
{ST_L2_8, EV_L2_I, l2_got_iframe},
{ST_L2_5, EV_L2_T200, l2_st5_tout_200},
{ST_L2_6, EV_L2_T200, l2_st6_tout_200},
{ST_L2_7, EV_L2_T200, l2_st7_tout_200},
{ST_L2_8, EV_L2_T200, l2_st8_tout_200},
{ST_L2_7, EV_L2_T203, l2_st7_tout_203},
{ST_L2_5, EV_L2_T200, l2_timeout},
{ST_L2_6, EV_L2_T200, l2_timeout},
{ST_L2_7, EV_L2_T200, l2_timeout},
{ST_L2_8, EV_L2_T200, l2_timeout},
{ST_L2_7, EV_L2_T203, l2_timeout},
{ST_L2_5, EV_L2_T200I, l2_st5_tout_200},
{ST_L2_6, EV_L2_T200I, l2_st6_tout_200},
{ST_L2_7, EV_L2_T200I, l2_st7_tout_200},
{ST_L2_8, EV_L2_T200I, l2_st8_tout_200},
{ST_L2_7, EV_L2_T203I, l2_st7_tout_203},
{ST_L2_7, EV_L2_ACK_PULL, l2_pull_iqueue},
{ST_L2_7, EV_L2_SET_OWN_BUSY, l2_set_own_busy},
{ST_L2_8, EV_L2_SET_OWN_BUSY, l2_set_own_busy},
@ -1932,6 +1966,14 @@ l2_send(struct mISDNchannel *ch, struct sk_buff *skb)
if (*debug & DEBUG_L2_RECV)
printk(KERN_DEBUG "%s: prim(%x) id(%x) sapi(%d) tei(%d)\n",
__func__, hh->prim, hh->id, l2->sapi, l2->tei);
if (hh->prim == DL_INTERN_MSG) {
struct mISDNhead *chh = hh + 1; /* saved copy */
*hh = *chh;
if (*debug & DEBUG_L2_RECV)
printk(KERN_DEBUG "%s: prim(%x) id(%x) internal msg\n",
__func__, hh->prim, hh->id);
}
switch (hh->prim) {
case PH_DATA_IND:
ret = ph_data_indication(l2, hh, skb);
@ -1987,6 +2029,12 @@ l2_send(struct mISDNchannel *ch, struct sk_buff *skb)
ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DL_RELEASE_REQ,
skb);
break;
case DL_TIMER200_IND:
mISDN_FsmEvent(&l2->l2m, EV_L2_T200I, NULL);
break;
case DL_TIMER203_IND:
mISDN_FsmEvent(&l2->l2m, EV_L2_T203I, NULL);
break;
default:
if (*debug & DEBUG_L2)
l2m_debug(&l2->l2m, "l2 unknown pr %04x",

View File

@ -1294,7 +1294,7 @@ static int
mgr_bcast(struct mISDNchannel *ch, struct sk_buff *skb)
{
struct manager *mgr = container_of(ch, struct manager, bcast);
struct mISDNhead *hh = mISDN_HEAD_P(skb);
struct mISDNhead *hhc, *hh = mISDN_HEAD_P(skb);
struct sk_buff *cskb = NULL;
struct layer2 *l2;
u_long flags;
@ -1309,10 +1309,17 @@ mgr_bcast(struct mISDNchannel *ch, struct sk_buff *skb)
skb = NULL;
} else {
if (!cskb)
cskb = skb_copy(skb, GFP_KERNEL);
cskb = skb_copy(skb, GFP_ATOMIC);
}
if (cskb) {
ret = l2->ch.send(&l2->ch, cskb);
hhc = mISDN_HEAD_P(cskb);
/* save original header behind normal header */
hhc++;
*hhc = *hh;
hhc--;
hhc->prim = DL_INTERN_MSG;
hhc->id = l2->ch.nr;
ret = ch->st->own.recv(&ch->st->own, cskb);
if (ret) {
if (*debug & DEBUG_SEND_ERR)
printk(KERN_DEBUG

View File

@ -37,7 +37,7 @@
*/
#define MISDN_MAJOR_VERSION 1
#define MISDN_MINOR_VERSION 1
#define MISDN_RELEASE 21
#define MISDN_RELEASE 26
/* primitives for information exchange
* generell format
@ -115,6 +115,11 @@
#define MDL_ERROR_IND 0x1F04
#define MDL_ERROR_RSP 0x5F04
/* intern layer 2 */
#define DL_TIMER200_IND 0x7004
#define DL_TIMER203_IND 0x7304
#define DL_INTERN_MSG 0x7804
/* DL_INFORMATION_IND types */
#define DL_INFO_L2_CONNECT 0x0001
#define DL_INFO_L2_REMOVED 0x0002