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#include "layer2.h" 98c2ecf20Sopenharmony_ci#include <linux/random.h> 108c2ecf20Sopenharmony_ci#include <linux/slab.h> 118c2ecf20Sopenharmony_ci#include "core.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#define ID_REQUEST 1 148c2ecf20Sopenharmony_ci#define ID_ASSIGNED 2 158c2ecf20Sopenharmony_ci#define ID_DENIED 3 168c2ecf20Sopenharmony_ci#define ID_CHK_REQ 4 178c2ecf20Sopenharmony_ci#define ID_CHK_RES 5 188c2ecf20Sopenharmony_ci#define ID_REMOVE 6 198c2ecf20Sopenharmony_ci#define ID_VERIFY 7 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define TEI_ENTITY_ID 0xf 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define MGR_PH_ACTIVE 16 248c2ecf20Sopenharmony_ci#define MGR_PH_NOTREADY 17 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define DATIMER_VAL 10000 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic u_int *debug; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic struct Fsm deactfsm = {NULL, 0, 0, NULL, NULL}; 318c2ecf20Sopenharmony_cistatic struct Fsm teifsmu = {NULL, 0, 0, NULL, NULL}; 328c2ecf20Sopenharmony_cistatic struct Fsm teifsmn = {NULL, 0, 0, NULL, NULL}; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cienum { 358c2ecf20Sopenharmony_ci ST_L1_DEACT, 368c2ecf20Sopenharmony_ci ST_L1_DEACT_PENDING, 378c2ecf20Sopenharmony_ci ST_L1_ACTIV, 388c2ecf20Sopenharmony_ci}; 398c2ecf20Sopenharmony_ci#define DEACT_STATE_COUNT (ST_L1_ACTIV + 1) 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic char *strDeactState[] = 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci "ST_L1_DEACT", 448c2ecf20Sopenharmony_ci "ST_L1_DEACT_PENDING", 458c2ecf20Sopenharmony_ci "ST_L1_ACTIV", 468c2ecf20Sopenharmony_ci}; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cienum { 498c2ecf20Sopenharmony_ci EV_ACTIVATE, 508c2ecf20Sopenharmony_ci EV_ACTIVATE_IND, 518c2ecf20Sopenharmony_ci EV_DEACTIVATE, 528c2ecf20Sopenharmony_ci EV_DEACTIVATE_IND, 538c2ecf20Sopenharmony_ci EV_UI, 548c2ecf20Sopenharmony_ci EV_DATIMER, 558c2ecf20Sopenharmony_ci}; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci#define DEACT_EVENT_COUNT (EV_DATIMER + 1) 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic char *strDeactEvent[] = 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci "EV_ACTIVATE", 628c2ecf20Sopenharmony_ci "EV_ACTIVATE_IND", 638c2ecf20Sopenharmony_ci "EV_DEACTIVATE", 648c2ecf20Sopenharmony_ci "EV_DEACTIVATE_IND", 658c2ecf20Sopenharmony_ci "EV_UI", 668c2ecf20Sopenharmony_ci "EV_DATIMER", 678c2ecf20Sopenharmony_ci}; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic void 708c2ecf20Sopenharmony_cida_debug(struct FsmInst *fi, char *fmt, ...) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci struct manager *mgr = fi->userdata; 738c2ecf20Sopenharmony_ci struct va_format vaf; 748c2ecf20Sopenharmony_ci va_list va; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci if (!(*debug & DEBUG_L2_TEIFSM)) 778c2ecf20Sopenharmony_ci return; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci va_start(va, fmt); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci vaf.fmt = fmt; 828c2ecf20Sopenharmony_ci vaf.va = &va; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci printk(KERN_DEBUG "mgr(%d): %pV\n", mgr->ch.st->dev->id, &vaf); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci va_end(va); 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic void 908c2ecf20Sopenharmony_cida_activate(struct FsmInst *fi, int event, void *arg) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci struct manager *mgr = fi->userdata; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci if (fi->state == ST_L1_DEACT_PENDING) 958c2ecf20Sopenharmony_ci mISDN_FsmDelTimer(&mgr->datimer, 1); 968c2ecf20Sopenharmony_ci mISDN_FsmChangeState(fi, ST_L1_ACTIV); 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic void 1008c2ecf20Sopenharmony_cida_deactivate_ind(struct FsmInst *fi, int event, void *arg) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci mISDN_FsmChangeState(fi, ST_L1_DEACT); 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic void 1068c2ecf20Sopenharmony_cida_deactivate(struct FsmInst *fi, int event, void *arg) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci struct manager *mgr = fi->userdata; 1098c2ecf20Sopenharmony_ci struct layer2 *l2; 1108c2ecf20Sopenharmony_ci u_long flags; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci read_lock_irqsave(&mgr->lock, flags); 1138c2ecf20Sopenharmony_ci list_for_each_entry(l2, &mgr->layer2, list) { 1148c2ecf20Sopenharmony_ci if (l2->l2m.state > ST_L2_4) { 1158c2ecf20Sopenharmony_ci /* have still activ TEI */ 1168c2ecf20Sopenharmony_ci read_unlock_irqrestore(&mgr->lock, flags); 1178c2ecf20Sopenharmony_ci return; 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci read_unlock_irqrestore(&mgr->lock, flags); 1218c2ecf20Sopenharmony_ci /* All TEI are inactiv */ 1228c2ecf20Sopenharmony_ci if (!test_bit(OPTION_L1_HOLD, &mgr->options)) { 1238c2ecf20Sopenharmony_ci mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER, 1248c2ecf20Sopenharmony_ci NULL, 1); 1258c2ecf20Sopenharmony_ci mISDN_FsmChangeState(fi, ST_L1_DEACT_PENDING); 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic void 1308c2ecf20Sopenharmony_cida_ui(struct FsmInst *fi, int event, void *arg) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci struct manager *mgr = fi->userdata; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci /* restart da timer */ 1358c2ecf20Sopenharmony_ci if (!test_bit(OPTION_L1_HOLD, &mgr->options)) { 1368c2ecf20Sopenharmony_ci mISDN_FsmDelTimer(&mgr->datimer, 2); 1378c2ecf20Sopenharmony_ci mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER, 1388c2ecf20Sopenharmony_ci NULL, 2); 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic void 1438c2ecf20Sopenharmony_cida_timer(struct FsmInst *fi, int event, void *arg) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci struct manager *mgr = fi->userdata; 1468c2ecf20Sopenharmony_ci struct layer2 *l2; 1478c2ecf20Sopenharmony_ci u_long flags; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci /* check again */ 1508c2ecf20Sopenharmony_ci read_lock_irqsave(&mgr->lock, flags); 1518c2ecf20Sopenharmony_ci list_for_each_entry(l2, &mgr->layer2, list) { 1528c2ecf20Sopenharmony_ci if (l2->l2m.state > ST_L2_4) { 1538c2ecf20Sopenharmony_ci /* have still activ TEI */ 1548c2ecf20Sopenharmony_ci read_unlock_irqrestore(&mgr->lock, flags); 1558c2ecf20Sopenharmony_ci mISDN_FsmChangeState(fi, ST_L1_ACTIV); 1568c2ecf20Sopenharmony_ci return; 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci read_unlock_irqrestore(&mgr->lock, flags); 1608c2ecf20Sopenharmony_ci /* All TEI are inactiv */ 1618c2ecf20Sopenharmony_ci mISDN_FsmChangeState(fi, ST_L1_DEACT); 1628c2ecf20Sopenharmony_ci _queue_data(&mgr->ch, PH_DEACTIVATE_REQ, MISDN_ID_ANY, 0, NULL, 1638c2ecf20Sopenharmony_ci GFP_ATOMIC); 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic struct FsmNode DeactFnList[] = 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci {ST_L1_DEACT, EV_ACTIVATE_IND, da_activate}, 1698c2ecf20Sopenharmony_ci {ST_L1_ACTIV, EV_DEACTIVATE_IND, da_deactivate_ind}, 1708c2ecf20Sopenharmony_ci {ST_L1_ACTIV, EV_DEACTIVATE, da_deactivate}, 1718c2ecf20Sopenharmony_ci {ST_L1_DEACT_PENDING, EV_ACTIVATE, da_activate}, 1728c2ecf20Sopenharmony_ci {ST_L1_DEACT_PENDING, EV_UI, da_ui}, 1738c2ecf20Sopenharmony_ci {ST_L1_DEACT_PENDING, EV_DATIMER, da_timer}, 1748c2ecf20Sopenharmony_ci}; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cienum { 1778c2ecf20Sopenharmony_ci ST_TEI_NOP, 1788c2ecf20Sopenharmony_ci ST_TEI_IDREQ, 1798c2ecf20Sopenharmony_ci ST_TEI_IDVERIFY, 1808c2ecf20Sopenharmony_ci}; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci#define TEI_STATE_COUNT (ST_TEI_IDVERIFY + 1) 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic char *strTeiState[] = 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci "ST_TEI_NOP", 1878c2ecf20Sopenharmony_ci "ST_TEI_IDREQ", 1888c2ecf20Sopenharmony_ci "ST_TEI_IDVERIFY", 1898c2ecf20Sopenharmony_ci}; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cienum { 1928c2ecf20Sopenharmony_ci EV_IDREQ, 1938c2ecf20Sopenharmony_ci EV_ASSIGN, 1948c2ecf20Sopenharmony_ci EV_ASSIGN_REQ, 1958c2ecf20Sopenharmony_ci EV_DENIED, 1968c2ecf20Sopenharmony_ci EV_CHKREQ, 1978c2ecf20Sopenharmony_ci EV_CHKRESP, 1988c2ecf20Sopenharmony_ci EV_REMOVE, 1998c2ecf20Sopenharmony_ci EV_VERIFY, 2008c2ecf20Sopenharmony_ci EV_TIMER, 2018c2ecf20Sopenharmony_ci}; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci#define TEI_EVENT_COUNT (EV_TIMER + 1) 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic char *strTeiEvent[] = 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci "EV_IDREQ", 2088c2ecf20Sopenharmony_ci "EV_ASSIGN", 2098c2ecf20Sopenharmony_ci "EV_ASSIGN_REQ", 2108c2ecf20Sopenharmony_ci "EV_DENIED", 2118c2ecf20Sopenharmony_ci "EV_CHKREQ", 2128c2ecf20Sopenharmony_ci "EV_CHKRESP", 2138c2ecf20Sopenharmony_ci "EV_REMOVE", 2148c2ecf20Sopenharmony_ci "EV_VERIFY", 2158c2ecf20Sopenharmony_ci "EV_TIMER", 2168c2ecf20Sopenharmony_ci}; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistatic void 2198c2ecf20Sopenharmony_citei_debug(struct FsmInst *fi, char *fmt, ...) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci struct teimgr *tm = fi->userdata; 2228c2ecf20Sopenharmony_ci struct va_format vaf; 2238c2ecf20Sopenharmony_ci va_list va; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci if (!(*debug & DEBUG_L2_TEIFSM)) 2268c2ecf20Sopenharmony_ci return; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci va_start(va, fmt); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci vaf.fmt = fmt; 2318c2ecf20Sopenharmony_ci vaf.va = &va; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci printk(KERN_DEBUG "sapi(%d) tei(%d): %pV\n", 2348c2ecf20Sopenharmony_ci tm->l2->sapi, tm->l2->tei, &vaf); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci va_end(va); 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistatic int 2428c2ecf20Sopenharmony_ciget_free_id(struct manager *mgr) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci DECLARE_BITMAP(ids, 64) = { [0 ... BITS_TO_LONGS(64) - 1] = 0 }; 2458c2ecf20Sopenharmony_ci int i; 2468c2ecf20Sopenharmony_ci struct layer2 *l2; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci list_for_each_entry(l2, &mgr->layer2, list) { 2498c2ecf20Sopenharmony_ci if (l2->ch.nr > 63) { 2508c2ecf20Sopenharmony_ci printk(KERN_WARNING 2518c2ecf20Sopenharmony_ci "%s: more as 63 layer2 for one device\n", 2528c2ecf20Sopenharmony_ci __func__); 2538c2ecf20Sopenharmony_ci return -EBUSY; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci __set_bit(l2->ch.nr, ids); 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci i = find_next_zero_bit(ids, 64, 1); 2588c2ecf20Sopenharmony_ci if (i < 64) 2598c2ecf20Sopenharmony_ci return i; 2608c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: more as 63 layer2 for one device\n", 2618c2ecf20Sopenharmony_ci __func__); 2628c2ecf20Sopenharmony_ci return -EBUSY; 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cistatic int 2668c2ecf20Sopenharmony_ciget_free_tei(struct manager *mgr) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci DECLARE_BITMAP(ids, 64) = { [0 ... BITS_TO_LONGS(64) - 1] = 0 }; 2698c2ecf20Sopenharmony_ci int i; 2708c2ecf20Sopenharmony_ci struct layer2 *l2; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci list_for_each_entry(l2, &mgr->layer2, list) { 2738c2ecf20Sopenharmony_ci if (l2->ch.nr == 0) 2748c2ecf20Sopenharmony_ci continue; 2758c2ecf20Sopenharmony_ci if ((l2->ch.addr & 0xff) != 0) 2768c2ecf20Sopenharmony_ci continue; 2778c2ecf20Sopenharmony_ci i = l2->ch.addr >> 8; 2788c2ecf20Sopenharmony_ci if (i < 64) 2798c2ecf20Sopenharmony_ci continue; 2808c2ecf20Sopenharmony_ci i -= 64; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci __set_bit(i, ids); 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci i = find_first_zero_bit(ids, 64); 2858c2ecf20Sopenharmony_ci if (i < 64) 2868c2ecf20Sopenharmony_ci return i + 64; 2878c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: more as 63 dynamic tei for one device\n", 2888c2ecf20Sopenharmony_ci __func__); 2898c2ecf20Sopenharmony_ci return -1; 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cistatic void 2938c2ecf20Sopenharmony_citeiup_create(struct manager *mgr, u_int prim, int len, void *arg) 2948c2ecf20Sopenharmony_ci{ 2958c2ecf20Sopenharmony_ci struct sk_buff *skb; 2968c2ecf20Sopenharmony_ci struct mISDNhead *hh; 2978c2ecf20Sopenharmony_ci int err; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci skb = mI_alloc_skb(len, GFP_ATOMIC); 3008c2ecf20Sopenharmony_ci if (!skb) 3018c2ecf20Sopenharmony_ci return; 3028c2ecf20Sopenharmony_ci hh = mISDN_HEAD_P(skb); 3038c2ecf20Sopenharmony_ci hh->prim = prim; 3048c2ecf20Sopenharmony_ci hh->id = (mgr->ch.nr << 16) | mgr->ch.addr; 3058c2ecf20Sopenharmony_ci if (len) 3068c2ecf20Sopenharmony_ci skb_put_data(skb, arg, len); 3078c2ecf20Sopenharmony_ci err = mgr->up->send(mgr->up, skb); 3088c2ecf20Sopenharmony_ci if (err) { 3098c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: err=%d\n", __func__, err); 3108c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic u_int 3158c2ecf20Sopenharmony_cinew_id(struct manager *mgr) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci u_int id; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci id = mgr->nextid++; 3208c2ecf20Sopenharmony_ci if (id == 0x7fff) 3218c2ecf20Sopenharmony_ci mgr->nextid = 1; 3228c2ecf20Sopenharmony_ci id <<= 16; 3238c2ecf20Sopenharmony_ci id |= GROUP_TEI << 8; 3248c2ecf20Sopenharmony_ci id |= TEI_SAPI; 3258c2ecf20Sopenharmony_ci return id; 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cistatic void 3298c2ecf20Sopenharmony_cido_send(struct manager *mgr) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci if (!test_bit(MGR_PH_ACTIVE, &mgr->options)) 3328c2ecf20Sopenharmony_ci return; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if (!test_and_set_bit(MGR_PH_NOTREADY, &mgr->options)) { 3358c2ecf20Sopenharmony_ci struct sk_buff *skb = skb_dequeue(&mgr->sendq); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci if (!skb) { 3388c2ecf20Sopenharmony_ci test_and_clear_bit(MGR_PH_NOTREADY, &mgr->options); 3398c2ecf20Sopenharmony_ci return; 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci mgr->lastid = mISDN_HEAD_ID(skb); 3428c2ecf20Sopenharmony_ci mISDN_FsmEvent(&mgr->deact, EV_UI, NULL); 3438c2ecf20Sopenharmony_ci if (mgr->ch.recv(mgr->ch.peer, skb)) { 3448c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 3458c2ecf20Sopenharmony_ci test_and_clear_bit(MGR_PH_NOTREADY, &mgr->options); 3468c2ecf20Sopenharmony_ci mgr->lastid = MISDN_ID_NONE; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_cistatic void 3528c2ecf20Sopenharmony_cido_ack(struct manager *mgr, u_int id) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci if (test_bit(MGR_PH_NOTREADY, &mgr->options)) { 3558c2ecf20Sopenharmony_ci if (id == mgr->lastid) { 3568c2ecf20Sopenharmony_ci if (test_bit(MGR_PH_ACTIVE, &mgr->options)) { 3578c2ecf20Sopenharmony_ci struct sk_buff *skb; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci skb = skb_dequeue(&mgr->sendq); 3608c2ecf20Sopenharmony_ci if (skb) { 3618c2ecf20Sopenharmony_ci mgr->lastid = mISDN_HEAD_ID(skb); 3628c2ecf20Sopenharmony_ci if (!mgr->ch.recv(mgr->ch.peer, skb)) 3638c2ecf20Sopenharmony_ci return; 3648c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci mgr->lastid = MISDN_ID_NONE; 3688c2ecf20Sopenharmony_ci test_and_clear_bit(MGR_PH_NOTREADY, &mgr->options); 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci} 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_cistatic void 3748c2ecf20Sopenharmony_cimgr_send_down(struct manager *mgr, struct sk_buff *skb) 3758c2ecf20Sopenharmony_ci{ 3768c2ecf20Sopenharmony_ci skb_queue_tail(&mgr->sendq, skb); 3778c2ecf20Sopenharmony_ci if (!test_bit(MGR_PH_ACTIVE, &mgr->options)) { 3788c2ecf20Sopenharmony_ci _queue_data(&mgr->ch, PH_ACTIVATE_REQ, MISDN_ID_ANY, 0, 3798c2ecf20Sopenharmony_ci NULL, GFP_KERNEL); 3808c2ecf20Sopenharmony_ci } else { 3818c2ecf20Sopenharmony_ci do_send(mgr); 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci} 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_cistatic int 3868c2ecf20Sopenharmony_cidl_unit_data(struct manager *mgr, struct sk_buff *skb) 3878c2ecf20Sopenharmony_ci{ 3888c2ecf20Sopenharmony_ci if (!test_bit(MGR_OPT_NETWORK, &mgr->options)) /* only net send UI */ 3898c2ecf20Sopenharmony_ci return -EINVAL; 3908c2ecf20Sopenharmony_ci if (!test_bit(MGR_PH_ACTIVE, &mgr->options)) 3918c2ecf20Sopenharmony_ci _queue_data(&mgr->ch, PH_ACTIVATE_REQ, MISDN_ID_ANY, 0, 3928c2ecf20Sopenharmony_ci NULL, GFP_KERNEL); 3938c2ecf20Sopenharmony_ci skb_push(skb, 3); 3948c2ecf20Sopenharmony_ci skb->data[0] = 0x02; /* SAPI 0 C/R = 1 */ 3958c2ecf20Sopenharmony_ci skb->data[1] = 0xff; /* TEI 127 */ 3968c2ecf20Sopenharmony_ci skb->data[2] = UI; /* UI frame */ 3978c2ecf20Sopenharmony_ci mISDN_HEAD_PRIM(skb) = PH_DATA_REQ; 3988c2ecf20Sopenharmony_ci mISDN_HEAD_ID(skb) = new_id(mgr); 3998c2ecf20Sopenharmony_ci skb_queue_tail(&mgr->sendq, skb); 4008c2ecf20Sopenharmony_ci do_send(mgr); 4018c2ecf20Sopenharmony_ci return 0; 4028c2ecf20Sopenharmony_ci} 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_cistatic unsigned int 4058c2ecf20Sopenharmony_cirandom_ri(void) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci u16 x; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci get_random_bytes(&x, sizeof(x)); 4108c2ecf20Sopenharmony_ci return x; 4118c2ecf20Sopenharmony_ci} 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_cistatic struct layer2 * 4148c2ecf20Sopenharmony_cifindtei(struct manager *mgr, int tei) 4158c2ecf20Sopenharmony_ci{ 4168c2ecf20Sopenharmony_ci struct layer2 *l2; 4178c2ecf20Sopenharmony_ci u_long flags; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci read_lock_irqsave(&mgr->lock, flags); 4208c2ecf20Sopenharmony_ci list_for_each_entry(l2, &mgr->layer2, list) { 4218c2ecf20Sopenharmony_ci if ((l2->sapi == 0) && (l2->tei > 0) && 4228c2ecf20Sopenharmony_ci (l2->tei != GROUP_TEI) && (l2->tei == tei)) 4238c2ecf20Sopenharmony_ci goto done; 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci l2 = NULL; 4268c2ecf20Sopenharmony_cidone: 4278c2ecf20Sopenharmony_ci read_unlock_irqrestore(&mgr->lock, flags); 4288c2ecf20Sopenharmony_ci return l2; 4298c2ecf20Sopenharmony_ci} 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_cistatic void 4328c2ecf20Sopenharmony_ciput_tei_msg(struct manager *mgr, u_char m_id, unsigned int ri, int tei) 4338c2ecf20Sopenharmony_ci{ 4348c2ecf20Sopenharmony_ci struct sk_buff *skb; 4358c2ecf20Sopenharmony_ci u_char bp[8]; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci bp[0] = (TEI_SAPI << 2); 4388c2ecf20Sopenharmony_ci if (test_bit(MGR_OPT_NETWORK, &mgr->options)) 4398c2ecf20Sopenharmony_ci bp[0] |= 2; /* CR:=1 for net command */ 4408c2ecf20Sopenharmony_ci bp[1] = (GROUP_TEI << 1) | 0x1; 4418c2ecf20Sopenharmony_ci bp[2] = UI; 4428c2ecf20Sopenharmony_ci bp[3] = TEI_ENTITY_ID; 4438c2ecf20Sopenharmony_ci bp[4] = ri >> 8; 4448c2ecf20Sopenharmony_ci bp[5] = ri & 0xff; 4458c2ecf20Sopenharmony_ci bp[6] = m_id; 4468c2ecf20Sopenharmony_ci bp[7] = ((tei << 1) & 0xff) | 1; 4478c2ecf20Sopenharmony_ci skb = _alloc_mISDN_skb(PH_DATA_REQ, new_id(mgr), 8, bp, GFP_ATOMIC); 4488c2ecf20Sopenharmony_ci if (!skb) { 4498c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: no skb for tei msg\n", __func__); 4508c2ecf20Sopenharmony_ci return; 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci mgr_send_down(mgr, skb); 4538c2ecf20Sopenharmony_ci} 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_cistatic void 4568c2ecf20Sopenharmony_citei_id_request(struct FsmInst *fi, int event, void *arg) 4578c2ecf20Sopenharmony_ci{ 4588c2ecf20Sopenharmony_ci struct teimgr *tm = fi->userdata; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci if (tm->l2->tei != GROUP_TEI) { 4618c2ecf20Sopenharmony_ci tm->tei_m.printdebug(&tm->tei_m, 4628c2ecf20Sopenharmony_ci "assign request for already assigned tei %d", 4638c2ecf20Sopenharmony_ci tm->l2->tei); 4648c2ecf20Sopenharmony_ci return; 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci tm->ri = random_ri(); 4678c2ecf20Sopenharmony_ci if (*debug & DEBUG_L2_TEI) 4688c2ecf20Sopenharmony_ci tm->tei_m.printdebug(&tm->tei_m, 4698c2ecf20Sopenharmony_ci "assign request ri %d", tm->ri); 4708c2ecf20Sopenharmony_ci put_tei_msg(tm->mgr, ID_REQUEST, tm->ri, GROUP_TEI); 4718c2ecf20Sopenharmony_ci mISDN_FsmChangeState(fi, ST_TEI_IDREQ); 4728c2ecf20Sopenharmony_ci mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 1); 4738c2ecf20Sopenharmony_ci tm->nval = 3; 4748c2ecf20Sopenharmony_ci} 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_cistatic void 4778c2ecf20Sopenharmony_citei_id_assign(struct FsmInst *fi, int event, void *arg) 4788c2ecf20Sopenharmony_ci{ 4798c2ecf20Sopenharmony_ci struct teimgr *tm = fi->userdata; 4808c2ecf20Sopenharmony_ci struct layer2 *l2; 4818c2ecf20Sopenharmony_ci u_char *dp = arg; 4828c2ecf20Sopenharmony_ci int ri, tei; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci ri = ((unsigned int) *dp++ << 8); 4858c2ecf20Sopenharmony_ci ri += *dp++; 4868c2ecf20Sopenharmony_ci dp++; 4878c2ecf20Sopenharmony_ci tei = *dp >> 1; 4888c2ecf20Sopenharmony_ci if (*debug & DEBUG_L2_TEI) 4898c2ecf20Sopenharmony_ci tm->tei_m.printdebug(fi, "identity assign ri %d tei %d", 4908c2ecf20Sopenharmony_ci ri, tei); 4918c2ecf20Sopenharmony_ci l2 = findtei(tm->mgr, tei); 4928c2ecf20Sopenharmony_ci if (l2) { /* same tei is in use */ 4938c2ecf20Sopenharmony_ci if (ri != l2->tm->ri) { 4948c2ecf20Sopenharmony_ci tm->tei_m.printdebug(fi, 4958c2ecf20Sopenharmony_ci "possible duplicate assignment tei %d", tei); 4968c2ecf20Sopenharmony_ci tei_l2(l2, MDL_ERROR_RSP, 0); 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci } else if (ri == tm->ri) { 4998c2ecf20Sopenharmony_ci mISDN_FsmDelTimer(&tm->timer, 1); 5008c2ecf20Sopenharmony_ci mISDN_FsmChangeState(fi, ST_TEI_NOP); 5018c2ecf20Sopenharmony_ci tei_l2(tm->l2, MDL_ASSIGN_REQ, tei); 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci} 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_cistatic void 5068c2ecf20Sopenharmony_citei_id_test_dup(struct FsmInst *fi, int event, void *arg) 5078c2ecf20Sopenharmony_ci{ 5088c2ecf20Sopenharmony_ci struct teimgr *tm = fi->userdata; 5098c2ecf20Sopenharmony_ci struct layer2 *l2; 5108c2ecf20Sopenharmony_ci u_char *dp = arg; 5118c2ecf20Sopenharmony_ci int tei, ri; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci ri = ((unsigned int) *dp++ << 8); 5148c2ecf20Sopenharmony_ci ri += *dp++; 5158c2ecf20Sopenharmony_ci dp++; 5168c2ecf20Sopenharmony_ci tei = *dp >> 1; 5178c2ecf20Sopenharmony_ci if (*debug & DEBUG_L2_TEI) 5188c2ecf20Sopenharmony_ci tm->tei_m.printdebug(fi, "foreign identity assign ri %d tei %d", 5198c2ecf20Sopenharmony_ci ri, tei); 5208c2ecf20Sopenharmony_ci l2 = findtei(tm->mgr, tei); 5218c2ecf20Sopenharmony_ci if (l2) { /* same tei is in use */ 5228c2ecf20Sopenharmony_ci if (ri != l2->tm->ri) { /* and it wasn't our request */ 5238c2ecf20Sopenharmony_ci tm->tei_m.printdebug(fi, 5248c2ecf20Sopenharmony_ci "possible duplicate assignment tei %d", tei); 5258c2ecf20Sopenharmony_ci mISDN_FsmEvent(&l2->tm->tei_m, EV_VERIFY, NULL); 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci } 5288c2ecf20Sopenharmony_ci} 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_cistatic void 5318c2ecf20Sopenharmony_citei_id_denied(struct FsmInst *fi, int event, void *arg) 5328c2ecf20Sopenharmony_ci{ 5338c2ecf20Sopenharmony_ci struct teimgr *tm = fi->userdata; 5348c2ecf20Sopenharmony_ci u_char *dp = arg; 5358c2ecf20Sopenharmony_ci int ri, tei; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci ri = ((unsigned int) *dp++ << 8); 5388c2ecf20Sopenharmony_ci ri += *dp++; 5398c2ecf20Sopenharmony_ci dp++; 5408c2ecf20Sopenharmony_ci tei = *dp >> 1; 5418c2ecf20Sopenharmony_ci if (*debug & DEBUG_L2_TEI) 5428c2ecf20Sopenharmony_ci tm->tei_m.printdebug(fi, "identity denied ri %d tei %d", 5438c2ecf20Sopenharmony_ci ri, tei); 5448c2ecf20Sopenharmony_ci} 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_cistatic void 5478c2ecf20Sopenharmony_citei_id_chk_req(struct FsmInst *fi, int event, void *arg) 5488c2ecf20Sopenharmony_ci{ 5498c2ecf20Sopenharmony_ci struct teimgr *tm = fi->userdata; 5508c2ecf20Sopenharmony_ci u_char *dp = arg; 5518c2ecf20Sopenharmony_ci int tei; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci tei = *(dp + 3) >> 1; 5548c2ecf20Sopenharmony_ci if (*debug & DEBUG_L2_TEI) 5558c2ecf20Sopenharmony_ci tm->tei_m.printdebug(fi, "identity check req tei %d", tei); 5568c2ecf20Sopenharmony_ci if ((tm->l2->tei != GROUP_TEI) && ((tei == GROUP_TEI) || 5578c2ecf20Sopenharmony_ci (tei == tm->l2->tei))) { 5588c2ecf20Sopenharmony_ci mISDN_FsmDelTimer(&tm->timer, 4); 5598c2ecf20Sopenharmony_ci mISDN_FsmChangeState(&tm->tei_m, ST_TEI_NOP); 5608c2ecf20Sopenharmony_ci put_tei_msg(tm->mgr, ID_CHK_RES, random_ri(), tm->l2->tei); 5618c2ecf20Sopenharmony_ci } 5628c2ecf20Sopenharmony_ci} 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_cistatic void 5658c2ecf20Sopenharmony_citei_id_remove(struct FsmInst *fi, int event, void *arg) 5668c2ecf20Sopenharmony_ci{ 5678c2ecf20Sopenharmony_ci struct teimgr *tm = fi->userdata; 5688c2ecf20Sopenharmony_ci u_char *dp = arg; 5698c2ecf20Sopenharmony_ci int tei; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci tei = *(dp + 3) >> 1; 5728c2ecf20Sopenharmony_ci if (*debug & DEBUG_L2_TEI) 5738c2ecf20Sopenharmony_ci tm->tei_m.printdebug(fi, "identity remove tei %d", tei); 5748c2ecf20Sopenharmony_ci if ((tm->l2->tei != GROUP_TEI) && 5758c2ecf20Sopenharmony_ci ((tei == GROUP_TEI) || (tei == tm->l2->tei))) { 5768c2ecf20Sopenharmony_ci mISDN_FsmDelTimer(&tm->timer, 5); 5778c2ecf20Sopenharmony_ci mISDN_FsmChangeState(&tm->tei_m, ST_TEI_NOP); 5788c2ecf20Sopenharmony_ci tei_l2(tm->l2, MDL_REMOVE_REQ, 0); 5798c2ecf20Sopenharmony_ci } 5808c2ecf20Sopenharmony_ci} 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_cistatic void 5838c2ecf20Sopenharmony_citei_id_verify(struct FsmInst *fi, int event, void *arg) 5848c2ecf20Sopenharmony_ci{ 5858c2ecf20Sopenharmony_ci struct teimgr *tm = fi->userdata; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci if (*debug & DEBUG_L2_TEI) 5888c2ecf20Sopenharmony_ci tm->tei_m.printdebug(fi, "id verify request for tei %d", 5898c2ecf20Sopenharmony_ci tm->l2->tei); 5908c2ecf20Sopenharmony_ci put_tei_msg(tm->mgr, ID_VERIFY, 0, tm->l2->tei); 5918c2ecf20Sopenharmony_ci mISDN_FsmChangeState(&tm->tei_m, ST_TEI_IDVERIFY); 5928c2ecf20Sopenharmony_ci mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 2); 5938c2ecf20Sopenharmony_ci tm->nval = 2; 5948c2ecf20Sopenharmony_ci} 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_cistatic void 5978c2ecf20Sopenharmony_citei_id_req_tout(struct FsmInst *fi, int event, void *arg) 5988c2ecf20Sopenharmony_ci{ 5998c2ecf20Sopenharmony_ci struct teimgr *tm = fi->userdata; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci if (--tm->nval) { 6028c2ecf20Sopenharmony_ci tm->ri = random_ri(); 6038c2ecf20Sopenharmony_ci if (*debug & DEBUG_L2_TEI) 6048c2ecf20Sopenharmony_ci tm->tei_m.printdebug(fi, "assign req(%d) ri %d", 6058c2ecf20Sopenharmony_ci 4 - tm->nval, tm->ri); 6068c2ecf20Sopenharmony_ci put_tei_msg(tm->mgr, ID_REQUEST, tm->ri, GROUP_TEI); 6078c2ecf20Sopenharmony_ci mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 3); 6088c2ecf20Sopenharmony_ci } else { 6098c2ecf20Sopenharmony_ci tm->tei_m.printdebug(fi, "assign req failed"); 6108c2ecf20Sopenharmony_ci tei_l2(tm->l2, MDL_ERROR_RSP, 0); 6118c2ecf20Sopenharmony_ci mISDN_FsmChangeState(fi, ST_TEI_NOP); 6128c2ecf20Sopenharmony_ci } 6138c2ecf20Sopenharmony_ci} 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_cistatic void 6168c2ecf20Sopenharmony_citei_id_ver_tout(struct FsmInst *fi, int event, void *arg) 6178c2ecf20Sopenharmony_ci{ 6188c2ecf20Sopenharmony_ci struct teimgr *tm = fi->userdata; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci if (--tm->nval) { 6218c2ecf20Sopenharmony_ci if (*debug & DEBUG_L2_TEI) 6228c2ecf20Sopenharmony_ci tm->tei_m.printdebug(fi, 6238c2ecf20Sopenharmony_ci "id verify req(%d) for tei %d", 6248c2ecf20Sopenharmony_ci 3 - tm->nval, tm->l2->tei); 6258c2ecf20Sopenharmony_ci put_tei_msg(tm->mgr, ID_VERIFY, 0, tm->l2->tei); 6268c2ecf20Sopenharmony_ci mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 4); 6278c2ecf20Sopenharmony_ci } else { 6288c2ecf20Sopenharmony_ci tm->tei_m.printdebug(fi, "verify req for tei %d failed", 6298c2ecf20Sopenharmony_ci tm->l2->tei); 6308c2ecf20Sopenharmony_ci tei_l2(tm->l2, MDL_REMOVE_REQ, 0); 6318c2ecf20Sopenharmony_ci mISDN_FsmChangeState(fi, ST_TEI_NOP); 6328c2ecf20Sopenharmony_ci } 6338c2ecf20Sopenharmony_ci} 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_cistatic struct FsmNode TeiFnListUser[] = 6368c2ecf20Sopenharmony_ci{ 6378c2ecf20Sopenharmony_ci {ST_TEI_NOP, EV_IDREQ, tei_id_request}, 6388c2ecf20Sopenharmony_ci {ST_TEI_NOP, EV_ASSIGN, tei_id_test_dup}, 6398c2ecf20Sopenharmony_ci {ST_TEI_NOP, EV_VERIFY, tei_id_verify}, 6408c2ecf20Sopenharmony_ci {ST_TEI_NOP, EV_REMOVE, tei_id_remove}, 6418c2ecf20Sopenharmony_ci {ST_TEI_NOP, EV_CHKREQ, tei_id_chk_req}, 6428c2ecf20Sopenharmony_ci {ST_TEI_IDREQ, EV_TIMER, tei_id_req_tout}, 6438c2ecf20Sopenharmony_ci {ST_TEI_IDREQ, EV_ASSIGN, tei_id_assign}, 6448c2ecf20Sopenharmony_ci {ST_TEI_IDREQ, EV_DENIED, tei_id_denied}, 6458c2ecf20Sopenharmony_ci {ST_TEI_IDVERIFY, EV_TIMER, tei_id_ver_tout}, 6468c2ecf20Sopenharmony_ci {ST_TEI_IDVERIFY, EV_REMOVE, tei_id_remove}, 6478c2ecf20Sopenharmony_ci {ST_TEI_IDVERIFY, EV_CHKREQ, tei_id_chk_req}, 6488c2ecf20Sopenharmony_ci}; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_cistatic void 6518c2ecf20Sopenharmony_citei_l2remove(struct layer2 *l2) 6528c2ecf20Sopenharmony_ci{ 6538c2ecf20Sopenharmony_ci put_tei_msg(l2->tm->mgr, ID_REMOVE, 0, l2->tei); 6548c2ecf20Sopenharmony_ci tei_l2(l2, MDL_REMOVE_REQ, 0); 6558c2ecf20Sopenharmony_ci list_del(&l2->ch.list); 6568c2ecf20Sopenharmony_ci l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); 6578c2ecf20Sopenharmony_ci} 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_cistatic void 6608c2ecf20Sopenharmony_citei_assign_req(struct FsmInst *fi, int event, void *arg) 6618c2ecf20Sopenharmony_ci{ 6628c2ecf20Sopenharmony_ci struct teimgr *tm = fi->userdata; 6638c2ecf20Sopenharmony_ci u_char *dp = arg; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci if (tm->l2->tei == GROUP_TEI) { 6668c2ecf20Sopenharmony_ci tm->tei_m.printdebug(&tm->tei_m, 6678c2ecf20Sopenharmony_ci "net tei assign request without tei"); 6688c2ecf20Sopenharmony_ci return; 6698c2ecf20Sopenharmony_ci } 6708c2ecf20Sopenharmony_ci tm->ri = ((unsigned int) *dp++ << 8); 6718c2ecf20Sopenharmony_ci tm->ri += *dp++; 6728c2ecf20Sopenharmony_ci if (*debug & DEBUG_L2_TEI) 6738c2ecf20Sopenharmony_ci tm->tei_m.printdebug(&tm->tei_m, 6748c2ecf20Sopenharmony_ci "net assign request ri %d teim %d", tm->ri, *dp); 6758c2ecf20Sopenharmony_ci put_tei_msg(tm->mgr, ID_ASSIGNED, tm->ri, tm->l2->tei); 6768c2ecf20Sopenharmony_ci mISDN_FsmChangeState(fi, ST_TEI_NOP); 6778c2ecf20Sopenharmony_ci} 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_cistatic void 6808c2ecf20Sopenharmony_citei_id_chk_req_net(struct FsmInst *fi, int event, void *arg) 6818c2ecf20Sopenharmony_ci{ 6828c2ecf20Sopenharmony_ci struct teimgr *tm = fi->userdata; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci if (*debug & DEBUG_L2_TEI) 6858c2ecf20Sopenharmony_ci tm->tei_m.printdebug(fi, "id check request for tei %d", 6868c2ecf20Sopenharmony_ci tm->l2->tei); 6878c2ecf20Sopenharmony_ci tm->rcnt = 0; 6888c2ecf20Sopenharmony_ci put_tei_msg(tm->mgr, ID_CHK_REQ, 0, tm->l2->tei); 6898c2ecf20Sopenharmony_ci mISDN_FsmChangeState(&tm->tei_m, ST_TEI_IDVERIFY); 6908c2ecf20Sopenharmony_ci mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 2); 6918c2ecf20Sopenharmony_ci tm->nval = 2; 6928c2ecf20Sopenharmony_ci} 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_cistatic void 6958c2ecf20Sopenharmony_citei_id_chk_resp(struct FsmInst *fi, int event, void *arg) 6968c2ecf20Sopenharmony_ci{ 6978c2ecf20Sopenharmony_ci struct teimgr *tm = fi->userdata; 6988c2ecf20Sopenharmony_ci u_char *dp = arg; 6998c2ecf20Sopenharmony_ci int tei; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci tei = dp[3] >> 1; 7028c2ecf20Sopenharmony_ci if (*debug & DEBUG_L2_TEI) 7038c2ecf20Sopenharmony_ci tm->tei_m.printdebug(fi, "identity check resp tei %d", tei); 7048c2ecf20Sopenharmony_ci if (tei == tm->l2->tei) 7058c2ecf20Sopenharmony_ci tm->rcnt++; 7068c2ecf20Sopenharmony_ci} 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_cistatic void 7098c2ecf20Sopenharmony_citei_id_verify_net(struct FsmInst *fi, int event, void *arg) 7108c2ecf20Sopenharmony_ci{ 7118c2ecf20Sopenharmony_ci struct teimgr *tm = fi->userdata; 7128c2ecf20Sopenharmony_ci u_char *dp = arg; 7138c2ecf20Sopenharmony_ci int tei; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci tei = dp[3] >> 1; 7168c2ecf20Sopenharmony_ci if (*debug & DEBUG_L2_TEI) 7178c2ecf20Sopenharmony_ci tm->tei_m.printdebug(fi, "identity verify req tei %d/%d", 7188c2ecf20Sopenharmony_ci tei, tm->l2->tei); 7198c2ecf20Sopenharmony_ci if (tei == tm->l2->tei) 7208c2ecf20Sopenharmony_ci tei_id_chk_req_net(fi, event, arg); 7218c2ecf20Sopenharmony_ci} 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_cistatic void 7248c2ecf20Sopenharmony_citei_id_ver_tout_net(struct FsmInst *fi, int event, void *arg) 7258c2ecf20Sopenharmony_ci{ 7268c2ecf20Sopenharmony_ci struct teimgr *tm = fi->userdata; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci if (tm->rcnt == 1) { 7298c2ecf20Sopenharmony_ci if (*debug & DEBUG_L2_TEI) 7308c2ecf20Sopenharmony_ci tm->tei_m.printdebug(fi, 7318c2ecf20Sopenharmony_ci "check req for tei %d successful\n", tm->l2->tei); 7328c2ecf20Sopenharmony_ci mISDN_FsmChangeState(fi, ST_TEI_NOP); 7338c2ecf20Sopenharmony_ci } else if (tm->rcnt > 1) { 7348c2ecf20Sopenharmony_ci /* duplicate assignment; remove */ 7358c2ecf20Sopenharmony_ci tei_l2remove(tm->l2); 7368c2ecf20Sopenharmony_ci } else if (--tm->nval) { 7378c2ecf20Sopenharmony_ci if (*debug & DEBUG_L2_TEI) 7388c2ecf20Sopenharmony_ci tm->tei_m.printdebug(fi, 7398c2ecf20Sopenharmony_ci "id check req(%d) for tei %d", 7408c2ecf20Sopenharmony_ci 3 - tm->nval, tm->l2->tei); 7418c2ecf20Sopenharmony_ci put_tei_msg(tm->mgr, ID_CHK_REQ, 0, tm->l2->tei); 7428c2ecf20Sopenharmony_ci mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 4); 7438c2ecf20Sopenharmony_ci } else { 7448c2ecf20Sopenharmony_ci tm->tei_m.printdebug(fi, "check req for tei %d failed", 7458c2ecf20Sopenharmony_ci tm->l2->tei); 7468c2ecf20Sopenharmony_ci mISDN_FsmChangeState(fi, ST_TEI_NOP); 7478c2ecf20Sopenharmony_ci tei_l2remove(tm->l2); 7488c2ecf20Sopenharmony_ci } 7498c2ecf20Sopenharmony_ci} 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_cistatic struct FsmNode TeiFnListNet[] = 7528c2ecf20Sopenharmony_ci{ 7538c2ecf20Sopenharmony_ci {ST_TEI_NOP, EV_ASSIGN_REQ, tei_assign_req}, 7548c2ecf20Sopenharmony_ci {ST_TEI_NOP, EV_VERIFY, tei_id_verify_net}, 7558c2ecf20Sopenharmony_ci {ST_TEI_NOP, EV_CHKREQ, tei_id_chk_req_net}, 7568c2ecf20Sopenharmony_ci {ST_TEI_IDVERIFY, EV_TIMER, tei_id_ver_tout_net}, 7578c2ecf20Sopenharmony_ci {ST_TEI_IDVERIFY, EV_CHKRESP, tei_id_chk_resp}, 7588c2ecf20Sopenharmony_ci}; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_cistatic void 7618c2ecf20Sopenharmony_citei_ph_data_ind(struct teimgr *tm, u_int mt, u_char *dp, int len) 7628c2ecf20Sopenharmony_ci{ 7638c2ecf20Sopenharmony_ci if (test_bit(FLG_FIXED_TEI, &tm->l2->flag)) 7648c2ecf20Sopenharmony_ci return; 7658c2ecf20Sopenharmony_ci if (*debug & DEBUG_L2_TEI) 7668c2ecf20Sopenharmony_ci tm->tei_m.printdebug(&tm->tei_m, "tei handler mt %x", mt); 7678c2ecf20Sopenharmony_ci if (mt == ID_ASSIGNED) 7688c2ecf20Sopenharmony_ci mISDN_FsmEvent(&tm->tei_m, EV_ASSIGN, dp); 7698c2ecf20Sopenharmony_ci else if (mt == ID_DENIED) 7708c2ecf20Sopenharmony_ci mISDN_FsmEvent(&tm->tei_m, EV_DENIED, dp); 7718c2ecf20Sopenharmony_ci else if (mt == ID_CHK_REQ) 7728c2ecf20Sopenharmony_ci mISDN_FsmEvent(&tm->tei_m, EV_CHKREQ, dp); 7738c2ecf20Sopenharmony_ci else if (mt == ID_REMOVE) 7748c2ecf20Sopenharmony_ci mISDN_FsmEvent(&tm->tei_m, EV_REMOVE, dp); 7758c2ecf20Sopenharmony_ci else if (mt == ID_VERIFY) 7768c2ecf20Sopenharmony_ci mISDN_FsmEvent(&tm->tei_m, EV_VERIFY, dp); 7778c2ecf20Sopenharmony_ci else if (mt == ID_CHK_RES) 7788c2ecf20Sopenharmony_ci mISDN_FsmEvent(&tm->tei_m, EV_CHKRESP, dp); 7798c2ecf20Sopenharmony_ci} 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_cistatic struct layer2 * 7828c2ecf20Sopenharmony_cicreate_new_tei(struct manager *mgr, int tei, int sapi) 7838c2ecf20Sopenharmony_ci{ 7848c2ecf20Sopenharmony_ci unsigned long opt = 0; 7858c2ecf20Sopenharmony_ci unsigned long flags; 7868c2ecf20Sopenharmony_ci int id; 7878c2ecf20Sopenharmony_ci struct layer2 *l2; 7888c2ecf20Sopenharmony_ci struct channel_req rq; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci if (!mgr->up) 7918c2ecf20Sopenharmony_ci return NULL; 7928c2ecf20Sopenharmony_ci if ((tei >= 0) && (tei < 64)) 7938c2ecf20Sopenharmony_ci test_and_set_bit(OPTION_L2_FIXEDTEI, &opt); 7948c2ecf20Sopenharmony_ci if (mgr->ch.st->dev->Dprotocols & ((1 << ISDN_P_TE_E1) | 7958c2ecf20Sopenharmony_ci (1 << ISDN_P_NT_E1))) { 7968c2ecf20Sopenharmony_ci test_and_set_bit(OPTION_L2_PMX, &opt); 7978c2ecf20Sopenharmony_ci rq.protocol = ISDN_P_NT_E1; 7988c2ecf20Sopenharmony_ci } else { 7998c2ecf20Sopenharmony_ci rq.protocol = ISDN_P_NT_S0; 8008c2ecf20Sopenharmony_ci } 8018c2ecf20Sopenharmony_ci l2 = create_l2(mgr->up, ISDN_P_LAPD_NT, opt, tei, sapi); 8028c2ecf20Sopenharmony_ci if (!l2) { 8038c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s:no memory for layer2\n", __func__); 8048c2ecf20Sopenharmony_ci return NULL; 8058c2ecf20Sopenharmony_ci } 8068c2ecf20Sopenharmony_ci l2->tm = kzalloc(sizeof(struct teimgr), GFP_KERNEL); 8078c2ecf20Sopenharmony_ci if (!l2->tm) { 8088c2ecf20Sopenharmony_ci kfree(l2); 8098c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s:no memory for teimgr\n", __func__); 8108c2ecf20Sopenharmony_ci return NULL; 8118c2ecf20Sopenharmony_ci } 8128c2ecf20Sopenharmony_ci l2->tm->mgr = mgr; 8138c2ecf20Sopenharmony_ci l2->tm->l2 = l2; 8148c2ecf20Sopenharmony_ci l2->tm->tei_m.debug = *debug & DEBUG_L2_TEIFSM; 8158c2ecf20Sopenharmony_ci l2->tm->tei_m.userdata = l2->tm; 8168c2ecf20Sopenharmony_ci l2->tm->tei_m.printdebug = tei_debug; 8178c2ecf20Sopenharmony_ci l2->tm->tei_m.fsm = &teifsmn; 8188c2ecf20Sopenharmony_ci l2->tm->tei_m.state = ST_TEI_NOP; 8198c2ecf20Sopenharmony_ci l2->tm->tval = 2000; /* T202 2 sec */ 8208c2ecf20Sopenharmony_ci mISDN_FsmInitTimer(&l2->tm->tei_m, &l2->tm->timer); 8218c2ecf20Sopenharmony_ci write_lock_irqsave(&mgr->lock, flags); 8228c2ecf20Sopenharmony_ci id = get_free_id(mgr); 8238c2ecf20Sopenharmony_ci list_add_tail(&l2->list, &mgr->layer2); 8248c2ecf20Sopenharmony_ci write_unlock_irqrestore(&mgr->lock, flags); 8258c2ecf20Sopenharmony_ci if (id < 0) { 8268c2ecf20Sopenharmony_ci l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); 8278c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s:no free id\n", __func__); 8288c2ecf20Sopenharmony_ci return NULL; 8298c2ecf20Sopenharmony_ci } else { 8308c2ecf20Sopenharmony_ci l2->ch.nr = id; 8318c2ecf20Sopenharmony_ci __add_layer2(&l2->ch, mgr->ch.st); 8328c2ecf20Sopenharmony_ci l2->ch.recv = mgr->ch.recv; 8338c2ecf20Sopenharmony_ci l2->ch.peer = mgr->ch.peer; 8348c2ecf20Sopenharmony_ci l2->ch.ctrl(&l2->ch, OPEN_CHANNEL, NULL); 8358c2ecf20Sopenharmony_ci /* We need open here L1 for the manager as well (refcounting) */ 8368c2ecf20Sopenharmony_ci rq.adr.dev = mgr->ch.st->dev->id; 8378c2ecf20Sopenharmony_ci id = mgr->ch.st->own.ctrl(&mgr->ch.st->own, OPEN_CHANNEL, &rq); 8388c2ecf20Sopenharmony_ci if (id < 0) { 8398c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: cannot open L1\n", __func__); 8408c2ecf20Sopenharmony_ci l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); 8418c2ecf20Sopenharmony_ci l2 = NULL; 8428c2ecf20Sopenharmony_ci } 8438c2ecf20Sopenharmony_ci } 8448c2ecf20Sopenharmony_ci return l2; 8458c2ecf20Sopenharmony_ci} 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_cistatic void 8488c2ecf20Sopenharmony_cinew_tei_req(struct manager *mgr, u_char *dp) 8498c2ecf20Sopenharmony_ci{ 8508c2ecf20Sopenharmony_ci int tei, ri; 8518c2ecf20Sopenharmony_ci struct layer2 *l2; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci ri = dp[0] << 8; 8548c2ecf20Sopenharmony_ci ri += dp[1]; 8558c2ecf20Sopenharmony_ci if (!mgr->up) 8568c2ecf20Sopenharmony_ci goto denied; 8578c2ecf20Sopenharmony_ci if (!(dp[3] & 1)) /* Extension bit != 1 */ 8588c2ecf20Sopenharmony_ci goto denied; 8598c2ecf20Sopenharmony_ci if (dp[3] != 0xff) 8608c2ecf20Sopenharmony_ci tei = dp[3] >> 1; /* 3GPP TS 08.56 6.1.11.2 */ 8618c2ecf20Sopenharmony_ci else 8628c2ecf20Sopenharmony_ci tei = get_free_tei(mgr); 8638c2ecf20Sopenharmony_ci if (tei < 0) { 8648c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s:No free tei\n", __func__); 8658c2ecf20Sopenharmony_ci goto denied; 8668c2ecf20Sopenharmony_ci } 8678c2ecf20Sopenharmony_ci l2 = create_new_tei(mgr, tei, CTRL_SAPI); 8688c2ecf20Sopenharmony_ci if (!l2) 8698c2ecf20Sopenharmony_ci goto denied; 8708c2ecf20Sopenharmony_ci else 8718c2ecf20Sopenharmony_ci mISDN_FsmEvent(&l2->tm->tei_m, EV_ASSIGN_REQ, dp); 8728c2ecf20Sopenharmony_ci return; 8738c2ecf20Sopenharmony_cidenied: 8748c2ecf20Sopenharmony_ci put_tei_msg(mgr, ID_DENIED, ri, GROUP_TEI); 8758c2ecf20Sopenharmony_ci} 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_cistatic int 8788c2ecf20Sopenharmony_ciph_data_ind(struct manager *mgr, struct sk_buff *skb) 8798c2ecf20Sopenharmony_ci{ 8808c2ecf20Sopenharmony_ci int ret = -EINVAL; 8818c2ecf20Sopenharmony_ci struct layer2 *l2, *nl2; 8828c2ecf20Sopenharmony_ci u_char mt; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci if (skb->len < 8) { 8858c2ecf20Sopenharmony_ci if (*debug & DEBUG_L2_TEI) 8868c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: short mgr frame %d/8\n", 8878c2ecf20Sopenharmony_ci __func__, skb->len); 8888c2ecf20Sopenharmony_ci goto done; 8898c2ecf20Sopenharmony_ci } 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci if ((skb->data[0] >> 2) != TEI_SAPI) /* not for us */ 8928c2ecf20Sopenharmony_ci goto done; 8938c2ecf20Sopenharmony_ci if (skb->data[0] & 1) /* EA0 formal error */ 8948c2ecf20Sopenharmony_ci goto done; 8958c2ecf20Sopenharmony_ci if (!(skb->data[1] & 1)) /* EA1 formal error */ 8968c2ecf20Sopenharmony_ci goto done; 8978c2ecf20Sopenharmony_ci if ((skb->data[1] >> 1) != GROUP_TEI) /* not for us */ 8988c2ecf20Sopenharmony_ci goto done; 8998c2ecf20Sopenharmony_ci if ((skb->data[2] & 0xef) != UI) /* not UI */ 9008c2ecf20Sopenharmony_ci goto done; 9018c2ecf20Sopenharmony_ci if (skb->data[3] != TEI_ENTITY_ID) /* not tei entity */ 9028c2ecf20Sopenharmony_ci goto done; 9038c2ecf20Sopenharmony_ci mt = skb->data[6]; 9048c2ecf20Sopenharmony_ci switch (mt) { 9058c2ecf20Sopenharmony_ci case ID_REQUEST: 9068c2ecf20Sopenharmony_ci case ID_CHK_RES: 9078c2ecf20Sopenharmony_ci case ID_VERIFY: 9088c2ecf20Sopenharmony_ci if (!test_bit(MGR_OPT_NETWORK, &mgr->options)) 9098c2ecf20Sopenharmony_ci goto done; 9108c2ecf20Sopenharmony_ci break; 9118c2ecf20Sopenharmony_ci case ID_ASSIGNED: 9128c2ecf20Sopenharmony_ci case ID_DENIED: 9138c2ecf20Sopenharmony_ci case ID_CHK_REQ: 9148c2ecf20Sopenharmony_ci case ID_REMOVE: 9158c2ecf20Sopenharmony_ci if (test_bit(MGR_OPT_NETWORK, &mgr->options)) 9168c2ecf20Sopenharmony_ci goto done; 9178c2ecf20Sopenharmony_ci break; 9188c2ecf20Sopenharmony_ci default: 9198c2ecf20Sopenharmony_ci goto done; 9208c2ecf20Sopenharmony_ci } 9218c2ecf20Sopenharmony_ci ret = 0; 9228c2ecf20Sopenharmony_ci if (mt == ID_REQUEST) { 9238c2ecf20Sopenharmony_ci new_tei_req(mgr, &skb->data[4]); 9248c2ecf20Sopenharmony_ci goto done; 9258c2ecf20Sopenharmony_ci } 9268c2ecf20Sopenharmony_ci list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) { 9278c2ecf20Sopenharmony_ci tei_ph_data_ind(l2->tm, mt, &skb->data[4], skb->len - 4); 9288c2ecf20Sopenharmony_ci } 9298c2ecf20Sopenharmony_cidone: 9308c2ecf20Sopenharmony_ci return ret; 9318c2ecf20Sopenharmony_ci} 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ciint 9348c2ecf20Sopenharmony_cil2_tei(struct layer2 *l2, u_int cmd, u_long arg) 9358c2ecf20Sopenharmony_ci{ 9368c2ecf20Sopenharmony_ci struct teimgr *tm = l2->tm; 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci if (test_bit(FLG_FIXED_TEI, &l2->flag)) 9398c2ecf20Sopenharmony_ci return 0; 9408c2ecf20Sopenharmony_ci if (*debug & DEBUG_L2_TEI) 9418c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: cmd(%x)\n", __func__, cmd); 9428c2ecf20Sopenharmony_ci switch (cmd) { 9438c2ecf20Sopenharmony_ci case MDL_ASSIGN_IND: 9448c2ecf20Sopenharmony_ci mISDN_FsmEvent(&tm->tei_m, EV_IDREQ, NULL); 9458c2ecf20Sopenharmony_ci break; 9468c2ecf20Sopenharmony_ci case MDL_ERROR_IND: 9478c2ecf20Sopenharmony_ci if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options)) 9488c2ecf20Sopenharmony_ci mISDN_FsmEvent(&tm->tei_m, EV_CHKREQ, &l2->tei); 9498c2ecf20Sopenharmony_ci if (test_bit(MGR_OPT_USER, &tm->mgr->options)) 9508c2ecf20Sopenharmony_ci mISDN_FsmEvent(&tm->tei_m, EV_VERIFY, NULL); 9518c2ecf20Sopenharmony_ci break; 9528c2ecf20Sopenharmony_ci case MDL_STATUS_UP_IND: 9538c2ecf20Sopenharmony_ci if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options)) 9548c2ecf20Sopenharmony_ci mISDN_FsmEvent(&tm->mgr->deact, EV_ACTIVATE, NULL); 9558c2ecf20Sopenharmony_ci break; 9568c2ecf20Sopenharmony_ci case MDL_STATUS_DOWN_IND: 9578c2ecf20Sopenharmony_ci if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options)) 9588c2ecf20Sopenharmony_ci mISDN_FsmEvent(&tm->mgr->deact, EV_DEACTIVATE, NULL); 9598c2ecf20Sopenharmony_ci break; 9608c2ecf20Sopenharmony_ci case MDL_STATUS_UI_IND: 9618c2ecf20Sopenharmony_ci if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options)) 9628c2ecf20Sopenharmony_ci mISDN_FsmEvent(&tm->mgr->deact, EV_UI, NULL); 9638c2ecf20Sopenharmony_ci break; 9648c2ecf20Sopenharmony_ci } 9658c2ecf20Sopenharmony_ci return 0; 9668c2ecf20Sopenharmony_ci} 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_civoid 9698c2ecf20Sopenharmony_ciTEIrelease(struct layer2 *l2) 9708c2ecf20Sopenharmony_ci{ 9718c2ecf20Sopenharmony_ci struct teimgr *tm = l2->tm; 9728c2ecf20Sopenharmony_ci u_long flags; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci mISDN_FsmDelTimer(&tm->timer, 1); 9758c2ecf20Sopenharmony_ci write_lock_irqsave(&tm->mgr->lock, flags); 9768c2ecf20Sopenharmony_ci list_del(&l2->list); 9778c2ecf20Sopenharmony_ci write_unlock_irqrestore(&tm->mgr->lock, flags); 9788c2ecf20Sopenharmony_ci l2->tm = NULL; 9798c2ecf20Sopenharmony_ci kfree(tm); 9808c2ecf20Sopenharmony_ci} 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_cistatic int 9838c2ecf20Sopenharmony_cicreate_teimgr(struct manager *mgr, struct channel_req *crq) 9848c2ecf20Sopenharmony_ci{ 9858c2ecf20Sopenharmony_ci struct layer2 *l2; 9868c2ecf20Sopenharmony_ci unsigned long opt = 0; 9878c2ecf20Sopenharmony_ci unsigned long flags; 9888c2ecf20Sopenharmony_ci int id; 9898c2ecf20Sopenharmony_ci struct channel_req l1rq; 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci if (*debug & DEBUG_L2_TEI) 9928c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n", 9938c2ecf20Sopenharmony_ci __func__, dev_name(&mgr->ch.st->dev->dev), 9948c2ecf20Sopenharmony_ci crq->protocol, crq->adr.dev, crq->adr.channel, 9958c2ecf20Sopenharmony_ci crq->adr.sapi, crq->adr.tei); 9968c2ecf20Sopenharmony_ci if (crq->adr.tei > GROUP_TEI) 9978c2ecf20Sopenharmony_ci return -EINVAL; 9988c2ecf20Sopenharmony_ci if (crq->adr.tei < 64) 9998c2ecf20Sopenharmony_ci test_and_set_bit(OPTION_L2_FIXEDTEI, &opt); 10008c2ecf20Sopenharmony_ci if (crq->adr.tei == 0) 10018c2ecf20Sopenharmony_ci test_and_set_bit(OPTION_L2_PTP, &opt); 10028c2ecf20Sopenharmony_ci if (test_bit(MGR_OPT_NETWORK, &mgr->options)) { 10038c2ecf20Sopenharmony_ci if (crq->protocol == ISDN_P_LAPD_TE) 10048c2ecf20Sopenharmony_ci return -EPROTONOSUPPORT; 10058c2ecf20Sopenharmony_ci if ((crq->adr.tei != 0) && (crq->adr.tei != 127)) 10068c2ecf20Sopenharmony_ci return -EINVAL; 10078c2ecf20Sopenharmony_ci if (mgr->up) { 10088c2ecf20Sopenharmony_ci printk(KERN_WARNING 10098c2ecf20Sopenharmony_ci "%s: only one network manager is allowed\n", 10108c2ecf20Sopenharmony_ci __func__); 10118c2ecf20Sopenharmony_ci return -EBUSY; 10128c2ecf20Sopenharmony_ci } 10138c2ecf20Sopenharmony_ci } else if (test_bit(MGR_OPT_USER, &mgr->options)) { 10148c2ecf20Sopenharmony_ci if (crq->protocol == ISDN_P_LAPD_NT) 10158c2ecf20Sopenharmony_ci return -EPROTONOSUPPORT; 10168c2ecf20Sopenharmony_ci if ((crq->adr.tei >= 64) && (crq->adr.tei < GROUP_TEI)) 10178c2ecf20Sopenharmony_ci return -EINVAL; /* dyn tei */ 10188c2ecf20Sopenharmony_ci } else { 10198c2ecf20Sopenharmony_ci if (crq->protocol == ISDN_P_LAPD_NT) 10208c2ecf20Sopenharmony_ci test_and_set_bit(MGR_OPT_NETWORK, &mgr->options); 10218c2ecf20Sopenharmony_ci if (crq->protocol == ISDN_P_LAPD_TE) 10228c2ecf20Sopenharmony_ci test_and_set_bit(MGR_OPT_USER, &mgr->options); 10238c2ecf20Sopenharmony_ci } 10248c2ecf20Sopenharmony_ci l1rq.adr = crq->adr; 10258c2ecf20Sopenharmony_ci if (mgr->ch.st->dev->Dprotocols 10268c2ecf20Sopenharmony_ci & ((1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1))) 10278c2ecf20Sopenharmony_ci test_and_set_bit(OPTION_L2_PMX, &opt); 10288c2ecf20Sopenharmony_ci if ((crq->protocol == ISDN_P_LAPD_NT) && (crq->adr.tei == 127)) { 10298c2ecf20Sopenharmony_ci mgr->up = crq->ch; 10308c2ecf20Sopenharmony_ci id = DL_INFO_L2_CONNECT; 10318c2ecf20Sopenharmony_ci teiup_create(mgr, DL_INFORMATION_IND, sizeof(id), &id); 10328c2ecf20Sopenharmony_ci if (test_bit(MGR_PH_ACTIVE, &mgr->options)) 10338c2ecf20Sopenharmony_ci teiup_create(mgr, PH_ACTIVATE_IND, 0, NULL); 10348c2ecf20Sopenharmony_ci crq->ch = NULL; 10358c2ecf20Sopenharmony_ci if (!list_empty(&mgr->layer2)) { 10368c2ecf20Sopenharmony_ci read_lock_irqsave(&mgr->lock, flags); 10378c2ecf20Sopenharmony_ci list_for_each_entry(l2, &mgr->layer2, list) { 10388c2ecf20Sopenharmony_ci l2->up = mgr->up; 10398c2ecf20Sopenharmony_ci l2->ch.ctrl(&l2->ch, OPEN_CHANNEL, NULL); 10408c2ecf20Sopenharmony_ci } 10418c2ecf20Sopenharmony_ci read_unlock_irqrestore(&mgr->lock, flags); 10428c2ecf20Sopenharmony_ci } 10438c2ecf20Sopenharmony_ci return 0; 10448c2ecf20Sopenharmony_ci } 10458c2ecf20Sopenharmony_ci l2 = create_l2(crq->ch, crq->protocol, opt, 10468c2ecf20Sopenharmony_ci crq->adr.tei, crq->adr.sapi); 10478c2ecf20Sopenharmony_ci if (!l2) 10488c2ecf20Sopenharmony_ci return -ENOMEM; 10498c2ecf20Sopenharmony_ci l2->tm = kzalloc(sizeof(struct teimgr), GFP_KERNEL); 10508c2ecf20Sopenharmony_ci if (!l2->tm) { 10518c2ecf20Sopenharmony_ci kfree(l2); 10528c2ecf20Sopenharmony_ci printk(KERN_ERR "kmalloc teimgr failed\n"); 10538c2ecf20Sopenharmony_ci return -ENOMEM; 10548c2ecf20Sopenharmony_ci } 10558c2ecf20Sopenharmony_ci l2->tm->mgr = mgr; 10568c2ecf20Sopenharmony_ci l2->tm->l2 = l2; 10578c2ecf20Sopenharmony_ci l2->tm->tei_m.debug = *debug & DEBUG_L2_TEIFSM; 10588c2ecf20Sopenharmony_ci l2->tm->tei_m.userdata = l2->tm; 10598c2ecf20Sopenharmony_ci l2->tm->tei_m.printdebug = tei_debug; 10608c2ecf20Sopenharmony_ci if (crq->protocol == ISDN_P_LAPD_TE) { 10618c2ecf20Sopenharmony_ci l2->tm->tei_m.fsm = &teifsmu; 10628c2ecf20Sopenharmony_ci l2->tm->tei_m.state = ST_TEI_NOP; 10638c2ecf20Sopenharmony_ci l2->tm->tval = 1000; /* T201 1 sec */ 10648c2ecf20Sopenharmony_ci if (test_bit(OPTION_L2_PMX, &opt)) 10658c2ecf20Sopenharmony_ci l1rq.protocol = ISDN_P_TE_E1; 10668c2ecf20Sopenharmony_ci else 10678c2ecf20Sopenharmony_ci l1rq.protocol = ISDN_P_TE_S0; 10688c2ecf20Sopenharmony_ci } else { 10698c2ecf20Sopenharmony_ci l2->tm->tei_m.fsm = &teifsmn; 10708c2ecf20Sopenharmony_ci l2->tm->tei_m.state = ST_TEI_NOP; 10718c2ecf20Sopenharmony_ci l2->tm->tval = 2000; /* T202 2 sec */ 10728c2ecf20Sopenharmony_ci if (test_bit(OPTION_L2_PMX, &opt)) 10738c2ecf20Sopenharmony_ci l1rq.protocol = ISDN_P_NT_E1; 10748c2ecf20Sopenharmony_ci else 10758c2ecf20Sopenharmony_ci l1rq.protocol = ISDN_P_NT_S0; 10768c2ecf20Sopenharmony_ci } 10778c2ecf20Sopenharmony_ci mISDN_FsmInitTimer(&l2->tm->tei_m, &l2->tm->timer); 10788c2ecf20Sopenharmony_ci write_lock_irqsave(&mgr->lock, flags); 10798c2ecf20Sopenharmony_ci id = get_free_id(mgr); 10808c2ecf20Sopenharmony_ci list_add_tail(&l2->list, &mgr->layer2); 10818c2ecf20Sopenharmony_ci write_unlock_irqrestore(&mgr->lock, flags); 10828c2ecf20Sopenharmony_ci if (id >= 0) { 10838c2ecf20Sopenharmony_ci l2->ch.nr = id; 10848c2ecf20Sopenharmony_ci l2->up->nr = id; 10858c2ecf20Sopenharmony_ci crq->ch = &l2->ch; 10868c2ecf20Sopenharmony_ci /* We need open here L1 for the manager as well (refcounting) */ 10878c2ecf20Sopenharmony_ci id = mgr->ch.st->own.ctrl(&mgr->ch.st->own, OPEN_CHANNEL, 10888c2ecf20Sopenharmony_ci &l1rq); 10898c2ecf20Sopenharmony_ci } 10908c2ecf20Sopenharmony_ci if (id < 0) 10918c2ecf20Sopenharmony_ci l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); 10928c2ecf20Sopenharmony_ci return id; 10938c2ecf20Sopenharmony_ci} 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_cistatic int 10968c2ecf20Sopenharmony_cimgr_send(struct mISDNchannel *ch, struct sk_buff *skb) 10978c2ecf20Sopenharmony_ci{ 10988c2ecf20Sopenharmony_ci struct manager *mgr; 10998c2ecf20Sopenharmony_ci struct mISDNhead *hh = mISDN_HEAD_P(skb); 11008c2ecf20Sopenharmony_ci int ret = -EINVAL; 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci mgr = container_of(ch, struct manager, ch); 11038c2ecf20Sopenharmony_ci if (*debug & DEBUG_L2_RECV) 11048c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: prim(%x) id(%x)\n", 11058c2ecf20Sopenharmony_ci __func__, hh->prim, hh->id); 11068c2ecf20Sopenharmony_ci switch (hh->prim) { 11078c2ecf20Sopenharmony_ci case PH_DATA_IND: 11088c2ecf20Sopenharmony_ci mISDN_FsmEvent(&mgr->deact, EV_UI, NULL); 11098c2ecf20Sopenharmony_ci ret = ph_data_ind(mgr, skb); 11108c2ecf20Sopenharmony_ci break; 11118c2ecf20Sopenharmony_ci case PH_DATA_CNF: 11128c2ecf20Sopenharmony_ci do_ack(mgr, hh->id); 11138c2ecf20Sopenharmony_ci ret = 0; 11148c2ecf20Sopenharmony_ci break; 11158c2ecf20Sopenharmony_ci case PH_ACTIVATE_IND: 11168c2ecf20Sopenharmony_ci test_and_set_bit(MGR_PH_ACTIVE, &mgr->options); 11178c2ecf20Sopenharmony_ci if (mgr->up) 11188c2ecf20Sopenharmony_ci teiup_create(mgr, PH_ACTIVATE_IND, 0, NULL); 11198c2ecf20Sopenharmony_ci mISDN_FsmEvent(&mgr->deact, EV_ACTIVATE_IND, NULL); 11208c2ecf20Sopenharmony_ci do_send(mgr); 11218c2ecf20Sopenharmony_ci ret = 0; 11228c2ecf20Sopenharmony_ci break; 11238c2ecf20Sopenharmony_ci case PH_DEACTIVATE_IND: 11248c2ecf20Sopenharmony_ci test_and_clear_bit(MGR_PH_ACTIVE, &mgr->options); 11258c2ecf20Sopenharmony_ci if (mgr->up) 11268c2ecf20Sopenharmony_ci teiup_create(mgr, PH_DEACTIVATE_IND, 0, NULL); 11278c2ecf20Sopenharmony_ci mISDN_FsmEvent(&mgr->deact, EV_DEACTIVATE_IND, NULL); 11288c2ecf20Sopenharmony_ci ret = 0; 11298c2ecf20Sopenharmony_ci break; 11308c2ecf20Sopenharmony_ci case DL_UNITDATA_REQ: 11318c2ecf20Sopenharmony_ci return dl_unit_data(mgr, skb); 11328c2ecf20Sopenharmony_ci } 11338c2ecf20Sopenharmony_ci if (!ret) 11348c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 11358c2ecf20Sopenharmony_ci return ret; 11368c2ecf20Sopenharmony_ci} 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_cistatic int 11398c2ecf20Sopenharmony_cifree_teimanager(struct manager *mgr) 11408c2ecf20Sopenharmony_ci{ 11418c2ecf20Sopenharmony_ci struct layer2 *l2, *nl2; 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci test_and_clear_bit(OPTION_L1_HOLD, &mgr->options); 11448c2ecf20Sopenharmony_ci if (test_bit(MGR_OPT_NETWORK, &mgr->options)) { 11458c2ecf20Sopenharmony_ci /* not locked lock is taken in release tei */ 11468c2ecf20Sopenharmony_ci mgr->up = NULL; 11478c2ecf20Sopenharmony_ci if (test_bit(OPTION_L2_CLEANUP, &mgr->options)) { 11488c2ecf20Sopenharmony_ci list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) { 11498c2ecf20Sopenharmony_ci put_tei_msg(mgr, ID_REMOVE, 0, l2->tei); 11508c2ecf20Sopenharmony_ci mutex_lock(&mgr->ch.st->lmutex); 11518c2ecf20Sopenharmony_ci list_del(&l2->ch.list); 11528c2ecf20Sopenharmony_ci mutex_unlock(&mgr->ch.st->lmutex); 11538c2ecf20Sopenharmony_ci l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); 11548c2ecf20Sopenharmony_ci } 11558c2ecf20Sopenharmony_ci test_and_clear_bit(MGR_OPT_NETWORK, &mgr->options); 11568c2ecf20Sopenharmony_ci } else { 11578c2ecf20Sopenharmony_ci list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) { 11588c2ecf20Sopenharmony_ci l2->up = NULL; 11598c2ecf20Sopenharmony_ci } 11608c2ecf20Sopenharmony_ci } 11618c2ecf20Sopenharmony_ci } 11628c2ecf20Sopenharmony_ci if (test_bit(MGR_OPT_USER, &mgr->options)) { 11638c2ecf20Sopenharmony_ci if (list_empty(&mgr->layer2)) 11648c2ecf20Sopenharmony_ci test_and_clear_bit(MGR_OPT_USER, &mgr->options); 11658c2ecf20Sopenharmony_ci } 11668c2ecf20Sopenharmony_ci mgr->ch.st->dev->D.ctrl(&mgr->ch.st->dev->D, CLOSE_CHANNEL, NULL); 11678c2ecf20Sopenharmony_ci return 0; 11688c2ecf20Sopenharmony_ci} 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_cistatic int 11718c2ecf20Sopenharmony_cictrl_teimanager(struct manager *mgr, void *arg) 11728c2ecf20Sopenharmony_ci{ 11738c2ecf20Sopenharmony_ci /* currently we only have one option */ 11748c2ecf20Sopenharmony_ci unsigned int *val = (unsigned int *)arg; 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci switch (val[0]) { 11778c2ecf20Sopenharmony_ci case IMCLEAR_L2: 11788c2ecf20Sopenharmony_ci if (val[1]) 11798c2ecf20Sopenharmony_ci test_and_set_bit(OPTION_L2_CLEANUP, &mgr->options); 11808c2ecf20Sopenharmony_ci else 11818c2ecf20Sopenharmony_ci test_and_clear_bit(OPTION_L2_CLEANUP, &mgr->options); 11828c2ecf20Sopenharmony_ci break; 11838c2ecf20Sopenharmony_ci case IMHOLD_L1: 11848c2ecf20Sopenharmony_ci if (val[1]) 11858c2ecf20Sopenharmony_ci test_and_set_bit(OPTION_L1_HOLD, &mgr->options); 11868c2ecf20Sopenharmony_ci else 11878c2ecf20Sopenharmony_ci test_and_clear_bit(OPTION_L1_HOLD, &mgr->options); 11888c2ecf20Sopenharmony_ci break; 11898c2ecf20Sopenharmony_ci default: 11908c2ecf20Sopenharmony_ci return -EINVAL; 11918c2ecf20Sopenharmony_ci } 11928c2ecf20Sopenharmony_ci return 0; 11938c2ecf20Sopenharmony_ci} 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci/* This function does create a L2 for fixed TEI in NT Mode */ 11968c2ecf20Sopenharmony_cistatic int 11978c2ecf20Sopenharmony_cicheck_data(struct manager *mgr, struct sk_buff *skb) 11988c2ecf20Sopenharmony_ci{ 11998c2ecf20Sopenharmony_ci struct mISDNhead *hh = mISDN_HEAD_P(skb); 12008c2ecf20Sopenharmony_ci int ret, tei, sapi; 12018c2ecf20Sopenharmony_ci struct layer2 *l2; 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci if (*debug & DEBUG_L2_CTRL) 12048c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: prim(%x) id(%x)\n", 12058c2ecf20Sopenharmony_ci __func__, hh->prim, hh->id); 12068c2ecf20Sopenharmony_ci if (test_bit(MGR_OPT_USER, &mgr->options)) 12078c2ecf20Sopenharmony_ci return -ENOTCONN; 12088c2ecf20Sopenharmony_ci if (hh->prim != PH_DATA_IND) 12098c2ecf20Sopenharmony_ci return -ENOTCONN; 12108c2ecf20Sopenharmony_ci if (skb->len != 3) 12118c2ecf20Sopenharmony_ci return -ENOTCONN; 12128c2ecf20Sopenharmony_ci if (skb->data[0] & 3) /* EA0 and CR must be 0 */ 12138c2ecf20Sopenharmony_ci return -EINVAL; 12148c2ecf20Sopenharmony_ci sapi = skb->data[0] >> 2; 12158c2ecf20Sopenharmony_ci if (!(skb->data[1] & 1)) /* invalid EA1 */ 12168c2ecf20Sopenharmony_ci return -EINVAL; 12178c2ecf20Sopenharmony_ci tei = skb->data[1] >> 1; 12188c2ecf20Sopenharmony_ci if (tei > 63) /* not a fixed tei */ 12198c2ecf20Sopenharmony_ci return -ENOTCONN; 12208c2ecf20Sopenharmony_ci if ((skb->data[2] & ~0x10) != SABME) 12218c2ecf20Sopenharmony_ci return -ENOTCONN; 12228c2ecf20Sopenharmony_ci /* We got a SABME for a fixed TEI */ 12238c2ecf20Sopenharmony_ci if (*debug & DEBUG_L2_CTRL) 12248c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: SABME sapi(%d) tei(%d)\n", 12258c2ecf20Sopenharmony_ci __func__, sapi, tei); 12268c2ecf20Sopenharmony_ci l2 = create_new_tei(mgr, tei, sapi); 12278c2ecf20Sopenharmony_ci if (!l2) { 12288c2ecf20Sopenharmony_ci if (*debug & DEBUG_L2_CTRL) 12298c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: failed to create new tei\n", 12308c2ecf20Sopenharmony_ci __func__); 12318c2ecf20Sopenharmony_ci return -ENOMEM; 12328c2ecf20Sopenharmony_ci } 12338c2ecf20Sopenharmony_ci ret = l2->ch.send(&l2->ch, skb); 12348c2ecf20Sopenharmony_ci return ret; 12358c2ecf20Sopenharmony_ci} 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_civoid 12388c2ecf20Sopenharmony_cidelete_teimanager(struct mISDNchannel *ch) 12398c2ecf20Sopenharmony_ci{ 12408c2ecf20Sopenharmony_ci struct manager *mgr; 12418c2ecf20Sopenharmony_ci struct layer2 *l2, *nl2; 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci mgr = container_of(ch, struct manager, ch); 12448c2ecf20Sopenharmony_ci /* not locked lock is taken in release tei */ 12458c2ecf20Sopenharmony_ci list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) { 12468c2ecf20Sopenharmony_ci mutex_lock(&mgr->ch.st->lmutex); 12478c2ecf20Sopenharmony_ci list_del(&l2->ch.list); 12488c2ecf20Sopenharmony_ci mutex_unlock(&mgr->ch.st->lmutex); 12498c2ecf20Sopenharmony_ci l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); 12508c2ecf20Sopenharmony_ci } 12518c2ecf20Sopenharmony_ci list_del(&mgr->ch.list); 12528c2ecf20Sopenharmony_ci list_del(&mgr->bcast.list); 12538c2ecf20Sopenharmony_ci skb_queue_purge(&mgr->sendq); 12548c2ecf20Sopenharmony_ci kfree(mgr); 12558c2ecf20Sopenharmony_ci} 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_cistatic int 12588c2ecf20Sopenharmony_cimgr_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) 12598c2ecf20Sopenharmony_ci{ 12608c2ecf20Sopenharmony_ci struct manager *mgr; 12618c2ecf20Sopenharmony_ci int ret = -EINVAL; 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci mgr = container_of(ch, struct manager, ch); 12648c2ecf20Sopenharmony_ci if (*debug & DEBUG_L2_CTRL) 12658c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s(%x, %p)\n", __func__, cmd, arg); 12668c2ecf20Sopenharmony_ci switch (cmd) { 12678c2ecf20Sopenharmony_ci case OPEN_CHANNEL: 12688c2ecf20Sopenharmony_ci ret = create_teimgr(mgr, arg); 12698c2ecf20Sopenharmony_ci break; 12708c2ecf20Sopenharmony_ci case CLOSE_CHANNEL: 12718c2ecf20Sopenharmony_ci ret = free_teimanager(mgr); 12728c2ecf20Sopenharmony_ci break; 12738c2ecf20Sopenharmony_ci case CONTROL_CHANNEL: 12748c2ecf20Sopenharmony_ci ret = ctrl_teimanager(mgr, arg); 12758c2ecf20Sopenharmony_ci break; 12768c2ecf20Sopenharmony_ci case CHECK_DATA: 12778c2ecf20Sopenharmony_ci ret = check_data(mgr, arg); 12788c2ecf20Sopenharmony_ci break; 12798c2ecf20Sopenharmony_ci } 12808c2ecf20Sopenharmony_ci return ret; 12818c2ecf20Sopenharmony_ci} 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_cistatic int 12848c2ecf20Sopenharmony_cimgr_bcast(struct mISDNchannel *ch, struct sk_buff *skb) 12858c2ecf20Sopenharmony_ci{ 12868c2ecf20Sopenharmony_ci struct manager *mgr = container_of(ch, struct manager, bcast); 12878c2ecf20Sopenharmony_ci struct mISDNhead *hhc, *hh = mISDN_HEAD_P(skb); 12888c2ecf20Sopenharmony_ci struct sk_buff *cskb = NULL; 12898c2ecf20Sopenharmony_ci struct layer2 *l2; 12908c2ecf20Sopenharmony_ci u_long flags; 12918c2ecf20Sopenharmony_ci int ret; 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci read_lock_irqsave(&mgr->lock, flags); 12948c2ecf20Sopenharmony_ci list_for_each_entry(l2, &mgr->layer2, list) { 12958c2ecf20Sopenharmony_ci if ((hh->id & MISDN_ID_SAPI_MASK) == 12968c2ecf20Sopenharmony_ci (l2->ch.addr & MISDN_ID_SAPI_MASK)) { 12978c2ecf20Sopenharmony_ci if (list_is_last(&l2->list, &mgr->layer2)) { 12988c2ecf20Sopenharmony_ci cskb = skb; 12998c2ecf20Sopenharmony_ci skb = NULL; 13008c2ecf20Sopenharmony_ci } else { 13018c2ecf20Sopenharmony_ci if (!cskb) 13028c2ecf20Sopenharmony_ci cskb = skb_copy(skb, GFP_ATOMIC); 13038c2ecf20Sopenharmony_ci } 13048c2ecf20Sopenharmony_ci if (cskb) { 13058c2ecf20Sopenharmony_ci hhc = mISDN_HEAD_P(cskb); 13068c2ecf20Sopenharmony_ci /* save original header behind normal header */ 13078c2ecf20Sopenharmony_ci hhc++; 13088c2ecf20Sopenharmony_ci *hhc = *hh; 13098c2ecf20Sopenharmony_ci hhc--; 13108c2ecf20Sopenharmony_ci hhc->prim = DL_INTERN_MSG; 13118c2ecf20Sopenharmony_ci hhc->id = l2->ch.nr; 13128c2ecf20Sopenharmony_ci ret = ch->st->own.recv(&ch->st->own, cskb); 13138c2ecf20Sopenharmony_ci if (ret) { 13148c2ecf20Sopenharmony_ci if (*debug & DEBUG_SEND_ERR) 13158c2ecf20Sopenharmony_ci printk(KERN_DEBUG 13168c2ecf20Sopenharmony_ci "%s ch%d prim(%x) addr(%x)" 13178c2ecf20Sopenharmony_ci " err %d\n", 13188c2ecf20Sopenharmony_ci __func__, l2->ch.nr, 13198c2ecf20Sopenharmony_ci hh->prim, l2->ch.addr, ret); 13208c2ecf20Sopenharmony_ci } else 13218c2ecf20Sopenharmony_ci cskb = NULL; 13228c2ecf20Sopenharmony_ci } else { 13238c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s ch%d addr %x no mem\n", 13248c2ecf20Sopenharmony_ci __func__, ch->nr, ch->addr); 13258c2ecf20Sopenharmony_ci goto out; 13268c2ecf20Sopenharmony_ci } 13278c2ecf20Sopenharmony_ci } 13288c2ecf20Sopenharmony_ci } 13298c2ecf20Sopenharmony_ciout: 13308c2ecf20Sopenharmony_ci read_unlock_irqrestore(&mgr->lock, flags); 13318c2ecf20Sopenharmony_ci dev_kfree_skb(cskb); 13328c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 13338c2ecf20Sopenharmony_ci return 0; 13348c2ecf20Sopenharmony_ci} 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_cistatic int 13378c2ecf20Sopenharmony_cimgr_bcast_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) 13388c2ecf20Sopenharmony_ci{ 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci return -EINVAL; 13418c2ecf20Sopenharmony_ci} 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ciint 13448c2ecf20Sopenharmony_cicreate_teimanager(struct mISDNdevice *dev) 13458c2ecf20Sopenharmony_ci{ 13468c2ecf20Sopenharmony_ci struct manager *mgr; 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci mgr = kzalloc(sizeof(struct manager), GFP_KERNEL); 13498c2ecf20Sopenharmony_ci if (!mgr) 13508c2ecf20Sopenharmony_ci return -ENOMEM; 13518c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&mgr->layer2); 13528c2ecf20Sopenharmony_ci rwlock_init(&mgr->lock); 13538c2ecf20Sopenharmony_ci skb_queue_head_init(&mgr->sendq); 13548c2ecf20Sopenharmony_ci mgr->nextid = 1; 13558c2ecf20Sopenharmony_ci mgr->lastid = MISDN_ID_NONE; 13568c2ecf20Sopenharmony_ci mgr->ch.send = mgr_send; 13578c2ecf20Sopenharmony_ci mgr->ch.ctrl = mgr_ctrl; 13588c2ecf20Sopenharmony_ci mgr->ch.st = dev->D.st; 13598c2ecf20Sopenharmony_ci set_channel_address(&mgr->ch, TEI_SAPI, GROUP_TEI); 13608c2ecf20Sopenharmony_ci add_layer2(&mgr->ch, dev->D.st); 13618c2ecf20Sopenharmony_ci mgr->bcast.send = mgr_bcast; 13628c2ecf20Sopenharmony_ci mgr->bcast.ctrl = mgr_bcast_ctrl; 13638c2ecf20Sopenharmony_ci mgr->bcast.st = dev->D.st; 13648c2ecf20Sopenharmony_ci set_channel_address(&mgr->bcast, 0, GROUP_TEI); 13658c2ecf20Sopenharmony_ci add_layer2(&mgr->bcast, dev->D.st); 13668c2ecf20Sopenharmony_ci mgr->deact.debug = *debug & DEBUG_MANAGER; 13678c2ecf20Sopenharmony_ci mgr->deact.userdata = mgr; 13688c2ecf20Sopenharmony_ci mgr->deact.printdebug = da_debug; 13698c2ecf20Sopenharmony_ci mgr->deact.fsm = &deactfsm; 13708c2ecf20Sopenharmony_ci mgr->deact.state = ST_L1_DEACT; 13718c2ecf20Sopenharmony_ci mISDN_FsmInitTimer(&mgr->deact, &mgr->datimer); 13728c2ecf20Sopenharmony_ci dev->teimgr = &mgr->ch; 13738c2ecf20Sopenharmony_ci return 0; 13748c2ecf20Sopenharmony_ci} 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ciint TEIInit(u_int *deb) 13778c2ecf20Sopenharmony_ci{ 13788c2ecf20Sopenharmony_ci int res; 13798c2ecf20Sopenharmony_ci debug = deb; 13808c2ecf20Sopenharmony_ci teifsmu.state_count = TEI_STATE_COUNT; 13818c2ecf20Sopenharmony_ci teifsmu.event_count = TEI_EVENT_COUNT; 13828c2ecf20Sopenharmony_ci teifsmu.strEvent = strTeiEvent; 13838c2ecf20Sopenharmony_ci teifsmu.strState = strTeiState; 13848c2ecf20Sopenharmony_ci res = mISDN_FsmNew(&teifsmu, TeiFnListUser, ARRAY_SIZE(TeiFnListUser)); 13858c2ecf20Sopenharmony_ci if (res) 13868c2ecf20Sopenharmony_ci goto error; 13878c2ecf20Sopenharmony_ci teifsmn.state_count = TEI_STATE_COUNT; 13888c2ecf20Sopenharmony_ci teifsmn.event_count = TEI_EVENT_COUNT; 13898c2ecf20Sopenharmony_ci teifsmn.strEvent = strTeiEvent; 13908c2ecf20Sopenharmony_ci teifsmn.strState = strTeiState; 13918c2ecf20Sopenharmony_ci res = mISDN_FsmNew(&teifsmn, TeiFnListNet, ARRAY_SIZE(TeiFnListNet)); 13928c2ecf20Sopenharmony_ci if (res) 13938c2ecf20Sopenharmony_ci goto error_smn; 13948c2ecf20Sopenharmony_ci deactfsm.state_count = DEACT_STATE_COUNT; 13958c2ecf20Sopenharmony_ci deactfsm.event_count = DEACT_EVENT_COUNT; 13968c2ecf20Sopenharmony_ci deactfsm.strEvent = strDeactEvent; 13978c2ecf20Sopenharmony_ci deactfsm.strState = strDeactState; 13988c2ecf20Sopenharmony_ci res = mISDN_FsmNew(&deactfsm, DeactFnList, ARRAY_SIZE(DeactFnList)); 13998c2ecf20Sopenharmony_ci if (res) 14008c2ecf20Sopenharmony_ci goto error_deact; 14018c2ecf20Sopenharmony_ci return 0; 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_cierror_deact: 14048c2ecf20Sopenharmony_ci mISDN_FsmFree(&teifsmn); 14058c2ecf20Sopenharmony_cierror_smn: 14068c2ecf20Sopenharmony_ci mISDN_FsmFree(&teifsmu); 14078c2ecf20Sopenharmony_cierror: 14088c2ecf20Sopenharmony_ci return res; 14098c2ecf20Sopenharmony_ci} 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_civoid TEIFree(void) 14128c2ecf20Sopenharmony_ci{ 14138c2ecf20Sopenharmony_ci mISDN_FsmFree(&teifsmu); 14148c2ecf20Sopenharmony_ci mISDN_FsmFree(&teifsmn); 14158c2ecf20Sopenharmony_ci mISDN_FsmFree(&deactfsm); 14168c2ecf20Sopenharmony_ci} 1417