162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Author Karsten Keil <kkeil@novell.com> 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright 2008 by Karsten Keil <kkeil@novell.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci#include "layer2.h" 962306a36Sopenharmony_ci#include <linux/random.h> 1062306a36Sopenharmony_ci#include <linux/slab.h> 1162306a36Sopenharmony_ci#include "core.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#define ID_REQUEST 1 1462306a36Sopenharmony_ci#define ID_ASSIGNED 2 1562306a36Sopenharmony_ci#define ID_DENIED 3 1662306a36Sopenharmony_ci#define ID_CHK_REQ 4 1762306a36Sopenharmony_ci#define ID_CHK_RES 5 1862306a36Sopenharmony_ci#define ID_REMOVE 6 1962306a36Sopenharmony_ci#define ID_VERIFY 7 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define TEI_ENTITY_ID 0xf 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define MGR_PH_ACTIVE 16 2462306a36Sopenharmony_ci#define MGR_PH_NOTREADY 17 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define DATIMER_VAL 10000 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic u_int *debug; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic struct Fsm deactfsm = {NULL, 0, 0, NULL, NULL}; 3162306a36Sopenharmony_cistatic struct Fsm teifsmu = {NULL, 0, 0, NULL, NULL}; 3262306a36Sopenharmony_cistatic struct Fsm teifsmn = {NULL, 0, 0, NULL, NULL}; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cienum { 3562306a36Sopenharmony_ci ST_L1_DEACT, 3662306a36Sopenharmony_ci ST_L1_DEACT_PENDING, 3762306a36Sopenharmony_ci ST_L1_ACTIV, 3862306a36Sopenharmony_ci}; 3962306a36Sopenharmony_ci#define DEACT_STATE_COUNT (ST_L1_ACTIV + 1) 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic char *strDeactState[] = 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci "ST_L1_DEACT", 4462306a36Sopenharmony_ci "ST_L1_DEACT_PENDING", 4562306a36Sopenharmony_ci "ST_L1_ACTIV", 4662306a36Sopenharmony_ci}; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cienum { 4962306a36Sopenharmony_ci EV_ACTIVATE, 5062306a36Sopenharmony_ci EV_ACTIVATE_IND, 5162306a36Sopenharmony_ci EV_DEACTIVATE, 5262306a36Sopenharmony_ci EV_DEACTIVATE_IND, 5362306a36Sopenharmony_ci EV_UI, 5462306a36Sopenharmony_ci EV_DATIMER, 5562306a36Sopenharmony_ci}; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci#define DEACT_EVENT_COUNT (EV_DATIMER + 1) 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic char *strDeactEvent[] = 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci "EV_ACTIVATE", 6262306a36Sopenharmony_ci "EV_ACTIVATE_IND", 6362306a36Sopenharmony_ci "EV_DEACTIVATE", 6462306a36Sopenharmony_ci "EV_DEACTIVATE_IND", 6562306a36Sopenharmony_ci "EV_UI", 6662306a36Sopenharmony_ci "EV_DATIMER", 6762306a36Sopenharmony_ci}; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic void 7062306a36Sopenharmony_cida_debug(struct FsmInst *fi, char *fmt, ...) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci struct manager *mgr = fi->userdata; 7362306a36Sopenharmony_ci struct va_format vaf; 7462306a36Sopenharmony_ci va_list va; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci if (!(*debug & DEBUG_L2_TEIFSM)) 7762306a36Sopenharmony_ci return; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci va_start(va, fmt); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci vaf.fmt = fmt; 8262306a36Sopenharmony_ci vaf.va = &va; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci printk(KERN_DEBUG "mgr(%d): %pV\n", mgr->ch.st->dev->id, &vaf); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci va_end(va); 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic void 9062306a36Sopenharmony_cida_activate(struct FsmInst *fi, int event, void *arg) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci struct manager *mgr = fi->userdata; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci if (fi->state == ST_L1_DEACT_PENDING) 9562306a36Sopenharmony_ci mISDN_FsmDelTimer(&mgr->datimer, 1); 9662306a36Sopenharmony_ci mISDN_FsmChangeState(fi, ST_L1_ACTIV); 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic void 10062306a36Sopenharmony_cida_deactivate_ind(struct FsmInst *fi, int event, void *arg) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci mISDN_FsmChangeState(fi, ST_L1_DEACT); 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic void 10662306a36Sopenharmony_cida_deactivate(struct FsmInst *fi, int event, void *arg) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci struct manager *mgr = fi->userdata; 10962306a36Sopenharmony_ci struct layer2 *l2; 11062306a36Sopenharmony_ci u_long flags; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci read_lock_irqsave(&mgr->lock, flags); 11362306a36Sopenharmony_ci list_for_each_entry(l2, &mgr->layer2, list) { 11462306a36Sopenharmony_ci if (l2->l2m.state > ST_L2_4) { 11562306a36Sopenharmony_ci /* have still activ TEI */ 11662306a36Sopenharmony_ci read_unlock_irqrestore(&mgr->lock, flags); 11762306a36Sopenharmony_ci return; 11862306a36Sopenharmony_ci } 11962306a36Sopenharmony_ci } 12062306a36Sopenharmony_ci read_unlock_irqrestore(&mgr->lock, flags); 12162306a36Sopenharmony_ci /* All TEI are inactiv */ 12262306a36Sopenharmony_ci if (!test_bit(OPTION_L1_HOLD, &mgr->options)) { 12362306a36Sopenharmony_ci mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER, 12462306a36Sopenharmony_ci NULL, 1); 12562306a36Sopenharmony_ci mISDN_FsmChangeState(fi, ST_L1_DEACT_PENDING); 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic void 13062306a36Sopenharmony_cida_ui(struct FsmInst *fi, int event, void *arg) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci struct manager *mgr = fi->userdata; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci /* restart da timer */ 13562306a36Sopenharmony_ci if (!test_bit(OPTION_L1_HOLD, &mgr->options)) { 13662306a36Sopenharmony_ci mISDN_FsmDelTimer(&mgr->datimer, 2); 13762306a36Sopenharmony_ci mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER, 13862306a36Sopenharmony_ci NULL, 2); 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic void 14362306a36Sopenharmony_cida_timer(struct FsmInst *fi, int event, void *arg) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci struct manager *mgr = fi->userdata; 14662306a36Sopenharmony_ci struct layer2 *l2; 14762306a36Sopenharmony_ci u_long flags; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci /* check again */ 15062306a36Sopenharmony_ci read_lock_irqsave(&mgr->lock, flags); 15162306a36Sopenharmony_ci list_for_each_entry(l2, &mgr->layer2, list) { 15262306a36Sopenharmony_ci if (l2->l2m.state > ST_L2_4) { 15362306a36Sopenharmony_ci /* have still activ TEI */ 15462306a36Sopenharmony_ci read_unlock_irqrestore(&mgr->lock, flags); 15562306a36Sopenharmony_ci mISDN_FsmChangeState(fi, ST_L1_ACTIV); 15662306a36Sopenharmony_ci return; 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci read_unlock_irqrestore(&mgr->lock, flags); 16062306a36Sopenharmony_ci /* All TEI are inactiv */ 16162306a36Sopenharmony_ci mISDN_FsmChangeState(fi, ST_L1_DEACT); 16262306a36Sopenharmony_ci _queue_data(&mgr->ch, PH_DEACTIVATE_REQ, MISDN_ID_ANY, 0, NULL, 16362306a36Sopenharmony_ci GFP_ATOMIC); 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic struct FsmNode DeactFnList[] = 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci {ST_L1_DEACT, EV_ACTIVATE_IND, da_activate}, 16962306a36Sopenharmony_ci {ST_L1_ACTIV, EV_DEACTIVATE_IND, da_deactivate_ind}, 17062306a36Sopenharmony_ci {ST_L1_ACTIV, EV_DEACTIVATE, da_deactivate}, 17162306a36Sopenharmony_ci {ST_L1_DEACT_PENDING, EV_ACTIVATE, da_activate}, 17262306a36Sopenharmony_ci {ST_L1_DEACT_PENDING, EV_UI, da_ui}, 17362306a36Sopenharmony_ci {ST_L1_DEACT_PENDING, EV_DATIMER, da_timer}, 17462306a36Sopenharmony_ci}; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cienum { 17762306a36Sopenharmony_ci ST_TEI_NOP, 17862306a36Sopenharmony_ci ST_TEI_IDREQ, 17962306a36Sopenharmony_ci ST_TEI_IDVERIFY, 18062306a36Sopenharmony_ci}; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci#define TEI_STATE_COUNT (ST_TEI_IDVERIFY + 1) 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cistatic char *strTeiState[] = 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci "ST_TEI_NOP", 18762306a36Sopenharmony_ci "ST_TEI_IDREQ", 18862306a36Sopenharmony_ci "ST_TEI_IDVERIFY", 18962306a36Sopenharmony_ci}; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cienum { 19262306a36Sopenharmony_ci EV_IDREQ, 19362306a36Sopenharmony_ci EV_ASSIGN, 19462306a36Sopenharmony_ci EV_ASSIGN_REQ, 19562306a36Sopenharmony_ci EV_DENIED, 19662306a36Sopenharmony_ci EV_CHKREQ, 19762306a36Sopenharmony_ci EV_CHKRESP, 19862306a36Sopenharmony_ci EV_REMOVE, 19962306a36Sopenharmony_ci EV_VERIFY, 20062306a36Sopenharmony_ci EV_TIMER, 20162306a36Sopenharmony_ci}; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci#define TEI_EVENT_COUNT (EV_TIMER + 1) 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistatic char *strTeiEvent[] = 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci "EV_IDREQ", 20862306a36Sopenharmony_ci "EV_ASSIGN", 20962306a36Sopenharmony_ci "EV_ASSIGN_REQ", 21062306a36Sopenharmony_ci "EV_DENIED", 21162306a36Sopenharmony_ci "EV_CHKREQ", 21262306a36Sopenharmony_ci "EV_CHKRESP", 21362306a36Sopenharmony_ci "EV_REMOVE", 21462306a36Sopenharmony_ci "EV_VERIFY", 21562306a36Sopenharmony_ci "EV_TIMER", 21662306a36Sopenharmony_ci}; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cistatic void 21962306a36Sopenharmony_citei_debug(struct FsmInst *fi, char *fmt, ...) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci struct teimgr *tm = fi->userdata; 22262306a36Sopenharmony_ci struct va_format vaf; 22362306a36Sopenharmony_ci va_list va; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci if (!(*debug & DEBUG_L2_TEIFSM)) 22662306a36Sopenharmony_ci return; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci va_start(va, fmt); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci vaf.fmt = fmt; 23162306a36Sopenharmony_ci vaf.va = &va; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci printk(KERN_DEBUG "sapi(%d) tei(%d): %pV\n", 23462306a36Sopenharmony_ci tm->l2->sapi, tm->l2->tei, &vaf); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci va_end(va); 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic int 24262306a36Sopenharmony_ciget_free_id(struct manager *mgr) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci DECLARE_BITMAP(ids, 64) = { [0 ... BITS_TO_LONGS(64) - 1] = 0 }; 24562306a36Sopenharmony_ci int i; 24662306a36Sopenharmony_ci struct layer2 *l2; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci list_for_each_entry(l2, &mgr->layer2, list) { 24962306a36Sopenharmony_ci if (l2->ch.nr > 63) { 25062306a36Sopenharmony_ci printk(KERN_WARNING 25162306a36Sopenharmony_ci "%s: more as 63 layer2 for one device\n", 25262306a36Sopenharmony_ci __func__); 25362306a36Sopenharmony_ci return -EBUSY; 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci __set_bit(l2->ch.nr, ids); 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci i = find_next_zero_bit(ids, 64, 1); 25862306a36Sopenharmony_ci if (i < 64) 25962306a36Sopenharmony_ci return i; 26062306a36Sopenharmony_ci printk(KERN_WARNING "%s: more as 63 layer2 for one device\n", 26162306a36Sopenharmony_ci __func__); 26262306a36Sopenharmony_ci return -EBUSY; 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_cistatic int 26662306a36Sopenharmony_ciget_free_tei(struct manager *mgr) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci DECLARE_BITMAP(ids, 64) = { [0 ... BITS_TO_LONGS(64) - 1] = 0 }; 26962306a36Sopenharmony_ci int i; 27062306a36Sopenharmony_ci struct layer2 *l2; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci list_for_each_entry(l2, &mgr->layer2, list) { 27362306a36Sopenharmony_ci if (l2->ch.nr == 0) 27462306a36Sopenharmony_ci continue; 27562306a36Sopenharmony_ci if ((l2->ch.addr & 0xff) != 0) 27662306a36Sopenharmony_ci continue; 27762306a36Sopenharmony_ci i = l2->ch.addr >> 8; 27862306a36Sopenharmony_ci if (i < 64) 27962306a36Sopenharmony_ci continue; 28062306a36Sopenharmony_ci i -= 64; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci __set_bit(i, ids); 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci i = find_first_zero_bit(ids, 64); 28562306a36Sopenharmony_ci if (i < 64) 28662306a36Sopenharmony_ci return i + 64; 28762306a36Sopenharmony_ci printk(KERN_WARNING "%s: more as 63 dynamic tei for one device\n", 28862306a36Sopenharmony_ci __func__); 28962306a36Sopenharmony_ci return -1; 29062306a36Sopenharmony_ci} 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_cistatic void 29362306a36Sopenharmony_citeiup_create(struct manager *mgr, u_int prim, int len, void *arg) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci struct sk_buff *skb; 29662306a36Sopenharmony_ci struct mISDNhead *hh; 29762306a36Sopenharmony_ci int err; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci skb = mI_alloc_skb(len, GFP_ATOMIC); 30062306a36Sopenharmony_ci if (!skb) 30162306a36Sopenharmony_ci return; 30262306a36Sopenharmony_ci hh = mISDN_HEAD_P(skb); 30362306a36Sopenharmony_ci hh->prim = prim; 30462306a36Sopenharmony_ci hh->id = (mgr->ch.nr << 16) | mgr->ch.addr; 30562306a36Sopenharmony_ci if (len) 30662306a36Sopenharmony_ci skb_put_data(skb, arg, len); 30762306a36Sopenharmony_ci err = mgr->up->send(mgr->up, skb); 30862306a36Sopenharmony_ci if (err) { 30962306a36Sopenharmony_ci printk(KERN_WARNING "%s: err=%d\n", __func__, err); 31062306a36Sopenharmony_ci dev_kfree_skb(skb); 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cistatic u_int 31562306a36Sopenharmony_cinew_id(struct manager *mgr) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci u_int id; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci id = mgr->nextid++; 32062306a36Sopenharmony_ci if (id == 0x7fff) 32162306a36Sopenharmony_ci mgr->nextid = 1; 32262306a36Sopenharmony_ci id <<= 16; 32362306a36Sopenharmony_ci id |= GROUP_TEI << 8; 32462306a36Sopenharmony_ci id |= TEI_SAPI; 32562306a36Sopenharmony_ci return id; 32662306a36Sopenharmony_ci} 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_cistatic void 32962306a36Sopenharmony_cido_send(struct manager *mgr) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci if (!test_bit(MGR_PH_ACTIVE, &mgr->options)) 33262306a36Sopenharmony_ci return; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci if (!test_and_set_bit(MGR_PH_NOTREADY, &mgr->options)) { 33562306a36Sopenharmony_ci struct sk_buff *skb = skb_dequeue(&mgr->sendq); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci if (!skb) { 33862306a36Sopenharmony_ci test_and_clear_bit(MGR_PH_NOTREADY, &mgr->options); 33962306a36Sopenharmony_ci return; 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci mgr->lastid = mISDN_HEAD_ID(skb); 34262306a36Sopenharmony_ci mISDN_FsmEvent(&mgr->deact, EV_UI, NULL); 34362306a36Sopenharmony_ci if (mgr->ch.recv(mgr->ch.peer, skb)) { 34462306a36Sopenharmony_ci dev_kfree_skb(skb); 34562306a36Sopenharmony_ci test_and_clear_bit(MGR_PH_NOTREADY, &mgr->options); 34662306a36Sopenharmony_ci mgr->lastid = MISDN_ID_NONE; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_cistatic void 35262306a36Sopenharmony_cido_ack(struct manager *mgr, u_int id) 35362306a36Sopenharmony_ci{ 35462306a36Sopenharmony_ci if (test_bit(MGR_PH_NOTREADY, &mgr->options)) { 35562306a36Sopenharmony_ci if (id == mgr->lastid) { 35662306a36Sopenharmony_ci if (test_bit(MGR_PH_ACTIVE, &mgr->options)) { 35762306a36Sopenharmony_ci struct sk_buff *skb; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci skb = skb_dequeue(&mgr->sendq); 36062306a36Sopenharmony_ci if (skb) { 36162306a36Sopenharmony_ci mgr->lastid = mISDN_HEAD_ID(skb); 36262306a36Sopenharmony_ci if (!mgr->ch.recv(mgr->ch.peer, skb)) 36362306a36Sopenharmony_ci return; 36462306a36Sopenharmony_ci dev_kfree_skb(skb); 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci mgr->lastid = MISDN_ID_NONE; 36862306a36Sopenharmony_ci test_and_clear_bit(MGR_PH_NOTREADY, &mgr->options); 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_cistatic void 37462306a36Sopenharmony_cimgr_send_down(struct manager *mgr, struct sk_buff *skb) 37562306a36Sopenharmony_ci{ 37662306a36Sopenharmony_ci skb_queue_tail(&mgr->sendq, skb); 37762306a36Sopenharmony_ci if (!test_bit(MGR_PH_ACTIVE, &mgr->options)) { 37862306a36Sopenharmony_ci _queue_data(&mgr->ch, PH_ACTIVATE_REQ, MISDN_ID_ANY, 0, 37962306a36Sopenharmony_ci NULL, GFP_KERNEL); 38062306a36Sopenharmony_ci } else { 38162306a36Sopenharmony_ci do_send(mgr); 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci} 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_cistatic int 38662306a36Sopenharmony_cidl_unit_data(struct manager *mgr, struct sk_buff *skb) 38762306a36Sopenharmony_ci{ 38862306a36Sopenharmony_ci if (!test_bit(MGR_OPT_NETWORK, &mgr->options)) /* only net send UI */ 38962306a36Sopenharmony_ci return -EINVAL; 39062306a36Sopenharmony_ci if (!test_bit(MGR_PH_ACTIVE, &mgr->options)) 39162306a36Sopenharmony_ci _queue_data(&mgr->ch, PH_ACTIVATE_REQ, MISDN_ID_ANY, 0, 39262306a36Sopenharmony_ci NULL, GFP_KERNEL); 39362306a36Sopenharmony_ci skb_push(skb, 3); 39462306a36Sopenharmony_ci skb->data[0] = 0x02; /* SAPI 0 C/R = 1 */ 39562306a36Sopenharmony_ci skb->data[1] = 0xff; /* TEI 127 */ 39662306a36Sopenharmony_ci skb->data[2] = UI; /* UI frame */ 39762306a36Sopenharmony_ci mISDN_HEAD_PRIM(skb) = PH_DATA_REQ; 39862306a36Sopenharmony_ci mISDN_HEAD_ID(skb) = new_id(mgr); 39962306a36Sopenharmony_ci skb_queue_tail(&mgr->sendq, skb); 40062306a36Sopenharmony_ci do_send(mgr); 40162306a36Sopenharmony_ci return 0; 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_cistatic unsigned int 40562306a36Sopenharmony_cirandom_ri(void) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci u16 x; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci get_random_bytes(&x, sizeof(x)); 41062306a36Sopenharmony_ci return x; 41162306a36Sopenharmony_ci} 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_cistatic struct layer2 * 41462306a36Sopenharmony_cifindtei(struct manager *mgr, int tei) 41562306a36Sopenharmony_ci{ 41662306a36Sopenharmony_ci struct layer2 *l2; 41762306a36Sopenharmony_ci u_long flags; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci read_lock_irqsave(&mgr->lock, flags); 42062306a36Sopenharmony_ci list_for_each_entry(l2, &mgr->layer2, list) { 42162306a36Sopenharmony_ci if ((l2->sapi == 0) && (l2->tei > 0) && 42262306a36Sopenharmony_ci (l2->tei != GROUP_TEI) && (l2->tei == tei)) 42362306a36Sopenharmony_ci goto done; 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci l2 = NULL; 42662306a36Sopenharmony_cidone: 42762306a36Sopenharmony_ci read_unlock_irqrestore(&mgr->lock, flags); 42862306a36Sopenharmony_ci return l2; 42962306a36Sopenharmony_ci} 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_cistatic void 43262306a36Sopenharmony_ciput_tei_msg(struct manager *mgr, u_char m_id, unsigned int ri, int tei) 43362306a36Sopenharmony_ci{ 43462306a36Sopenharmony_ci struct sk_buff *skb; 43562306a36Sopenharmony_ci u_char bp[8]; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci bp[0] = (TEI_SAPI << 2); 43862306a36Sopenharmony_ci if (test_bit(MGR_OPT_NETWORK, &mgr->options)) 43962306a36Sopenharmony_ci bp[0] |= 2; /* CR:=1 for net command */ 44062306a36Sopenharmony_ci bp[1] = (GROUP_TEI << 1) | 0x1; 44162306a36Sopenharmony_ci bp[2] = UI; 44262306a36Sopenharmony_ci bp[3] = TEI_ENTITY_ID; 44362306a36Sopenharmony_ci bp[4] = ri >> 8; 44462306a36Sopenharmony_ci bp[5] = ri & 0xff; 44562306a36Sopenharmony_ci bp[6] = m_id; 44662306a36Sopenharmony_ci bp[7] = ((tei << 1) & 0xff) | 1; 44762306a36Sopenharmony_ci skb = _alloc_mISDN_skb(PH_DATA_REQ, new_id(mgr), 8, bp, GFP_ATOMIC); 44862306a36Sopenharmony_ci if (!skb) { 44962306a36Sopenharmony_ci printk(KERN_WARNING "%s: no skb for tei msg\n", __func__); 45062306a36Sopenharmony_ci return; 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci mgr_send_down(mgr, skb); 45362306a36Sopenharmony_ci} 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_cistatic void 45662306a36Sopenharmony_citei_id_request(struct FsmInst *fi, int event, void *arg) 45762306a36Sopenharmony_ci{ 45862306a36Sopenharmony_ci struct teimgr *tm = fi->userdata; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci if (tm->l2->tei != GROUP_TEI) { 46162306a36Sopenharmony_ci tm->tei_m.printdebug(&tm->tei_m, 46262306a36Sopenharmony_ci "assign request for already assigned tei %d", 46362306a36Sopenharmony_ci tm->l2->tei); 46462306a36Sopenharmony_ci return; 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ci tm->ri = random_ri(); 46762306a36Sopenharmony_ci if (*debug & DEBUG_L2_TEI) 46862306a36Sopenharmony_ci tm->tei_m.printdebug(&tm->tei_m, 46962306a36Sopenharmony_ci "assign request ri %d", tm->ri); 47062306a36Sopenharmony_ci put_tei_msg(tm->mgr, ID_REQUEST, tm->ri, GROUP_TEI); 47162306a36Sopenharmony_ci mISDN_FsmChangeState(fi, ST_TEI_IDREQ); 47262306a36Sopenharmony_ci mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 1); 47362306a36Sopenharmony_ci tm->nval = 3; 47462306a36Sopenharmony_ci} 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_cistatic void 47762306a36Sopenharmony_citei_id_assign(struct FsmInst *fi, int event, void *arg) 47862306a36Sopenharmony_ci{ 47962306a36Sopenharmony_ci struct teimgr *tm = fi->userdata; 48062306a36Sopenharmony_ci struct layer2 *l2; 48162306a36Sopenharmony_ci u_char *dp = arg; 48262306a36Sopenharmony_ci int ri, tei; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci ri = ((unsigned int) *dp++ << 8); 48562306a36Sopenharmony_ci ri += *dp++; 48662306a36Sopenharmony_ci dp++; 48762306a36Sopenharmony_ci tei = *dp >> 1; 48862306a36Sopenharmony_ci if (*debug & DEBUG_L2_TEI) 48962306a36Sopenharmony_ci tm->tei_m.printdebug(fi, "identity assign ri %d tei %d", 49062306a36Sopenharmony_ci ri, tei); 49162306a36Sopenharmony_ci l2 = findtei(tm->mgr, tei); 49262306a36Sopenharmony_ci if (l2) { /* same tei is in use */ 49362306a36Sopenharmony_ci if (ri != l2->tm->ri) { 49462306a36Sopenharmony_ci tm->tei_m.printdebug(fi, 49562306a36Sopenharmony_ci "possible duplicate assignment tei %d", tei); 49662306a36Sopenharmony_ci tei_l2(l2, MDL_ERROR_RSP, 0); 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci } else if (ri == tm->ri) { 49962306a36Sopenharmony_ci mISDN_FsmDelTimer(&tm->timer, 1); 50062306a36Sopenharmony_ci mISDN_FsmChangeState(fi, ST_TEI_NOP); 50162306a36Sopenharmony_ci tei_l2(tm->l2, MDL_ASSIGN_REQ, tei); 50262306a36Sopenharmony_ci } 50362306a36Sopenharmony_ci} 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_cistatic void 50662306a36Sopenharmony_citei_id_test_dup(struct FsmInst *fi, int event, void *arg) 50762306a36Sopenharmony_ci{ 50862306a36Sopenharmony_ci struct teimgr *tm = fi->userdata; 50962306a36Sopenharmony_ci struct layer2 *l2; 51062306a36Sopenharmony_ci u_char *dp = arg; 51162306a36Sopenharmony_ci int tei, ri; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci ri = ((unsigned int) *dp++ << 8); 51462306a36Sopenharmony_ci ri += *dp++; 51562306a36Sopenharmony_ci dp++; 51662306a36Sopenharmony_ci tei = *dp >> 1; 51762306a36Sopenharmony_ci if (*debug & DEBUG_L2_TEI) 51862306a36Sopenharmony_ci tm->tei_m.printdebug(fi, "foreign identity assign ri %d tei %d", 51962306a36Sopenharmony_ci ri, tei); 52062306a36Sopenharmony_ci l2 = findtei(tm->mgr, tei); 52162306a36Sopenharmony_ci if (l2) { /* same tei is in use */ 52262306a36Sopenharmony_ci if (ri != l2->tm->ri) { /* and it wasn't our request */ 52362306a36Sopenharmony_ci tm->tei_m.printdebug(fi, 52462306a36Sopenharmony_ci "possible duplicate assignment tei %d", tei); 52562306a36Sopenharmony_ci mISDN_FsmEvent(&l2->tm->tei_m, EV_VERIFY, NULL); 52662306a36Sopenharmony_ci } 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci} 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_cistatic void 53162306a36Sopenharmony_citei_id_denied(struct FsmInst *fi, int event, void *arg) 53262306a36Sopenharmony_ci{ 53362306a36Sopenharmony_ci struct teimgr *tm = fi->userdata; 53462306a36Sopenharmony_ci u_char *dp = arg; 53562306a36Sopenharmony_ci int ri, tei; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci ri = ((unsigned int) *dp++ << 8); 53862306a36Sopenharmony_ci ri += *dp++; 53962306a36Sopenharmony_ci dp++; 54062306a36Sopenharmony_ci tei = *dp >> 1; 54162306a36Sopenharmony_ci if (*debug & DEBUG_L2_TEI) 54262306a36Sopenharmony_ci tm->tei_m.printdebug(fi, "identity denied ri %d tei %d", 54362306a36Sopenharmony_ci ri, tei); 54462306a36Sopenharmony_ci} 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_cistatic void 54762306a36Sopenharmony_citei_id_chk_req(struct FsmInst *fi, int event, void *arg) 54862306a36Sopenharmony_ci{ 54962306a36Sopenharmony_ci struct teimgr *tm = fi->userdata; 55062306a36Sopenharmony_ci u_char *dp = arg; 55162306a36Sopenharmony_ci int tei; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci tei = *(dp + 3) >> 1; 55462306a36Sopenharmony_ci if (*debug & DEBUG_L2_TEI) 55562306a36Sopenharmony_ci tm->tei_m.printdebug(fi, "identity check req tei %d", tei); 55662306a36Sopenharmony_ci if ((tm->l2->tei != GROUP_TEI) && ((tei == GROUP_TEI) || 55762306a36Sopenharmony_ci (tei == tm->l2->tei))) { 55862306a36Sopenharmony_ci mISDN_FsmDelTimer(&tm->timer, 4); 55962306a36Sopenharmony_ci mISDN_FsmChangeState(&tm->tei_m, ST_TEI_NOP); 56062306a36Sopenharmony_ci put_tei_msg(tm->mgr, ID_CHK_RES, random_ri(), tm->l2->tei); 56162306a36Sopenharmony_ci } 56262306a36Sopenharmony_ci} 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_cistatic void 56562306a36Sopenharmony_citei_id_remove(struct FsmInst *fi, int event, void *arg) 56662306a36Sopenharmony_ci{ 56762306a36Sopenharmony_ci struct teimgr *tm = fi->userdata; 56862306a36Sopenharmony_ci u_char *dp = arg; 56962306a36Sopenharmony_ci int tei; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci tei = *(dp + 3) >> 1; 57262306a36Sopenharmony_ci if (*debug & DEBUG_L2_TEI) 57362306a36Sopenharmony_ci tm->tei_m.printdebug(fi, "identity remove tei %d", tei); 57462306a36Sopenharmony_ci if ((tm->l2->tei != GROUP_TEI) && 57562306a36Sopenharmony_ci ((tei == GROUP_TEI) || (tei == tm->l2->tei))) { 57662306a36Sopenharmony_ci mISDN_FsmDelTimer(&tm->timer, 5); 57762306a36Sopenharmony_ci mISDN_FsmChangeState(&tm->tei_m, ST_TEI_NOP); 57862306a36Sopenharmony_ci tei_l2(tm->l2, MDL_REMOVE_REQ, 0); 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci} 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_cistatic void 58362306a36Sopenharmony_citei_id_verify(struct FsmInst *fi, int event, void *arg) 58462306a36Sopenharmony_ci{ 58562306a36Sopenharmony_ci struct teimgr *tm = fi->userdata; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci if (*debug & DEBUG_L2_TEI) 58862306a36Sopenharmony_ci tm->tei_m.printdebug(fi, "id verify request for tei %d", 58962306a36Sopenharmony_ci tm->l2->tei); 59062306a36Sopenharmony_ci put_tei_msg(tm->mgr, ID_VERIFY, 0, tm->l2->tei); 59162306a36Sopenharmony_ci mISDN_FsmChangeState(&tm->tei_m, ST_TEI_IDVERIFY); 59262306a36Sopenharmony_ci mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 2); 59362306a36Sopenharmony_ci tm->nval = 2; 59462306a36Sopenharmony_ci} 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_cistatic void 59762306a36Sopenharmony_citei_id_req_tout(struct FsmInst *fi, int event, void *arg) 59862306a36Sopenharmony_ci{ 59962306a36Sopenharmony_ci struct teimgr *tm = fi->userdata; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci if (--tm->nval) { 60262306a36Sopenharmony_ci tm->ri = random_ri(); 60362306a36Sopenharmony_ci if (*debug & DEBUG_L2_TEI) 60462306a36Sopenharmony_ci tm->tei_m.printdebug(fi, "assign req(%d) ri %d", 60562306a36Sopenharmony_ci 4 - tm->nval, tm->ri); 60662306a36Sopenharmony_ci put_tei_msg(tm->mgr, ID_REQUEST, tm->ri, GROUP_TEI); 60762306a36Sopenharmony_ci mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 3); 60862306a36Sopenharmony_ci } else { 60962306a36Sopenharmony_ci tm->tei_m.printdebug(fi, "assign req failed"); 61062306a36Sopenharmony_ci tei_l2(tm->l2, MDL_ERROR_RSP, 0); 61162306a36Sopenharmony_ci mISDN_FsmChangeState(fi, ST_TEI_NOP); 61262306a36Sopenharmony_ci } 61362306a36Sopenharmony_ci} 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_cistatic void 61662306a36Sopenharmony_citei_id_ver_tout(struct FsmInst *fi, int event, void *arg) 61762306a36Sopenharmony_ci{ 61862306a36Sopenharmony_ci struct teimgr *tm = fi->userdata; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci if (--tm->nval) { 62162306a36Sopenharmony_ci if (*debug & DEBUG_L2_TEI) 62262306a36Sopenharmony_ci tm->tei_m.printdebug(fi, 62362306a36Sopenharmony_ci "id verify req(%d) for tei %d", 62462306a36Sopenharmony_ci 3 - tm->nval, tm->l2->tei); 62562306a36Sopenharmony_ci put_tei_msg(tm->mgr, ID_VERIFY, 0, tm->l2->tei); 62662306a36Sopenharmony_ci mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 4); 62762306a36Sopenharmony_ci } else { 62862306a36Sopenharmony_ci tm->tei_m.printdebug(fi, "verify req for tei %d failed", 62962306a36Sopenharmony_ci tm->l2->tei); 63062306a36Sopenharmony_ci tei_l2(tm->l2, MDL_REMOVE_REQ, 0); 63162306a36Sopenharmony_ci mISDN_FsmChangeState(fi, ST_TEI_NOP); 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci} 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_cistatic struct FsmNode TeiFnListUser[] = 63662306a36Sopenharmony_ci{ 63762306a36Sopenharmony_ci {ST_TEI_NOP, EV_IDREQ, tei_id_request}, 63862306a36Sopenharmony_ci {ST_TEI_NOP, EV_ASSIGN, tei_id_test_dup}, 63962306a36Sopenharmony_ci {ST_TEI_NOP, EV_VERIFY, tei_id_verify}, 64062306a36Sopenharmony_ci {ST_TEI_NOP, EV_REMOVE, tei_id_remove}, 64162306a36Sopenharmony_ci {ST_TEI_NOP, EV_CHKREQ, tei_id_chk_req}, 64262306a36Sopenharmony_ci {ST_TEI_IDREQ, EV_TIMER, tei_id_req_tout}, 64362306a36Sopenharmony_ci {ST_TEI_IDREQ, EV_ASSIGN, tei_id_assign}, 64462306a36Sopenharmony_ci {ST_TEI_IDREQ, EV_DENIED, tei_id_denied}, 64562306a36Sopenharmony_ci {ST_TEI_IDVERIFY, EV_TIMER, tei_id_ver_tout}, 64662306a36Sopenharmony_ci {ST_TEI_IDVERIFY, EV_REMOVE, tei_id_remove}, 64762306a36Sopenharmony_ci {ST_TEI_IDVERIFY, EV_CHKREQ, tei_id_chk_req}, 64862306a36Sopenharmony_ci}; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_cistatic void 65162306a36Sopenharmony_citei_l2remove(struct layer2 *l2) 65262306a36Sopenharmony_ci{ 65362306a36Sopenharmony_ci put_tei_msg(l2->tm->mgr, ID_REMOVE, 0, l2->tei); 65462306a36Sopenharmony_ci tei_l2(l2, MDL_REMOVE_REQ, 0); 65562306a36Sopenharmony_ci list_del(&l2->ch.list); 65662306a36Sopenharmony_ci l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); 65762306a36Sopenharmony_ci} 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_cistatic void 66062306a36Sopenharmony_citei_assign_req(struct FsmInst *fi, int event, void *arg) 66162306a36Sopenharmony_ci{ 66262306a36Sopenharmony_ci struct teimgr *tm = fi->userdata; 66362306a36Sopenharmony_ci u_char *dp = arg; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci if (tm->l2->tei == GROUP_TEI) { 66662306a36Sopenharmony_ci tm->tei_m.printdebug(&tm->tei_m, 66762306a36Sopenharmony_ci "net tei assign request without tei"); 66862306a36Sopenharmony_ci return; 66962306a36Sopenharmony_ci } 67062306a36Sopenharmony_ci tm->ri = ((unsigned int) *dp++ << 8); 67162306a36Sopenharmony_ci tm->ri += *dp++; 67262306a36Sopenharmony_ci if (*debug & DEBUG_L2_TEI) 67362306a36Sopenharmony_ci tm->tei_m.printdebug(&tm->tei_m, 67462306a36Sopenharmony_ci "net assign request ri %d teim %d", tm->ri, *dp); 67562306a36Sopenharmony_ci put_tei_msg(tm->mgr, ID_ASSIGNED, tm->ri, tm->l2->tei); 67662306a36Sopenharmony_ci mISDN_FsmChangeState(fi, ST_TEI_NOP); 67762306a36Sopenharmony_ci} 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_cistatic void 68062306a36Sopenharmony_citei_id_chk_req_net(struct FsmInst *fi, int event, void *arg) 68162306a36Sopenharmony_ci{ 68262306a36Sopenharmony_ci struct teimgr *tm = fi->userdata; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci if (*debug & DEBUG_L2_TEI) 68562306a36Sopenharmony_ci tm->tei_m.printdebug(fi, "id check request for tei %d", 68662306a36Sopenharmony_ci tm->l2->tei); 68762306a36Sopenharmony_ci tm->rcnt = 0; 68862306a36Sopenharmony_ci put_tei_msg(tm->mgr, ID_CHK_REQ, 0, tm->l2->tei); 68962306a36Sopenharmony_ci mISDN_FsmChangeState(&tm->tei_m, ST_TEI_IDVERIFY); 69062306a36Sopenharmony_ci mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 2); 69162306a36Sopenharmony_ci tm->nval = 2; 69262306a36Sopenharmony_ci} 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_cistatic void 69562306a36Sopenharmony_citei_id_chk_resp(struct FsmInst *fi, int event, void *arg) 69662306a36Sopenharmony_ci{ 69762306a36Sopenharmony_ci struct teimgr *tm = fi->userdata; 69862306a36Sopenharmony_ci u_char *dp = arg; 69962306a36Sopenharmony_ci int tei; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci tei = dp[3] >> 1; 70262306a36Sopenharmony_ci if (*debug & DEBUG_L2_TEI) 70362306a36Sopenharmony_ci tm->tei_m.printdebug(fi, "identity check resp tei %d", tei); 70462306a36Sopenharmony_ci if (tei == tm->l2->tei) 70562306a36Sopenharmony_ci tm->rcnt++; 70662306a36Sopenharmony_ci} 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_cistatic void 70962306a36Sopenharmony_citei_id_verify_net(struct FsmInst *fi, int event, void *arg) 71062306a36Sopenharmony_ci{ 71162306a36Sopenharmony_ci struct teimgr *tm = fi->userdata; 71262306a36Sopenharmony_ci u_char *dp = arg; 71362306a36Sopenharmony_ci int tei; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci tei = dp[3] >> 1; 71662306a36Sopenharmony_ci if (*debug & DEBUG_L2_TEI) 71762306a36Sopenharmony_ci tm->tei_m.printdebug(fi, "identity verify req tei %d/%d", 71862306a36Sopenharmony_ci tei, tm->l2->tei); 71962306a36Sopenharmony_ci if (tei == tm->l2->tei) 72062306a36Sopenharmony_ci tei_id_chk_req_net(fi, event, arg); 72162306a36Sopenharmony_ci} 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_cistatic void 72462306a36Sopenharmony_citei_id_ver_tout_net(struct FsmInst *fi, int event, void *arg) 72562306a36Sopenharmony_ci{ 72662306a36Sopenharmony_ci struct teimgr *tm = fi->userdata; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci if (tm->rcnt == 1) { 72962306a36Sopenharmony_ci if (*debug & DEBUG_L2_TEI) 73062306a36Sopenharmony_ci tm->tei_m.printdebug(fi, 73162306a36Sopenharmony_ci "check req for tei %d successful\n", tm->l2->tei); 73262306a36Sopenharmony_ci mISDN_FsmChangeState(fi, ST_TEI_NOP); 73362306a36Sopenharmony_ci } else if (tm->rcnt > 1) { 73462306a36Sopenharmony_ci /* duplicate assignment; remove */ 73562306a36Sopenharmony_ci tei_l2remove(tm->l2); 73662306a36Sopenharmony_ci } else if (--tm->nval) { 73762306a36Sopenharmony_ci if (*debug & DEBUG_L2_TEI) 73862306a36Sopenharmony_ci tm->tei_m.printdebug(fi, 73962306a36Sopenharmony_ci "id check req(%d) for tei %d", 74062306a36Sopenharmony_ci 3 - tm->nval, tm->l2->tei); 74162306a36Sopenharmony_ci put_tei_msg(tm->mgr, ID_CHK_REQ, 0, tm->l2->tei); 74262306a36Sopenharmony_ci mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 4); 74362306a36Sopenharmony_ci } else { 74462306a36Sopenharmony_ci tm->tei_m.printdebug(fi, "check req for tei %d failed", 74562306a36Sopenharmony_ci tm->l2->tei); 74662306a36Sopenharmony_ci mISDN_FsmChangeState(fi, ST_TEI_NOP); 74762306a36Sopenharmony_ci tei_l2remove(tm->l2); 74862306a36Sopenharmony_ci } 74962306a36Sopenharmony_ci} 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_cistatic struct FsmNode TeiFnListNet[] = 75262306a36Sopenharmony_ci{ 75362306a36Sopenharmony_ci {ST_TEI_NOP, EV_ASSIGN_REQ, tei_assign_req}, 75462306a36Sopenharmony_ci {ST_TEI_NOP, EV_VERIFY, tei_id_verify_net}, 75562306a36Sopenharmony_ci {ST_TEI_NOP, EV_CHKREQ, tei_id_chk_req_net}, 75662306a36Sopenharmony_ci {ST_TEI_IDVERIFY, EV_TIMER, tei_id_ver_tout_net}, 75762306a36Sopenharmony_ci {ST_TEI_IDVERIFY, EV_CHKRESP, tei_id_chk_resp}, 75862306a36Sopenharmony_ci}; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_cistatic void 76162306a36Sopenharmony_citei_ph_data_ind(struct teimgr *tm, u_int mt, u_char *dp, int len) 76262306a36Sopenharmony_ci{ 76362306a36Sopenharmony_ci if (test_bit(FLG_FIXED_TEI, &tm->l2->flag)) 76462306a36Sopenharmony_ci return; 76562306a36Sopenharmony_ci if (*debug & DEBUG_L2_TEI) 76662306a36Sopenharmony_ci tm->tei_m.printdebug(&tm->tei_m, "tei handler mt %x", mt); 76762306a36Sopenharmony_ci if (mt == ID_ASSIGNED) 76862306a36Sopenharmony_ci mISDN_FsmEvent(&tm->tei_m, EV_ASSIGN, dp); 76962306a36Sopenharmony_ci else if (mt == ID_DENIED) 77062306a36Sopenharmony_ci mISDN_FsmEvent(&tm->tei_m, EV_DENIED, dp); 77162306a36Sopenharmony_ci else if (mt == ID_CHK_REQ) 77262306a36Sopenharmony_ci mISDN_FsmEvent(&tm->tei_m, EV_CHKREQ, dp); 77362306a36Sopenharmony_ci else if (mt == ID_REMOVE) 77462306a36Sopenharmony_ci mISDN_FsmEvent(&tm->tei_m, EV_REMOVE, dp); 77562306a36Sopenharmony_ci else if (mt == ID_VERIFY) 77662306a36Sopenharmony_ci mISDN_FsmEvent(&tm->tei_m, EV_VERIFY, dp); 77762306a36Sopenharmony_ci else if (mt == ID_CHK_RES) 77862306a36Sopenharmony_ci mISDN_FsmEvent(&tm->tei_m, EV_CHKRESP, dp); 77962306a36Sopenharmony_ci} 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_cistatic struct layer2 * 78262306a36Sopenharmony_cicreate_new_tei(struct manager *mgr, int tei, int sapi) 78362306a36Sopenharmony_ci{ 78462306a36Sopenharmony_ci unsigned long opt = 0; 78562306a36Sopenharmony_ci unsigned long flags; 78662306a36Sopenharmony_ci int id; 78762306a36Sopenharmony_ci struct layer2 *l2; 78862306a36Sopenharmony_ci struct channel_req rq; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci if (!mgr->up) 79162306a36Sopenharmony_ci return NULL; 79262306a36Sopenharmony_ci if ((tei >= 0) && (tei < 64)) 79362306a36Sopenharmony_ci test_and_set_bit(OPTION_L2_FIXEDTEI, &opt); 79462306a36Sopenharmony_ci if (mgr->ch.st->dev->Dprotocols & ((1 << ISDN_P_TE_E1) | 79562306a36Sopenharmony_ci (1 << ISDN_P_NT_E1))) { 79662306a36Sopenharmony_ci test_and_set_bit(OPTION_L2_PMX, &opt); 79762306a36Sopenharmony_ci rq.protocol = ISDN_P_NT_E1; 79862306a36Sopenharmony_ci } else { 79962306a36Sopenharmony_ci rq.protocol = ISDN_P_NT_S0; 80062306a36Sopenharmony_ci } 80162306a36Sopenharmony_ci l2 = create_l2(mgr->up, ISDN_P_LAPD_NT, opt, tei, sapi); 80262306a36Sopenharmony_ci if (!l2) { 80362306a36Sopenharmony_ci printk(KERN_WARNING "%s:no memory for layer2\n", __func__); 80462306a36Sopenharmony_ci return NULL; 80562306a36Sopenharmony_ci } 80662306a36Sopenharmony_ci l2->tm = kzalloc(sizeof(struct teimgr), GFP_KERNEL); 80762306a36Sopenharmony_ci if (!l2->tm) { 80862306a36Sopenharmony_ci kfree(l2); 80962306a36Sopenharmony_ci printk(KERN_WARNING "%s:no memory for teimgr\n", __func__); 81062306a36Sopenharmony_ci return NULL; 81162306a36Sopenharmony_ci } 81262306a36Sopenharmony_ci l2->tm->mgr = mgr; 81362306a36Sopenharmony_ci l2->tm->l2 = l2; 81462306a36Sopenharmony_ci l2->tm->tei_m.debug = *debug & DEBUG_L2_TEIFSM; 81562306a36Sopenharmony_ci l2->tm->tei_m.userdata = l2->tm; 81662306a36Sopenharmony_ci l2->tm->tei_m.printdebug = tei_debug; 81762306a36Sopenharmony_ci l2->tm->tei_m.fsm = &teifsmn; 81862306a36Sopenharmony_ci l2->tm->tei_m.state = ST_TEI_NOP; 81962306a36Sopenharmony_ci l2->tm->tval = 2000; /* T202 2 sec */ 82062306a36Sopenharmony_ci mISDN_FsmInitTimer(&l2->tm->tei_m, &l2->tm->timer); 82162306a36Sopenharmony_ci write_lock_irqsave(&mgr->lock, flags); 82262306a36Sopenharmony_ci id = get_free_id(mgr); 82362306a36Sopenharmony_ci list_add_tail(&l2->list, &mgr->layer2); 82462306a36Sopenharmony_ci write_unlock_irqrestore(&mgr->lock, flags); 82562306a36Sopenharmony_ci if (id < 0) { 82662306a36Sopenharmony_ci l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); 82762306a36Sopenharmony_ci printk(KERN_WARNING "%s:no free id\n", __func__); 82862306a36Sopenharmony_ci return NULL; 82962306a36Sopenharmony_ci } else { 83062306a36Sopenharmony_ci l2->ch.nr = id; 83162306a36Sopenharmony_ci __add_layer2(&l2->ch, mgr->ch.st); 83262306a36Sopenharmony_ci l2->ch.recv = mgr->ch.recv; 83362306a36Sopenharmony_ci l2->ch.peer = mgr->ch.peer; 83462306a36Sopenharmony_ci l2->ch.ctrl(&l2->ch, OPEN_CHANNEL, NULL); 83562306a36Sopenharmony_ci /* We need open here L1 for the manager as well (refcounting) */ 83662306a36Sopenharmony_ci rq.adr.dev = mgr->ch.st->dev->id; 83762306a36Sopenharmony_ci id = mgr->ch.st->own.ctrl(&mgr->ch.st->own, OPEN_CHANNEL, &rq); 83862306a36Sopenharmony_ci if (id < 0) { 83962306a36Sopenharmony_ci printk(KERN_WARNING "%s: cannot open L1\n", __func__); 84062306a36Sopenharmony_ci l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); 84162306a36Sopenharmony_ci l2 = NULL; 84262306a36Sopenharmony_ci } 84362306a36Sopenharmony_ci } 84462306a36Sopenharmony_ci return l2; 84562306a36Sopenharmony_ci} 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_cistatic void 84862306a36Sopenharmony_cinew_tei_req(struct manager *mgr, u_char *dp) 84962306a36Sopenharmony_ci{ 85062306a36Sopenharmony_ci int tei, ri; 85162306a36Sopenharmony_ci struct layer2 *l2; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci ri = dp[0] << 8; 85462306a36Sopenharmony_ci ri += dp[1]; 85562306a36Sopenharmony_ci if (!mgr->up) 85662306a36Sopenharmony_ci goto denied; 85762306a36Sopenharmony_ci if (!(dp[3] & 1)) /* Extension bit != 1 */ 85862306a36Sopenharmony_ci goto denied; 85962306a36Sopenharmony_ci if (dp[3] != 0xff) 86062306a36Sopenharmony_ci tei = dp[3] >> 1; /* 3GPP TS 08.56 6.1.11.2 */ 86162306a36Sopenharmony_ci else 86262306a36Sopenharmony_ci tei = get_free_tei(mgr); 86362306a36Sopenharmony_ci if (tei < 0) { 86462306a36Sopenharmony_ci printk(KERN_WARNING "%s:No free tei\n", __func__); 86562306a36Sopenharmony_ci goto denied; 86662306a36Sopenharmony_ci } 86762306a36Sopenharmony_ci l2 = create_new_tei(mgr, tei, CTRL_SAPI); 86862306a36Sopenharmony_ci if (!l2) 86962306a36Sopenharmony_ci goto denied; 87062306a36Sopenharmony_ci else 87162306a36Sopenharmony_ci mISDN_FsmEvent(&l2->tm->tei_m, EV_ASSIGN_REQ, dp); 87262306a36Sopenharmony_ci return; 87362306a36Sopenharmony_cidenied: 87462306a36Sopenharmony_ci put_tei_msg(mgr, ID_DENIED, ri, GROUP_TEI); 87562306a36Sopenharmony_ci} 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_cistatic int 87862306a36Sopenharmony_ciph_data_ind(struct manager *mgr, struct sk_buff *skb) 87962306a36Sopenharmony_ci{ 88062306a36Sopenharmony_ci int ret = -EINVAL; 88162306a36Sopenharmony_ci struct layer2 *l2, *nl2; 88262306a36Sopenharmony_ci u_char mt; 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci if (skb->len < 8) { 88562306a36Sopenharmony_ci if (*debug & DEBUG_L2_TEI) 88662306a36Sopenharmony_ci printk(KERN_DEBUG "%s: short mgr frame %d/8\n", 88762306a36Sopenharmony_ci __func__, skb->len); 88862306a36Sopenharmony_ci goto done; 88962306a36Sopenharmony_ci } 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci if ((skb->data[0] >> 2) != TEI_SAPI) /* not for us */ 89262306a36Sopenharmony_ci goto done; 89362306a36Sopenharmony_ci if (skb->data[0] & 1) /* EA0 formal error */ 89462306a36Sopenharmony_ci goto done; 89562306a36Sopenharmony_ci if (!(skb->data[1] & 1)) /* EA1 formal error */ 89662306a36Sopenharmony_ci goto done; 89762306a36Sopenharmony_ci if ((skb->data[1] >> 1) != GROUP_TEI) /* not for us */ 89862306a36Sopenharmony_ci goto done; 89962306a36Sopenharmony_ci if ((skb->data[2] & 0xef) != UI) /* not UI */ 90062306a36Sopenharmony_ci goto done; 90162306a36Sopenharmony_ci if (skb->data[3] != TEI_ENTITY_ID) /* not tei entity */ 90262306a36Sopenharmony_ci goto done; 90362306a36Sopenharmony_ci mt = skb->data[6]; 90462306a36Sopenharmony_ci switch (mt) { 90562306a36Sopenharmony_ci case ID_REQUEST: 90662306a36Sopenharmony_ci case ID_CHK_RES: 90762306a36Sopenharmony_ci case ID_VERIFY: 90862306a36Sopenharmony_ci if (!test_bit(MGR_OPT_NETWORK, &mgr->options)) 90962306a36Sopenharmony_ci goto done; 91062306a36Sopenharmony_ci break; 91162306a36Sopenharmony_ci case ID_ASSIGNED: 91262306a36Sopenharmony_ci case ID_DENIED: 91362306a36Sopenharmony_ci case ID_CHK_REQ: 91462306a36Sopenharmony_ci case ID_REMOVE: 91562306a36Sopenharmony_ci if (test_bit(MGR_OPT_NETWORK, &mgr->options)) 91662306a36Sopenharmony_ci goto done; 91762306a36Sopenharmony_ci break; 91862306a36Sopenharmony_ci default: 91962306a36Sopenharmony_ci goto done; 92062306a36Sopenharmony_ci } 92162306a36Sopenharmony_ci ret = 0; 92262306a36Sopenharmony_ci if (mt == ID_REQUEST) { 92362306a36Sopenharmony_ci new_tei_req(mgr, &skb->data[4]); 92462306a36Sopenharmony_ci goto done; 92562306a36Sopenharmony_ci } 92662306a36Sopenharmony_ci list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) { 92762306a36Sopenharmony_ci tei_ph_data_ind(l2->tm, mt, &skb->data[4], skb->len - 4); 92862306a36Sopenharmony_ci } 92962306a36Sopenharmony_cidone: 93062306a36Sopenharmony_ci return ret; 93162306a36Sopenharmony_ci} 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ciint 93462306a36Sopenharmony_cil2_tei(struct layer2 *l2, u_int cmd, u_long arg) 93562306a36Sopenharmony_ci{ 93662306a36Sopenharmony_ci struct teimgr *tm = l2->tm; 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci if (test_bit(FLG_FIXED_TEI, &l2->flag)) 93962306a36Sopenharmony_ci return 0; 94062306a36Sopenharmony_ci if (*debug & DEBUG_L2_TEI) 94162306a36Sopenharmony_ci printk(KERN_DEBUG "%s: cmd(%x)\n", __func__, cmd); 94262306a36Sopenharmony_ci switch (cmd) { 94362306a36Sopenharmony_ci case MDL_ASSIGN_IND: 94462306a36Sopenharmony_ci mISDN_FsmEvent(&tm->tei_m, EV_IDREQ, NULL); 94562306a36Sopenharmony_ci break; 94662306a36Sopenharmony_ci case MDL_ERROR_IND: 94762306a36Sopenharmony_ci if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options)) 94862306a36Sopenharmony_ci mISDN_FsmEvent(&tm->tei_m, EV_CHKREQ, &l2->tei); 94962306a36Sopenharmony_ci if (test_bit(MGR_OPT_USER, &tm->mgr->options)) 95062306a36Sopenharmony_ci mISDN_FsmEvent(&tm->tei_m, EV_VERIFY, NULL); 95162306a36Sopenharmony_ci break; 95262306a36Sopenharmony_ci case MDL_STATUS_UP_IND: 95362306a36Sopenharmony_ci if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options)) 95462306a36Sopenharmony_ci mISDN_FsmEvent(&tm->mgr->deact, EV_ACTIVATE, NULL); 95562306a36Sopenharmony_ci break; 95662306a36Sopenharmony_ci case MDL_STATUS_DOWN_IND: 95762306a36Sopenharmony_ci if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options)) 95862306a36Sopenharmony_ci mISDN_FsmEvent(&tm->mgr->deact, EV_DEACTIVATE, NULL); 95962306a36Sopenharmony_ci break; 96062306a36Sopenharmony_ci case MDL_STATUS_UI_IND: 96162306a36Sopenharmony_ci if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options)) 96262306a36Sopenharmony_ci mISDN_FsmEvent(&tm->mgr->deact, EV_UI, NULL); 96362306a36Sopenharmony_ci break; 96462306a36Sopenharmony_ci } 96562306a36Sopenharmony_ci return 0; 96662306a36Sopenharmony_ci} 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_civoid 96962306a36Sopenharmony_ciTEIrelease(struct layer2 *l2) 97062306a36Sopenharmony_ci{ 97162306a36Sopenharmony_ci struct teimgr *tm = l2->tm; 97262306a36Sopenharmony_ci u_long flags; 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci mISDN_FsmDelTimer(&tm->timer, 1); 97562306a36Sopenharmony_ci write_lock_irqsave(&tm->mgr->lock, flags); 97662306a36Sopenharmony_ci list_del(&l2->list); 97762306a36Sopenharmony_ci write_unlock_irqrestore(&tm->mgr->lock, flags); 97862306a36Sopenharmony_ci l2->tm = NULL; 97962306a36Sopenharmony_ci kfree(tm); 98062306a36Sopenharmony_ci} 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_cistatic int 98362306a36Sopenharmony_cicreate_teimgr(struct manager *mgr, struct channel_req *crq) 98462306a36Sopenharmony_ci{ 98562306a36Sopenharmony_ci struct layer2 *l2; 98662306a36Sopenharmony_ci unsigned long opt = 0; 98762306a36Sopenharmony_ci unsigned long flags; 98862306a36Sopenharmony_ci int id; 98962306a36Sopenharmony_ci struct channel_req l1rq; 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci if (*debug & DEBUG_L2_TEI) 99262306a36Sopenharmony_ci printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n", 99362306a36Sopenharmony_ci __func__, dev_name(&mgr->ch.st->dev->dev), 99462306a36Sopenharmony_ci crq->protocol, crq->adr.dev, crq->adr.channel, 99562306a36Sopenharmony_ci crq->adr.sapi, crq->adr.tei); 99662306a36Sopenharmony_ci if (crq->adr.tei > GROUP_TEI) 99762306a36Sopenharmony_ci return -EINVAL; 99862306a36Sopenharmony_ci if (crq->adr.tei < 64) 99962306a36Sopenharmony_ci test_and_set_bit(OPTION_L2_FIXEDTEI, &opt); 100062306a36Sopenharmony_ci if (crq->adr.tei == 0) 100162306a36Sopenharmony_ci test_and_set_bit(OPTION_L2_PTP, &opt); 100262306a36Sopenharmony_ci if (test_bit(MGR_OPT_NETWORK, &mgr->options)) { 100362306a36Sopenharmony_ci if (crq->protocol == ISDN_P_LAPD_TE) 100462306a36Sopenharmony_ci return -EPROTONOSUPPORT; 100562306a36Sopenharmony_ci if ((crq->adr.tei != 0) && (crq->adr.tei != 127)) 100662306a36Sopenharmony_ci return -EINVAL; 100762306a36Sopenharmony_ci if (mgr->up) { 100862306a36Sopenharmony_ci printk(KERN_WARNING 100962306a36Sopenharmony_ci "%s: only one network manager is allowed\n", 101062306a36Sopenharmony_ci __func__); 101162306a36Sopenharmony_ci return -EBUSY; 101262306a36Sopenharmony_ci } 101362306a36Sopenharmony_ci } else if (test_bit(MGR_OPT_USER, &mgr->options)) { 101462306a36Sopenharmony_ci if (crq->protocol == ISDN_P_LAPD_NT) 101562306a36Sopenharmony_ci return -EPROTONOSUPPORT; 101662306a36Sopenharmony_ci if ((crq->adr.tei >= 64) && (crq->adr.tei < GROUP_TEI)) 101762306a36Sopenharmony_ci return -EINVAL; /* dyn tei */ 101862306a36Sopenharmony_ci } else { 101962306a36Sopenharmony_ci if (crq->protocol == ISDN_P_LAPD_NT) 102062306a36Sopenharmony_ci test_and_set_bit(MGR_OPT_NETWORK, &mgr->options); 102162306a36Sopenharmony_ci if (crq->protocol == ISDN_P_LAPD_TE) 102262306a36Sopenharmony_ci test_and_set_bit(MGR_OPT_USER, &mgr->options); 102362306a36Sopenharmony_ci } 102462306a36Sopenharmony_ci l1rq.adr = crq->adr; 102562306a36Sopenharmony_ci if (mgr->ch.st->dev->Dprotocols 102662306a36Sopenharmony_ci & ((1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1))) 102762306a36Sopenharmony_ci test_and_set_bit(OPTION_L2_PMX, &opt); 102862306a36Sopenharmony_ci if ((crq->protocol == ISDN_P_LAPD_NT) && (crq->adr.tei == 127)) { 102962306a36Sopenharmony_ci mgr->up = crq->ch; 103062306a36Sopenharmony_ci id = DL_INFO_L2_CONNECT; 103162306a36Sopenharmony_ci teiup_create(mgr, DL_INFORMATION_IND, sizeof(id), &id); 103262306a36Sopenharmony_ci if (test_bit(MGR_PH_ACTIVE, &mgr->options)) 103362306a36Sopenharmony_ci teiup_create(mgr, PH_ACTIVATE_IND, 0, NULL); 103462306a36Sopenharmony_ci crq->ch = NULL; 103562306a36Sopenharmony_ci if (!list_empty(&mgr->layer2)) { 103662306a36Sopenharmony_ci read_lock_irqsave(&mgr->lock, flags); 103762306a36Sopenharmony_ci list_for_each_entry(l2, &mgr->layer2, list) { 103862306a36Sopenharmony_ci l2->up = mgr->up; 103962306a36Sopenharmony_ci l2->ch.ctrl(&l2->ch, OPEN_CHANNEL, NULL); 104062306a36Sopenharmony_ci } 104162306a36Sopenharmony_ci read_unlock_irqrestore(&mgr->lock, flags); 104262306a36Sopenharmony_ci } 104362306a36Sopenharmony_ci return 0; 104462306a36Sopenharmony_ci } 104562306a36Sopenharmony_ci l2 = create_l2(crq->ch, crq->protocol, opt, 104662306a36Sopenharmony_ci crq->adr.tei, crq->adr.sapi); 104762306a36Sopenharmony_ci if (!l2) 104862306a36Sopenharmony_ci return -ENOMEM; 104962306a36Sopenharmony_ci l2->tm = kzalloc(sizeof(struct teimgr), GFP_KERNEL); 105062306a36Sopenharmony_ci if (!l2->tm) { 105162306a36Sopenharmony_ci kfree(l2); 105262306a36Sopenharmony_ci printk(KERN_ERR "kmalloc teimgr failed\n"); 105362306a36Sopenharmony_ci return -ENOMEM; 105462306a36Sopenharmony_ci } 105562306a36Sopenharmony_ci l2->tm->mgr = mgr; 105662306a36Sopenharmony_ci l2->tm->l2 = l2; 105762306a36Sopenharmony_ci l2->tm->tei_m.debug = *debug & DEBUG_L2_TEIFSM; 105862306a36Sopenharmony_ci l2->tm->tei_m.userdata = l2->tm; 105962306a36Sopenharmony_ci l2->tm->tei_m.printdebug = tei_debug; 106062306a36Sopenharmony_ci if (crq->protocol == ISDN_P_LAPD_TE) { 106162306a36Sopenharmony_ci l2->tm->tei_m.fsm = &teifsmu; 106262306a36Sopenharmony_ci l2->tm->tei_m.state = ST_TEI_NOP; 106362306a36Sopenharmony_ci l2->tm->tval = 1000; /* T201 1 sec */ 106462306a36Sopenharmony_ci if (test_bit(OPTION_L2_PMX, &opt)) 106562306a36Sopenharmony_ci l1rq.protocol = ISDN_P_TE_E1; 106662306a36Sopenharmony_ci else 106762306a36Sopenharmony_ci l1rq.protocol = ISDN_P_TE_S0; 106862306a36Sopenharmony_ci } else { 106962306a36Sopenharmony_ci l2->tm->tei_m.fsm = &teifsmn; 107062306a36Sopenharmony_ci l2->tm->tei_m.state = ST_TEI_NOP; 107162306a36Sopenharmony_ci l2->tm->tval = 2000; /* T202 2 sec */ 107262306a36Sopenharmony_ci if (test_bit(OPTION_L2_PMX, &opt)) 107362306a36Sopenharmony_ci l1rq.protocol = ISDN_P_NT_E1; 107462306a36Sopenharmony_ci else 107562306a36Sopenharmony_ci l1rq.protocol = ISDN_P_NT_S0; 107662306a36Sopenharmony_ci } 107762306a36Sopenharmony_ci mISDN_FsmInitTimer(&l2->tm->tei_m, &l2->tm->timer); 107862306a36Sopenharmony_ci write_lock_irqsave(&mgr->lock, flags); 107962306a36Sopenharmony_ci id = get_free_id(mgr); 108062306a36Sopenharmony_ci list_add_tail(&l2->list, &mgr->layer2); 108162306a36Sopenharmony_ci write_unlock_irqrestore(&mgr->lock, flags); 108262306a36Sopenharmony_ci if (id >= 0) { 108362306a36Sopenharmony_ci l2->ch.nr = id; 108462306a36Sopenharmony_ci l2->up->nr = id; 108562306a36Sopenharmony_ci crq->ch = &l2->ch; 108662306a36Sopenharmony_ci /* We need open here L1 for the manager as well (refcounting) */ 108762306a36Sopenharmony_ci id = mgr->ch.st->own.ctrl(&mgr->ch.st->own, OPEN_CHANNEL, 108862306a36Sopenharmony_ci &l1rq); 108962306a36Sopenharmony_ci } 109062306a36Sopenharmony_ci if (id < 0) 109162306a36Sopenharmony_ci l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); 109262306a36Sopenharmony_ci return id; 109362306a36Sopenharmony_ci} 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_cistatic int 109662306a36Sopenharmony_cimgr_send(struct mISDNchannel *ch, struct sk_buff *skb) 109762306a36Sopenharmony_ci{ 109862306a36Sopenharmony_ci struct manager *mgr; 109962306a36Sopenharmony_ci struct mISDNhead *hh = mISDN_HEAD_P(skb); 110062306a36Sopenharmony_ci int ret = -EINVAL; 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci mgr = container_of(ch, struct manager, ch); 110362306a36Sopenharmony_ci if (*debug & DEBUG_L2_RECV) 110462306a36Sopenharmony_ci printk(KERN_DEBUG "%s: prim(%x) id(%x)\n", 110562306a36Sopenharmony_ci __func__, hh->prim, hh->id); 110662306a36Sopenharmony_ci switch (hh->prim) { 110762306a36Sopenharmony_ci case PH_DATA_IND: 110862306a36Sopenharmony_ci mISDN_FsmEvent(&mgr->deact, EV_UI, NULL); 110962306a36Sopenharmony_ci ret = ph_data_ind(mgr, skb); 111062306a36Sopenharmony_ci break; 111162306a36Sopenharmony_ci case PH_DATA_CNF: 111262306a36Sopenharmony_ci do_ack(mgr, hh->id); 111362306a36Sopenharmony_ci ret = 0; 111462306a36Sopenharmony_ci break; 111562306a36Sopenharmony_ci case PH_ACTIVATE_IND: 111662306a36Sopenharmony_ci test_and_set_bit(MGR_PH_ACTIVE, &mgr->options); 111762306a36Sopenharmony_ci if (mgr->up) 111862306a36Sopenharmony_ci teiup_create(mgr, PH_ACTIVATE_IND, 0, NULL); 111962306a36Sopenharmony_ci mISDN_FsmEvent(&mgr->deact, EV_ACTIVATE_IND, NULL); 112062306a36Sopenharmony_ci do_send(mgr); 112162306a36Sopenharmony_ci ret = 0; 112262306a36Sopenharmony_ci break; 112362306a36Sopenharmony_ci case PH_DEACTIVATE_IND: 112462306a36Sopenharmony_ci test_and_clear_bit(MGR_PH_ACTIVE, &mgr->options); 112562306a36Sopenharmony_ci if (mgr->up) 112662306a36Sopenharmony_ci teiup_create(mgr, PH_DEACTIVATE_IND, 0, NULL); 112762306a36Sopenharmony_ci mISDN_FsmEvent(&mgr->deact, EV_DEACTIVATE_IND, NULL); 112862306a36Sopenharmony_ci ret = 0; 112962306a36Sopenharmony_ci break; 113062306a36Sopenharmony_ci case DL_UNITDATA_REQ: 113162306a36Sopenharmony_ci return dl_unit_data(mgr, skb); 113262306a36Sopenharmony_ci } 113362306a36Sopenharmony_ci if (!ret) 113462306a36Sopenharmony_ci dev_kfree_skb(skb); 113562306a36Sopenharmony_ci return ret; 113662306a36Sopenharmony_ci} 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_cistatic int 113962306a36Sopenharmony_cifree_teimanager(struct manager *mgr) 114062306a36Sopenharmony_ci{ 114162306a36Sopenharmony_ci struct layer2 *l2, *nl2; 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci test_and_clear_bit(OPTION_L1_HOLD, &mgr->options); 114462306a36Sopenharmony_ci if (test_bit(MGR_OPT_NETWORK, &mgr->options)) { 114562306a36Sopenharmony_ci /* not locked lock is taken in release tei */ 114662306a36Sopenharmony_ci mgr->up = NULL; 114762306a36Sopenharmony_ci if (test_bit(OPTION_L2_CLEANUP, &mgr->options)) { 114862306a36Sopenharmony_ci list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) { 114962306a36Sopenharmony_ci put_tei_msg(mgr, ID_REMOVE, 0, l2->tei); 115062306a36Sopenharmony_ci mutex_lock(&mgr->ch.st->lmutex); 115162306a36Sopenharmony_ci list_del(&l2->ch.list); 115262306a36Sopenharmony_ci mutex_unlock(&mgr->ch.st->lmutex); 115362306a36Sopenharmony_ci l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); 115462306a36Sopenharmony_ci } 115562306a36Sopenharmony_ci test_and_clear_bit(MGR_OPT_NETWORK, &mgr->options); 115662306a36Sopenharmony_ci } else { 115762306a36Sopenharmony_ci list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) { 115862306a36Sopenharmony_ci l2->up = NULL; 115962306a36Sopenharmony_ci } 116062306a36Sopenharmony_ci } 116162306a36Sopenharmony_ci } 116262306a36Sopenharmony_ci if (test_bit(MGR_OPT_USER, &mgr->options)) { 116362306a36Sopenharmony_ci if (list_empty(&mgr->layer2)) 116462306a36Sopenharmony_ci test_and_clear_bit(MGR_OPT_USER, &mgr->options); 116562306a36Sopenharmony_ci } 116662306a36Sopenharmony_ci mgr->ch.st->dev->D.ctrl(&mgr->ch.st->dev->D, CLOSE_CHANNEL, NULL); 116762306a36Sopenharmony_ci return 0; 116862306a36Sopenharmony_ci} 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_cistatic int 117162306a36Sopenharmony_cictrl_teimanager(struct manager *mgr, void *arg) 117262306a36Sopenharmony_ci{ 117362306a36Sopenharmony_ci /* currently we only have one option */ 117462306a36Sopenharmony_ci unsigned int *val = (unsigned int *)arg; 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci switch (val[0]) { 117762306a36Sopenharmony_ci case IMCLEAR_L2: 117862306a36Sopenharmony_ci if (val[1]) 117962306a36Sopenharmony_ci test_and_set_bit(OPTION_L2_CLEANUP, &mgr->options); 118062306a36Sopenharmony_ci else 118162306a36Sopenharmony_ci test_and_clear_bit(OPTION_L2_CLEANUP, &mgr->options); 118262306a36Sopenharmony_ci break; 118362306a36Sopenharmony_ci case IMHOLD_L1: 118462306a36Sopenharmony_ci if (val[1]) 118562306a36Sopenharmony_ci test_and_set_bit(OPTION_L1_HOLD, &mgr->options); 118662306a36Sopenharmony_ci else 118762306a36Sopenharmony_ci test_and_clear_bit(OPTION_L1_HOLD, &mgr->options); 118862306a36Sopenharmony_ci break; 118962306a36Sopenharmony_ci default: 119062306a36Sopenharmony_ci return -EINVAL; 119162306a36Sopenharmony_ci } 119262306a36Sopenharmony_ci return 0; 119362306a36Sopenharmony_ci} 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci/* This function does create a L2 for fixed TEI in NT Mode */ 119662306a36Sopenharmony_cistatic int 119762306a36Sopenharmony_cicheck_data(struct manager *mgr, struct sk_buff *skb) 119862306a36Sopenharmony_ci{ 119962306a36Sopenharmony_ci struct mISDNhead *hh = mISDN_HEAD_P(skb); 120062306a36Sopenharmony_ci int ret, tei, sapi; 120162306a36Sopenharmony_ci struct layer2 *l2; 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci if (*debug & DEBUG_L2_CTRL) 120462306a36Sopenharmony_ci printk(KERN_DEBUG "%s: prim(%x) id(%x)\n", 120562306a36Sopenharmony_ci __func__, hh->prim, hh->id); 120662306a36Sopenharmony_ci if (test_bit(MGR_OPT_USER, &mgr->options)) 120762306a36Sopenharmony_ci return -ENOTCONN; 120862306a36Sopenharmony_ci if (hh->prim != PH_DATA_IND) 120962306a36Sopenharmony_ci return -ENOTCONN; 121062306a36Sopenharmony_ci if (skb->len != 3) 121162306a36Sopenharmony_ci return -ENOTCONN; 121262306a36Sopenharmony_ci if (skb->data[0] & 3) /* EA0 and CR must be 0 */ 121362306a36Sopenharmony_ci return -EINVAL; 121462306a36Sopenharmony_ci sapi = skb->data[0] >> 2; 121562306a36Sopenharmony_ci if (!(skb->data[1] & 1)) /* invalid EA1 */ 121662306a36Sopenharmony_ci return -EINVAL; 121762306a36Sopenharmony_ci tei = skb->data[1] >> 1; 121862306a36Sopenharmony_ci if (tei > 63) /* not a fixed tei */ 121962306a36Sopenharmony_ci return -ENOTCONN; 122062306a36Sopenharmony_ci if ((skb->data[2] & ~0x10) != SABME) 122162306a36Sopenharmony_ci return -ENOTCONN; 122262306a36Sopenharmony_ci /* We got a SABME for a fixed TEI */ 122362306a36Sopenharmony_ci if (*debug & DEBUG_L2_CTRL) 122462306a36Sopenharmony_ci printk(KERN_DEBUG "%s: SABME sapi(%d) tei(%d)\n", 122562306a36Sopenharmony_ci __func__, sapi, tei); 122662306a36Sopenharmony_ci l2 = create_new_tei(mgr, tei, sapi); 122762306a36Sopenharmony_ci if (!l2) { 122862306a36Sopenharmony_ci if (*debug & DEBUG_L2_CTRL) 122962306a36Sopenharmony_ci printk(KERN_DEBUG "%s: failed to create new tei\n", 123062306a36Sopenharmony_ci __func__); 123162306a36Sopenharmony_ci return -ENOMEM; 123262306a36Sopenharmony_ci } 123362306a36Sopenharmony_ci ret = l2->ch.send(&l2->ch, skb); 123462306a36Sopenharmony_ci return ret; 123562306a36Sopenharmony_ci} 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_civoid 123862306a36Sopenharmony_cidelete_teimanager(struct mISDNchannel *ch) 123962306a36Sopenharmony_ci{ 124062306a36Sopenharmony_ci struct manager *mgr; 124162306a36Sopenharmony_ci struct layer2 *l2, *nl2; 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci mgr = container_of(ch, struct manager, ch); 124462306a36Sopenharmony_ci /* not locked lock is taken in release tei */ 124562306a36Sopenharmony_ci list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) { 124662306a36Sopenharmony_ci mutex_lock(&mgr->ch.st->lmutex); 124762306a36Sopenharmony_ci list_del(&l2->ch.list); 124862306a36Sopenharmony_ci mutex_unlock(&mgr->ch.st->lmutex); 124962306a36Sopenharmony_ci l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); 125062306a36Sopenharmony_ci } 125162306a36Sopenharmony_ci list_del(&mgr->ch.list); 125262306a36Sopenharmony_ci list_del(&mgr->bcast.list); 125362306a36Sopenharmony_ci skb_queue_purge(&mgr->sendq); 125462306a36Sopenharmony_ci kfree(mgr); 125562306a36Sopenharmony_ci} 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_cistatic int 125862306a36Sopenharmony_cimgr_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) 125962306a36Sopenharmony_ci{ 126062306a36Sopenharmony_ci struct manager *mgr; 126162306a36Sopenharmony_ci int ret = -EINVAL; 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci mgr = container_of(ch, struct manager, ch); 126462306a36Sopenharmony_ci if (*debug & DEBUG_L2_CTRL) 126562306a36Sopenharmony_ci printk(KERN_DEBUG "%s(%x, %p)\n", __func__, cmd, arg); 126662306a36Sopenharmony_ci switch (cmd) { 126762306a36Sopenharmony_ci case OPEN_CHANNEL: 126862306a36Sopenharmony_ci ret = create_teimgr(mgr, arg); 126962306a36Sopenharmony_ci break; 127062306a36Sopenharmony_ci case CLOSE_CHANNEL: 127162306a36Sopenharmony_ci ret = free_teimanager(mgr); 127262306a36Sopenharmony_ci break; 127362306a36Sopenharmony_ci case CONTROL_CHANNEL: 127462306a36Sopenharmony_ci ret = ctrl_teimanager(mgr, arg); 127562306a36Sopenharmony_ci break; 127662306a36Sopenharmony_ci case CHECK_DATA: 127762306a36Sopenharmony_ci ret = check_data(mgr, arg); 127862306a36Sopenharmony_ci break; 127962306a36Sopenharmony_ci } 128062306a36Sopenharmony_ci return ret; 128162306a36Sopenharmony_ci} 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_cistatic int 128462306a36Sopenharmony_cimgr_bcast(struct mISDNchannel *ch, struct sk_buff *skb) 128562306a36Sopenharmony_ci{ 128662306a36Sopenharmony_ci struct manager *mgr = container_of(ch, struct manager, bcast); 128762306a36Sopenharmony_ci struct mISDNhead *hhc, *hh = mISDN_HEAD_P(skb); 128862306a36Sopenharmony_ci struct sk_buff *cskb = NULL; 128962306a36Sopenharmony_ci struct layer2 *l2; 129062306a36Sopenharmony_ci u_long flags; 129162306a36Sopenharmony_ci int ret; 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci read_lock_irqsave(&mgr->lock, flags); 129462306a36Sopenharmony_ci list_for_each_entry(l2, &mgr->layer2, list) { 129562306a36Sopenharmony_ci if ((hh->id & MISDN_ID_SAPI_MASK) == 129662306a36Sopenharmony_ci (l2->ch.addr & MISDN_ID_SAPI_MASK)) { 129762306a36Sopenharmony_ci if (list_is_last(&l2->list, &mgr->layer2)) { 129862306a36Sopenharmony_ci cskb = skb; 129962306a36Sopenharmony_ci skb = NULL; 130062306a36Sopenharmony_ci } else { 130162306a36Sopenharmony_ci if (!cskb) 130262306a36Sopenharmony_ci cskb = skb_copy(skb, GFP_ATOMIC); 130362306a36Sopenharmony_ci } 130462306a36Sopenharmony_ci if (cskb) { 130562306a36Sopenharmony_ci hhc = mISDN_HEAD_P(cskb); 130662306a36Sopenharmony_ci /* save original header behind normal header */ 130762306a36Sopenharmony_ci hhc++; 130862306a36Sopenharmony_ci *hhc = *hh; 130962306a36Sopenharmony_ci hhc--; 131062306a36Sopenharmony_ci hhc->prim = DL_INTERN_MSG; 131162306a36Sopenharmony_ci hhc->id = l2->ch.nr; 131262306a36Sopenharmony_ci ret = ch->st->own.recv(&ch->st->own, cskb); 131362306a36Sopenharmony_ci if (ret) { 131462306a36Sopenharmony_ci if (*debug & DEBUG_SEND_ERR) 131562306a36Sopenharmony_ci printk(KERN_DEBUG 131662306a36Sopenharmony_ci "%s ch%d prim(%x) addr(%x)" 131762306a36Sopenharmony_ci " err %d\n", 131862306a36Sopenharmony_ci __func__, l2->ch.nr, 131962306a36Sopenharmony_ci hh->prim, l2->ch.addr, ret); 132062306a36Sopenharmony_ci } else 132162306a36Sopenharmony_ci cskb = NULL; 132262306a36Sopenharmony_ci } else { 132362306a36Sopenharmony_ci printk(KERN_WARNING "%s ch%d addr %x no mem\n", 132462306a36Sopenharmony_ci __func__, ch->nr, ch->addr); 132562306a36Sopenharmony_ci goto out; 132662306a36Sopenharmony_ci } 132762306a36Sopenharmony_ci } 132862306a36Sopenharmony_ci } 132962306a36Sopenharmony_ciout: 133062306a36Sopenharmony_ci read_unlock_irqrestore(&mgr->lock, flags); 133162306a36Sopenharmony_ci dev_kfree_skb(cskb); 133262306a36Sopenharmony_ci dev_kfree_skb(skb); 133362306a36Sopenharmony_ci return 0; 133462306a36Sopenharmony_ci} 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_cistatic int 133762306a36Sopenharmony_cimgr_bcast_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) 133862306a36Sopenharmony_ci{ 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci return -EINVAL; 134162306a36Sopenharmony_ci} 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ciint 134462306a36Sopenharmony_cicreate_teimanager(struct mISDNdevice *dev) 134562306a36Sopenharmony_ci{ 134662306a36Sopenharmony_ci struct manager *mgr; 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci mgr = kzalloc(sizeof(struct manager), GFP_KERNEL); 134962306a36Sopenharmony_ci if (!mgr) 135062306a36Sopenharmony_ci return -ENOMEM; 135162306a36Sopenharmony_ci INIT_LIST_HEAD(&mgr->layer2); 135262306a36Sopenharmony_ci rwlock_init(&mgr->lock); 135362306a36Sopenharmony_ci skb_queue_head_init(&mgr->sendq); 135462306a36Sopenharmony_ci mgr->nextid = 1; 135562306a36Sopenharmony_ci mgr->lastid = MISDN_ID_NONE; 135662306a36Sopenharmony_ci mgr->ch.send = mgr_send; 135762306a36Sopenharmony_ci mgr->ch.ctrl = mgr_ctrl; 135862306a36Sopenharmony_ci mgr->ch.st = dev->D.st; 135962306a36Sopenharmony_ci set_channel_address(&mgr->ch, TEI_SAPI, GROUP_TEI); 136062306a36Sopenharmony_ci add_layer2(&mgr->ch, dev->D.st); 136162306a36Sopenharmony_ci mgr->bcast.send = mgr_bcast; 136262306a36Sopenharmony_ci mgr->bcast.ctrl = mgr_bcast_ctrl; 136362306a36Sopenharmony_ci mgr->bcast.st = dev->D.st; 136462306a36Sopenharmony_ci set_channel_address(&mgr->bcast, 0, GROUP_TEI); 136562306a36Sopenharmony_ci add_layer2(&mgr->bcast, dev->D.st); 136662306a36Sopenharmony_ci mgr->deact.debug = *debug & DEBUG_MANAGER; 136762306a36Sopenharmony_ci mgr->deact.userdata = mgr; 136862306a36Sopenharmony_ci mgr->deact.printdebug = da_debug; 136962306a36Sopenharmony_ci mgr->deact.fsm = &deactfsm; 137062306a36Sopenharmony_ci mgr->deact.state = ST_L1_DEACT; 137162306a36Sopenharmony_ci mISDN_FsmInitTimer(&mgr->deact, &mgr->datimer); 137262306a36Sopenharmony_ci dev->teimgr = &mgr->ch; 137362306a36Sopenharmony_ci return 0; 137462306a36Sopenharmony_ci} 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ciint TEIInit(u_int *deb) 137762306a36Sopenharmony_ci{ 137862306a36Sopenharmony_ci int res; 137962306a36Sopenharmony_ci debug = deb; 138062306a36Sopenharmony_ci teifsmu.state_count = TEI_STATE_COUNT; 138162306a36Sopenharmony_ci teifsmu.event_count = TEI_EVENT_COUNT; 138262306a36Sopenharmony_ci teifsmu.strEvent = strTeiEvent; 138362306a36Sopenharmony_ci teifsmu.strState = strTeiState; 138462306a36Sopenharmony_ci res = mISDN_FsmNew(&teifsmu, TeiFnListUser, ARRAY_SIZE(TeiFnListUser)); 138562306a36Sopenharmony_ci if (res) 138662306a36Sopenharmony_ci goto error; 138762306a36Sopenharmony_ci teifsmn.state_count = TEI_STATE_COUNT; 138862306a36Sopenharmony_ci teifsmn.event_count = TEI_EVENT_COUNT; 138962306a36Sopenharmony_ci teifsmn.strEvent = strTeiEvent; 139062306a36Sopenharmony_ci teifsmn.strState = strTeiState; 139162306a36Sopenharmony_ci res = mISDN_FsmNew(&teifsmn, TeiFnListNet, ARRAY_SIZE(TeiFnListNet)); 139262306a36Sopenharmony_ci if (res) 139362306a36Sopenharmony_ci goto error_smn; 139462306a36Sopenharmony_ci deactfsm.state_count = DEACT_STATE_COUNT; 139562306a36Sopenharmony_ci deactfsm.event_count = DEACT_EVENT_COUNT; 139662306a36Sopenharmony_ci deactfsm.strEvent = strDeactEvent; 139762306a36Sopenharmony_ci deactfsm.strState = strDeactState; 139862306a36Sopenharmony_ci res = mISDN_FsmNew(&deactfsm, DeactFnList, ARRAY_SIZE(DeactFnList)); 139962306a36Sopenharmony_ci if (res) 140062306a36Sopenharmony_ci goto error_deact; 140162306a36Sopenharmony_ci return 0; 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_cierror_deact: 140462306a36Sopenharmony_ci mISDN_FsmFree(&teifsmn); 140562306a36Sopenharmony_cierror_smn: 140662306a36Sopenharmony_ci mISDN_FsmFree(&teifsmu); 140762306a36Sopenharmony_cierror: 140862306a36Sopenharmony_ci return res; 140962306a36Sopenharmony_ci} 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_civoid TEIFree(void) 141262306a36Sopenharmony_ci{ 141362306a36Sopenharmony_ci mISDN_FsmFree(&teifsmu); 141462306a36Sopenharmony_ci mISDN_FsmFree(&teifsmn); 141562306a36Sopenharmony_ci mISDN_FsmFree(&deactfsm); 141662306a36Sopenharmony_ci} 1417