162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Author	Karsten Keil <kkeil@novell.com>
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright 2008  by Karsten Keil <kkeil@novell.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/slab.h>
1062306a36Sopenharmony_ci#include <linux/mISDNif.h>
1162306a36Sopenharmony_ci#include <linux/kthread.h>
1262306a36Sopenharmony_ci#include <linux/sched.h>
1362306a36Sopenharmony_ci#include <linux/sched/cputime.h>
1462306a36Sopenharmony_ci#include <linux/signal.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include "core.h"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_cistatic u_int	*debug;
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistatic inline void
2162306a36Sopenharmony_ci_queue_message(struct mISDNstack *st, struct sk_buff *skb)
2262306a36Sopenharmony_ci{
2362306a36Sopenharmony_ci	struct mISDNhead	*hh = mISDN_HEAD_P(skb);
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	if (*debug & DEBUG_QUEUE_FUNC)
2662306a36Sopenharmony_ci		printk(KERN_DEBUG "%s prim(%x) id(%x) %p\n",
2762306a36Sopenharmony_ci		       __func__, hh->prim, hh->id, skb);
2862306a36Sopenharmony_ci	skb_queue_tail(&st->msgq, skb);
2962306a36Sopenharmony_ci	if (likely(!test_bit(mISDN_STACK_STOPPED, &st->status))) {
3062306a36Sopenharmony_ci		test_and_set_bit(mISDN_STACK_WORK, &st->status);
3162306a36Sopenharmony_ci		wake_up_interruptible(&st->workq);
3262306a36Sopenharmony_ci	}
3362306a36Sopenharmony_ci}
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic int
3662306a36Sopenharmony_cimISDN_queue_message(struct mISDNchannel *ch, struct sk_buff *skb)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	_queue_message(ch->st, skb);
3962306a36Sopenharmony_ci	return 0;
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic struct mISDNchannel *
4362306a36Sopenharmony_ciget_channel4id(struct mISDNstack *st, u_int id)
4462306a36Sopenharmony_ci{
4562306a36Sopenharmony_ci	struct mISDNchannel	*ch;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	mutex_lock(&st->lmutex);
4862306a36Sopenharmony_ci	list_for_each_entry(ch, &st->layer2, list) {
4962306a36Sopenharmony_ci		if (id == ch->nr)
5062306a36Sopenharmony_ci			goto unlock;
5162306a36Sopenharmony_ci	}
5262306a36Sopenharmony_ci	ch = NULL;
5362306a36Sopenharmony_ciunlock:
5462306a36Sopenharmony_ci	mutex_unlock(&st->lmutex);
5562306a36Sopenharmony_ci	return ch;
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistatic void
5962306a36Sopenharmony_cisend_socklist(struct mISDN_sock_list *sl, struct sk_buff *skb)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	struct sock		*sk;
6262306a36Sopenharmony_ci	struct sk_buff		*cskb = NULL;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	read_lock(&sl->lock);
6562306a36Sopenharmony_ci	sk_for_each(sk, &sl->head) {
6662306a36Sopenharmony_ci		if (sk->sk_state != MISDN_BOUND)
6762306a36Sopenharmony_ci			continue;
6862306a36Sopenharmony_ci		if (!cskb)
6962306a36Sopenharmony_ci			cskb = skb_copy(skb, GFP_ATOMIC);
7062306a36Sopenharmony_ci		if (!cskb) {
7162306a36Sopenharmony_ci			printk(KERN_WARNING "%s no skb\n", __func__);
7262306a36Sopenharmony_ci			break;
7362306a36Sopenharmony_ci		}
7462306a36Sopenharmony_ci		if (!sock_queue_rcv_skb(sk, cskb))
7562306a36Sopenharmony_ci			cskb = NULL;
7662306a36Sopenharmony_ci	}
7762306a36Sopenharmony_ci	read_unlock(&sl->lock);
7862306a36Sopenharmony_ci	dev_kfree_skb(cskb);
7962306a36Sopenharmony_ci}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistatic void
8262306a36Sopenharmony_cisend_layer2(struct mISDNstack *st, struct sk_buff *skb)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	struct sk_buff		*cskb;
8562306a36Sopenharmony_ci	struct mISDNhead	*hh = mISDN_HEAD_P(skb);
8662306a36Sopenharmony_ci	struct mISDNchannel	*ch;
8762306a36Sopenharmony_ci	int			ret;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	if (!st)
9062306a36Sopenharmony_ci		return;
9162306a36Sopenharmony_ci	mutex_lock(&st->lmutex);
9262306a36Sopenharmony_ci	if ((hh->id & MISDN_ID_ADDR_MASK) == MISDN_ID_ANY) { /* L2 for all */
9362306a36Sopenharmony_ci		list_for_each_entry(ch, &st->layer2, list) {
9462306a36Sopenharmony_ci			if (list_is_last(&ch->list, &st->layer2)) {
9562306a36Sopenharmony_ci				cskb = skb;
9662306a36Sopenharmony_ci				skb = NULL;
9762306a36Sopenharmony_ci			} else {
9862306a36Sopenharmony_ci				cskb = skb_copy(skb, GFP_KERNEL);
9962306a36Sopenharmony_ci			}
10062306a36Sopenharmony_ci			if (cskb) {
10162306a36Sopenharmony_ci				ret = ch->send(ch, cskb);
10262306a36Sopenharmony_ci				if (ret) {
10362306a36Sopenharmony_ci					if (*debug & DEBUG_SEND_ERR)
10462306a36Sopenharmony_ci						printk(KERN_DEBUG
10562306a36Sopenharmony_ci						       "%s ch%d prim(%x) addr(%x)"
10662306a36Sopenharmony_ci						       " err %d\n",
10762306a36Sopenharmony_ci						       __func__, ch->nr,
10862306a36Sopenharmony_ci						       hh->prim, ch->addr, ret);
10962306a36Sopenharmony_ci					dev_kfree_skb(cskb);
11062306a36Sopenharmony_ci				}
11162306a36Sopenharmony_ci			} else {
11262306a36Sopenharmony_ci				printk(KERN_WARNING "%s ch%d addr %x no mem\n",
11362306a36Sopenharmony_ci				       __func__, ch->nr, ch->addr);
11462306a36Sopenharmony_ci				goto out;
11562306a36Sopenharmony_ci			}
11662306a36Sopenharmony_ci		}
11762306a36Sopenharmony_ci	} else {
11862306a36Sopenharmony_ci		list_for_each_entry(ch, &st->layer2, list) {
11962306a36Sopenharmony_ci			if ((hh->id & MISDN_ID_ADDR_MASK) == ch->addr) {
12062306a36Sopenharmony_ci				ret = ch->send(ch, skb);
12162306a36Sopenharmony_ci				if (!ret)
12262306a36Sopenharmony_ci					skb = NULL;
12362306a36Sopenharmony_ci				goto out;
12462306a36Sopenharmony_ci			}
12562306a36Sopenharmony_ci		}
12662306a36Sopenharmony_ci		ret = st->dev->teimgr->ctrl(st->dev->teimgr, CHECK_DATA, skb);
12762306a36Sopenharmony_ci		if (!ret)
12862306a36Sopenharmony_ci			skb = NULL;
12962306a36Sopenharmony_ci		else if (*debug & DEBUG_SEND_ERR)
13062306a36Sopenharmony_ci			printk(KERN_DEBUG
13162306a36Sopenharmony_ci			       "%s mgr prim(%x) err %d\n",
13262306a36Sopenharmony_ci			       __func__, hh->prim, ret);
13362306a36Sopenharmony_ci	}
13462306a36Sopenharmony_ciout:
13562306a36Sopenharmony_ci	mutex_unlock(&st->lmutex);
13662306a36Sopenharmony_ci	dev_kfree_skb(skb);
13762306a36Sopenharmony_ci}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_cistatic inline int
14062306a36Sopenharmony_cisend_msg_to_layer(struct mISDNstack *st, struct sk_buff *skb)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	struct mISDNhead	*hh = mISDN_HEAD_P(skb);
14362306a36Sopenharmony_ci	struct mISDNchannel	*ch;
14462306a36Sopenharmony_ci	int	lm;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	lm = hh->prim & MISDN_LAYERMASK;
14762306a36Sopenharmony_ci	if (*debug & DEBUG_QUEUE_FUNC)
14862306a36Sopenharmony_ci		printk(KERN_DEBUG "%s prim(%x) id(%x) %p\n",
14962306a36Sopenharmony_ci		       __func__, hh->prim, hh->id, skb);
15062306a36Sopenharmony_ci	if (lm == 0x1) {
15162306a36Sopenharmony_ci		if (!hlist_empty(&st->l1sock.head)) {
15262306a36Sopenharmony_ci			__net_timestamp(skb);
15362306a36Sopenharmony_ci			send_socklist(&st->l1sock, skb);
15462306a36Sopenharmony_ci		}
15562306a36Sopenharmony_ci		return st->layer1->send(st->layer1, skb);
15662306a36Sopenharmony_ci	} else if (lm == 0x2) {
15762306a36Sopenharmony_ci		if (!hlist_empty(&st->l1sock.head))
15862306a36Sopenharmony_ci			send_socklist(&st->l1sock, skb);
15962306a36Sopenharmony_ci		send_layer2(st, skb);
16062306a36Sopenharmony_ci		return 0;
16162306a36Sopenharmony_ci	} else if (lm == 0x4) {
16262306a36Sopenharmony_ci		ch = get_channel4id(st, hh->id);
16362306a36Sopenharmony_ci		if (ch)
16462306a36Sopenharmony_ci			return ch->send(ch, skb);
16562306a36Sopenharmony_ci		else
16662306a36Sopenharmony_ci			printk(KERN_WARNING
16762306a36Sopenharmony_ci			       "%s: dev(%s) prim(%x) id(%x) no channel\n",
16862306a36Sopenharmony_ci			       __func__, dev_name(&st->dev->dev), hh->prim,
16962306a36Sopenharmony_ci			       hh->id);
17062306a36Sopenharmony_ci	} else if (lm == 0x8) {
17162306a36Sopenharmony_ci		WARN_ON(lm == 0x8);
17262306a36Sopenharmony_ci		ch = get_channel4id(st, hh->id);
17362306a36Sopenharmony_ci		if (ch)
17462306a36Sopenharmony_ci			return ch->send(ch, skb);
17562306a36Sopenharmony_ci		else
17662306a36Sopenharmony_ci			printk(KERN_WARNING
17762306a36Sopenharmony_ci			       "%s: dev(%s) prim(%x) id(%x) no channel\n",
17862306a36Sopenharmony_ci			       __func__, dev_name(&st->dev->dev), hh->prim,
17962306a36Sopenharmony_ci			       hh->id);
18062306a36Sopenharmony_ci	} else {
18162306a36Sopenharmony_ci		/* broadcast not handled yet */
18262306a36Sopenharmony_ci		printk(KERN_WARNING "%s: dev(%s) prim %x not delivered\n",
18362306a36Sopenharmony_ci		       __func__, dev_name(&st->dev->dev), hh->prim);
18462306a36Sopenharmony_ci	}
18562306a36Sopenharmony_ci	return -ESRCH;
18662306a36Sopenharmony_ci}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_cistatic void
18962306a36Sopenharmony_cido_clear_stack(struct mISDNstack *st)
19062306a36Sopenharmony_ci{
19162306a36Sopenharmony_ci}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_cistatic int
19462306a36Sopenharmony_cimISDNStackd(void *data)
19562306a36Sopenharmony_ci{
19662306a36Sopenharmony_ci	struct mISDNstack *st = data;
19762306a36Sopenharmony_ci#ifdef MISDN_MSG_STATS
19862306a36Sopenharmony_ci	u64 utime, stime;
19962306a36Sopenharmony_ci#endif
20062306a36Sopenharmony_ci	int err = 0;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	sigfillset(&current->blocked);
20362306a36Sopenharmony_ci	if (*debug & DEBUG_MSG_THREAD)
20462306a36Sopenharmony_ci		printk(KERN_DEBUG "mISDNStackd %s started\n",
20562306a36Sopenharmony_ci		       dev_name(&st->dev->dev));
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	if (st->notify != NULL) {
20862306a36Sopenharmony_ci		complete(st->notify);
20962306a36Sopenharmony_ci		st->notify = NULL;
21062306a36Sopenharmony_ci	}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	for (;;) {
21362306a36Sopenharmony_ci		struct sk_buff	*skb;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci		if (unlikely(test_bit(mISDN_STACK_STOPPED, &st->status))) {
21662306a36Sopenharmony_ci			test_and_clear_bit(mISDN_STACK_WORK, &st->status);
21762306a36Sopenharmony_ci			test_and_clear_bit(mISDN_STACK_RUNNING, &st->status);
21862306a36Sopenharmony_ci		} else
21962306a36Sopenharmony_ci			test_and_set_bit(mISDN_STACK_RUNNING, &st->status);
22062306a36Sopenharmony_ci		while (test_bit(mISDN_STACK_WORK, &st->status)) {
22162306a36Sopenharmony_ci			skb = skb_dequeue(&st->msgq);
22262306a36Sopenharmony_ci			if (!skb) {
22362306a36Sopenharmony_ci				test_and_clear_bit(mISDN_STACK_WORK,
22462306a36Sopenharmony_ci						   &st->status);
22562306a36Sopenharmony_ci				/* test if a race happens */
22662306a36Sopenharmony_ci				skb = skb_dequeue(&st->msgq);
22762306a36Sopenharmony_ci				if (!skb)
22862306a36Sopenharmony_ci					continue;
22962306a36Sopenharmony_ci				test_and_set_bit(mISDN_STACK_WORK,
23062306a36Sopenharmony_ci						 &st->status);
23162306a36Sopenharmony_ci			}
23262306a36Sopenharmony_ci#ifdef MISDN_MSG_STATS
23362306a36Sopenharmony_ci			st->msg_cnt++;
23462306a36Sopenharmony_ci#endif
23562306a36Sopenharmony_ci			err = send_msg_to_layer(st, skb);
23662306a36Sopenharmony_ci			if (unlikely(err)) {
23762306a36Sopenharmony_ci				if (*debug & DEBUG_SEND_ERR)
23862306a36Sopenharmony_ci					printk(KERN_DEBUG
23962306a36Sopenharmony_ci					       "%s: %s prim(%x) id(%x) "
24062306a36Sopenharmony_ci					       "send call(%d)\n",
24162306a36Sopenharmony_ci					       __func__, dev_name(&st->dev->dev),
24262306a36Sopenharmony_ci					       mISDN_HEAD_PRIM(skb),
24362306a36Sopenharmony_ci					       mISDN_HEAD_ID(skb), err);
24462306a36Sopenharmony_ci				dev_kfree_skb(skb);
24562306a36Sopenharmony_ci				continue;
24662306a36Sopenharmony_ci			}
24762306a36Sopenharmony_ci			if (unlikely(test_bit(mISDN_STACK_STOPPED,
24862306a36Sopenharmony_ci					      &st->status))) {
24962306a36Sopenharmony_ci				test_and_clear_bit(mISDN_STACK_WORK,
25062306a36Sopenharmony_ci						   &st->status);
25162306a36Sopenharmony_ci				test_and_clear_bit(mISDN_STACK_RUNNING,
25262306a36Sopenharmony_ci						   &st->status);
25362306a36Sopenharmony_ci				break;
25462306a36Sopenharmony_ci			}
25562306a36Sopenharmony_ci		}
25662306a36Sopenharmony_ci		if (test_bit(mISDN_STACK_CLEARING, &st->status)) {
25762306a36Sopenharmony_ci			test_and_set_bit(mISDN_STACK_STOPPED, &st->status);
25862306a36Sopenharmony_ci			test_and_clear_bit(mISDN_STACK_RUNNING, &st->status);
25962306a36Sopenharmony_ci			do_clear_stack(st);
26062306a36Sopenharmony_ci			test_and_clear_bit(mISDN_STACK_CLEARING, &st->status);
26162306a36Sopenharmony_ci			test_and_set_bit(mISDN_STACK_RESTART, &st->status);
26262306a36Sopenharmony_ci		}
26362306a36Sopenharmony_ci		if (test_and_clear_bit(mISDN_STACK_RESTART, &st->status)) {
26462306a36Sopenharmony_ci			test_and_clear_bit(mISDN_STACK_STOPPED, &st->status);
26562306a36Sopenharmony_ci			test_and_set_bit(mISDN_STACK_RUNNING, &st->status);
26662306a36Sopenharmony_ci			if (!skb_queue_empty(&st->msgq))
26762306a36Sopenharmony_ci				test_and_set_bit(mISDN_STACK_WORK,
26862306a36Sopenharmony_ci						 &st->status);
26962306a36Sopenharmony_ci		}
27062306a36Sopenharmony_ci		if (test_bit(mISDN_STACK_ABORT, &st->status))
27162306a36Sopenharmony_ci			break;
27262306a36Sopenharmony_ci		if (st->notify != NULL) {
27362306a36Sopenharmony_ci			complete(st->notify);
27462306a36Sopenharmony_ci			st->notify = NULL;
27562306a36Sopenharmony_ci		}
27662306a36Sopenharmony_ci#ifdef MISDN_MSG_STATS
27762306a36Sopenharmony_ci		st->sleep_cnt++;
27862306a36Sopenharmony_ci#endif
27962306a36Sopenharmony_ci		test_and_clear_bit(mISDN_STACK_ACTIVE, &st->status);
28062306a36Sopenharmony_ci		wait_event_interruptible(st->workq, (st->status &
28162306a36Sopenharmony_ci						     mISDN_STACK_ACTION_MASK));
28262306a36Sopenharmony_ci		if (*debug & DEBUG_MSG_THREAD)
28362306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: %s wake status %08lx\n",
28462306a36Sopenharmony_ci			       __func__, dev_name(&st->dev->dev), st->status);
28562306a36Sopenharmony_ci		test_and_set_bit(mISDN_STACK_ACTIVE, &st->status);
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci		test_and_clear_bit(mISDN_STACK_WAKEUP, &st->status);
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci		if (test_bit(mISDN_STACK_STOPPED, &st->status)) {
29062306a36Sopenharmony_ci			test_and_clear_bit(mISDN_STACK_RUNNING, &st->status);
29162306a36Sopenharmony_ci#ifdef MISDN_MSG_STATS
29262306a36Sopenharmony_ci			st->stopped_cnt++;
29362306a36Sopenharmony_ci#endif
29462306a36Sopenharmony_ci		}
29562306a36Sopenharmony_ci	}
29662306a36Sopenharmony_ci#ifdef MISDN_MSG_STATS
29762306a36Sopenharmony_ci	printk(KERN_DEBUG "mISDNStackd daemon for %s proceed %d "
29862306a36Sopenharmony_ci	       "msg %d sleep %d stopped\n",
29962306a36Sopenharmony_ci	       dev_name(&st->dev->dev), st->msg_cnt, st->sleep_cnt,
30062306a36Sopenharmony_ci	       st->stopped_cnt);
30162306a36Sopenharmony_ci	task_cputime(st->thread, &utime, &stime);
30262306a36Sopenharmony_ci	printk(KERN_DEBUG
30362306a36Sopenharmony_ci	       "mISDNStackd daemon for %s utime(%llu) stime(%llu)\n",
30462306a36Sopenharmony_ci	       dev_name(&st->dev->dev), utime, stime);
30562306a36Sopenharmony_ci	printk(KERN_DEBUG
30662306a36Sopenharmony_ci	       "mISDNStackd daemon for %s nvcsw(%ld) nivcsw(%ld)\n",
30762306a36Sopenharmony_ci	       dev_name(&st->dev->dev), st->thread->nvcsw, st->thread->nivcsw);
30862306a36Sopenharmony_ci	printk(KERN_DEBUG "mISDNStackd daemon for %s killed now\n",
30962306a36Sopenharmony_ci	       dev_name(&st->dev->dev));
31062306a36Sopenharmony_ci#endif
31162306a36Sopenharmony_ci	test_and_set_bit(mISDN_STACK_KILLED, &st->status);
31262306a36Sopenharmony_ci	test_and_clear_bit(mISDN_STACK_RUNNING, &st->status);
31362306a36Sopenharmony_ci	test_and_clear_bit(mISDN_STACK_ACTIVE, &st->status);
31462306a36Sopenharmony_ci	test_and_clear_bit(mISDN_STACK_ABORT, &st->status);
31562306a36Sopenharmony_ci	skb_queue_purge(&st->msgq);
31662306a36Sopenharmony_ci	st->thread = NULL;
31762306a36Sopenharmony_ci	if (st->notify != NULL) {
31862306a36Sopenharmony_ci		complete(st->notify);
31962306a36Sopenharmony_ci		st->notify = NULL;
32062306a36Sopenharmony_ci	}
32162306a36Sopenharmony_ci	return 0;
32262306a36Sopenharmony_ci}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_cistatic int
32562306a36Sopenharmony_cil1_receive(struct mISDNchannel *ch, struct sk_buff *skb)
32662306a36Sopenharmony_ci{
32762306a36Sopenharmony_ci	if (!ch->st)
32862306a36Sopenharmony_ci		return -ENODEV;
32962306a36Sopenharmony_ci	__net_timestamp(skb);
33062306a36Sopenharmony_ci	_queue_message(ch->st, skb);
33162306a36Sopenharmony_ci	return 0;
33262306a36Sopenharmony_ci}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_civoid
33562306a36Sopenharmony_ciset_channel_address(struct mISDNchannel *ch, u_int sapi, u_int tei)
33662306a36Sopenharmony_ci{
33762306a36Sopenharmony_ci	ch->addr = sapi | (tei << 8);
33862306a36Sopenharmony_ci}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_civoid
34162306a36Sopenharmony_ci__add_layer2(struct mISDNchannel *ch, struct mISDNstack *st)
34262306a36Sopenharmony_ci{
34362306a36Sopenharmony_ci	list_add_tail(&ch->list, &st->layer2);
34462306a36Sopenharmony_ci}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_civoid
34762306a36Sopenharmony_ciadd_layer2(struct mISDNchannel *ch, struct mISDNstack *st)
34862306a36Sopenharmony_ci{
34962306a36Sopenharmony_ci	mutex_lock(&st->lmutex);
35062306a36Sopenharmony_ci	__add_layer2(ch, st);
35162306a36Sopenharmony_ci	mutex_unlock(&st->lmutex);
35262306a36Sopenharmony_ci}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_cistatic int
35562306a36Sopenharmony_cist_own_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
35662306a36Sopenharmony_ci{
35762306a36Sopenharmony_ci	if (!ch->st || !ch->st->layer1)
35862306a36Sopenharmony_ci		return -EINVAL;
35962306a36Sopenharmony_ci	return ch->st->layer1->ctrl(ch->st->layer1, cmd, arg);
36062306a36Sopenharmony_ci}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ciint
36362306a36Sopenharmony_cicreate_stack(struct mISDNdevice *dev)
36462306a36Sopenharmony_ci{
36562306a36Sopenharmony_ci	struct mISDNstack	*newst;
36662306a36Sopenharmony_ci	int			err;
36762306a36Sopenharmony_ci	DECLARE_COMPLETION_ONSTACK(done);
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	newst = kzalloc(sizeof(struct mISDNstack), GFP_KERNEL);
37062306a36Sopenharmony_ci	if (!newst) {
37162306a36Sopenharmony_ci		printk(KERN_ERR "kmalloc mISDN_stack failed\n");
37262306a36Sopenharmony_ci		return -ENOMEM;
37362306a36Sopenharmony_ci	}
37462306a36Sopenharmony_ci	newst->dev = dev;
37562306a36Sopenharmony_ci	INIT_LIST_HEAD(&newst->layer2);
37662306a36Sopenharmony_ci	INIT_HLIST_HEAD(&newst->l1sock.head);
37762306a36Sopenharmony_ci	rwlock_init(&newst->l1sock.lock);
37862306a36Sopenharmony_ci	init_waitqueue_head(&newst->workq);
37962306a36Sopenharmony_ci	skb_queue_head_init(&newst->msgq);
38062306a36Sopenharmony_ci	mutex_init(&newst->lmutex);
38162306a36Sopenharmony_ci	dev->D.st = newst;
38262306a36Sopenharmony_ci	err = create_teimanager(dev);
38362306a36Sopenharmony_ci	if (err) {
38462306a36Sopenharmony_ci		printk(KERN_ERR "kmalloc teimanager failed\n");
38562306a36Sopenharmony_ci		kfree(newst);
38662306a36Sopenharmony_ci		return err;
38762306a36Sopenharmony_ci	}
38862306a36Sopenharmony_ci	dev->teimgr->peer = &newst->own;
38962306a36Sopenharmony_ci	dev->teimgr->recv = mISDN_queue_message;
39062306a36Sopenharmony_ci	dev->teimgr->st = newst;
39162306a36Sopenharmony_ci	newst->layer1 = &dev->D;
39262306a36Sopenharmony_ci	dev->D.recv = l1_receive;
39362306a36Sopenharmony_ci	dev->D.peer = &newst->own;
39462306a36Sopenharmony_ci	newst->own.st = newst;
39562306a36Sopenharmony_ci	newst->own.ctrl = st_own_ctrl;
39662306a36Sopenharmony_ci	newst->own.send = mISDN_queue_message;
39762306a36Sopenharmony_ci	newst->own.recv = mISDN_queue_message;
39862306a36Sopenharmony_ci	if (*debug & DEBUG_CORE_FUNC)
39962306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: st(%s)\n", __func__,
40062306a36Sopenharmony_ci		       dev_name(&newst->dev->dev));
40162306a36Sopenharmony_ci	newst->notify = &done;
40262306a36Sopenharmony_ci	newst->thread = kthread_run(mISDNStackd, (void *)newst, "mISDN_%s",
40362306a36Sopenharmony_ci				    dev_name(&newst->dev->dev));
40462306a36Sopenharmony_ci	if (IS_ERR(newst->thread)) {
40562306a36Sopenharmony_ci		err = PTR_ERR(newst->thread);
40662306a36Sopenharmony_ci		printk(KERN_ERR
40762306a36Sopenharmony_ci		       "mISDN:cannot create kernel thread for %s (%d)\n",
40862306a36Sopenharmony_ci		       dev_name(&newst->dev->dev), err);
40962306a36Sopenharmony_ci		delete_teimanager(dev->teimgr);
41062306a36Sopenharmony_ci		kfree(newst);
41162306a36Sopenharmony_ci	} else
41262306a36Sopenharmony_ci		wait_for_completion(&done);
41362306a36Sopenharmony_ci	return err;
41462306a36Sopenharmony_ci}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ciint
41762306a36Sopenharmony_ciconnect_layer1(struct mISDNdevice *dev, struct mISDNchannel *ch,
41862306a36Sopenharmony_ci	       u_int protocol, struct sockaddr_mISDN *adr)
41962306a36Sopenharmony_ci{
42062306a36Sopenharmony_ci	struct mISDN_sock	*msk = container_of(ch, struct mISDN_sock, ch);
42162306a36Sopenharmony_ci	struct channel_req	rq;
42262306a36Sopenharmony_ci	int			err;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	if (*debug &  DEBUG_CORE_FUNC)
42662306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n",
42762306a36Sopenharmony_ci		       __func__, dev_name(&dev->dev), protocol, adr->dev,
42862306a36Sopenharmony_ci		       adr->channel, adr->sapi, adr->tei);
42962306a36Sopenharmony_ci	switch (protocol) {
43062306a36Sopenharmony_ci	case ISDN_P_NT_S0:
43162306a36Sopenharmony_ci	case ISDN_P_NT_E1:
43262306a36Sopenharmony_ci	case ISDN_P_TE_S0:
43362306a36Sopenharmony_ci	case ISDN_P_TE_E1:
43462306a36Sopenharmony_ci		ch->recv = mISDN_queue_message;
43562306a36Sopenharmony_ci		ch->peer = &dev->D.st->own;
43662306a36Sopenharmony_ci		ch->st = dev->D.st;
43762306a36Sopenharmony_ci		rq.protocol = protocol;
43862306a36Sopenharmony_ci		rq.adr.channel = adr->channel;
43962306a36Sopenharmony_ci		err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq);
44062306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: ret %d (dev %d)\n", __func__, err,
44162306a36Sopenharmony_ci		       dev->id);
44262306a36Sopenharmony_ci		if (err)
44362306a36Sopenharmony_ci			return err;
44462306a36Sopenharmony_ci		write_lock_bh(&dev->D.st->l1sock.lock);
44562306a36Sopenharmony_ci		sk_add_node(&msk->sk, &dev->D.st->l1sock.head);
44662306a36Sopenharmony_ci		write_unlock_bh(&dev->D.st->l1sock.lock);
44762306a36Sopenharmony_ci		break;
44862306a36Sopenharmony_ci	default:
44962306a36Sopenharmony_ci		return -ENOPROTOOPT;
45062306a36Sopenharmony_ci	}
45162306a36Sopenharmony_ci	return 0;
45262306a36Sopenharmony_ci}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ciint
45562306a36Sopenharmony_ciconnect_Bstack(struct mISDNdevice *dev, struct mISDNchannel *ch,
45662306a36Sopenharmony_ci	       u_int protocol, struct sockaddr_mISDN *adr)
45762306a36Sopenharmony_ci{
45862306a36Sopenharmony_ci	struct channel_req	rq, rq2;
45962306a36Sopenharmony_ci	int			pmask, err;
46062306a36Sopenharmony_ci	struct Bprotocol	*bp;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	if (*debug &  DEBUG_CORE_FUNC)
46362306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n",
46462306a36Sopenharmony_ci		       __func__, dev_name(&dev->dev), protocol,
46562306a36Sopenharmony_ci		       adr->dev, adr->channel, adr->sapi,
46662306a36Sopenharmony_ci		       adr->tei);
46762306a36Sopenharmony_ci	ch->st = dev->D.st;
46862306a36Sopenharmony_ci	pmask = 1 << (protocol & ISDN_P_B_MASK);
46962306a36Sopenharmony_ci	if (pmask & dev->Bprotocols) {
47062306a36Sopenharmony_ci		rq.protocol = protocol;
47162306a36Sopenharmony_ci		rq.adr = *adr;
47262306a36Sopenharmony_ci		err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq);
47362306a36Sopenharmony_ci		if (err)
47462306a36Sopenharmony_ci			return err;
47562306a36Sopenharmony_ci		ch->recv = rq.ch->send;
47662306a36Sopenharmony_ci		ch->peer = rq.ch;
47762306a36Sopenharmony_ci		rq.ch->recv = ch->send;
47862306a36Sopenharmony_ci		rq.ch->peer = ch;
47962306a36Sopenharmony_ci		rq.ch->st = dev->D.st;
48062306a36Sopenharmony_ci	} else {
48162306a36Sopenharmony_ci		bp = get_Bprotocol4mask(pmask);
48262306a36Sopenharmony_ci		if (!bp)
48362306a36Sopenharmony_ci			return -ENOPROTOOPT;
48462306a36Sopenharmony_ci		rq2.protocol = protocol;
48562306a36Sopenharmony_ci		rq2.adr = *adr;
48662306a36Sopenharmony_ci		rq2.ch = ch;
48762306a36Sopenharmony_ci		err = bp->create(&rq2);
48862306a36Sopenharmony_ci		if (err)
48962306a36Sopenharmony_ci			return err;
49062306a36Sopenharmony_ci		ch->recv = rq2.ch->send;
49162306a36Sopenharmony_ci		ch->peer = rq2.ch;
49262306a36Sopenharmony_ci		rq2.ch->st = dev->D.st;
49362306a36Sopenharmony_ci		rq.protocol = rq2.protocol;
49462306a36Sopenharmony_ci		rq.adr = *adr;
49562306a36Sopenharmony_ci		err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq);
49662306a36Sopenharmony_ci		if (err) {
49762306a36Sopenharmony_ci			rq2.ch->ctrl(rq2.ch, CLOSE_CHANNEL, NULL);
49862306a36Sopenharmony_ci			return err;
49962306a36Sopenharmony_ci		}
50062306a36Sopenharmony_ci		rq2.ch->recv = rq.ch->send;
50162306a36Sopenharmony_ci		rq2.ch->peer = rq.ch;
50262306a36Sopenharmony_ci		rq.ch->recv = rq2.ch->send;
50362306a36Sopenharmony_ci		rq.ch->peer = rq2.ch;
50462306a36Sopenharmony_ci		rq.ch->st = dev->D.st;
50562306a36Sopenharmony_ci	}
50662306a36Sopenharmony_ci	ch->protocol = protocol;
50762306a36Sopenharmony_ci	ch->nr = rq.ch->nr;
50862306a36Sopenharmony_ci	return 0;
50962306a36Sopenharmony_ci}
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ciint
51262306a36Sopenharmony_cicreate_l2entity(struct mISDNdevice *dev, struct mISDNchannel *ch,
51362306a36Sopenharmony_ci		u_int protocol, struct sockaddr_mISDN *adr)
51462306a36Sopenharmony_ci{
51562306a36Sopenharmony_ci	struct channel_req	rq;
51662306a36Sopenharmony_ci	int			err;
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	if (*debug &  DEBUG_CORE_FUNC)
51962306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n",
52062306a36Sopenharmony_ci		       __func__, dev_name(&dev->dev), protocol,
52162306a36Sopenharmony_ci		       adr->dev, adr->channel, adr->sapi,
52262306a36Sopenharmony_ci		       adr->tei);
52362306a36Sopenharmony_ci	rq.protocol = ISDN_P_TE_S0;
52462306a36Sopenharmony_ci	if (dev->Dprotocols & (1 << ISDN_P_TE_E1))
52562306a36Sopenharmony_ci		rq.protocol = ISDN_P_TE_E1;
52662306a36Sopenharmony_ci	switch (protocol) {
52762306a36Sopenharmony_ci	case ISDN_P_LAPD_NT:
52862306a36Sopenharmony_ci		rq.protocol = ISDN_P_NT_S0;
52962306a36Sopenharmony_ci		if (dev->Dprotocols & (1 << ISDN_P_NT_E1))
53062306a36Sopenharmony_ci			rq.protocol = ISDN_P_NT_E1;
53162306a36Sopenharmony_ci		fallthrough;
53262306a36Sopenharmony_ci	case ISDN_P_LAPD_TE:
53362306a36Sopenharmony_ci		ch->recv = mISDN_queue_message;
53462306a36Sopenharmony_ci		ch->peer = &dev->D.st->own;
53562306a36Sopenharmony_ci		ch->st = dev->D.st;
53662306a36Sopenharmony_ci		rq.adr.channel = 0;
53762306a36Sopenharmony_ci		err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq);
53862306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: ret 1 %d\n", __func__, err);
53962306a36Sopenharmony_ci		if (err)
54062306a36Sopenharmony_ci			break;
54162306a36Sopenharmony_ci		rq.protocol = protocol;
54262306a36Sopenharmony_ci		rq.adr = *adr;
54362306a36Sopenharmony_ci		rq.ch = ch;
54462306a36Sopenharmony_ci		err = dev->teimgr->ctrl(dev->teimgr, OPEN_CHANNEL, &rq);
54562306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: ret 2 %d\n", __func__, err);
54662306a36Sopenharmony_ci		if (!err) {
54762306a36Sopenharmony_ci			if ((protocol == ISDN_P_LAPD_NT) && !rq.ch)
54862306a36Sopenharmony_ci				break;
54962306a36Sopenharmony_ci			add_layer2(rq.ch, dev->D.st);
55062306a36Sopenharmony_ci			rq.ch->recv = mISDN_queue_message;
55162306a36Sopenharmony_ci			rq.ch->peer = &dev->D.st->own;
55262306a36Sopenharmony_ci			rq.ch->ctrl(rq.ch, OPEN_CHANNEL, NULL); /* can't fail */
55362306a36Sopenharmony_ci		}
55462306a36Sopenharmony_ci		break;
55562306a36Sopenharmony_ci	default:
55662306a36Sopenharmony_ci		err = -EPROTONOSUPPORT;
55762306a36Sopenharmony_ci	}
55862306a36Sopenharmony_ci	return err;
55962306a36Sopenharmony_ci}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_civoid
56262306a36Sopenharmony_cidelete_channel(struct mISDNchannel *ch)
56362306a36Sopenharmony_ci{
56462306a36Sopenharmony_ci	struct mISDN_sock	*msk = container_of(ch, struct mISDN_sock, ch);
56562306a36Sopenharmony_ci	struct mISDNchannel	*pch;
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	if (!ch->st) {
56862306a36Sopenharmony_ci		printk(KERN_WARNING "%s: no stack\n", __func__);
56962306a36Sopenharmony_ci		return;
57062306a36Sopenharmony_ci	}
57162306a36Sopenharmony_ci	if (*debug & DEBUG_CORE_FUNC)
57262306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: st(%s) protocol(%x)\n", __func__,
57362306a36Sopenharmony_ci		       dev_name(&ch->st->dev->dev), ch->protocol);
57462306a36Sopenharmony_ci	if (ch->protocol >= ISDN_P_B_START) {
57562306a36Sopenharmony_ci		if (ch->peer) {
57662306a36Sopenharmony_ci			ch->peer->ctrl(ch->peer, CLOSE_CHANNEL, NULL);
57762306a36Sopenharmony_ci			ch->peer = NULL;
57862306a36Sopenharmony_ci		}
57962306a36Sopenharmony_ci		return;
58062306a36Sopenharmony_ci	}
58162306a36Sopenharmony_ci	switch (ch->protocol) {
58262306a36Sopenharmony_ci	case ISDN_P_NT_S0:
58362306a36Sopenharmony_ci	case ISDN_P_TE_S0:
58462306a36Sopenharmony_ci	case ISDN_P_NT_E1:
58562306a36Sopenharmony_ci	case ISDN_P_TE_E1:
58662306a36Sopenharmony_ci		write_lock_bh(&ch->st->l1sock.lock);
58762306a36Sopenharmony_ci		sk_del_node_init(&msk->sk);
58862306a36Sopenharmony_ci		write_unlock_bh(&ch->st->l1sock.lock);
58962306a36Sopenharmony_ci		ch->st->dev->D.ctrl(&ch->st->dev->D, CLOSE_CHANNEL, NULL);
59062306a36Sopenharmony_ci		break;
59162306a36Sopenharmony_ci	case ISDN_P_LAPD_TE:
59262306a36Sopenharmony_ci		pch = get_channel4id(ch->st, ch->nr);
59362306a36Sopenharmony_ci		if (pch) {
59462306a36Sopenharmony_ci			mutex_lock(&ch->st->lmutex);
59562306a36Sopenharmony_ci			list_del(&pch->list);
59662306a36Sopenharmony_ci			mutex_unlock(&ch->st->lmutex);
59762306a36Sopenharmony_ci			pch->ctrl(pch, CLOSE_CHANNEL, NULL);
59862306a36Sopenharmony_ci			pch = ch->st->dev->teimgr;
59962306a36Sopenharmony_ci			pch->ctrl(pch, CLOSE_CHANNEL, NULL);
60062306a36Sopenharmony_ci		} else
60162306a36Sopenharmony_ci			printk(KERN_WARNING "%s: no l2 channel\n",
60262306a36Sopenharmony_ci			       __func__);
60362306a36Sopenharmony_ci		break;
60462306a36Sopenharmony_ci	case ISDN_P_LAPD_NT:
60562306a36Sopenharmony_ci		pch = ch->st->dev->teimgr;
60662306a36Sopenharmony_ci		if (pch) {
60762306a36Sopenharmony_ci			pch->ctrl(pch, CLOSE_CHANNEL, NULL);
60862306a36Sopenharmony_ci		} else
60962306a36Sopenharmony_ci			printk(KERN_WARNING "%s: no l2 channel\n",
61062306a36Sopenharmony_ci			       __func__);
61162306a36Sopenharmony_ci		break;
61262306a36Sopenharmony_ci	default:
61362306a36Sopenharmony_ci		break;
61462306a36Sopenharmony_ci	}
61562306a36Sopenharmony_ci	return;
61662306a36Sopenharmony_ci}
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_civoid
61962306a36Sopenharmony_cidelete_stack(struct mISDNdevice *dev)
62062306a36Sopenharmony_ci{
62162306a36Sopenharmony_ci	struct mISDNstack	*st = dev->D.st;
62262306a36Sopenharmony_ci	DECLARE_COMPLETION_ONSTACK(done);
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	if (*debug & DEBUG_CORE_FUNC)
62562306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: st(%s)\n", __func__,
62662306a36Sopenharmony_ci		       dev_name(&st->dev->dev));
62762306a36Sopenharmony_ci	if (dev->teimgr)
62862306a36Sopenharmony_ci		delete_teimanager(dev->teimgr);
62962306a36Sopenharmony_ci	if (st->thread) {
63062306a36Sopenharmony_ci		if (st->notify) {
63162306a36Sopenharmony_ci			printk(KERN_WARNING "%s: notifier in use\n",
63262306a36Sopenharmony_ci			       __func__);
63362306a36Sopenharmony_ci			complete(st->notify);
63462306a36Sopenharmony_ci		}
63562306a36Sopenharmony_ci		st->notify = &done;
63662306a36Sopenharmony_ci		test_and_set_bit(mISDN_STACK_ABORT, &st->status);
63762306a36Sopenharmony_ci		test_and_set_bit(mISDN_STACK_WAKEUP, &st->status);
63862306a36Sopenharmony_ci		wake_up_interruptible(&st->workq);
63962306a36Sopenharmony_ci		wait_for_completion(&done);
64062306a36Sopenharmony_ci	}
64162306a36Sopenharmony_ci	if (!list_empty(&st->layer2))
64262306a36Sopenharmony_ci		printk(KERN_WARNING "%s: layer2 list not empty\n",
64362306a36Sopenharmony_ci		       __func__);
64462306a36Sopenharmony_ci	if (!hlist_empty(&st->l1sock.head))
64562306a36Sopenharmony_ci		printk(KERN_WARNING "%s: layer1 list not empty\n",
64662306a36Sopenharmony_ci		       __func__);
64762306a36Sopenharmony_ci	kfree(st);
64862306a36Sopenharmony_ci}
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_civoid
65162306a36Sopenharmony_cimISDN_initstack(u_int *dp)
65262306a36Sopenharmony_ci{
65362306a36Sopenharmony_ci	debug = dp;
65462306a36Sopenharmony_ci}
655