18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Author	Karsten Keil <kkeil@novell.com>
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright 2008  by Karsten Keil <kkeil@novell.com>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/slab.h>
108c2ecf20Sopenharmony_ci#include <linux/mISDNif.h>
118c2ecf20Sopenharmony_ci#include <linux/kthread.h>
128c2ecf20Sopenharmony_ci#include <linux/sched.h>
138c2ecf20Sopenharmony_ci#include <linux/sched/cputime.h>
148c2ecf20Sopenharmony_ci#include <linux/signal.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include "core.h"
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_cistatic u_int	*debug;
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistatic inline void
218c2ecf20Sopenharmony_ci_queue_message(struct mISDNstack *st, struct sk_buff *skb)
228c2ecf20Sopenharmony_ci{
238c2ecf20Sopenharmony_ci	struct mISDNhead	*hh = mISDN_HEAD_P(skb);
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci	if (*debug & DEBUG_QUEUE_FUNC)
268c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "%s prim(%x) id(%x) %p\n",
278c2ecf20Sopenharmony_ci		       __func__, hh->prim, hh->id, skb);
288c2ecf20Sopenharmony_ci	skb_queue_tail(&st->msgq, skb);
298c2ecf20Sopenharmony_ci	if (likely(!test_bit(mISDN_STACK_STOPPED, &st->status))) {
308c2ecf20Sopenharmony_ci		test_and_set_bit(mISDN_STACK_WORK, &st->status);
318c2ecf20Sopenharmony_ci		wake_up_interruptible(&st->workq);
328c2ecf20Sopenharmony_ci	}
338c2ecf20Sopenharmony_ci}
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistatic int
368c2ecf20Sopenharmony_cimISDN_queue_message(struct mISDNchannel *ch, struct sk_buff *skb)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	_queue_message(ch->st, skb);
398c2ecf20Sopenharmony_ci	return 0;
408c2ecf20Sopenharmony_ci}
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic struct mISDNchannel *
438c2ecf20Sopenharmony_ciget_channel4id(struct mISDNstack *st, u_int id)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	struct mISDNchannel	*ch;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	mutex_lock(&st->lmutex);
488c2ecf20Sopenharmony_ci	list_for_each_entry(ch, &st->layer2, list) {
498c2ecf20Sopenharmony_ci		if (id == ch->nr)
508c2ecf20Sopenharmony_ci			goto unlock;
518c2ecf20Sopenharmony_ci	}
528c2ecf20Sopenharmony_ci	ch = NULL;
538c2ecf20Sopenharmony_ciunlock:
548c2ecf20Sopenharmony_ci	mutex_unlock(&st->lmutex);
558c2ecf20Sopenharmony_ci	return ch;
568c2ecf20Sopenharmony_ci}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cistatic void
598c2ecf20Sopenharmony_cisend_socklist(struct mISDN_sock_list *sl, struct sk_buff *skb)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	struct sock		*sk;
628c2ecf20Sopenharmony_ci	struct sk_buff		*cskb = NULL;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	read_lock(&sl->lock);
658c2ecf20Sopenharmony_ci	sk_for_each(sk, &sl->head) {
668c2ecf20Sopenharmony_ci		if (sk->sk_state != MISDN_BOUND)
678c2ecf20Sopenharmony_ci			continue;
688c2ecf20Sopenharmony_ci		if (!cskb)
698c2ecf20Sopenharmony_ci			cskb = skb_copy(skb, GFP_ATOMIC);
708c2ecf20Sopenharmony_ci		if (!cskb) {
718c2ecf20Sopenharmony_ci			printk(KERN_WARNING "%s no skb\n", __func__);
728c2ecf20Sopenharmony_ci			break;
738c2ecf20Sopenharmony_ci		}
748c2ecf20Sopenharmony_ci		if (!sock_queue_rcv_skb(sk, cskb))
758c2ecf20Sopenharmony_ci			cskb = NULL;
768c2ecf20Sopenharmony_ci	}
778c2ecf20Sopenharmony_ci	read_unlock(&sl->lock);
788c2ecf20Sopenharmony_ci	dev_kfree_skb(cskb);
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistatic void
828c2ecf20Sopenharmony_cisend_layer2(struct mISDNstack *st, struct sk_buff *skb)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	struct sk_buff		*cskb;
858c2ecf20Sopenharmony_ci	struct mISDNhead	*hh = mISDN_HEAD_P(skb);
868c2ecf20Sopenharmony_ci	struct mISDNchannel	*ch;
878c2ecf20Sopenharmony_ci	int			ret;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	if (!st)
908c2ecf20Sopenharmony_ci		return;
918c2ecf20Sopenharmony_ci	mutex_lock(&st->lmutex);
928c2ecf20Sopenharmony_ci	if ((hh->id & MISDN_ID_ADDR_MASK) == MISDN_ID_ANY) { /* L2 for all */
938c2ecf20Sopenharmony_ci		list_for_each_entry(ch, &st->layer2, list) {
948c2ecf20Sopenharmony_ci			if (list_is_last(&ch->list, &st->layer2)) {
958c2ecf20Sopenharmony_ci				cskb = skb;
968c2ecf20Sopenharmony_ci				skb = NULL;
978c2ecf20Sopenharmony_ci			} else {
988c2ecf20Sopenharmony_ci				cskb = skb_copy(skb, GFP_KERNEL);
998c2ecf20Sopenharmony_ci			}
1008c2ecf20Sopenharmony_ci			if (cskb) {
1018c2ecf20Sopenharmony_ci				ret = ch->send(ch, cskb);
1028c2ecf20Sopenharmony_ci				if (ret) {
1038c2ecf20Sopenharmony_ci					if (*debug & DEBUG_SEND_ERR)
1048c2ecf20Sopenharmony_ci						printk(KERN_DEBUG
1058c2ecf20Sopenharmony_ci						       "%s ch%d prim(%x) addr(%x)"
1068c2ecf20Sopenharmony_ci						       " err %d\n",
1078c2ecf20Sopenharmony_ci						       __func__, ch->nr,
1088c2ecf20Sopenharmony_ci						       hh->prim, ch->addr, ret);
1098c2ecf20Sopenharmony_ci					dev_kfree_skb(cskb);
1108c2ecf20Sopenharmony_ci				}
1118c2ecf20Sopenharmony_ci			} else {
1128c2ecf20Sopenharmony_ci				printk(KERN_WARNING "%s ch%d addr %x no mem\n",
1138c2ecf20Sopenharmony_ci				       __func__, ch->nr, ch->addr);
1148c2ecf20Sopenharmony_ci				goto out;
1158c2ecf20Sopenharmony_ci			}
1168c2ecf20Sopenharmony_ci		}
1178c2ecf20Sopenharmony_ci	} else {
1188c2ecf20Sopenharmony_ci		list_for_each_entry(ch, &st->layer2, list) {
1198c2ecf20Sopenharmony_ci			if ((hh->id & MISDN_ID_ADDR_MASK) == ch->addr) {
1208c2ecf20Sopenharmony_ci				ret = ch->send(ch, skb);
1218c2ecf20Sopenharmony_ci				if (!ret)
1228c2ecf20Sopenharmony_ci					skb = NULL;
1238c2ecf20Sopenharmony_ci				goto out;
1248c2ecf20Sopenharmony_ci			}
1258c2ecf20Sopenharmony_ci		}
1268c2ecf20Sopenharmony_ci		ret = st->dev->teimgr->ctrl(st->dev->teimgr, CHECK_DATA, skb);
1278c2ecf20Sopenharmony_ci		if (!ret)
1288c2ecf20Sopenharmony_ci			skb = NULL;
1298c2ecf20Sopenharmony_ci		else if (*debug & DEBUG_SEND_ERR)
1308c2ecf20Sopenharmony_ci			printk(KERN_DEBUG
1318c2ecf20Sopenharmony_ci			       "%s mgr prim(%x) err %d\n",
1328c2ecf20Sopenharmony_ci			       __func__, hh->prim, ret);
1338c2ecf20Sopenharmony_ci	}
1348c2ecf20Sopenharmony_ciout:
1358c2ecf20Sopenharmony_ci	mutex_unlock(&st->lmutex);
1368c2ecf20Sopenharmony_ci	dev_kfree_skb(skb);
1378c2ecf20Sopenharmony_ci}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_cistatic inline int
1408c2ecf20Sopenharmony_cisend_msg_to_layer(struct mISDNstack *st, struct sk_buff *skb)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	struct mISDNhead	*hh = mISDN_HEAD_P(skb);
1438c2ecf20Sopenharmony_ci	struct mISDNchannel	*ch;
1448c2ecf20Sopenharmony_ci	int	lm;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	lm = hh->prim & MISDN_LAYERMASK;
1478c2ecf20Sopenharmony_ci	if (*debug & DEBUG_QUEUE_FUNC)
1488c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "%s prim(%x) id(%x) %p\n",
1498c2ecf20Sopenharmony_ci		       __func__, hh->prim, hh->id, skb);
1508c2ecf20Sopenharmony_ci	if (lm == 0x1) {
1518c2ecf20Sopenharmony_ci		if (!hlist_empty(&st->l1sock.head)) {
1528c2ecf20Sopenharmony_ci			__net_timestamp(skb);
1538c2ecf20Sopenharmony_ci			send_socklist(&st->l1sock, skb);
1548c2ecf20Sopenharmony_ci		}
1558c2ecf20Sopenharmony_ci		return st->layer1->send(st->layer1, skb);
1568c2ecf20Sopenharmony_ci	} else if (lm == 0x2) {
1578c2ecf20Sopenharmony_ci		if (!hlist_empty(&st->l1sock.head))
1588c2ecf20Sopenharmony_ci			send_socklist(&st->l1sock, skb);
1598c2ecf20Sopenharmony_ci		send_layer2(st, skb);
1608c2ecf20Sopenharmony_ci		return 0;
1618c2ecf20Sopenharmony_ci	} else if (lm == 0x4) {
1628c2ecf20Sopenharmony_ci		ch = get_channel4id(st, hh->id);
1638c2ecf20Sopenharmony_ci		if (ch)
1648c2ecf20Sopenharmony_ci			return ch->send(ch, skb);
1658c2ecf20Sopenharmony_ci		else
1668c2ecf20Sopenharmony_ci			printk(KERN_WARNING
1678c2ecf20Sopenharmony_ci			       "%s: dev(%s) prim(%x) id(%x) no channel\n",
1688c2ecf20Sopenharmony_ci			       __func__, dev_name(&st->dev->dev), hh->prim,
1698c2ecf20Sopenharmony_ci			       hh->id);
1708c2ecf20Sopenharmony_ci	} else if (lm == 0x8) {
1718c2ecf20Sopenharmony_ci		WARN_ON(lm == 0x8);
1728c2ecf20Sopenharmony_ci		ch = get_channel4id(st, hh->id);
1738c2ecf20Sopenharmony_ci		if (ch)
1748c2ecf20Sopenharmony_ci			return ch->send(ch, skb);
1758c2ecf20Sopenharmony_ci		else
1768c2ecf20Sopenharmony_ci			printk(KERN_WARNING
1778c2ecf20Sopenharmony_ci			       "%s: dev(%s) prim(%x) id(%x) no channel\n",
1788c2ecf20Sopenharmony_ci			       __func__, dev_name(&st->dev->dev), hh->prim,
1798c2ecf20Sopenharmony_ci			       hh->id);
1808c2ecf20Sopenharmony_ci	} else {
1818c2ecf20Sopenharmony_ci		/* broadcast not handled yet */
1828c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: dev(%s) prim %x not delivered\n",
1838c2ecf20Sopenharmony_ci		       __func__, dev_name(&st->dev->dev), hh->prim);
1848c2ecf20Sopenharmony_ci	}
1858c2ecf20Sopenharmony_ci	return -ESRCH;
1868c2ecf20Sopenharmony_ci}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_cistatic void
1898c2ecf20Sopenharmony_cido_clear_stack(struct mISDNstack *st)
1908c2ecf20Sopenharmony_ci{
1918c2ecf20Sopenharmony_ci}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_cistatic int
1948c2ecf20Sopenharmony_cimISDNStackd(void *data)
1958c2ecf20Sopenharmony_ci{
1968c2ecf20Sopenharmony_ci	struct mISDNstack *st = data;
1978c2ecf20Sopenharmony_ci#ifdef MISDN_MSG_STATS
1988c2ecf20Sopenharmony_ci	u64 utime, stime;
1998c2ecf20Sopenharmony_ci#endif
2008c2ecf20Sopenharmony_ci	int err = 0;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	sigfillset(&current->blocked);
2038c2ecf20Sopenharmony_ci	if (*debug & DEBUG_MSG_THREAD)
2048c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "mISDNStackd %s started\n",
2058c2ecf20Sopenharmony_ci		       dev_name(&st->dev->dev));
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	if (st->notify != NULL) {
2088c2ecf20Sopenharmony_ci		complete(st->notify);
2098c2ecf20Sopenharmony_ci		st->notify = NULL;
2108c2ecf20Sopenharmony_ci	}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	for (;;) {
2138c2ecf20Sopenharmony_ci		struct sk_buff	*skb;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci		if (unlikely(test_bit(mISDN_STACK_STOPPED, &st->status))) {
2168c2ecf20Sopenharmony_ci			test_and_clear_bit(mISDN_STACK_WORK, &st->status);
2178c2ecf20Sopenharmony_ci			test_and_clear_bit(mISDN_STACK_RUNNING, &st->status);
2188c2ecf20Sopenharmony_ci		} else
2198c2ecf20Sopenharmony_ci			test_and_set_bit(mISDN_STACK_RUNNING, &st->status);
2208c2ecf20Sopenharmony_ci		while (test_bit(mISDN_STACK_WORK, &st->status)) {
2218c2ecf20Sopenharmony_ci			skb = skb_dequeue(&st->msgq);
2228c2ecf20Sopenharmony_ci			if (!skb) {
2238c2ecf20Sopenharmony_ci				test_and_clear_bit(mISDN_STACK_WORK,
2248c2ecf20Sopenharmony_ci						   &st->status);
2258c2ecf20Sopenharmony_ci				/* test if a race happens */
2268c2ecf20Sopenharmony_ci				skb = skb_dequeue(&st->msgq);
2278c2ecf20Sopenharmony_ci				if (!skb)
2288c2ecf20Sopenharmony_ci					continue;
2298c2ecf20Sopenharmony_ci				test_and_set_bit(mISDN_STACK_WORK,
2308c2ecf20Sopenharmony_ci						 &st->status);
2318c2ecf20Sopenharmony_ci			}
2328c2ecf20Sopenharmony_ci#ifdef MISDN_MSG_STATS
2338c2ecf20Sopenharmony_ci			st->msg_cnt++;
2348c2ecf20Sopenharmony_ci#endif
2358c2ecf20Sopenharmony_ci			err = send_msg_to_layer(st, skb);
2368c2ecf20Sopenharmony_ci			if (unlikely(err)) {
2378c2ecf20Sopenharmony_ci				if (*debug & DEBUG_SEND_ERR)
2388c2ecf20Sopenharmony_ci					printk(KERN_DEBUG
2398c2ecf20Sopenharmony_ci					       "%s: %s prim(%x) id(%x) "
2408c2ecf20Sopenharmony_ci					       "send call(%d)\n",
2418c2ecf20Sopenharmony_ci					       __func__, dev_name(&st->dev->dev),
2428c2ecf20Sopenharmony_ci					       mISDN_HEAD_PRIM(skb),
2438c2ecf20Sopenharmony_ci					       mISDN_HEAD_ID(skb), err);
2448c2ecf20Sopenharmony_ci				dev_kfree_skb(skb);
2458c2ecf20Sopenharmony_ci				continue;
2468c2ecf20Sopenharmony_ci			}
2478c2ecf20Sopenharmony_ci			if (unlikely(test_bit(mISDN_STACK_STOPPED,
2488c2ecf20Sopenharmony_ci					      &st->status))) {
2498c2ecf20Sopenharmony_ci				test_and_clear_bit(mISDN_STACK_WORK,
2508c2ecf20Sopenharmony_ci						   &st->status);
2518c2ecf20Sopenharmony_ci				test_and_clear_bit(mISDN_STACK_RUNNING,
2528c2ecf20Sopenharmony_ci						   &st->status);
2538c2ecf20Sopenharmony_ci				break;
2548c2ecf20Sopenharmony_ci			}
2558c2ecf20Sopenharmony_ci		}
2568c2ecf20Sopenharmony_ci		if (test_bit(mISDN_STACK_CLEARING, &st->status)) {
2578c2ecf20Sopenharmony_ci			test_and_set_bit(mISDN_STACK_STOPPED, &st->status);
2588c2ecf20Sopenharmony_ci			test_and_clear_bit(mISDN_STACK_RUNNING, &st->status);
2598c2ecf20Sopenharmony_ci			do_clear_stack(st);
2608c2ecf20Sopenharmony_ci			test_and_clear_bit(mISDN_STACK_CLEARING, &st->status);
2618c2ecf20Sopenharmony_ci			test_and_set_bit(mISDN_STACK_RESTART, &st->status);
2628c2ecf20Sopenharmony_ci		}
2638c2ecf20Sopenharmony_ci		if (test_and_clear_bit(mISDN_STACK_RESTART, &st->status)) {
2648c2ecf20Sopenharmony_ci			test_and_clear_bit(mISDN_STACK_STOPPED, &st->status);
2658c2ecf20Sopenharmony_ci			test_and_set_bit(mISDN_STACK_RUNNING, &st->status);
2668c2ecf20Sopenharmony_ci			if (!skb_queue_empty(&st->msgq))
2678c2ecf20Sopenharmony_ci				test_and_set_bit(mISDN_STACK_WORK,
2688c2ecf20Sopenharmony_ci						 &st->status);
2698c2ecf20Sopenharmony_ci		}
2708c2ecf20Sopenharmony_ci		if (test_bit(mISDN_STACK_ABORT, &st->status))
2718c2ecf20Sopenharmony_ci			break;
2728c2ecf20Sopenharmony_ci		if (st->notify != NULL) {
2738c2ecf20Sopenharmony_ci			complete(st->notify);
2748c2ecf20Sopenharmony_ci			st->notify = NULL;
2758c2ecf20Sopenharmony_ci		}
2768c2ecf20Sopenharmony_ci#ifdef MISDN_MSG_STATS
2778c2ecf20Sopenharmony_ci		st->sleep_cnt++;
2788c2ecf20Sopenharmony_ci#endif
2798c2ecf20Sopenharmony_ci		test_and_clear_bit(mISDN_STACK_ACTIVE, &st->status);
2808c2ecf20Sopenharmony_ci		wait_event_interruptible(st->workq, (st->status &
2818c2ecf20Sopenharmony_ci						     mISDN_STACK_ACTION_MASK));
2828c2ecf20Sopenharmony_ci		if (*debug & DEBUG_MSG_THREAD)
2838c2ecf20Sopenharmony_ci			printk(KERN_DEBUG "%s: %s wake status %08lx\n",
2848c2ecf20Sopenharmony_ci			       __func__, dev_name(&st->dev->dev), st->status);
2858c2ecf20Sopenharmony_ci		test_and_set_bit(mISDN_STACK_ACTIVE, &st->status);
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci		test_and_clear_bit(mISDN_STACK_WAKEUP, &st->status);
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci		if (test_bit(mISDN_STACK_STOPPED, &st->status)) {
2908c2ecf20Sopenharmony_ci			test_and_clear_bit(mISDN_STACK_RUNNING, &st->status);
2918c2ecf20Sopenharmony_ci#ifdef MISDN_MSG_STATS
2928c2ecf20Sopenharmony_ci			st->stopped_cnt++;
2938c2ecf20Sopenharmony_ci#endif
2948c2ecf20Sopenharmony_ci		}
2958c2ecf20Sopenharmony_ci	}
2968c2ecf20Sopenharmony_ci#ifdef MISDN_MSG_STATS
2978c2ecf20Sopenharmony_ci	printk(KERN_DEBUG "mISDNStackd daemon for %s proceed %d "
2988c2ecf20Sopenharmony_ci	       "msg %d sleep %d stopped\n",
2998c2ecf20Sopenharmony_ci	       dev_name(&st->dev->dev), st->msg_cnt, st->sleep_cnt,
3008c2ecf20Sopenharmony_ci	       st->stopped_cnt);
3018c2ecf20Sopenharmony_ci	task_cputime(st->thread, &utime, &stime);
3028c2ecf20Sopenharmony_ci	printk(KERN_DEBUG
3038c2ecf20Sopenharmony_ci	       "mISDNStackd daemon for %s utime(%llu) stime(%llu)\n",
3048c2ecf20Sopenharmony_ci	       dev_name(&st->dev->dev), utime, stime);
3058c2ecf20Sopenharmony_ci	printk(KERN_DEBUG
3068c2ecf20Sopenharmony_ci	       "mISDNStackd daemon for %s nvcsw(%ld) nivcsw(%ld)\n",
3078c2ecf20Sopenharmony_ci	       dev_name(&st->dev->dev), st->thread->nvcsw, st->thread->nivcsw);
3088c2ecf20Sopenharmony_ci	printk(KERN_DEBUG "mISDNStackd daemon for %s killed now\n",
3098c2ecf20Sopenharmony_ci	       dev_name(&st->dev->dev));
3108c2ecf20Sopenharmony_ci#endif
3118c2ecf20Sopenharmony_ci	test_and_set_bit(mISDN_STACK_KILLED, &st->status);
3128c2ecf20Sopenharmony_ci	test_and_clear_bit(mISDN_STACK_RUNNING, &st->status);
3138c2ecf20Sopenharmony_ci	test_and_clear_bit(mISDN_STACK_ACTIVE, &st->status);
3148c2ecf20Sopenharmony_ci	test_and_clear_bit(mISDN_STACK_ABORT, &st->status);
3158c2ecf20Sopenharmony_ci	skb_queue_purge(&st->msgq);
3168c2ecf20Sopenharmony_ci	st->thread = NULL;
3178c2ecf20Sopenharmony_ci	if (st->notify != NULL) {
3188c2ecf20Sopenharmony_ci		complete(st->notify);
3198c2ecf20Sopenharmony_ci		st->notify = NULL;
3208c2ecf20Sopenharmony_ci	}
3218c2ecf20Sopenharmony_ci	return 0;
3228c2ecf20Sopenharmony_ci}
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_cistatic int
3258c2ecf20Sopenharmony_cil1_receive(struct mISDNchannel *ch, struct sk_buff *skb)
3268c2ecf20Sopenharmony_ci{
3278c2ecf20Sopenharmony_ci	if (!ch->st)
3288c2ecf20Sopenharmony_ci		return -ENODEV;
3298c2ecf20Sopenharmony_ci	__net_timestamp(skb);
3308c2ecf20Sopenharmony_ci	_queue_message(ch->st, skb);
3318c2ecf20Sopenharmony_ci	return 0;
3328c2ecf20Sopenharmony_ci}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_civoid
3358c2ecf20Sopenharmony_ciset_channel_address(struct mISDNchannel *ch, u_int sapi, u_int tei)
3368c2ecf20Sopenharmony_ci{
3378c2ecf20Sopenharmony_ci	ch->addr = sapi | (tei << 8);
3388c2ecf20Sopenharmony_ci}
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_civoid
3418c2ecf20Sopenharmony_ci__add_layer2(struct mISDNchannel *ch, struct mISDNstack *st)
3428c2ecf20Sopenharmony_ci{
3438c2ecf20Sopenharmony_ci	list_add_tail(&ch->list, &st->layer2);
3448c2ecf20Sopenharmony_ci}
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_civoid
3478c2ecf20Sopenharmony_ciadd_layer2(struct mISDNchannel *ch, struct mISDNstack *st)
3488c2ecf20Sopenharmony_ci{
3498c2ecf20Sopenharmony_ci	mutex_lock(&st->lmutex);
3508c2ecf20Sopenharmony_ci	__add_layer2(ch, st);
3518c2ecf20Sopenharmony_ci	mutex_unlock(&st->lmutex);
3528c2ecf20Sopenharmony_ci}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_cistatic int
3558c2ecf20Sopenharmony_cist_own_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
3568c2ecf20Sopenharmony_ci{
3578c2ecf20Sopenharmony_ci	if (!ch->st || !ch->st->layer1)
3588c2ecf20Sopenharmony_ci		return -EINVAL;
3598c2ecf20Sopenharmony_ci	return ch->st->layer1->ctrl(ch->st->layer1, cmd, arg);
3608c2ecf20Sopenharmony_ci}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ciint
3638c2ecf20Sopenharmony_cicreate_stack(struct mISDNdevice *dev)
3648c2ecf20Sopenharmony_ci{
3658c2ecf20Sopenharmony_ci	struct mISDNstack	*newst;
3668c2ecf20Sopenharmony_ci	int			err;
3678c2ecf20Sopenharmony_ci	DECLARE_COMPLETION_ONSTACK(done);
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	newst = kzalloc(sizeof(struct mISDNstack), GFP_KERNEL);
3708c2ecf20Sopenharmony_ci	if (!newst) {
3718c2ecf20Sopenharmony_ci		printk(KERN_ERR "kmalloc mISDN_stack failed\n");
3728c2ecf20Sopenharmony_ci		return -ENOMEM;
3738c2ecf20Sopenharmony_ci	}
3748c2ecf20Sopenharmony_ci	newst->dev = dev;
3758c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&newst->layer2);
3768c2ecf20Sopenharmony_ci	INIT_HLIST_HEAD(&newst->l1sock.head);
3778c2ecf20Sopenharmony_ci	rwlock_init(&newst->l1sock.lock);
3788c2ecf20Sopenharmony_ci	init_waitqueue_head(&newst->workq);
3798c2ecf20Sopenharmony_ci	skb_queue_head_init(&newst->msgq);
3808c2ecf20Sopenharmony_ci	mutex_init(&newst->lmutex);
3818c2ecf20Sopenharmony_ci	dev->D.st = newst;
3828c2ecf20Sopenharmony_ci	err = create_teimanager(dev);
3838c2ecf20Sopenharmony_ci	if (err) {
3848c2ecf20Sopenharmony_ci		printk(KERN_ERR "kmalloc teimanager failed\n");
3858c2ecf20Sopenharmony_ci		kfree(newst);
3868c2ecf20Sopenharmony_ci		return err;
3878c2ecf20Sopenharmony_ci	}
3888c2ecf20Sopenharmony_ci	dev->teimgr->peer = &newst->own;
3898c2ecf20Sopenharmony_ci	dev->teimgr->recv = mISDN_queue_message;
3908c2ecf20Sopenharmony_ci	dev->teimgr->st = newst;
3918c2ecf20Sopenharmony_ci	newst->layer1 = &dev->D;
3928c2ecf20Sopenharmony_ci	dev->D.recv = l1_receive;
3938c2ecf20Sopenharmony_ci	dev->D.peer = &newst->own;
3948c2ecf20Sopenharmony_ci	newst->own.st = newst;
3958c2ecf20Sopenharmony_ci	newst->own.ctrl = st_own_ctrl;
3968c2ecf20Sopenharmony_ci	newst->own.send = mISDN_queue_message;
3978c2ecf20Sopenharmony_ci	newst->own.recv = mISDN_queue_message;
3988c2ecf20Sopenharmony_ci	if (*debug & DEBUG_CORE_FUNC)
3998c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "%s: st(%s)\n", __func__,
4008c2ecf20Sopenharmony_ci		       dev_name(&newst->dev->dev));
4018c2ecf20Sopenharmony_ci	newst->notify = &done;
4028c2ecf20Sopenharmony_ci	newst->thread = kthread_run(mISDNStackd, (void *)newst, "mISDN_%s",
4038c2ecf20Sopenharmony_ci				    dev_name(&newst->dev->dev));
4048c2ecf20Sopenharmony_ci	if (IS_ERR(newst->thread)) {
4058c2ecf20Sopenharmony_ci		err = PTR_ERR(newst->thread);
4068c2ecf20Sopenharmony_ci		printk(KERN_ERR
4078c2ecf20Sopenharmony_ci		       "mISDN:cannot create kernel thread for %s (%d)\n",
4088c2ecf20Sopenharmony_ci		       dev_name(&newst->dev->dev), err);
4098c2ecf20Sopenharmony_ci		delete_teimanager(dev->teimgr);
4108c2ecf20Sopenharmony_ci		kfree(newst);
4118c2ecf20Sopenharmony_ci	} else
4128c2ecf20Sopenharmony_ci		wait_for_completion(&done);
4138c2ecf20Sopenharmony_ci	return err;
4148c2ecf20Sopenharmony_ci}
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ciint
4178c2ecf20Sopenharmony_ciconnect_layer1(struct mISDNdevice *dev, struct mISDNchannel *ch,
4188c2ecf20Sopenharmony_ci	       u_int protocol, struct sockaddr_mISDN *adr)
4198c2ecf20Sopenharmony_ci{
4208c2ecf20Sopenharmony_ci	struct mISDN_sock	*msk = container_of(ch, struct mISDN_sock, ch);
4218c2ecf20Sopenharmony_ci	struct channel_req	rq;
4228c2ecf20Sopenharmony_ci	int			err;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	if (*debug &  DEBUG_CORE_FUNC)
4268c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n",
4278c2ecf20Sopenharmony_ci		       __func__, dev_name(&dev->dev), protocol, adr->dev,
4288c2ecf20Sopenharmony_ci		       adr->channel, adr->sapi, adr->tei);
4298c2ecf20Sopenharmony_ci	switch (protocol) {
4308c2ecf20Sopenharmony_ci	case ISDN_P_NT_S0:
4318c2ecf20Sopenharmony_ci	case ISDN_P_NT_E1:
4328c2ecf20Sopenharmony_ci	case ISDN_P_TE_S0:
4338c2ecf20Sopenharmony_ci	case ISDN_P_TE_E1:
4348c2ecf20Sopenharmony_ci		ch->recv = mISDN_queue_message;
4358c2ecf20Sopenharmony_ci		ch->peer = &dev->D.st->own;
4368c2ecf20Sopenharmony_ci		ch->st = dev->D.st;
4378c2ecf20Sopenharmony_ci		rq.protocol = protocol;
4388c2ecf20Sopenharmony_ci		rq.adr.channel = adr->channel;
4398c2ecf20Sopenharmony_ci		err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq);
4408c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "%s: ret %d (dev %d)\n", __func__, err,
4418c2ecf20Sopenharmony_ci		       dev->id);
4428c2ecf20Sopenharmony_ci		if (err)
4438c2ecf20Sopenharmony_ci			return err;
4448c2ecf20Sopenharmony_ci		write_lock_bh(&dev->D.st->l1sock.lock);
4458c2ecf20Sopenharmony_ci		sk_add_node(&msk->sk, &dev->D.st->l1sock.head);
4468c2ecf20Sopenharmony_ci		write_unlock_bh(&dev->D.st->l1sock.lock);
4478c2ecf20Sopenharmony_ci		break;
4488c2ecf20Sopenharmony_ci	default:
4498c2ecf20Sopenharmony_ci		return -ENOPROTOOPT;
4508c2ecf20Sopenharmony_ci	}
4518c2ecf20Sopenharmony_ci	return 0;
4528c2ecf20Sopenharmony_ci}
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ciint
4558c2ecf20Sopenharmony_ciconnect_Bstack(struct mISDNdevice *dev, struct mISDNchannel *ch,
4568c2ecf20Sopenharmony_ci	       u_int protocol, struct sockaddr_mISDN *adr)
4578c2ecf20Sopenharmony_ci{
4588c2ecf20Sopenharmony_ci	struct channel_req	rq, rq2;
4598c2ecf20Sopenharmony_ci	int			pmask, err;
4608c2ecf20Sopenharmony_ci	struct Bprotocol	*bp;
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	if (*debug &  DEBUG_CORE_FUNC)
4638c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n",
4648c2ecf20Sopenharmony_ci		       __func__, dev_name(&dev->dev), protocol,
4658c2ecf20Sopenharmony_ci		       adr->dev, adr->channel, adr->sapi,
4668c2ecf20Sopenharmony_ci		       adr->tei);
4678c2ecf20Sopenharmony_ci	ch->st = dev->D.st;
4688c2ecf20Sopenharmony_ci	pmask = 1 << (protocol & ISDN_P_B_MASK);
4698c2ecf20Sopenharmony_ci	if (pmask & dev->Bprotocols) {
4708c2ecf20Sopenharmony_ci		rq.protocol = protocol;
4718c2ecf20Sopenharmony_ci		rq.adr = *adr;
4728c2ecf20Sopenharmony_ci		err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq);
4738c2ecf20Sopenharmony_ci		if (err)
4748c2ecf20Sopenharmony_ci			return err;
4758c2ecf20Sopenharmony_ci		ch->recv = rq.ch->send;
4768c2ecf20Sopenharmony_ci		ch->peer = rq.ch;
4778c2ecf20Sopenharmony_ci		rq.ch->recv = ch->send;
4788c2ecf20Sopenharmony_ci		rq.ch->peer = ch;
4798c2ecf20Sopenharmony_ci		rq.ch->st = dev->D.st;
4808c2ecf20Sopenharmony_ci	} else {
4818c2ecf20Sopenharmony_ci		bp = get_Bprotocol4mask(pmask);
4828c2ecf20Sopenharmony_ci		if (!bp)
4838c2ecf20Sopenharmony_ci			return -ENOPROTOOPT;
4848c2ecf20Sopenharmony_ci		rq2.protocol = protocol;
4858c2ecf20Sopenharmony_ci		rq2.adr = *adr;
4868c2ecf20Sopenharmony_ci		rq2.ch = ch;
4878c2ecf20Sopenharmony_ci		err = bp->create(&rq2);
4888c2ecf20Sopenharmony_ci		if (err)
4898c2ecf20Sopenharmony_ci			return err;
4908c2ecf20Sopenharmony_ci		ch->recv = rq2.ch->send;
4918c2ecf20Sopenharmony_ci		ch->peer = rq2.ch;
4928c2ecf20Sopenharmony_ci		rq2.ch->st = dev->D.st;
4938c2ecf20Sopenharmony_ci		rq.protocol = rq2.protocol;
4948c2ecf20Sopenharmony_ci		rq.adr = *adr;
4958c2ecf20Sopenharmony_ci		err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq);
4968c2ecf20Sopenharmony_ci		if (err) {
4978c2ecf20Sopenharmony_ci			rq2.ch->ctrl(rq2.ch, CLOSE_CHANNEL, NULL);
4988c2ecf20Sopenharmony_ci			return err;
4998c2ecf20Sopenharmony_ci		}
5008c2ecf20Sopenharmony_ci		rq2.ch->recv = rq.ch->send;
5018c2ecf20Sopenharmony_ci		rq2.ch->peer = rq.ch;
5028c2ecf20Sopenharmony_ci		rq.ch->recv = rq2.ch->send;
5038c2ecf20Sopenharmony_ci		rq.ch->peer = rq2.ch;
5048c2ecf20Sopenharmony_ci		rq.ch->st = dev->D.st;
5058c2ecf20Sopenharmony_ci	}
5068c2ecf20Sopenharmony_ci	ch->protocol = protocol;
5078c2ecf20Sopenharmony_ci	ch->nr = rq.ch->nr;
5088c2ecf20Sopenharmony_ci	return 0;
5098c2ecf20Sopenharmony_ci}
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ciint
5128c2ecf20Sopenharmony_cicreate_l2entity(struct mISDNdevice *dev, struct mISDNchannel *ch,
5138c2ecf20Sopenharmony_ci		u_int protocol, struct sockaddr_mISDN *adr)
5148c2ecf20Sopenharmony_ci{
5158c2ecf20Sopenharmony_ci	struct channel_req	rq;
5168c2ecf20Sopenharmony_ci	int			err;
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	if (*debug &  DEBUG_CORE_FUNC)
5198c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n",
5208c2ecf20Sopenharmony_ci		       __func__, dev_name(&dev->dev), protocol,
5218c2ecf20Sopenharmony_ci		       adr->dev, adr->channel, adr->sapi,
5228c2ecf20Sopenharmony_ci		       adr->tei);
5238c2ecf20Sopenharmony_ci	rq.protocol = ISDN_P_TE_S0;
5248c2ecf20Sopenharmony_ci	if (dev->Dprotocols & (1 << ISDN_P_TE_E1))
5258c2ecf20Sopenharmony_ci		rq.protocol = ISDN_P_TE_E1;
5268c2ecf20Sopenharmony_ci	switch (protocol) {
5278c2ecf20Sopenharmony_ci	case ISDN_P_LAPD_NT:
5288c2ecf20Sopenharmony_ci		rq.protocol = ISDN_P_NT_S0;
5298c2ecf20Sopenharmony_ci		if (dev->Dprotocols & (1 << ISDN_P_NT_E1))
5308c2ecf20Sopenharmony_ci			rq.protocol = ISDN_P_NT_E1;
5318c2ecf20Sopenharmony_ci		fallthrough;
5328c2ecf20Sopenharmony_ci	case ISDN_P_LAPD_TE:
5338c2ecf20Sopenharmony_ci		ch->recv = mISDN_queue_message;
5348c2ecf20Sopenharmony_ci		ch->peer = &dev->D.st->own;
5358c2ecf20Sopenharmony_ci		ch->st = dev->D.st;
5368c2ecf20Sopenharmony_ci		rq.adr.channel = 0;
5378c2ecf20Sopenharmony_ci		err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq);
5388c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "%s: ret 1 %d\n", __func__, err);
5398c2ecf20Sopenharmony_ci		if (err)
5408c2ecf20Sopenharmony_ci			break;
5418c2ecf20Sopenharmony_ci		rq.protocol = protocol;
5428c2ecf20Sopenharmony_ci		rq.adr = *adr;
5438c2ecf20Sopenharmony_ci		rq.ch = ch;
5448c2ecf20Sopenharmony_ci		err = dev->teimgr->ctrl(dev->teimgr, OPEN_CHANNEL, &rq);
5458c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "%s: ret 2 %d\n", __func__, err);
5468c2ecf20Sopenharmony_ci		if (!err) {
5478c2ecf20Sopenharmony_ci			if ((protocol == ISDN_P_LAPD_NT) && !rq.ch)
5488c2ecf20Sopenharmony_ci				break;
5498c2ecf20Sopenharmony_ci			add_layer2(rq.ch, dev->D.st);
5508c2ecf20Sopenharmony_ci			rq.ch->recv = mISDN_queue_message;
5518c2ecf20Sopenharmony_ci			rq.ch->peer = &dev->D.st->own;
5528c2ecf20Sopenharmony_ci			rq.ch->ctrl(rq.ch, OPEN_CHANNEL, NULL); /* can't fail */
5538c2ecf20Sopenharmony_ci		}
5548c2ecf20Sopenharmony_ci		break;
5558c2ecf20Sopenharmony_ci	default:
5568c2ecf20Sopenharmony_ci		err = -EPROTONOSUPPORT;
5578c2ecf20Sopenharmony_ci	}
5588c2ecf20Sopenharmony_ci	return err;
5598c2ecf20Sopenharmony_ci}
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_civoid
5628c2ecf20Sopenharmony_cidelete_channel(struct mISDNchannel *ch)
5638c2ecf20Sopenharmony_ci{
5648c2ecf20Sopenharmony_ci	struct mISDN_sock	*msk = container_of(ch, struct mISDN_sock, ch);
5658c2ecf20Sopenharmony_ci	struct mISDNchannel	*pch;
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	if (!ch->st) {
5688c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: no stack\n", __func__);
5698c2ecf20Sopenharmony_ci		return;
5708c2ecf20Sopenharmony_ci	}
5718c2ecf20Sopenharmony_ci	if (*debug & DEBUG_CORE_FUNC)
5728c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "%s: st(%s) protocol(%x)\n", __func__,
5738c2ecf20Sopenharmony_ci		       dev_name(&ch->st->dev->dev), ch->protocol);
5748c2ecf20Sopenharmony_ci	if (ch->protocol >= ISDN_P_B_START) {
5758c2ecf20Sopenharmony_ci		if (ch->peer) {
5768c2ecf20Sopenharmony_ci			ch->peer->ctrl(ch->peer, CLOSE_CHANNEL, NULL);
5778c2ecf20Sopenharmony_ci			ch->peer = NULL;
5788c2ecf20Sopenharmony_ci		}
5798c2ecf20Sopenharmony_ci		return;
5808c2ecf20Sopenharmony_ci	}
5818c2ecf20Sopenharmony_ci	switch (ch->protocol) {
5828c2ecf20Sopenharmony_ci	case ISDN_P_NT_S0:
5838c2ecf20Sopenharmony_ci	case ISDN_P_TE_S0:
5848c2ecf20Sopenharmony_ci	case ISDN_P_NT_E1:
5858c2ecf20Sopenharmony_ci	case ISDN_P_TE_E1:
5868c2ecf20Sopenharmony_ci		write_lock_bh(&ch->st->l1sock.lock);
5878c2ecf20Sopenharmony_ci		sk_del_node_init(&msk->sk);
5888c2ecf20Sopenharmony_ci		write_unlock_bh(&ch->st->l1sock.lock);
5898c2ecf20Sopenharmony_ci		ch->st->dev->D.ctrl(&ch->st->dev->D, CLOSE_CHANNEL, NULL);
5908c2ecf20Sopenharmony_ci		break;
5918c2ecf20Sopenharmony_ci	case ISDN_P_LAPD_TE:
5928c2ecf20Sopenharmony_ci		pch = get_channel4id(ch->st, ch->nr);
5938c2ecf20Sopenharmony_ci		if (pch) {
5948c2ecf20Sopenharmony_ci			mutex_lock(&ch->st->lmutex);
5958c2ecf20Sopenharmony_ci			list_del(&pch->list);
5968c2ecf20Sopenharmony_ci			mutex_unlock(&ch->st->lmutex);
5978c2ecf20Sopenharmony_ci			pch->ctrl(pch, CLOSE_CHANNEL, NULL);
5988c2ecf20Sopenharmony_ci			pch = ch->st->dev->teimgr;
5998c2ecf20Sopenharmony_ci			pch->ctrl(pch, CLOSE_CHANNEL, NULL);
6008c2ecf20Sopenharmony_ci		} else
6018c2ecf20Sopenharmony_ci			printk(KERN_WARNING "%s: no l2 channel\n",
6028c2ecf20Sopenharmony_ci			       __func__);
6038c2ecf20Sopenharmony_ci		break;
6048c2ecf20Sopenharmony_ci	case ISDN_P_LAPD_NT:
6058c2ecf20Sopenharmony_ci		pch = ch->st->dev->teimgr;
6068c2ecf20Sopenharmony_ci		if (pch) {
6078c2ecf20Sopenharmony_ci			pch->ctrl(pch, CLOSE_CHANNEL, NULL);
6088c2ecf20Sopenharmony_ci		} else
6098c2ecf20Sopenharmony_ci			printk(KERN_WARNING "%s: no l2 channel\n",
6108c2ecf20Sopenharmony_ci			       __func__);
6118c2ecf20Sopenharmony_ci		break;
6128c2ecf20Sopenharmony_ci	default:
6138c2ecf20Sopenharmony_ci		break;
6148c2ecf20Sopenharmony_ci	}
6158c2ecf20Sopenharmony_ci	return;
6168c2ecf20Sopenharmony_ci}
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_civoid
6198c2ecf20Sopenharmony_cidelete_stack(struct mISDNdevice *dev)
6208c2ecf20Sopenharmony_ci{
6218c2ecf20Sopenharmony_ci	struct mISDNstack	*st = dev->D.st;
6228c2ecf20Sopenharmony_ci	DECLARE_COMPLETION_ONSTACK(done);
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	if (*debug & DEBUG_CORE_FUNC)
6258c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "%s: st(%s)\n", __func__,
6268c2ecf20Sopenharmony_ci		       dev_name(&st->dev->dev));
6278c2ecf20Sopenharmony_ci	if (dev->teimgr)
6288c2ecf20Sopenharmony_ci		delete_teimanager(dev->teimgr);
6298c2ecf20Sopenharmony_ci	if (st->thread) {
6308c2ecf20Sopenharmony_ci		if (st->notify) {
6318c2ecf20Sopenharmony_ci			printk(KERN_WARNING "%s: notifier in use\n",
6328c2ecf20Sopenharmony_ci			       __func__);
6338c2ecf20Sopenharmony_ci			complete(st->notify);
6348c2ecf20Sopenharmony_ci		}
6358c2ecf20Sopenharmony_ci		st->notify = &done;
6368c2ecf20Sopenharmony_ci		test_and_set_bit(mISDN_STACK_ABORT, &st->status);
6378c2ecf20Sopenharmony_ci		test_and_set_bit(mISDN_STACK_WAKEUP, &st->status);
6388c2ecf20Sopenharmony_ci		wake_up_interruptible(&st->workq);
6398c2ecf20Sopenharmony_ci		wait_for_completion(&done);
6408c2ecf20Sopenharmony_ci	}
6418c2ecf20Sopenharmony_ci	if (!list_empty(&st->layer2))
6428c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: layer2 list not empty\n",
6438c2ecf20Sopenharmony_ci		       __func__);
6448c2ecf20Sopenharmony_ci	if (!hlist_empty(&st->l1sock.head))
6458c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: layer1 list not empty\n",
6468c2ecf20Sopenharmony_ci		       __func__);
6478c2ecf20Sopenharmony_ci	kfree(st);
6488c2ecf20Sopenharmony_ci}
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_civoid
6518c2ecf20Sopenharmony_cimISDN_initstack(u_int *dp)
6528c2ecf20Sopenharmony_ci{
6538c2ecf20Sopenharmony_ci	debug = dp;
6548c2ecf20Sopenharmony_ci}
655