📄 l3dss1.c
字号:
static voidl3dss1_t313(struct l3_process *pc, u_char pr, void *arg){ L3DelTimer(&pc->timer); pc->para.cause = 0xE6; l3dss1_disconnect_req(pc, pr, NULL); pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc);}static voidl3dss1_t308_1(struct l3_process *pc, u_char pr, void *arg){ newl3state(pc, 19); L3DelTimer(&pc->timer); l3dss1_message(pc, MT_RELEASE); L3AddTimer(&pc->timer, T308, CC_T308_2);}static voidl3dss1_t308_2(struct l3_process *pc, u_char pr, void *arg){ L3DelTimer(&pc->timer); pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc); release_l3_process(pc);}static voidl3dss1_t318(struct l3_process *pc, u_char pr, void *arg){ L3DelTimer(&pc->timer); pc->para.cause = 0x66; /* Timer expiry */ pc->para.loc = 0; /* local */ pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc); newl3state(pc, 19); l3dss1_message(pc, MT_RELEASE); L3AddTimer(&pc->timer, T308, CC_T308_1);}static voidl3dss1_t319(struct l3_process *pc, u_char pr, void *arg){ L3DelTimer(&pc->timer); pc->para.cause = 0x66; /* Timer expiry */ pc->para.loc = 0; /* local */ pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc); newl3state(pc, 10);}static voidl3dss1_restart(struct l3_process *pc, u_char pr, void *arg){ L3DelTimer(&pc->timer); pc->st->l3.l3l4(pc->st, CC_DLRL | INDICATION, pc); release_l3_process(pc);}static voidl3dss1_status(struct l3_process *pc, u_char pr, void *arg){ u_char *p; char tmp[64], *t; int l; struct sk_buff *skb = arg; int cause, callState; cause = callState = -1; p = skb->data; t = tmp; if ((p = findie(p, skb->len, IE_CAUSE, 0))) { p++; l = *p++; t += sprintf(t, "Status CR %x Cause:", pc->callref); while (l--) { cause = *p; t += sprintf(t, " %2x", *p++); } } else sprintf(t, "Status CR %x no Cause", pc->callref); l3_debug(pc->st, tmp); p = skb->data; t = tmp; t += sprintf(t, "Status state %x ", pc->state); if ((p = findie(p, skb->len, IE_CALL_STATE, 0))) { p++; if (1 == *p++) { callState = *p; t += sprintf(t, "peer state %x", *p); } else t += sprintf(t, "peer state len error"); } else sprintf(t, "no peer state"); l3_debug(pc->st, tmp); if (((cause & 0x7f) == 0x6f) && (callState == 0)) { /* ETS 300-104 7.6.1, 8.6.1, 10.6.1... * if received MT_STATUS with cause == 0x6f and call * state == 0, then we must set down layer 3 */ l3dss1_release_ind(pc, pr, arg); } else dev_kfree_skb(skb, FREE_READ);}static voidl3dss1_facility(struct l3_process *pc, u_char pr, void *arg){ u_char *p; struct sk_buff *skb = arg; p = skb->data; if ((p = findie(p, skb->len, IE_FACILITY, 0))) {#if HISAX_DE_AOC l3dss1_parse_facility(pc, p);#else p = NULL;#endif }}static voidl3dss1_suspend_req(struct l3_process *pc, u_char pr, void *arg){ struct sk_buff *skb; u_char tmp[32]; u_char *p = tmp; u_char i, l; u_char *msg = pc->chan->setup.phone; MsgHead(p, pc->callref, MT_SUSPEND); *p++ = IE_CALLID; l = *msg++; if (l && (l <= 10)) { /* Max length 10 octets */ *p++ = l; for (i = 0; i < l; i++) *p++ = *msg++; } else { l3_debug(pc->st, "SUS wrong CALLID len %d", l); return; } l = p - tmp; if (!(skb = l3_alloc_skb(l))) return; memcpy(skb_put(skb, l), tmp, l); l3_msg(pc->st, DL_DATA | REQUEST, skb); newl3state(pc, 15); L3AddTimer(&pc->timer, T319, CC_T319);}static voidl3dss1_suspend_ack(struct l3_process *pc, u_char pr, void *arg){ struct sk_buff *skb = arg; L3DelTimer(&pc->timer); newl3state(pc, 0); dev_kfree_skb(skb, FREE_READ); pc->para.cause = -1; pc->st->l3.l3l4(pc->st, CC_SUSPEND | CONFIRM, pc); release_l3_process(pc);}static voidl3dss1_suspend_rej(struct l3_process *pc, u_char pr, void *arg){ u_char *p; struct sk_buff *skb = arg; int cause = -1; L3DelTimer(&pc->timer); p = skb->data; if ((p = findie(p, skb->len, IE_CAUSE, 0))) { p++; if (*p++ == 2) pc->para.loc = *p++; cause = *p & 0x7f; } dev_kfree_skb(skb, FREE_READ); pc->para.cause = cause; pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc); newl3state(pc, 10);}static voidl3dss1_resume_req(struct l3_process *pc, u_char pr, void *arg){ struct sk_buff *skb; u_char tmp[32]; u_char *p = tmp; u_char i, l; u_char *msg = pc->para.setup.phone; MsgHead(p, pc->callref, MT_RESUME); *p++ = IE_CALLID; l = *msg++; if (l && (l <= 10)) { /* Max length 10 octets */ *p++ = l; for (i = 0; i < l; i++) *p++ = *msg++; } else { l3_debug(pc->st, "RES wrong CALLID len %d", l); return; } l = p - tmp; if (!(skb = l3_alloc_skb(l))) return; memcpy(skb_put(skb, l), tmp, l); l3_msg(pc->st, DL_DATA | REQUEST, skb); newl3state(pc, 17); L3AddTimer(&pc->timer, T319, CC_T319);}static voidl3dss1_resume_ack(struct l3_process *pc, u_char pr, void *arg){ u_char *p; struct sk_buff *skb = arg; L3DelTimer(&pc->timer); p = skb->data; if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) { pc->para.bchannel = p[2] & 0x3; if ((!pc->para.bchannel) && (pc->debug & L3_DEB_WARN)) l3_debug(pc->st, "resume ack without bchannel"); } else if (pc->debug & L3_DEB_WARN) l3_debug(pc->st, "resume ack without bchannel"); dev_kfree_skb(skb, FREE_READ); pc->st->l3.l3l4(pc->st, CC_RESUME | CONFIRM, pc); newl3state(pc, 10);}static voidl3dss1_resume_rej(struct l3_process *pc, u_char pr, void *arg){ u_char *p; struct sk_buff *skb = arg; int cause = -1; L3DelTimer(&pc->timer); p = skb->data; if ((p = findie(p, skb->len, IE_CAUSE, 0))) { p++; if (*p++ == 2) pc->para.loc = *p++; cause = *p & 0x7f; } dev_kfree_skb(skb, FREE_READ); pc->para.cause = cause; newl3state(pc, 0); pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc); release_l3_process(pc);}static voidl3dss1_global_restart(struct l3_process *pc, u_char pr, void *arg){ u_char tmp[32]; u_char *p; u_char ri, ch = 0, chan = 0; int l; struct sk_buff *skb = arg; struct l3_process *up; newl3state(pc, 2); L3DelTimer(&pc->timer); p = skb->data; if ((p = findie(p, skb->len, IE_RESTART_IND, 0))) { ri = p[2]; l3_debug(pc->st, "Restart %x", ri); } else { l3_debug(pc->st, "Restart without restart IE"); ri = 0x86; } p = skb->data; if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) { chan = p[2] & 3; ch = p[2]; if (pc->st->l3.debug) l3_debug(pc->st, "Restart for channel %d", chan); } dev_kfree_skb(skb, FREE_READ); newl3state(pc, 2); up = pc->st->l3.proc; while (up) { if ((ri & 7) == 7) up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up); else if (up->para.bchannel == chan) up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up); up = up->next; } p = tmp; MsgHead(p, pc->callref, MT_RESTART_ACKNOWLEDGE); if (chan) { *p++ = IE_CHANNEL_ID; *p++ = 1; *p++ = ch | 0x80; } *p++ = 0x79; /* RESTART Ind */ *p++ = 1; *p++ = ri; l = p - tmp; if (!(skb = l3_alloc_skb(l))) return; memcpy(skb_put(skb, l), tmp, l); newl3state(pc, 0); l3_msg(pc->st, DL_DATA | REQUEST, skb);}/* *INDENT-OFF* */static struct stateentry downstatelist[] ={ {SBIT(0), CC_SETUP | REQUEST, l3dss1_setup_req}, {SBIT(0), CC_RESUME | REQUEST, l3dss1_resume_req}, {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(10), CC_DISCONNECT | REQUEST, l3dss1_disconnect_req}, {SBIT(12), CC_RELEASE | REQUEST, l3dss1_release_req}, {ALL_STATES, CC_DLRL | REQUEST, l3dss1_reset}, {ALL_STATES, CC_RESTART | REQUEST, l3dss1_restart}, {SBIT(6), CC_IGNORE | REQUEST, l3dss1_reset}, {SBIT(6), CC_REJECT | REQUEST, l3dss1_reject_req}, {SBIT(6), CC_ALERTING | REQUEST, l3dss1_alert_req}, {SBIT(6) | SBIT(7), CC_SETUP | RESPONSE, l3dss1_setup_rsp}, {SBIT(10), CC_SUSPEND | REQUEST, l3dss1_suspend_req}, {SBIT(1), CC_T303, l3dss1_t303}, {SBIT(2), CC_T304, l3dss1_t304}, {SBIT(3), CC_T310, l3dss1_t310}, {SBIT(8), CC_T313, l3dss1_t313}, {SBIT(11), CC_T305, l3dss1_t305}, {SBIT(15), CC_T319, l3dss1_t319}, {SBIT(17), CC_T318, l3dss1_t318}, {SBIT(19), CC_T308_1, l3dss1_t308_1}, {SBIT(19), CC_T308_2, l3dss1_t308_2},};#define DOWNSLLEN \ (sizeof(downstatelist) / sizeof(struct stateentry))static struct stateentry datastatelist[] ={ {ALL_STATES, MT_STATUS_ENQUIRY, l3dss1_status_enq}, {ALL_STATES, MT_FACILITY, l3dss1_facility}, {SBIT(19), MT_STATUS, l3dss1_release_ind}, {ALL_STATES, MT_STATUS, l3dss1_status}, {SBIT(0) | SBIT(6), MT_SETUP, l3dss1_setup}, {SBIT(1) | SBIT(2), MT_CALL_PROCEEDING, l3dss1_call_proc}, {SBIT(3) | SBIT(4) | SBIT(8) | SBIT(10) | SBIT(11) | SBIT(19), MT_CALL_PROCEEDING, l3dss1_status_req}, {SBIT(1), MT_SETUP_ACKNOWLEDGE, l3dss1_setup_ack}, {SBIT(2) | SBIT(3) | SBIT(4) | SBIT(8) | SBIT(10) | SBIT(11) | SBIT(19), MT_SETUP_ACKNOWLEDGE, l3dss1_status_req}, {SBIT(1) | SBIT(2) | SBIT(3), MT_ALERTING, l3dss1_alerting}, {SBIT(4) | SBIT(8) | SBIT(10) | SBIT(11) | SBIT(19), MT_ALERTING, l3dss1_status_req}, {SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19), MT_RELEASE_COMPLETE, l3dss1_release_cmpl}, {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) /* | SBIT(17) | SBIT(19)*/, MT_RELEASE, l3dss1_release}, {SBIT(19), MT_RELEASE, l3dss1_release_ind}, {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10) | SBIT(15), MT_DISCONNECT, l3dss1_disconnect}, {SBIT(11), MT_DISCONNECT, l3dss1_release_req}, {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4), MT_CONNECT, l3dss1_connect}, {SBIT(8) | SBIT(10) | SBIT(11) | SBIT(19), MT_CONNECT, l3dss1_status_req}, {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(11) | SBIT(19), MT_CONNECT_ACKNOWLEDGE, l3dss1_status_req}, {SBIT(8), MT_CONNECT_ACKNOWLEDGE, l3dss1_connect_ack}, {SBIT(15), MT_SUSPEND_ACKNOWLEDGE, l3dss1_suspend_ack}, {SBIT(15), MT_SUSPEND_REJECT, l3dss1_suspend_rej}, {SBIT(17), MT_RESUME_ACKNOWLEDGE, l3dss1_resume_ack}, {SBIT(17), MT_RESUME_REJECT, l3dss1_resume_rej}, {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(8) | SBIT(10) | SBIT(11) | SBIT(15) | SBIT(17) | SBIT(19), MT_INVALID, l3dss1_status_req},};#define DATASLLEN \ (sizeof(datastatelist) / sizeof(struct stateentry))static struct stateentry globalmes_list[] ={ {ALL_STATES, MT_STATUS, l3dss1_status}, {SBIT(0), MT_RESTART, l3dss1_global_restart},/* {SBIT(1), MT_RESTART_ACKNOWLEDGE, l3dss1_restart_ack},*/};#define GLOBALM_LEN \ (sizeof(globalmes_list) / sizeof(struct stateentry))/* *INDENT-ON* */static voidglobal_handler(struct PStack *st, int mt, struct sk_buff *skb){ int i; struct l3_process *proc = st->l3.global; for (i = 0; i < GLOBALM_LEN; i++) if ((mt == globalmes_list[i].primitive) && ((1 << proc->state) & globalmes_list[i].state)) break; if (i == GLOBALM_LEN) { dev_kfree_skb(skb, FREE_READ); if (st->l3.debug & L3_DEB_STATE) { l3_debug(st, "dss1 global state %d mt %x unhandled", proc->state, mt); } return; } else { if (st->l3.debug & L3_DEB_STATE) { l3_debug(st, "dss1 global %d mt %x", proc->state, mt); } globalmes_list[i].rout(proc, mt, skb); }}static voiddss1up(struct PStack *st, int pr, void *arg){ int i, mt, cr, cause, callState; char *ptr; struct sk_buff *skb = arg; struct l3_process *proc; switch (pr) { case (DL_DATA | INDICATION): case (DL_UNIT_DATA | INDICATION): break; case (DL_ESTABLISH | CONFIRM): case (DL_ESTABLISH | INDICATION): case (DL_RELEASE | INDICATION): case (DL_RELEASE | CONFIRM): l3_msg(st, pr, arg); return; break; } if (skb->data[0] != PROTO_DIS_EURO) { if (st->l3.debug & L3_DEB_PROTERR) { l3_debug(st, "dss1up%sunexpected discriminator %x message len %d", (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", skb->data[0], skb->len); } dev_kfree_skb(skb, FREE_READ); return; } cr = getcallref(skb->data); mt = skb->data[skb->data[1] + 2]; if (!cr) { /* Global CallRef */ global_handler(st, mt, skb); return; } else if (cr == -1) { /* Dummy Callref */ dev_kfree_skb(skb, FREE_READ); return; } else if (!(proc = getl3proc(st, cr))) { /* No transaction process exist, that means no call with * this callreference is active */ if (mt == MT_SETUP) { /* Setup creates a new transaction process */ if (!(proc = new_l3_process(st, cr))) { /* May be to answer with RELEASE_COMPLETE and * CAUSE 0x2f "Resource unavailable", but this * need a new_l3_process too ... arghh */ dev_kfree_skb(skb, FREE_READ); return; } } else if (mt == MT_STATUS) { cause = 0; if ((ptr = findie(skb->data, skb->len, IE_CAUSE, 0)) != NULL) { ptr++; if (*ptr++ == 2) ptr++; cause = *ptr & 0x7f; } callState = 0; if ((ptr = findie(skb->data, skb->len, IE_CALL_STATE, 0)) != NULL) { ptr++; if (*ptr++ == 2) ptr++; callState = *ptr; } if (callState == 0) { /* ETS 300-104 part 2.4.1 * if setup has not been made and a message type * MT_STATUS is received with call state == 0, * we must send nothing */ dev_kfree_skb(skb, FREE_READ); return; } else { /* ETS 300-104 part 2.4.2 * if setup has not been made and a message type * MT_STATUS is received with call state != 0, * we must send MT_RELEASE_COMPLETE cause 101 */ dev_kfree_skb(skb, FREE_READ); if ((proc = new_l3_process(st, cr))) { proc->para.cause = 0x65; /* 101 */ l3dss1_msg_without_setup(proc, 0, NULL); } return; } } else if (mt == MT_RELEASE_COMPLETE) { dev_kfree_skb(skb, FREE_READ); return; } else { /* ETS 300-104 part 2 * if setup has not been made and a message type * (except MT_SETUP and RELEASE_COMPLETE) is received, * we must send MT_RELEASE_COMPLETE cause 81 */ dev_kfree_skb(skb, FREE_READ); if ((proc = new_l3_process(st, cr))) { proc->para.cause = 0x51; /* 81 */ l3dss1_msg_without_setup(proc, 0, NULL); } return; } } else if (!l3dss1_check_messagetype_validity(mt)) { /* ETS 300-104 7.4.2, 8.4.2, 10.3.2, 11.4.2, 12.4.2, 13.4.2, * 14.4.2... * if setup has been made and invalid message type is received, * we must send MT_STATUS cause 0x62 */ mt = MT_INVALID; /* sorry, not clean, but do the right thing ;-) */ } for (i = 0; i < DATASLLEN; i++) if ((mt == datastatelist[i].primitive) && ((1 << proc->state) & datastatelist[i].state)) break; if (i == DATASLLEN) { dev_kfree_skb(skb, FREE_READ); if (st->l3.debug & L3_DEB_STATE) { l3_debug(st, "dss1up%sstate %d mt %x unhandled", (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", proc->state, mt); } return; } else { if (st->l3.debug & L3_DEB_STATE) { l3_debug(st, "dss1up%sstate %d mt %x", (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", proc->state, mt); } datastatelist[i].rout(proc, pr, skb); }}static voiddss1down(struct PStack *st, int pr, void *arg){ int i, cr; struct l3_process *proc; struct Channel *chan; if (((DL_ESTABLISH | REQUEST) == pr) || ((DL_RELEASE | REQUEST) == pr)) { l3_msg(st, pr, NULL); return; } else if (((CC_SETUP | REQUEST) == pr) || ((CC_RESUME | REQUEST) == pr)) { chan = arg; cr = newcallref(); cr |= 0x80; if ((proc = new_l3_process(st, cr))) { proc->chan = chan; chan->proc = proc; proc->para.setup = chan->setup; proc->callref = cr; } } else { proc = arg; } if (!proc) { printk(KERN_ERR "HiSax dss1down without proc pr=%04x\n", pr); return; } for (i = 0; i < DOWNSLLEN; i++) if ((pr == downstatelist[i].primitive) && ((1 << proc->state) & downstatelist[i].state)) break; if (i == DOWNSLLEN) { if (st->l3.debug & L3_DEB_STATE) { l3_debug(st, "dss1down state %d prim %d unhandled", proc->state, pr); } } else { if (st->l3.debug & L3_DEB_STATE) { l3_debug(st, "dss1down state %d prim %d", proc->state, pr); } downstatelist[i].rout(proc, pr, arg); }}voidsetstack_dss1(struct PStack *st){ char tmp[64]; st->lli.l4l3 = dss1down; st->l2.l2l3 = dss1up; st->l3.N303 = 1; if (!(st->l3.global = kmalloc(sizeof(struct l3_process), GFP_ATOMIC))) { printk(KERN_ERR "HiSax can't get memory for dss1 global CR\n"); } else { st->l3.global->state = 0; st->l3.global->callref = 0; st->l3.global->next = NULL; st->l3.global->debug = L3_DEB_WARN; st->l3.global->st = st; st->l3.global->N303 = 1; L3InitTimer(st->l3.global, &st->l3.global->timer); } strcpy(tmp, dss1_revision); printk(KERN_INFO "HiSax: DSS1 Rev. %s\n", HiSax_getrev(tmp));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -