11b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil/*
21b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil *
31b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil * Author	Karsten Keil <kkeil@novell.com>
41b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil *
51b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil * Copyright 2008  by Karsten Keil <kkeil@novell.com>
61b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil *
71b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil * This program is free software; you can redistribute it and/or modify
81b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil * it under the terms of the GNU General Public License version 2 as
91b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil * published by the Free Software Foundation.
101b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil *
111b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil * This program is distributed in the hope that it will be useful,
121b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil * but WITHOUT ANY WARRANTY; without even the implied warranty of
131b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
141b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil * GNU General Public License for more details.
151b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil *
161b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil */
171b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
185a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
191b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil#include <linux/mISDNif.h>
201b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil#include <linux/kthread.h>
211b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil#include "core.h"
221b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
231b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic u_int	*debug;
241b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
251b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic inline void
261b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil_queue_message(struct mISDNstack *st, struct sk_buff *skb)
271b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
281b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct mISDNhead	*hh = mISDN_HEAD_P(skb);
291b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
301b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (*debug & DEBUG_QUEUE_FUNC)
311b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		printk(KERN_DEBUG "%s prim(%x) id(%x) %p\n",
32475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       __func__, hh->prim, hh->id, skb);
331b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	skb_queue_tail(&st->msgq, skb);
341b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (likely(!test_bit(mISDN_STACK_STOPPED, &st->status))) {
351b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		test_and_set_bit(mISDN_STACK_WORK, &st->status);
361b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		wake_up_interruptible(&st->workq);
371b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
381b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
391b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
405b8343540a3d27f87a4d9d72bb39b7d4cc3dd95eHannes Ederstatic int
411b2b03f8e514e4f68e293846ba511a948b80243cKarsten KeilmISDN_queue_message(struct mISDNchannel *ch, struct sk_buff *skb)
421b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
431b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	_queue_message(ch->st, skb);
441b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	return 0;
451b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
461b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
471b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic struct mISDNchannel *
481b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilget_channel4id(struct mISDNstack *st, u_int id)
491b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
501b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct mISDNchannel	*ch;
511b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
521b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	mutex_lock(&st->lmutex);
531b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	list_for_each_entry(ch, &st->layer2, list) {
541b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (id == ch->nr)
551b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			goto unlock;
561b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
571b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	ch = NULL;
581b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilunlock:
591b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	mutex_unlock(&st->lmutex);
601b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	return ch;
611b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
621b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
631b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic void
641b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilsend_socklist(struct mISDN_sock_list *sl, struct sk_buff *skb)
651b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
661b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct hlist_node	*node;
671b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct sock		*sk;
681b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct sk_buff		*cskb = NULL;
691b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
701b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	read_lock(&sl->lock);
711b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	sk_for_each(sk, node, &sl->head) {
721b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (sk->sk_state != MISDN_BOUND)
731b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			continue;
741b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (!cskb)
751b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			cskb = skb_copy(skb, GFP_KERNEL);
761b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (!cskb) {
771b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			printk(KERN_WARNING "%s no skb\n", __func__);
781b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			break;
791b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		}
801b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (!sock_queue_rcv_skb(sk, cskb))
811b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			cskb = NULL;
821b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
831b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	read_unlock(&sl->lock);
841b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (cskb)
851b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		dev_kfree_skb(cskb);
861b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
871b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
881b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic void
891b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilsend_layer2(struct mISDNstack *st, struct sk_buff *skb)
901b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
911b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct sk_buff		*cskb;
921b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct mISDNhead	*hh = mISDN_HEAD_P(skb);
931b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct mISDNchannel	*ch;
941b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	int			ret;
951b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
961b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (!st)
971b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		return;
981b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	mutex_lock(&st->lmutex);
991b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if ((hh->id & MISDN_ID_ADDR_MASK) == MISDN_ID_ANY) { /* L2 for all */
1001b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		list_for_each_entry(ch, &st->layer2, list) {
1011b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			if (list_is_last(&ch->list, &st->layer2)) {
1021b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil				cskb = skb;
1031b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil				skb = NULL;
1041b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			} else {
1051b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil				cskb = skb_copy(skb, GFP_KERNEL);
1061b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			}
1071b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			if (cskb) {
1081b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil				ret = ch->send(ch, cskb);
1091b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil				if (ret) {
1101b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil					if (*debug & DEBUG_SEND_ERR)
1111b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil						printk(KERN_DEBUG
112475be4d85a274d0961593db41cf85689db1d583cJoe Perches						       "%s ch%d prim(%x) addr(%x)"
113475be4d85a274d0961593db41cf85689db1d583cJoe Perches						       " err %d\n",
114475be4d85a274d0961593db41cf85689db1d583cJoe Perches						       __func__, ch->nr,
115475be4d85a274d0961593db41cf85689db1d583cJoe Perches						       hh->prim, ch->addr, ret);
1161b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil					dev_kfree_skb(cskb);
1171b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil				}
1181b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			} else {
1191b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil				printk(KERN_WARNING "%s ch%d addr %x no mem\n",
120475be4d85a274d0961593db41cf85689db1d583cJoe Perches				       __func__, ch->nr, ch->addr);
1211b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil				goto out;
1221b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			}
1231b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		}
1241b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	} else {
1251b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		list_for_each_entry(ch, &st->layer2, list) {
1261b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			if ((hh->id & MISDN_ID_ADDR_MASK) == ch->addr) {
1271b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil				ret = ch->send(ch, skb);
1281b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil				if (!ret)
1291b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil					skb = NULL;
1301b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil				goto out;
1311b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			}
1321b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		}
1331b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		ret = st->dev->teimgr->ctrl(st->dev->teimgr, CHECK_DATA, skb);
1341b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (!ret)
1351b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			skb = NULL;
1361b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		else if (*debug & DEBUG_SEND_ERR)
1371b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			printk(KERN_DEBUG
138475be4d85a274d0961593db41cf85689db1d583cJoe Perches			       "%s ch%d mgr prim(%x) addr(%x) err %d\n",
139475be4d85a274d0961593db41cf85689db1d583cJoe Perches			       __func__, ch->nr, hh->prim, ch->addr, ret);
1401b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
1411b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilout:
1421b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	mutex_unlock(&st->lmutex);
1431b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (skb)
1441b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		dev_kfree_skb(skb);
1451b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
1461b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
1471b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic inline int
1481b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilsend_msg_to_layer(struct mISDNstack *st, struct sk_buff *skb)
1491b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
1501b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct mISDNhead	*hh = mISDN_HEAD_P(skb);
1511b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct mISDNchannel	*ch;
1521b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	int	lm;
1531b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
1541b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	lm = hh->prim & MISDN_LAYERMASK;
1551b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (*debug & DEBUG_QUEUE_FUNC)
1561b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		printk(KERN_DEBUG "%s prim(%x) id(%x) %p\n",
157475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       __func__, hh->prim, hh->id, skb);
1581b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (lm == 0x1) {
1591b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (!hlist_empty(&st->l1sock.head)) {
1601b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			__net_timestamp(skb);
1611b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			send_socklist(&st->l1sock, skb);
1621b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		}
1631b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		return st->layer1->send(st->layer1, skb);
1641b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	} else if (lm == 0x2) {
1651b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (!hlist_empty(&st->l1sock.head))
1661b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			send_socklist(&st->l1sock, skb);
1671b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		send_layer2(st, skb);
1681b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		return 0;
1691b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	} else if (lm == 0x4) {
1701b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		ch = get_channel4id(st, hh->id);
1711b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (ch)
1721b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			return ch->send(ch, skb);
1731b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		else
1741b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			printk(KERN_WARNING
175475be4d85a274d0961593db41cf85689db1d583cJoe Perches			       "%s: dev(%s) prim(%x) id(%x) no channel\n",
176475be4d85a274d0961593db41cf85689db1d583cJoe Perches			       __func__, dev_name(&st->dev->dev), hh->prim,
177475be4d85a274d0961593db41cf85689db1d583cJoe Perches			       hh->id);
1781b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	} else if (lm == 0x8) {
1791b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		WARN_ON(lm == 0x8);
1801b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		ch = get_channel4id(st, hh->id);
1811b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (ch)
1821b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			return ch->send(ch, skb);
1831b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		else
1841b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			printk(KERN_WARNING
185475be4d85a274d0961593db41cf85689db1d583cJoe Perches			       "%s: dev(%s) prim(%x) id(%x) no channel\n",
186475be4d85a274d0961593db41cf85689db1d583cJoe Perches			       __func__, dev_name(&st->dev->dev), hh->prim,
187475be4d85a274d0961593db41cf85689db1d583cJoe Perches			       hh->id);
1881b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	} else {
1891b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		/* broadcast not handled yet */
1901b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		printk(KERN_WARNING "%s: dev(%s) prim %x not delivered\n",
191475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       __func__, dev_name(&st->dev->dev), hh->prim);
1921b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
1931b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	return -ESRCH;
1941b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
1951b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
1961b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic void
1971b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keildo_clear_stack(struct mISDNstack *st)
1981b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
1991b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
2001b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
2011b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic int
2021b2b03f8e514e4f68e293846ba511a948b80243cKarsten KeilmISDNStackd(void *data)
2031b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
2041b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct mISDNstack *st = data;
2051b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	int err = 0;
2061b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
2071b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	sigfillset(&current->blocked);
2081b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (*debug & DEBUG_MSG_THREAD)
209837468d135dcc49cdabc9fa92fc9550479f60704Matthias Urlichs		printk(KERN_DEBUG "mISDNStackd %s started\n",
210475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       dev_name(&st->dev->dev));
2111b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
2121b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (st->notify != NULL) {
2131b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		complete(st->notify);
2141b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		st->notify = NULL;
2151b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
2161b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
2171b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	for (;;) {
2181b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		struct sk_buff	*skb;
2191b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
2201b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (unlikely(test_bit(mISDN_STACK_STOPPED, &st->status))) {
2211b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			test_and_clear_bit(mISDN_STACK_WORK, &st->status);
2221b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			test_and_clear_bit(mISDN_STACK_RUNNING, &st->status);
2231b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		} else
2241b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			test_and_set_bit(mISDN_STACK_RUNNING, &st->status);
2251b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		while (test_bit(mISDN_STACK_WORK, &st->status)) {
2261b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			skb = skb_dequeue(&st->msgq);
2271b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			if (!skb) {
2281b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil				test_and_clear_bit(mISDN_STACK_WORK,
229475be4d85a274d0961593db41cf85689db1d583cJoe Perches						   &st->status);
2301b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil				/* test if a race happens */
2311b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil				skb = skb_dequeue(&st->msgq);
2321b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil				if (!skb)
2331b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil					continue;
2341b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil				test_and_set_bit(mISDN_STACK_WORK,
235475be4d85a274d0961593db41cf85689db1d583cJoe Perches						 &st->status);
2361b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			}
2371b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil#ifdef MISDN_MSG_STATS
2381b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			st->msg_cnt++;
2391b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil#endif
2401b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			err = send_msg_to_layer(st, skb);
2411b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			if (unlikely(err)) {
2421b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil				if (*debug & DEBUG_SEND_ERR)
2431b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil					printk(KERN_DEBUG
244475be4d85a274d0961593db41cf85689db1d583cJoe Perches					       "%s: %s prim(%x) id(%x) "
245475be4d85a274d0961593db41cf85689db1d583cJoe Perches					       "send call(%d)\n",
246475be4d85a274d0961593db41cf85689db1d583cJoe Perches					       __func__, dev_name(&st->dev->dev),
247475be4d85a274d0961593db41cf85689db1d583cJoe Perches					       mISDN_HEAD_PRIM(skb),
248475be4d85a274d0961593db41cf85689db1d583cJoe Perches					       mISDN_HEAD_ID(skb), err);
2491b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil				dev_kfree_skb(skb);
2501b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil				continue;
2511b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			}
2521b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			if (unlikely(test_bit(mISDN_STACK_STOPPED,
253475be4d85a274d0961593db41cf85689db1d583cJoe Perches					      &st->status))) {
2541b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil				test_and_clear_bit(mISDN_STACK_WORK,
255475be4d85a274d0961593db41cf85689db1d583cJoe Perches						   &st->status);
2561b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil				test_and_clear_bit(mISDN_STACK_RUNNING,
257475be4d85a274d0961593db41cf85689db1d583cJoe Perches						   &st->status);
2581b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil				break;
2591b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			}
2601b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		}
2611b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (test_bit(mISDN_STACK_CLEARING, &st->status)) {
2621b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			test_and_set_bit(mISDN_STACK_STOPPED, &st->status);
2631b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			test_and_clear_bit(mISDN_STACK_RUNNING, &st->status);
2641b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			do_clear_stack(st);
2651b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			test_and_clear_bit(mISDN_STACK_CLEARING, &st->status);
2661b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			test_and_set_bit(mISDN_STACK_RESTART, &st->status);
2671b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		}
2681b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (test_and_clear_bit(mISDN_STACK_RESTART, &st->status)) {
2691b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			test_and_clear_bit(mISDN_STACK_STOPPED, &st->status);
2701b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			test_and_set_bit(mISDN_STACK_RUNNING, &st->status);
2711b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			if (!skb_queue_empty(&st->msgq))
2721b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil				test_and_set_bit(mISDN_STACK_WORK,
273475be4d85a274d0961593db41cf85689db1d583cJoe Perches						 &st->status);
2741b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		}
2751b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (test_bit(mISDN_STACK_ABORT, &st->status))
2761b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			break;
2771b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (st->notify != NULL) {
2781b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			complete(st->notify);
2791b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			st->notify = NULL;
2801b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		}
2811b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil#ifdef MISDN_MSG_STATS
2821b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		st->sleep_cnt++;
2831b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil#endif
2841b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		test_and_clear_bit(mISDN_STACK_ACTIVE, &st->status);
2851b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		wait_event_interruptible(st->workq, (st->status &
286475be4d85a274d0961593db41cf85689db1d583cJoe Perches						     mISDN_STACK_ACTION_MASK));
2871b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (*debug & DEBUG_MSG_THREAD)
2881b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			printk(KERN_DEBUG "%s: %s wake status %08lx\n",
289475be4d85a274d0961593db41cf85689db1d583cJoe Perches			       __func__, dev_name(&st->dev->dev), st->status);
2901b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		test_and_set_bit(mISDN_STACK_ACTIVE, &st->status);
2911b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
2921b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		test_and_clear_bit(mISDN_STACK_WAKEUP, &st->status);
2931b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
2941b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (test_bit(mISDN_STACK_STOPPED, &st->status)) {
2951b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			test_and_clear_bit(mISDN_STACK_RUNNING, &st->status);
2961b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil#ifdef MISDN_MSG_STATS
2971b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			st->stopped_cnt++;
2981b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil#endif
2991b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		}
3001b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
3011b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil#ifdef MISDN_MSG_STATS
3021b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	printk(KERN_DEBUG "mISDNStackd daemon for %s proceed %d "
303475be4d85a274d0961593db41cf85689db1d583cJoe Perches	       "msg %d sleep %d stopped\n",
304475be4d85a274d0961593db41cf85689db1d583cJoe Perches	       dev_name(&st->dev->dev), st->msg_cnt, st->sleep_cnt,
305475be4d85a274d0961593db41cf85689db1d583cJoe Perches	       st->stopped_cnt);
3061b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	printk(KERN_DEBUG
307475be4d85a274d0961593db41cf85689db1d583cJoe Perches	       "mISDNStackd daemon for %s utime(%ld) stime(%ld)\n",
308475be4d85a274d0961593db41cf85689db1d583cJoe Perches	       dev_name(&st->dev->dev), st->thread->utime, st->thread->stime);
3091b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	printk(KERN_DEBUG
310475be4d85a274d0961593db41cf85689db1d583cJoe Perches	       "mISDNStackd daemon for %s nvcsw(%ld) nivcsw(%ld)\n",
311475be4d85a274d0961593db41cf85689db1d583cJoe Perches	       dev_name(&st->dev->dev), st->thread->nvcsw, st->thread->nivcsw);
3121b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	printk(KERN_DEBUG "mISDNStackd daemon for %s killed now\n",
313475be4d85a274d0961593db41cf85689db1d583cJoe Perches	       dev_name(&st->dev->dev));
3141b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil#endif
3151b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	test_and_set_bit(mISDN_STACK_KILLED, &st->status);
3161b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	test_and_clear_bit(mISDN_STACK_RUNNING, &st->status);
3171b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	test_and_clear_bit(mISDN_STACK_ACTIVE, &st->status);
3181b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	test_and_clear_bit(mISDN_STACK_ABORT, &st->status);
3191b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	skb_queue_purge(&st->msgq);
3201b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	st->thread = NULL;
3211b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (st->notify != NULL) {
3221b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		complete(st->notify);
3231b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		st->notify = NULL;
3241b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
3251b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	return 0;
3261b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
3271b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
3281b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic int
3291b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keill1_receive(struct mISDNchannel *ch, struct sk_buff *skb)
3301b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
3311b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (!ch->st)
3321b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		return -ENODEV;
3331b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	__net_timestamp(skb);
3341b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	_queue_message(ch->st, skb);
3351b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	return 0;
3361b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
3371b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
3381b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilvoid
3391b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilset_channel_address(struct mISDNchannel *ch, u_int sapi, u_int tei)
3401b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
3411b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	ch->addr = sapi | (tei << 8);
3421b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
3431b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
3441b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilvoid
3451b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil__add_layer2(struct mISDNchannel *ch, struct mISDNstack *st)
3461b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
3471b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	list_add_tail(&ch->list, &st->layer2);
3481b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
3491b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
3501b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilvoid
3511b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keiladd_layer2(struct mISDNchannel *ch, struct mISDNstack *st)
3521b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
3531b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	mutex_lock(&st->lmutex);
3541b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	__add_layer2(ch, st);
3551b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	mutex_unlock(&st->lmutex);
3561b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
3571b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
3581b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic int
3591b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilst_own_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
3601b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
36108cb3f60b2f866c906a5a779444b30ba8f9a93c8Dan Carpenter	if (!ch->st || !ch->st->layer1)
3621b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		return -EINVAL;
3631b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	return ch->st->layer1->ctrl(ch->st->layer1, cmd, arg);
3641b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
3651b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
3661b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilint
3671b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilcreate_stack(struct mISDNdevice *dev)
3681b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
3691b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct mISDNstack	*newst;
3701b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	int			err;
3711b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	DECLARE_COMPLETION_ONSTACK(done);
3721b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
3731b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	newst = kzalloc(sizeof(struct mISDNstack), GFP_KERNEL);
3741b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (!newst) {
3751b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		printk(KERN_ERR "kmalloc mISDN_stack failed\n");
3761b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		return -ENOMEM;
3771b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
3781b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	newst->dev = dev;
3791b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	INIT_LIST_HEAD(&newst->layer2);
3801b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	INIT_HLIST_HEAD(&newst->l1sock.head);
3811b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	rwlock_init(&newst->l1sock.lock);
3821b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	init_waitqueue_head(&newst->workq);
3831b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	skb_queue_head_init(&newst->msgq);
3841b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	mutex_init(&newst->lmutex);
3851b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	dev->D.st = newst;
3861b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	err = create_teimanager(dev);
3871b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (err) {
3881b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		printk(KERN_ERR "kmalloc teimanager failed\n");
3891b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		kfree(newst);
3901b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		return err;
3911b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
3921b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	dev->teimgr->peer = &newst->own;
3931b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	dev->teimgr->recv = mISDN_queue_message;
3941b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	dev->teimgr->st = newst;
3951b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	newst->layer1 = &dev->D;
3961b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	dev->D.recv = l1_receive;
3971b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	dev->D.peer = &newst->own;
3981b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	newst->own.st = newst;
3991b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	newst->own.ctrl = st_own_ctrl;
4001b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	newst->own.send = mISDN_queue_message;
4011b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	newst->own.recv = mISDN_queue_message;
4021b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (*debug & DEBUG_CORE_FUNC)
403837468d135dcc49cdabc9fa92fc9550479f60704Matthias Urlichs		printk(KERN_DEBUG "%s: st(%s)\n", __func__,
404475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       dev_name(&newst->dev->dev));
4051b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	newst->notify = &done;
4061b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	newst->thread = kthread_run(mISDNStackd, (void *)newst, "mISDN_%s",
407475be4d85a274d0961593db41cf85689db1d583cJoe Perches				    dev_name(&newst->dev->dev));
4081b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (IS_ERR(newst->thread)) {
4091b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		err = PTR_ERR(newst->thread);
4101b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		printk(KERN_ERR
411475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       "mISDN:cannot create kernel thread for %s (%d)\n",
412475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       dev_name(&newst->dev->dev), err);
4131b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		delete_teimanager(dev->teimgr);
4141b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		kfree(newst);
4151b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	} else
4161b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		wait_for_completion(&done);
4171b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	return err;
4181b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
4191b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
4201b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilint
4211b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilconnect_layer1(struct mISDNdevice *dev, struct mISDNchannel *ch,
422475be4d85a274d0961593db41cf85689db1d583cJoe Perches	       u_int protocol, struct sockaddr_mISDN *adr)
4231b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
4241b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct mISDN_sock	*msk = container_of(ch, struct mISDN_sock, ch);
4251b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct channel_req	rq;
4261b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	int			err;
4271b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
4281b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
4291b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (*debug &  DEBUG_CORE_FUNC)
4301b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n",
431475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       __func__, dev_name(&dev->dev), protocol, adr->dev,
432475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       adr->channel, adr->sapi, adr->tei);
4331b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	switch (protocol) {
4341b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_NT_S0:
4351b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_NT_E1:
4361b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_TE_S0:
4371b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_TE_E1:
4381b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		ch->recv = mISDN_queue_message;
4391b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		ch->peer = &dev->D.st->own;
4401b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		ch->st = dev->D.st;
4411b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		rq.protocol = protocol;
4421f28fa19d34c0d9186f274e61e4b3dcfc6428c5cMartin Bachem		rq.adr.channel = adr->channel;
4431b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq);
4449a812553bdc097a566aa79df7fae3457449c555bAndreas Eversberg		printk(KERN_DEBUG "%s: ret %d (dev %d)\n", __func__, err,
445475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       dev->id);
4461b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (err)
4471b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			return err;
4481b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		write_lock_bh(&dev->D.st->l1sock.lock);
4491b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		sk_add_node(&msk->sk, &dev->D.st->l1sock.head);
4501b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		write_unlock_bh(&dev->D.st->l1sock.lock);
4511b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		break;
4521b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	default:
4531b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		return -ENOPROTOOPT;
4541b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
4551b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	return 0;
4561b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
4571b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
4581b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilint
4591b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilconnect_Bstack(struct mISDNdevice *dev, struct mISDNchannel *ch,
460475be4d85a274d0961593db41cf85689db1d583cJoe Perches	       u_int protocol, struct sockaddr_mISDN *adr)
4611b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
4621b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct channel_req	rq, rq2;
4631b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	int			pmask, err;
4641b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct Bprotocol	*bp;
4651b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
4661b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (*debug &  DEBUG_CORE_FUNC)
4671b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n",
468475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       __func__, dev_name(&dev->dev), protocol,
469475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       adr->dev, adr->channel, adr->sapi,
470475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       adr->tei);
4711b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	ch->st = dev->D.st;
4721b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	pmask = 1 << (protocol & ISDN_P_B_MASK);
4731b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (pmask & dev->Bprotocols) {
4741b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		rq.protocol = protocol;
4751b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		rq.adr = *adr;
4761b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq);
4771b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (err)
4781b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			return err;
4791b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		ch->recv = rq.ch->send;
4801b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		ch->peer = rq.ch;
4811b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		rq.ch->recv = ch->send;
4821b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		rq.ch->peer = ch;
4831b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		rq.ch->st = dev->D.st;
4841b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	} else {
4851b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		bp = get_Bprotocol4mask(pmask);
4861b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (!bp)
4871b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			return -ENOPROTOOPT;
4881b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		rq2.protocol = protocol;
4891b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		rq2.adr = *adr;
4901b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		rq2.ch = ch;
4911b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		err = bp->create(&rq2);
4921b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (err)
4931b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			return err;
4941b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		ch->recv = rq2.ch->send;
4951b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		ch->peer = rq2.ch;
4961b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		rq2.ch->st = dev->D.st;
4971b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		rq.protocol = rq2.protocol;
4981b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		rq.adr = *adr;
4991b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq);
5001b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (err) {
5011b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			rq2.ch->ctrl(rq2.ch, CLOSE_CHANNEL, NULL);
5021b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			return err;
5031b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		}
5041b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		rq2.ch->recv = rq.ch->send;
5051b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		rq2.ch->peer = rq.ch;
5061b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		rq.ch->recv = rq2.ch->send;
5071b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		rq.ch->peer = rq2.ch;
5081b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		rq.ch->st = dev->D.st;
5091b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
5101b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	ch->protocol = protocol;
5111b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	ch->nr = rq.ch->nr;
5121b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	return 0;
5131b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
5141b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
5151b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilint
5161b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilcreate_l2entity(struct mISDNdevice *dev, struct mISDNchannel *ch,
517475be4d85a274d0961593db41cf85689db1d583cJoe Perches		u_int protocol, struct sockaddr_mISDN *adr)
5181b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
5191b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct channel_req	rq;
5201b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	int			err;
5211b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
5221b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (*debug &  DEBUG_CORE_FUNC)
5231b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n",
524475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       __func__, dev_name(&dev->dev), protocol,
525475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       adr->dev, adr->channel, adr->sapi,
526475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       adr->tei);
5271b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	rq.protocol = ISDN_P_TE_S0;
5281b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (dev->Dprotocols & (1 << ISDN_P_TE_E1))
5291b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		rq.protocol = ISDN_P_TE_E1;
5301b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	switch (protocol) {
5311b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_LAPD_NT:
5321b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		rq.protocol = ISDN_P_NT_S0;
5331b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (dev->Dprotocols & (1 << ISDN_P_NT_E1))
5341b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			rq.protocol = ISDN_P_NT_E1;
5351b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_LAPD_TE:
5361b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		ch->recv = mISDN_queue_message;
5371b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		ch->peer = &dev->D.st->own;
5381b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		ch->st = dev->D.st;
5391b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		rq.adr.channel = 0;
5401b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq);
5411b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		printk(KERN_DEBUG "%s: ret 1 %d\n", __func__, err);
5421b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (err)
5431b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			break;
5441b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		rq.protocol = protocol;
5451b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		rq.adr = *adr;
5461b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		rq.ch = ch;
5471b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		err = dev->teimgr->ctrl(dev->teimgr, OPEN_CHANNEL, &rq);
5481b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		printk(KERN_DEBUG "%s: ret 2 %d\n", __func__, err);
5491b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (!err) {
5501b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			if ((protocol == ISDN_P_LAPD_NT) && !rq.ch)
5511b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil				break;
5521b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			add_layer2(rq.ch, dev->D.st);
5531b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			rq.ch->recv = mISDN_queue_message;
5541b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			rq.ch->peer = &dev->D.st->own;
5551b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			rq.ch->ctrl(rq.ch, OPEN_CHANNEL, NULL); /* can't fail */
5561b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		}
5571b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		break;
5581b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	default:
5591b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		err = -EPROTONOSUPPORT;
5601b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
5611b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	return err;
5621b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
5631b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
5641b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilvoid
5651b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keildelete_channel(struct mISDNchannel *ch)
5661b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
5671b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct mISDN_sock	*msk = container_of(ch, struct mISDN_sock, ch);
5681b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct mISDNchannel	*pch;
5691b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
5701b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (!ch->st) {
5711b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		printk(KERN_WARNING "%s: no stack\n", __func__);
5721b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		return;
5731b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
5741b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (*debug & DEBUG_CORE_FUNC)
5751b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		printk(KERN_DEBUG "%s: st(%s) protocol(%x)\n", __func__,
576475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       dev_name(&ch->st->dev->dev), ch->protocol);
5771b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (ch->protocol >= ISDN_P_B_START) {
5781b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (ch->peer) {
5791b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			ch->peer->ctrl(ch->peer, CLOSE_CHANNEL, NULL);
5801b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			ch->peer = NULL;
5811b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		}
5821b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		return;
5831b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
5841b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	switch (ch->protocol) {
5851b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_NT_S0:
5861b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_TE_S0:
5871b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_NT_E1:
5881b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_TE_E1:
5891b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		write_lock_bh(&ch->st->l1sock.lock);
5901b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		sk_del_node_init(&msk->sk);
5911b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		write_unlock_bh(&ch->st->l1sock.lock);
5921b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		ch->st->dev->D.ctrl(&ch->st->dev->D, CLOSE_CHANNEL, NULL);
5931b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		break;
5941b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_LAPD_TE:
5951b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		pch = get_channel4id(ch->st, ch->nr);
5961b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (pch) {
5971b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			mutex_lock(&ch->st->lmutex);
5981b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			list_del(&pch->list);
5991b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			mutex_unlock(&ch->st->lmutex);
6001b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			pch->ctrl(pch, CLOSE_CHANNEL, NULL);
6011b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			pch = ch->st->dev->teimgr;
6021b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			pch->ctrl(pch, CLOSE_CHANNEL, NULL);
6031b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		} else
6041b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			printk(KERN_WARNING "%s: no l2 channel\n",
605475be4d85a274d0961593db41cf85689db1d583cJoe Perches			       __func__);
6061b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		break;
6071b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_LAPD_NT:
6081b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		pch = ch->st->dev->teimgr;
6091b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (pch) {
6101b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			pch->ctrl(pch, CLOSE_CHANNEL, NULL);
6111b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		} else
6121b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			printk(KERN_WARNING "%s: no l2 channel\n",
613475be4d85a274d0961593db41cf85689db1d583cJoe Perches			       __func__);
6141b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		break;
6151b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	default:
6161b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		break;
6171b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
6181b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	return;
6191b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
6201b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
6211b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilvoid
6221b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keildelete_stack(struct mISDNdevice *dev)
6231b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
6241b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct mISDNstack	*st = dev->D.st;
6251b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	DECLARE_COMPLETION_ONSTACK(done);
6261b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
6271b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (*debug & DEBUG_CORE_FUNC)
6281b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		printk(KERN_DEBUG "%s: st(%s)\n", __func__,
629475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       dev_name(&st->dev->dev));
6301b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (dev->teimgr)
6311b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		delete_teimanager(dev->teimgr);
6321b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (st->thread) {
6331b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (st->notify) {
6341b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			printk(KERN_WARNING "%s: notifier in use\n",
635475be4d85a274d0961593db41cf85689db1d583cJoe Perches			       __func__);
636475be4d85a274d0961593db41cf85689db1d583cJoe Perches			complete(st->notify);
6371b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		}
6381b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		st->notify = &done;
6391b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		test_and_set_bit(mISDN_STACK_ABORT, &st->status);
6401b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		test_and_set_bit(mISDN_STACK_WAKEUP, &st->status);
6411b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		wake_up_interruptible(&st->workq);
6421b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		wait_for_completion(&done);
6431b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
6441b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (!list_empty(&st->layer2))
6451b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		printk(KERN_WARNING "%s: layer2 list not empty\n",
646475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       __func__);
6471b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (!hlist_empty(&st->l1sock.head))
6481b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		printk(KERN_WARNING "%s: layer1 list not empty\n",
649475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       __func__);
6501b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	kfree(st);
6511b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
6521b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
6531b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilvoid
6541b2b03f8e514e4f68e293846ba511a948b80243cKarsten KeilmISDN_initstack(u_int *dp)
6551b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
6561b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	debug = dp;
6571b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
658