11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21b2b03f8SKarsten Keil /*
31b2b03f8SKarsten Keil *
41b2b03f8SKarsten Keil * Author Karsten Keil <kkeil@novell.com>
51b2b03f8SKarsten Keil *
61b2b03f8SKarsten Keil * Copyright 2008 by Karsten Keil <kkeil@novell.com>
71b2b03f8SKarsten Keil */
81b2b03f8SKarsten Keil
95a0e3ad6STejun Heo #include <linux/slab.h>
101b2b03f8SKarsten Keil #include <linux/mISDNif.h>
111b2b03f8SKarsten Keil #include <linux/kthread.h>
126fac4829SFrederic Weisbecker #include <linux/sched.h>
1332ef5517SIngo Molnar #include <linux/sched/cputime.h>
14f361bf4aSIngo Molnar #include <linux/signal.h>
15f361bf4aSIngo Molnar
161b2b03f8SKarsten Keil #include "core.h"
171b2b03f8SKarsten Keil
181b2b03f8SKarsten Keil static u_int *debug;
191b2b03f8SKarsten Keil
201b2b03f8SKarsten Keil static inline void
_queue_message(struct mISDNstack * st,struct sk_buff * skb)211b2b03f8SKarsten Keil _queue_message(struct mISDNstack *st, struct sk_buff *skb)
221b2b03f8SKarsten Keil {
231b2b03f8SKarsten Keil struct mISDNhead *hh = mISDN_HEAD_P(skb);
241b2b03f8SKarsten Keil
251b2b03f8SKarsten Keil if (*debug & DEBUG_QUEUE_FUNC)
261b2b03f8SKarsten Keil printk(KERN_DEBUG "%s prim(%x) id(%x) %p\n",
271b2b03f8SKarsten Keil __func__, hh->prim, hh->id, skb);
281b2b03f8SKarsten Keil skb_queue_tail(&st->msgq, skb);
291b2b03f8SKarsten Keil if (likely(!test_bit(mISDN_STACK_STOPPED, &st->status))) {
301b2b03f8SKarsten Keil test_and_set_bit(mISDN_STACK_WORK, &st->status);
311b2b03f8SKarsten Keil wake_up_interruptible(&st->workq);
321b2b03f8SKarsten Keil }
331b2b03f8SKarsten Keil }
341b2b03f8SKarsten Keil
355b834354SHannes Eder static int
mISDN_queue_message(struct mISDNchannel * ch,struct sk_buff * skb)361b2b03f8SKarsten Keil mISDN_queue_message(struct mISDNchannel *ch, struct sk_buff *skb)
371b2b03f8SKarsten Keil {
381b2b03f8SKarsten Keil _queue_message(ch->st, skb);
391b2b03f8SKarsten Keil return 0;
401b2b03f8SKarsten Keil }
411b2b03f8SKarsten Keil
421b2b03f8SKarsten Keil static struct mISDNchannel *
get_channel4id(struct mISDNstack * st,u_int id)431b2b03f8SKarsten Keil get_channel4id(struct mISDNstack *st, u_int id)
441b2b03f8SKarsten Keil {
451b2b03f8SKarsten Keil struct mISDNchannel *ch;
461b2b03f8SKarsten Keil
471b2b03f8SKarsten Keil mutex_lock(&st->lmutex);
481b2b03f8SKarsten Keil list_for_each_entry(ch, &st->layer2, list) {
491b2b03f8SKarsten Keil if (id == ch->nr)
501b2b03f8SKarsten Keil goto unlock;
511b2b03f8SKarsten Keil }
521b2b03f8SKarsten Keil ch = NULL;
531b2b03f8SKarsten Keil unlock:
541b2b03f8SKarsten Keil mutex_unlock(&st->lmutex);
551b2b03f8SKarsten Keil return ch;
561b2b03f8SKarsten Keil }
571b2b03f8SKarsten Keil
581b2b03f8SKarsten Keil static void
send_socklist(struct mISDN_sock_list * sl,struct sk_buff * skb)591b2b03f8SKarsten Keil send_socklist(struct mISDN_sock_list *sl, struct sk_buff *skb)
601b2b03f8SKarsten Keil {
611b2b03f8SKarsten Keil struct sock *sk;
621b2b03f8SKarsten Keil struct sk_buff *cskb = NULL;
631b2b03f8SKarsten Keil
641b2b03f8SKarsten Keil read_lock(&sl->lock);
65b67bfe0dSSasha Levin sk_for_each(sk, &sl->head) {
661b2b03f8SKarsten Keil if (sk->sk_state != MISDN_BOUND)
671b2b03f8SKarsten Keil continue;
681b2b03f8SKarsten Keil if (!cskb)
6993818da5SJia-Ju Bai cskb = skb_copy(skb, GFP_ATOMIC);
701b2b03f8SKarsten Keil if (!cskb) {
711b2b03f8SKarsten Keil printk(KERN_WARNING "%s no skb\n", __func__);
721b2b03f8SKarsten Keil break;
731b2b03f8SKarsten Keil }
741b2b03f8SKarsten Keil if (!sock_queue_rcv_skb(sk, cskb))
751b2b03f8SKarsten Keil cskb = NULL;
761b2b03f8SKarsten Keil }
771b2b03f8SKarsten Keil read_unlock(&sl->lock);
781b2b03f8SKarsten Keil dev_kfree_skb(cskb);
791b2b03f8SKarsten Keil }
801b2b03f8SKarsten Keil
811b2b03f8SKarsten Keil static void
send_layer2(struct mISDNstack * st,struct sk_buff * skb)821b2b03f8SKarsten Keil send_layer2(struct mISDNstack *st, struct sk_buff *skb)
831b2b03f8SKarsten Keil {
841b2b03f8SKarsten Keil struct sk_buff *cskb;
851b2b03f8SKarsten Keil struct mISDNhead *hh = mISDN_HEAD_P(skb);
861b2b03f8SKarsten Keil struct mISDNchannel *ch;
871b2b03f8SKarsten Keil int ret;
881b2b03f8SKarsten Keil
891b2b03f8SKarsten Keil if (!st)
901b2b03f8SKarsten Keil return;
911b2b03f8SKarsten Keil mutex_lock(&st->lmutex);
921b2b03f8SKarsten Keil if ((hh->id & MISDN_ID_ADDR_MASK) == MISDN_ID_ANY) { /* L2 for all */
931b2b03f8SKarsten Keil list_for_each_entry(ch, &st->layer2, list) {
941b2b03f8SKarsten Keil if (list_is_last(&ch->list, &st->layer2)) {
951b2b03f8SKarsten Keil cskb = skb;
961b2b03f8SKarsten Keil skb = NULL;
971b2b03f8SKarsten Keil } else {
981b2b03f8SKarsten Keil cskb = skb_copy(skb, GFP_KERNEL);
991b2b03f8SKarsten Keil }
1001b2b03f8SKarsten Keil if (cskb) {
1011b2b03f8SKarsten Keil ret = ch->send(ch, cskb);
1021b2b03f8SKarsten Keil if (ret) {
1031b2b03f8SKarsten Keil if (*debug & DEBUG_SEND_ERR)
1041b2b03f8SKarsten Keil printk(KERN_DEBUG
1051b2b03f8SKarsten Keil "%s ch%d prim(%x) addr(%x)"
1061b2b03f8SKarsten Keil " err %d\n",
1071b2b03f8SKarsten Keil __func__, ch->nr,
1081b2b03f8SKarsten Keil hh->prim, ch->addr, ret);
1091b2b03f8SKarsten Keil dev_kfree_skb(cskb);
1101b2b03f8SKarsten Keil }
1111b2b03f8SKarsten Keil } else {
1121b2b03f8SKarsten Keil printk(KERN_WARNING "%s ch%d addr %x no mem\n",
1131b2b03f8SKarsten Keil __func__, ch->nr, ch->addr);
1141b2b03f8SKarsten Keil goto out;
1151b2b03f8SKarsten Keil }
1161b2b03f8SKarsten Keil }
1171b2b03f8SKarsten Keil } else {
1181b2b03f8SKarsten Keil list_for_each_entry(ch, &st->layer2, list) {
1191b2b03f8SKarsten Keil if ((hh->id & MISDN_ID_ADDR_MASK) == ch->addr) {
1201b2b03f8SKarsten Keil ret = ch->send(ch, skb);
1211b2b03f8SKarsten Keil if (!ret)
1221b2b03f8SKarsten Keil skb = NULL;
1231b2b03f8SKarsten Keil goto out;
1241b2b03f8SKarsten Keil }
1251b2b03f8SKarsten Keil }
1261b2b03f8SKarsten Keil ret = st->dev->teimgr->ctrl(st->dev->teimgr, CHECK_DATA, skb);
1271b2b03f8SKarsten Keil if (!ret)
1281b2b03f8SKarsten Keil skb = NULL;
1291b2b03f8SKarsten Keil else if (*debug & DEBUG_SEND_ERR)
1301b2b03f8SKarsten Keil printk(KERN_DEBUG
1311b9faf5eSJulia Lawall "%s mgr prim(%x) err %d\n",
1321b9faf5eSJulia Lawall __func__, hh->prim, ret);
1331b2b03f8SKarsten Keil }
1341b2b03f8SKarsten Keil out:
1351b2b03f8SKarsten Keil mutex_unlock(&st->lmutex);
1361b2b03f8SKarsten Keil dev_kfree_skb(skb);
1371b2b03f8SKarsten Keil }
1381b2b03f8SKarsten Keil
1391b2b03f8SKarsten Keil static inline int
send_msg_to_layer(struct mISDNstack * st,struct sk_buff * skb)1401b2b03f8SKarsten Keil send_msg_to_layer(struct mISDNstack *st, struct sk_buff *skb)
1411b2b03f8SKarsten Keil {
1421b2b03f8SKarsten Keil struct mISDNhead *hh = mISDN_HEAD_P(skb);
1431b2b03f8SKarsten Keil struct mISDNchannel *ch;
1441b2b03f8SKarsten Keil int lm;
1451b2b03f8SKarsten Keil
1461b2b03f8SKarsten Keil lm = hh->prim & MISDN_LAYERMASK;
1471b2b03f8SKarsten Keil if (*debug & DEBUG_QUEUE_FUNC)
1481b2b03f8SKarsten Keil printk(KERN_DEBUG "%s prim(%x) id(%x) %p\n",
1491b2b03f8SKarsten Keil __func__, hh->prim, hh->id, skb);
1501b2b03f8SKarsten Keil if (lm == 0x1) {
1511b2b03f8SKarsten Keil if (!hlist_empty(&st->l1sock.head)) {
1521b2b03f8SKarsten Keil __net_timestamp(skb);
1531b2b03f8SKarsten Keil send_socklist(&st->l1sock, skb);
1541b2b03f8SKarsten Keil }
1551b2b03f8SKarsten Keil return st->layer1->send(st->layer1, skb);
1561b2b03f8SKarsten Keil } else if (lm == 0x2) {
1571b2b03f8SKarsten Keil if (!hlist_empty(&st->l1sock.head))
1581b2b03f8SKarsten Keil send_socklist(&st->l1sock, skb);
1591b2b03f8SKarsten Keil send_layer2(st, skb);
1601b2b03f8SKarsten Keil return 0;
1611b2b03f8SKarsten Keil } else if (lm == 0x4) {
1621b2b03f8SKarsten Keil ch = get_channel4id(st, hh->id);
1631b2b03f8SKarsten Keil if (ch)
1641b2b03f8SKarsten Keil return ch->send(ch, skb);
1651b2b03f8SKarsten Keil else
1661b2b03f8SKarsten Keil printk(KERN_WARNING
1671b2b03f8SKarsten Keil "%s: dev(%s) prim(%x) id(%x) no channel\n",
168837468d1SMatthias Urlichs __func__, dev_name(&st->dev->dev), hh->prim,
169837468d1SMatthias Urlichs hh->id);
1701b2b03f8SKarsten Keil } else if (lm == 0x8) {
1711b2b03f8SKarsten Keil WARN_ON(lm == 0x8);
1721b2b03f8SKarsten Keil ch = get_channel4id(st, hh->id);
1731b2b03f8SKarsten Keil if (ch)
1741b2b03f8SKarsten Keil return ch->send(ch, skb);
1751b2b03f8SKarsten Keil else
1761b2b03f8SKarsten Keil printk(KERN_WARNING
1771b2b03f8SKarsten Keil "%s: dev(%s) prim(%x) id(%x) no channel\n",
178837468d1SMatthias Urlichs __func__, dev_name(&st->dev->dev), hh->prim,
179837468d1SMatthias Urlichs hh->id);
1801b2b03f8SKarsten Keil } else {
1811b2b03f8SKarsten Keil /* broadcast not handled yet */
1821b2b03f8SKarsten Keil printk(KERN_WARNING "%s: dev(%s) prim %x not delivered\n",
183837468d1SMatthias Urlichs __func__, dev_name(&st->dev->dev), hh->prim);
1841b2b03f8SKarsten Keil }
1851b2b03f8SKarsten Keil return -ESRCH;
1861b2b03f8SKarsten Keil }
1871b2b03f8SKarsten Keil
1881b2b03f8SKarsten Keil static void
do_clear_stack(struct mISDNstack * st)1891b2b03f8SKarsten Keil do_clear_stack(struct mISDNstack *st)
1901b2b03f8SKarsten Keil {
1911b2b03f8SKarsten Keil }
1921b2b03f8SKarsten Keil
1931b2b03f8SKarsten Keil static int
mISDNStackd(void * data)1941b2b03f8SKarsten Keil mISDNStackd(void *data)
1951b2b03f8SKarsten Keil {
1961b2b03f8SKarsten Keil struct mISDNstack *st = data;
1976fac4829SFrederic Weisbecker #ifdef MISDN_MSG_STATS
198c0e7a500SFrederic Weisbecker u64 utime, stime;
1996fac4829SFrederic Weisbecker #endif
2001b2b03f8SKarsten Keil int err = 0;
2011b2b03f8SKarsten Keil
2021b2b03f8SKarsten Keil sigfillset(¤t->blocked);
2031b2b03f8SKarsten Keil if (*debug & DEBUG_MSG_THREAD)
204837468d1SMatthias Urlichs printk(KERN_DEBUG "mISDNStackd %s started\n",
205837468d1SMatthias Urlichs dev_name(&st->dev->dev));
2061b2b03f8SKarsten Keil
2071b2b03f8SKarsten Keil if (st->notify != NULL) {
2081b2b03f8SKarsten Keil complete(st->notify);
2091b2b03f8SKarsten Keil st->notify = NULL;
2101b2b03f8SKarsten Keil }
2111b2b03f8SKarsten Keil
2121b2b03f8SKarsten Keil for (;;) {
2131b2b03f8SKarsten Keil struct sk_buff *skb;
2141b2b03f8SKarsten Keil
2151b2b03f8SKarsten Keil if (unlikely(test_bit(mISDN_STACK_STOPPED, &st->status))) {
2161b2b03f8SKarsten Keil test_and_clear_bit(mISDN_STACK_WORK, &st->status);
2171b2b03f8SKarsten Keil test_and_clear_bit(mISDN_STACK_RUNNING, &st->status);
2181b2b03f8SKarsten Keil } else
2191b2b03f8SKarsten Keil test_and_set_bit(mISDN_STACK_RUNNING, &st->status);
2201b2b03f8SKarsten Keil while (test_bit(mISDN_STACK_WORK, &st->status)) {
2211b2b03f8SKarsten Keil skb = skb_dequeue(&st->msgq);
2221b2b03f8SKarsten Keil if (!skb) {
2231b2b03f8SKarsten Keil test_and_clear_bit(mISDN_STACK_WORK,
2241b2b03f8SKarsten Keil &st->status);
2251b2b03f8SKarsten Keil /* test if a race happens */
2261b2b03f8SKarsten Keil skb = skb_dequeue(&st->msgq);
2271b2b03f8SKarsten Keil if (!skb)
2281b2b03f8SKarsten Keil continue;
2291b2b03f8SKarsten Keil test_and_set_bit(mISDN_STACK_WORK,
2301b2b03f8SKarsten Keil &st->status);
2311b2b03f8SKarsten Keil }
2321b2b03f8SKarsten Keil #ifdef MISDN_MSG_STATS
2331b2b03f8SKarsten Keil st->msg_cnt++;
2341b2b03f8SKarsten Keil #endif
2351b2b03f8SKarsten Keil err = send_msg_to_layer(st, skb);
2361b2b03f8SKarsten Keil if (unlikely(err)) {
2371b2b03f8SKarsten Keil if (*debug & DEBUG_SEND_ERR)
2381b2b03f8SKarsten Keil printk(KERN_DEBUG
2391b2b03f8SKarsten Keil "%s: %s prim(%x) id(%x) "
2401b2b03f8SKarsten Keil "send call(%d)\n",
241837468d1SMatthias Urlichs __func__, dev_name(&st->dev->dev),
2421b2b03f8SKarsten Keil mISDN_HEAD_PRIM(skb),
2431b2b03f8SKarsten Keil mISDN_HEAD_ID(skb), err);
2441b2b03f8SKarsten Keil dev_kfree_skb(skb);
2451b2b03f8SKarsten Keil continue;
2461b2b03f8SKarsten Keil }
2471b2b03f8SKarsten Keil if (unlikely(test_bit(mISDN_STACK_STOPPED,
2481b2b03f8SKarsten Keil &st->status))) {
2491b2b03f8SKarsten Keil test_and_clear_bit(mISDN_STACK_WORK,
2501b2b03f8SKarsten Keil &st->status);
2511b2b03f8SKarsten Keil test_and_clear_bit(mISDN_STACK_RUNNING,
2521b2b03f8SKarsten Keil &st->status);
2531b2b03f8SKarsten Keil break;
2541b2b03f8SKarsten Keil }
2551b2b03f8SKarsten Keil }
2561b2b03f8SKarsten Keil if (test_bit(mISDN_STACK_CLEARING, &st->status)) {
2571b2b03f8SKarsten Keil test_and_set_bit(mISDN_STACK_STOPPED, &st->status);
2581b2b03f8SKarsten Keil test_and_clear_bit(mISDN_STACK_RUNNING, &st->status);
2591b2b03f8SKarsten Keil do_clear_stack(st);
2601b2b03f8SKarsten Keil test_and_clear_bit(mISDN_STACK_CLEARING, &st->status);
2611b2b03f8SKarsten Keil test_and_set_bit(mISDN_STACK_RESTART, &st->status);
2621b2b03f8SKarsten Keil }
2631b2b03f8SKarsten Keil if (test_and_clear_bit(mISDN_STACK_RESTART, &st->status)) {
2641b2b03f8SKarsten Keil test_and_clear_bit(mISDN_STACK_STOPPED, &st->status);
2651b2b03f8SKarsten Keil test_and_set_bit(mISDN_STACK_RUNNING, &st->status);
2661b2b03f8SKarsten Keil if (!skb_queue_empty(&st->msgq))
2671b2b03f8SKarsten Keil test_and_set_bit(mISDN_STACK_WORK,
2681b2b03f8SKarsten Keil &st->status);
2691b2b03f8SKarsten Keil }
2701b2b03f8SKarsten Keil if (test_bit(mISDN_STACK_ABORT, &st->status))
2711b2b03f8SKarsten Keil break;
2721b2b03f8SKarsten Keil if (st->notify != NULL) {
2731b2b03f8SKarsten Keil complete(st->notify);
2741b2b03f8SKarsten Keil st->notify = NULL;
2751b2b03f8SKarsten Keil }
2761b2b03f8SKarsten Keil #ifdef MISDN_MSG_STATS
2771b2b03f8SKarsten Keil st->sleep_cnt++;
2781b2b03f8SKarsten Keil #endif
2791b2b03f8SKarsten Keil test_and_clear_bit(mISDN_STACK_ACTIVE, &st->status);
2801b2b03f8SKarsten Keil wait_event_interruptible(st->workq, (st->status &
2811b2b03f8SKarsten Keil mISDN_STACK_ACTION_MASK));
2821b2b03f8SKarsten Keil if (*debug & DEBUG_MSG_THREAD)
2831b2b03f8SKarsten Keil printk(KERN_DEBUG "%s: %s wake status %08lx\n",
284837468d1SMatthias Urlichs __func__, dev_name(&st->dev->dev), st->status);
2851b2b03f8SKarsten Keil test_and_set_bit(mISDN_STACK_ACTIVE, &st->status);
2861b2b03f8SKarsten Keil
2871b2b03f8SKarsten Keil test_and_clear_bit(mISDN_STACK_WAKEUP, &st->status);
2881b2b03f8SKarsten Keil
2891b2b03f8SKarsten Keil if (test_bit(mISDN_STACK_STOPPED, &st->status)) {
2901b2b03f8SKarsten Keil test_and_clear_bit(mISDN_STACK_RUNNING, &st->status);
2911b2b03f8SKarsten Keil #ifdef MISDN_MSG_STATS
2921b2b03f8SKarsten Keil st->stopped_cnt++;
2931b2b03f8SKarsten Keil #endif
2941b2b03f8SKarsten Keil }
2951b2b03f8SKarsten Keil }
2961b2b03f8SKarsten Keil #ifdef MISDN_MSG_STATS
2971b2b03f8SKarsten Keil printk(KERN_DEBUG "mISDNStackd daemon for %s proceed %d "
2981b2b03f8SKarsten Keil "msg %d sleep %d stopped\n",
299837468d1SMatthias Urlichs dev_name(&st->dev->dev), st->msg_cnt, st->sleep_cnt,
300837468d1SMatthias Urlichs st->stopped_cnt);
301c0e7a500SFrederic Weisbecker task_cputime(st->thread, &utime, &stime);
3021b2b03f8SKarsten Keil printk(KERN_DEBUG
303c0e7a500SFrederic Weisbecker "mISDNStackd daemon for %s utime(%llu) stime(%llu)\n",
3046fac4829SFrederic Weisbecker dev_name(&st->dev->dev), utime, stime);
3051b2b03f8SKarsten Keil printk(KERN_DEBUG
3061b2b03f8SKarsten Keil "mISDNStackd daemon for %s nvcsw(%ld) nivcsw(%ld)\n",
307837468d1SMatthias Urlichs dev_name(&st->dev->dev), st->thread->nvcsw, st->thread->nivcsw);
3081b2b03f8SKarsten Keil printk(KERN_DEBUG "mISDNStackd daemon for %s killed now\n",
309837468d1SMatthias Urlichs dev_name(&st->dev->dev));
3101b2b03f8SKarsten Keil #endif
3111b2b03f8SKarsten Keil test_and_set_bit(mISDN_STACK_KILLED, &st->status);
3121b2b03f8SKarsten Keil test_and_clear_bit(mISDN_STACK_RUNNING, &st->status);
3131b2b03f8SKarsten Keil test_and_clear_bit(mISDN_STACK_ACTIVE, &st->status);
3141b2b03f8SKarsten Keil test_and_clear_bit(mISDN_STACK_ABORT, &st->status);
3151b2b03f8SKarsten Keil skb_queue_purge(&st->msgq);
3161b2b03f8SKarsten Keil st->thread = NULL;
3171b2b03f8SKarsten Keil if (st->notify != NULL) {
3181b2b03f8SKarsten Keil complete(st->notify);
3191b2b03f8SKarsten Keil st->notify = NULL;
3201b2b03f8SKarsten Keil }
3211b2b03f8SKarsten Keil return 0;
3221b2b03f8SKarsten Keil }
3231b2b03f8SKarsten Keil
3241b2b03f8SKarsten Keil static int
l1_receive(struct mISDNchannel * ch,struct sk_buff * skb)3251b2b03f8SKarsten Keil l1_receive(struct mISDNchannel *ch, struct sk_buff *skb)
3261b2b03f8SKarsten Keil {
3271b2b03f8SKarsten Keil if (!ch->st)
3281b2b03f8SKarsten Keil return -ENODEV;
3291b2b03f8SKarsten Keil __net_timestamp(skb);
3301b2b03f8SKarsten Keil _queue_message(ch->st, skb);
3311b2b03f8SKarsten Keil return 0;
3321b2b03f8SKarsten Keil }
3331b2b03f8SKarsten Keil
3341b2b03f8SKarsten Keil void
set_channel_address(struct mISDNchannel * ch,u_int sapi,u_int tei)3351b2b03f8SKarsten Keil set_channel_address(struct mISDNchannel *ch, u_int sapi, u_int tei)
3361b2b03f8SKarsten Keil {
3371b2b03f8SKarsten Keil ch->addr = sapi | (tei << 8);
3381b2b03f8SKarsten Keil }
3391b2b03f8SKarsten Keil
3401b2b03f8SKarsten Keil void
__add_layer2(struct mISDNchannel * ch,struct mISDNstack * st)3411b2b03f8SKarsten Keil __add_layer2(struct mISDNchannel *ch, struct mISDNstack *st)
3421b2b03f8SKarsten Keil {
3431b2b03f8SKarsten Keil list_add_tail(&ch->list, &st->layer2);
3441b2b03f8SKarsten Keil }
3451b2b03f8SKarsten Keil
3461b2b03f8SKarsten Keil void
add_layer2(struct mISDNchannel * ch,struct mISDNstack * st)3471b2b03f8SKarsten Keil add_layer2(struct mISDNchannel *ch, struct mISDNstack *st)
3481b2b03f8SKarsten Keil {
3491b2b03f8SKarsten Keil mutex_lock(&st->lmutex);
3501b2b03f8SKarsten Keil __add_layer2(ch, st);
3511b2b03f8SKarsten Keil mutex_unlock(&st->lmutex);
3521b2b03f8SKarsten Keil }
3531b2b03f8SKarsten Keil
3541b2b03f8SKarsten Keil static int
st_own_ctrl(struct mISDNchannel * ch,u_int cmd,void * arg)3551b2b03f8SKarsten Keil st_own_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
3561b2b03f8SKarsten Keil {
35708cb3f60SDan Carpenter if (!ch->st || !ch->st->layer1)
3581b2b03f8SKarsten Keil return -EINVAL;
3591b2b03f8SKarsten Keil return ch->st->layer1->ctrl(ch->st->layer1, cmd, arg);
3601b2b03f8SKarsten Keil }
3611b2b03f8SKarsten Keil
3621b2b03f8SKarsten Keil int
create_stack(struct mISDNdevice * dev)3631b2b03f8SKarsten Keil create_stack(struct mISDNdevice *dev)
3641b2b03f8SKarsten Keil {
3651b2b03f8SKarsten Keil struct mISDNstack *newst;
3661b2b03f8SKarsten Keil int err;
3671b2b03f8SKarsten Keil DECLARE_COMPLETION_ONSTACK(done);
3681b2b03f8SKarsten Keil
3691b2b03f8SKarsten Keil newst = kzalloc(sizeof(struct mISDNstack), GFP_KERNEL);
3701b2b03f8SKarsten Keil if (!newst) {
3711b2b03f8SKarsten Keil printk(KERN_ERR "kmalloc mISDN_stack failed\n");
3721b2b03f8SKarsten Keil return -ENOMEM;
3731b2b03f8SKarsten Keil }
3741b2b03f8SKarsten Keil newst->dev = dev;
3751b2b03f8SKarsten Keil INIT_LIST_HEAD(&newst->layer2);
3761b2b03f8SKarsten Keil INIT_HLIST_HEAD(&newst->l1sock.head);
3771b2b03f8SKarsten Keil rwlock_init(&newst->l1sock.lock);
3781b2b03f8SKarsten Keil init_waitqueue_head(&newst->workq);
3791b2b03f8SKarsten Keil skb_queue_head_init(&newst->msgq);
3801b2b03f8SKarsten Keil mutex_init(&newst->lmutex);
3811b2b03f8SKarsten Keil dev->D.st = newst;
3821b2b03f8SKarsten Keil err = create_teimanager(dev);
3831b2b03f8SKarsten Keil if (err) {
3841b2b03f8SKarsten Keil printk(KERN_ERR "kmalloc teimanager failed\n");
3851b2b03f8SKarsten Keil kfree(newst);
3861b2b03f8SKarsten Keil return err;
3871b2b03f8SKarsten Keil }
3881b2b03f8SKarsten Keil dev->teimgr->peer = &newst->own;
3891b2b03f8SKarsten Keil dev->teimgr->recv = mISDN_queue_message;
3901b2b03f8SKarsten Keil dev->teimgr->st = newst;
3911b2b03f8SKarsten Keil newst->layer1 = &dev->D;
3921b2b03f8SKarsten Keil dev->D.recv = l1_receive;
3931b2b03f8SKarsten Keil dev->D.peer = &newst->own;
3941b2b03f8SKarsten Keil newst->own.st = newst;
3951b2b03f8SKarsten Keil newst->own.ctrl = st_own_ctrl;
3961b2b03f8SKarsten Keil newst->own.send = mISDN_queue_message;
3971b2b03f8SKarsten Keil newst->own.recv = mISDN_queue_message;
3981b2b03f8SKarsten Keil if (*debug & DEBUG_CORE_FUNC)
399837468d1SMatthias Urlichs printk(KERN_DEBUG "%s: st(%s)\n", __func__,
400837468d1SMatthias Urlichs dev_name(&newst->dev->dev));
4011b2b03f8SKarsten Keil newst->notify = &done;
4021b2b03f8SKarsten Keil newst->thread = kthread_run(mISDNStackd, (void *)newst, "mISDN_%s",
403837468d1SMatthias Urlichs dev_name(&newst->dev->dev));
4041b2b03f8SKarsten Keil if (IS_ERR(newst->thread)) {
4051b2b03f8SKarsten Keil err = PTR_ERR(newst->thread);
4061b2b03f8SKarsten Keil printk(KERN_ERR
4071b2b03f8SKarsten Keil "mISDN:cannot create kernel thread for %s (%d)\n",
408837468d1SMatthias Urlichs dev_name(&newst->dev->dev), err);
4091b2b03f8SKarsten Keil delete_teimanager(dev->teimgr);
4101b2b03f8SKarsten Keil kfree(newst);
4111b2b03f8SKarsten Keil } else
4121b2b03f8SKarsten Keil wait_for_completion(&done);
4131b2b03f8SKarsten Keil return err;
4141b2b03f8SKarsten Keil }
4151b2b03f8SKarsten Keil
4161b2b03f8SKarsten Keil int
connect_layer1(struct mISDNdevice * dev,struct mISDNchannel * ch,u_int protocol,struct sockaddr_mISDN * adr)4171b2b03f8SKarsten Keil connect_layer1(struct mISDNdevice *dev, struct mISDNchannel *ch,
4181b2b03f8SKarsten Keil u_int protocol, struct sockaddr_mISDN *adr)
4191b2b03f8SKarsten Keil {
4201b2b03f8SKarsten Keil struct mISDN_sock *msk = container_of(ch, struct mISDN_sock, ch);
4211b2b03f8SKarsten Keil struct channel_req rq;
4221b2b03f8SKarsten Keil int err;
4231b2b03f8SKarsten Keil
4241b2b03f8SKarsten Keil
4251b2b03f8SKarsten Keil if (*debug & DEBUG_CORE_FUNC)
4261b2b03f8SKarsten Keil printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n",
427837468d1SMatthias Urlichs __func__, dev_name(&dev->dev), protocol, adr->dev,
428837468d1SMatthias Urlichs adr->channel, adr->sapi, adr->tei);
4291b2b03f8SKarsten Keil switch (protocol) {
4301b2b03f8SKarsten Keil case ISDN_P_NT_S0:
4311b2b03f8SKarsten Keil case ISDN_P_NT_E1:
4321b2b03f8SKarsten Keil case ISDN_P_TE_S0:
4331b2b03f8SKarsten Keil case ISDN_P_TE_E1:
4341b2b03f8SKarsten Keil ch->recv = mISDN_queue_message;
4351b2b03f8SKarsten Keil ch->peer = &dev->D.st->own;
4361b2b03f8SKarsten Keil ch->st = dev->D.st;
4371b2b03f8SKarsten Keil rq.protocol = protocol;
4381f28fa19SMartin Bachem rq.adr.channel = adr->channel;
4391b2b03f8SKarsten Keil err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq);
4409a812553SAndreas Eversberg printk(KERN_DEBUG "%s: ret %d (dev %d)\n", __func__, err,
4419a812553SAndreas Eversberg dev->id);
4421b2b03f8SKarsten Keil if (err)
4431b2b03f8SKarsten Keil return err;
4441b2b03f8SKarsten Keil write_lock_bh(&dev->D.st->l1sock.lock);
4451b2b03f8SKarsten Keil sk_add_node(&msk->sk, &dev->D.st->l1sock.head);
4461b2b03f8SKarsten Keil write_unlock_bh(&dev->D.st->l1sock.lock);
4471b2b03f8SKarsten Keil break;
4481b2b03f8SKarsten Keil default:
4491b2b03f8SKarsten Keil return -ENOPROTOOPT;
4501b2b03f8SKarsten Keil }
4511b2b03f8SKarsten Keil return 0;
4521b2b03f8SKarsten Keil }
4531b2b03f8SKarsten Keil
4541b2b03f8SKarsten Keil int
connect_Bstack(struct mISDNdevice * dev,struct mISDNchannel * ch,u_int protocol,struct sockaddr_mISDN * adr)4551b2b03f8SKarsten Keil connect_Bstack(struct mISDNdevice *dev, struct mISDNchannel *ch,
4561b2b03f8SKarsten Keil u_int protocol, struct sockaddr_mISDN *adr)
4571b2b03f8SKarsten Keil {
4581b2b03f8SKarsten Keil struct channel_req rq, rq2;
4591b2b03f8SKarsten Keil int pmask, err;
4601b2b03f8SKarsten Keil struct Bprotocol *bp;
4611b2b03f8SKarsten Keil
4621b2b03f8SKarsten Keil if (*debug & DEBUG_CORE_FUNC)
4631b2b03f8SKarsten Keil printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n",
464837468d1SMatthias Urlichs __func__, dev_name(&dev->dev), protocol,
4651b2b03f8SKarsten Keil adr->dev, adr->channel, adr->sapi,
4661b2b03f8SKarsten Keil adr->tei);
4671b2b03f8SKarsten Keil ch->st = dev->D.st;
4681b2b03f8SKarsten Keil pmask = 1 << (protocol & ISDN_P_B_MASK);
4691b2b03f8SKarsten Keil if (pmask & dev->Bprotocols) {
4701b2b03f8SKarsten Keil rq.protocol = protocol;
4711b2b03f8SKarsten Keil rq.adr = *adr;
4721b2b03f8SKarsten Keil err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq);
4731b2b03f8SKarsten Keil if (err)
4741b2b03f8SKarsten Keil return err;
4751b2b03f8SKarsten Keil ch->recv = rq.ch->send;
4761b2b03f8SKarsten Keil ch->peer = rq.ch;
4771b2b03f8SKarsten Keil rq.ch->recv = ch->send;
4781b2b03f8SKarsten Keil rq.ch->peer = ch;
4791b2b03f8SKarsten Keil rq.ch->st = dev->D.st;
4801b2b03f8SKarsten Keil } else {
4811b2b03f8SKarsten Keil bp = get_Bprotocol4mask(pmask);
4821b2b03f8SKarsten Keil if (!bp)
4831b2b03f8SKarsten Keil return -ENOPROTOOPT;
4841b2b03f8SKarsten Keil rq2.protocol = protocol;
4851b2b03f8SKarsten Keil rq2.adr = *adr;
4861b2b03f8SKarsten Keil rq2.ch = ch;
4871b2b03f8SKarsten Keil err = bp->create(&rq2);
4881b2b03f8SKarsten Keil if (err)
4891b2b03f8SKarsten Keil return err;
4901b2b03f8SKarsten Keil ch->recv = rq2.ch->send;
4911b2b03f8SKarsten Keil ch->peer = rq2.ch;
4921b2b03f8SKarsten Keil rq2.ch->st = dev->D.st;
4931b2b03f8SKarsten Keil rq.protocol = rq2.protocol;
4941b2b03f8SKarsten Keil rq.adr = *adr;
4951b2b03f8SKarsten Keil err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq);
4961b2b03f8SKarsten Keil if (err) {
4971b2b03f8SKarsten Keil rq2.ch->ctrl(rq2.ch, CLOSE_CHANNEL, NULL);
4981b2b03f8SKarsten Keil return err;
4991b2b03f8SKarsten Keil }
5001b2b03f8SKarsten Keil rq2.ch->recv = rq.ch->send;
5011b2b03f8SKarsten Keil rq2.ch->peer = rq.ch;
5021b2b03f8SKarsten Keil rq.ch->recv = rq2.ch->send;
5031b2b03f8SKarsten Keil rq.ch->peer = rq2.ch;
5041b2b03f8SKarsten Keil rq.ch->st = dev->D.st;
5051b2b03f8SKarsten Keil }
5061b2b03f8SKarsten Keil ch->protocol = protocol;
5071b2b03f8SKarsten Keil ch->nr = rq.ch->nr;
5081b2b03f8SKarsten Keil return 0;
5091b2b03f8SKarsten Keil }
5101b2b03f8SKarsten Keil
5111b2b03f8SKarsten Keil int
create_l2entity(struct mISDNdevice * dev,struct mISDNchannel * ch,u_int protocol,struct sockaddr_mISDN * adr)5121b2b03f8SKarsten Keil create_l2entity(struct mISDNdevice *dev, struct mISDNchannel *ch,
5131b2b03f8SKarsten Keil u_int protocol, struct sockaddr_mISDN *adr)
5141b2b03f8SKarsten Keil {
5151b2b03f8SKarsten Keil struct channel_req rq;
5161b2b03f8SKarsten Keil int err;
5171b2b03f8SKarsten Keil
5181b2b03f8SKarsten Keil if (*debug & DEBUG_CORE_FUNC)
5191b2b03f8SKarsten Keil printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n",
520837468d1SMatthias Urlichs __func__, dev_name(&dev->dev), protocol,
5211b2b03f8SKarsten Keil adr->dev, adr->channel, adr->sapi,
5221b2b03f8SKarsten Keil adr->tei);
5231b2b03f8SKarsten Keil rq.protocol = ISDN_P_TE_S0;
5241b2b03f8SKarsten Keil if (dev->Dprotocols & (1 << ISDN_P_TE_E1))
5251b2b03f8SKarsten Keil rq.protocol = ISDN_P_TE_E1;
5261b2b03f8SKarsten Keil switch (protocol) {
5271b2b03f8SKarsten Keil case ISDN_P_LAPD_NT:
5281b2b03f8SKarsten Keil rq.protocol = ISDN_P_NT_S0;
5291b2b03f8SKarsten Keil if (dev->Dprotocols & (1 << ISDN_P_NT_E1))
5301b2b03f8SKarsten Keil rq.protocol = ISDN_P_NT_E1;
531*df561f66SGustavo A. R. Silva fallthrough;
5321b2b03f8SKarsten Keil case ISDN_P_LAPD_TE:
5331b2b03f8SKarsten Keil ch->recv = mISDN_queue_message;
5341b2b03f8SKarsten Keil ch->peer = &dev->D.st->own;
5351b2b03f8SKarsten Keil ch->st = dev->D.st;
5361b2b03f8SKarsten Keil rq.adr.channel = 0;
5371b2b03f8SKarsten Keil err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq);
5381b2b03f8SKarsten Keil printk(KERN_DEBUG "%s: ret 1 %d\n", __func__, err);
5391b2b03f8SKarsten Keil if (err)
5401b2b03f8SKarsten Keil break;
5411b2b03f8SKarsten Keil rq.protocol = protocol;
5421b2b03f8SKarsten Keil rq.adr = *adr;
5431b2b03f8SKarsten Keil rq.ch = ch;
5441b2b03f8SKarsten Keil err = dev->teimgr->ctrl(dev->teimgr, OPEN_CHANNEL, &rq);
5451b2b03f8SKarsten Keil printk(KERN_DEBUG "%s: ret 2 %d\n", __func__, err);
5461b2b03f8SKarsten Keil if (!err) {
5471b2b03f8SKarsten Keil if ((protocol == ISDN_P_LAPD_NT) && !rq.ch)
5481b2b03f8SKarsten Keil break;
5491b2b03f8SKarsten Keil add_layer2(rq.ch, dev->D.st);
5501b2b03f8SKarsten Keil rq.ch->recv = mISDN_queue_message;
5511b2b03f8SKarsten Keil rq.ch->peer = &dev->D.st->own;
5521b2b03f8SKarsten Keil rq.ch->ctrl(rq.ch, OPEN_CHANNEL, NULL); /* can't fail */
5531b2b03f8SKarsten Keil }
5541b2b03f8SKarsten Keil break;
5551b2b03f8SKarsten Keil default:
5561b2b03f8SKarsten Keil err = -EPROTONOSUPPORT;
5571b2b03f8SKarsten Keil }
5581b2b03f8SKarsten Keil return err;
5591b2b03f8SKarsten Keil }
5601b2b03f8SKarsten Keil
5611b2b03f8SKarsten Keil void
delete_channel(struct mISDNchannel * ch)5621b2b03f8SKarsten Keil delete_channel(struct mISDNchannel *ch)
5631b2b03f8SKarsten Keil {
5641b2b03f8SKarsten Keil struct mISDN_sock *msk = container_of(ch, struct mISDN_sock, ch);
5651b2b03f8SKarsten Keil struct mISDNchannel *pch;
5661b2b03f8SKarsten Keil
5671b2b03f8SKarsten Keil if (!ch->st) {
5681b2b03f8SKarsten Keil printk(KERN_WARNING "%s: no stack\n", __func__);
5691b2b03f8SKarsten Keil return;
5701b2b03f8SKarsten Keil }
5711b2b03f8SKarsten Keil if (*debug & DEBUG_CORE_FUNC)
5721b2b03f8SKarsten Keil printk(KERN_DEBUG "%s: st(%s) protocol(%x)\n", __func__,
573837468d1SMatthias Urlichs dev_name(&ch->st->dev->dev), ch->protocol);
5741b2b03f8SKarsten Keil if (ch->protocol >= ISDN_P_B_START) {
5751b2b03f8SKarsten Keil if (ch->peer) {
5761b2b03f8SKarsten Keil ch->peer->ctrl(ch->peer, CLOSE_CHANNEL, NULL);
5771b2b03f8SKarsten Keil ch->peer = NULL;
5781b2b03f8SKarsten Keil }
5791b2b03f8SKarsten Keil return;
5801b2b03f8SKarsten Keil }
5811b2b03f8SKarsten Keil switch (ch->protocol) {
5821b2b03f8SKarsten Keil case ISDN_P_NT_S0:
5831b2b03f8SKarsten Keil case ISDN_P_TE_S0:
5841b2b03f8SKarsten Keil case ISDN_P_NT_E1:
5851b2b03f8SKarsten Keil case ISDN_P_TE_E1:
5861b2b03f8SKarsten Keil write_lock_bh(&ch->st->l1sock.lock);
5871b2b03f8SKarsten Keil sk_del_node_init(&msk->sk);
5881b2b03f8SKarsten Keil write_unlock_bh(&ch->st->l1sock.lock);
5891b2b03f8SKarsten Keil ch->st->dev->D.ctrl(&ch->st->dev->D, CLOSE_CHANNEL, NULL);
5901b2b03f8SKarsten Keil break;
5911b2b03f8SKarsten Keil case ISDN_P_LAPD_TE:
5921b2b03f8SKarsten Keil pch = get_channel4id(ch->st, ch->nr);
5931b2b03f8SKarsten Keil if (pch) {
5941b2b03f8SKarsten Keil mutex_lock(&ch->st->lmutex);
5951b2b03f8SKarsten Keil list_del(&pch->list);
5961b2b03f8SKarsten Keil mutex_unlock(&ch->st->lmutex);
5971b2b03f8SKarsten Keil pch->ctrl(pch, CLOSE_CHANNEL, NULL);
5981b2b03f8SKarsten Keil pch = ch->st->dev->teimgr;
5991b2b03f8SKarsten Keil pch->ctrl(pch, CLOSE_CHANNEL, NULL);
6001b2b03f8SKarsten Keil } else
6011b2b03f8SKarsten Keil printk(KERN_WARNING "%s: no l2 channel\n",
6021b2b03f8SKarsten Keil __func__);
6031b2b03f8SKarsten Keil break;
6041b2b03f8SKarsten Keil case ISDN_P_LAPD_NT:
6051b2b03f8SKarsten Keil pch = ch->st->dev->teimgr;
6061b2b03f8SKarsten Keil if (pch) {
6071b2b03f8SKarsten Keil pch->ctrl(pch, CLOSE_CHANNEL, NULL);
6081b2b03f8SKarsten Keil } else
6091b2b03f8SKarsten Keil printk(KERN_WARNING "%s: no l2 channel\n",
6101b2b03f8SKarsten Keil __func__);
6111b2b03f8SKarsten Keil break;
6121b2b03f8SKarsten Keil default:
6131b2b03f8SKarsten Keil break;
6141b2b03f8SKarsten Keil }
6151b2b03f8SKarsten Keil return;
6161b2b03f8SKarsten Keil }
6171b2b03f8SKarsten Keil
6181b2b03f8SKarsten Keil void
delete_stack(struct mISDNdevice * dev)6191b2b03f8SKarsten Keil delete_stack(struct mISDNdevice *dev)
6201b2b03f8SKarsten Keil {
6211b2b03f8SKarsten Keil struct mISDNstack *st = dev->D.st;
6221b2b03f8SKarsten Keil DECLARE_COMPLETION_ONSTACK(done);
6231b2b03f8SKarsten Keil
6241b2b03f8SKarsten Keil if (*debug & DEBUG_CORE_FUNC)
6251b2b03f8SKarsten Keil printk(KERN_DEBUG "%s: st(%s)\n", __func__,
626837468d1SMatthias Urlichs dev_name(&st->dev->dev));
6271b2b03f8SKarsten Keil if (dev->teimgr)
6281b2b03f8SKarsten Keil delete_teimanager(dev->teimgr);
6291b2b03f8SKarsten Keil if (st->thread) {
6301b2b03f8SKarsten Keil if (st->notify) {
6311b2b03f8SKarsten Keil printk(KERN_WARNING "%s: notifier in use\n",
6321b2b03f8SKarsten Keil __func__);
6331b2b03f8SKarsten Keil complete(st->notify);
6341b2b03f8SKarsten Keil }
6351b2b03f8SKarsten Keil st->notify = &done;
6361b2b03f8SKarsten Keil test_and_set_bit(mISDN_STACK_ABORT, &st->status);
6371b2b03f8SKarsten Keil test_and_set_bit(mISDN_STACK_WAKEUP, &st->status);
6381b2b03f8SKarsten Keil wake_up_interruptible(&st->workq);
6391b2b03f8SKarsten Keil wait_for_completion(&done);
6401b2b03f8SKarsten Keil }
6411b2b03f8SKarsten Keil if (!list_empty(&st->layer2))
6421b2b03f8SKarsten Keil printk(KERN_WARNING "%s: layer2 list not empty\n",
6431b2b03f8SKarsten Keil __func__);
6441b2b03f8SKarsten Keil if (!hlist_empty(&st->l1sock.head))
6451b2b03f8SKarsten Keil printk(KERN_WARNING "%s: layer1 list not empty\n",
6461b2b03f8SKarsten Keil __func__);
6471b2b03f8SKarsten Keil kfree(st);
6481b2b03f8SKarsten Keil }
6491b2b03f8SKarsten Keil
6501b2b03f8SKarsten Keil void
mISDN_initstack(u_int * dp)6511b2b03f8SKarsten Keil mISDN_initstack(u_int *dp)
6521b2b03f8SKarsten Keil {
6531b2b03f8SKarsten Keil debug = dp;
6541b2b03f8SKarsten Keil }
655