mISDN: L2 timeouts need to be queued as L2 event
authorKarsten Keil <isdn@linux-pingi.de>
Fri, 4 May 2012 04:15:32 +0000 (04:15 +0000)
committerDavid S. Miller <davem@davemloft.net>
Fri, 4 May 2012 15:54:27 +0000 (11:54 -0400)
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>
drivers/isdn/mISDN/layer2.c
drivers/isdn/mISDN/tei.c
include/linux/mISDNif.h

index 39d7375fa551ea60a6888232b8a05b4068dbd60b..b6fbaec1d61247434c096c9a0d14e472b537aef1 100644 (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",
index 109276a0d1a09eeba9a9c43f8b1321f3f5f73d96..be88728f110643dbaef2794b8ad64143a7224b08 100644 (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
index b5e7f22024848e956265426386b1f7999f87b7c5..b80f7648562ac73943d604c6d7212b2995dac498 100644 (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
 #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