Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8423e6b2 authored by Karsten Keil's avatar Karsten Keil Committed by David S. Miller
Browse files

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: default avatarKarsten Keil <kkeil@linux-pingi.de>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 7ed80fe4
Loading
Loading
Loading
Loading
+53 −5
Original line number Diff line number Diff line
@@ -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",
+10 −3
Original line number Diff line number Diff line
@@ -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
+6 −1
Original line number Diff line number Diff line
@@ -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