📄 callc.c
字号:
/* $Id: callc.c,v 2.51.6.6 2001/09/23 22:24:46 kai Exp $ * * Author Karsten Keil * Copyright by Karsten Keil <keil@isdn4linux.de> * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. * * For changes and modifications please read * ../../../Documentation/isdn/HiSax.cert * * based on the teles driver from Jan den Ouden * * Thanks to Jan den Ouden * Fritz Elfert * */#define __NO_VERSION__#include <linux/module.h>#include <linux/init.h>#include "hisax.h"#include <linux/isdn/capicmd.h>#ifdef MODULE#define MOD_USE_COUNT ( GET_USE_COUNT (&__this_module))#endif /* MODULE */const char *lli_revision = "$Revision: 2.51.6.6 $";extern struct IsdnCard cards[];extern int nrcards;extern void HiSax_mod_dec_use_count(struct IsdnCardState *cs);extern void HiSax_mod_inc_use_count(struct IsdnCardState *cs);static int init_b_st(struct Channel *chanp, int incoming);static void release_b_st(struct Channel *chanp);static struct Fsm callcfsm;static int chancount;/* experimental REJECT after ALERTING for CALLBACK to beat the 4s delay */#define ALERT_REJECT 0/* Value to delay the sending of the first B-channel paket after CONNECT * here is no value given by ITU, but experience shows that 300 ms will * work on many networks, if you or your other side is behind local exchanges * a greater value may be recommented. If the delay is to short the first paket * will be lost and autodetect on many comercial routers goes wrong ! * You can adjust this value on runtime with * hisaxctrl <id> 2 <value> * value is in milliseconds */#define DEFAULT_B_DELAY 300/* Flags for remembering action done in lli */#define FLG_START_B 0/* * Find card with given driverId */static inline struct IsdnCardState *hisax_findcard(int driverid){ int i; for (i = 0; i < nrcards; i++) if (cards[i].cs) if (cards[i].cs->myid == driverid) return (cards[i].cs); return (struct IsdnCardState *) 0;}static voidlink_debug(struct Channel *chanp, int direction, char *fmt, ...){ va_list args; char tmp[16]; va_start(args, fmt); sprintf(tmp, "Ch%d %s ", chanp->chan, direction ? "LL->HL" : "HL->LL"); VHiSax_putstatus(chanp->cs, tmp, fmt, args); va_end(args);}enum { ST_NULL, /* 0 inactive */ ST_OUT_DIAL, /* 1 outgoing, SETUP send; awaiting confirm */ ST_IN_WAIT_LL, /* 2 incoming call received; wait for LL confirm */ ST_IN_ALERT_SENT, /* 3 incoming call received; ALERT send */ ST_IN_WAIT_CONN_ACK, /* 4 incoming CONNECT send; awaiting CONN_ACK */ ST_WAIT_BCONN, /* 5 CONNECT/CONN_ACK received, awaiting b-channel prot. estbl. */ ST_ACTIVE, /* 6 active, b channel prot. established */ ST_WAIT_BRELEASE, /* 7 call clear. (initiator), awaiting b channel prot. rel. */ ST_WAIT_BREL_DISC, /* 8 call clear. (receiver), DISCONNECT req. received */ ST_WAIT_DCOMMAND, /* 9 call clear. (receiver), awaiting DCHANNEL message */ ST_WAIT_DRELEASE, /* 10 DISCONNECT sent, awaiting RELEASE */ ST_WAIT_D_REL_CNF, /* 11 RELEASE sent, awaiting RELEASE confirm */ ST_IN_PROCEED_SEND, /* 12 incoming call, proceeding send */ }; #define STATE_COUNT (ST_IN_PROCEED_SEND + 1)static char *strState[] ={ "ST_NULL", "ST_OUT_DIAL", "ST_IN_WAIT_LL", "ST_IN_ALERT_SENT", "ST_IN_WAIT_CONN_ACK", "ST_WAIT_BCONN", "ST_ACTIVE", "ST_WAIT_BRELEASE", "ST_WAIT_BREL_DISC", "ST_WAIT_DCOMMAND", "ST_WAIT_DRELEASE", "ST_WAIT_D_REL_CNF", "ST_IN_PROCEED_SEND",};enum { EV_DIAL, /* 0 */ EV_SETUP_CNF, /* 1 */ EV_ACCEPTB, /* 2 */ EV_DISCONNECT_IND, /* 3 */ EV_RELEASE, /* 4 */ EV_LEASED, /* 5 */ EV_LEASED_REL, /* 6 */ EV_SETUP_IND, /* 7 */ EV_ACCEPTD, /* 8 */ EV_SETUP_CMPL_IND, /* 9 */ EV_BC_EST, /* 10 */ EV_WRITEBUF, /* 11 */ EV_HANGUP, /* 12 */ EV_BC_REL, /* 13 */ EV_CINF, /* 14 */ EV_SUSPEND, /* 15 */ EV_RESUME, /* 16 */ EV_NOSETUP_RSP, /* 17 */ EV_SETUP_ERR, /* 18 */ EV_CONNECT_ERR, /* 19 */ EV_PROCEED, /* 20 */ EV_ALERT, /* 21 */ EV_REDIR, /* 22 */ };#define EVENT_COUNT (EV_REDIR + 1)static char *strEvent[] ={ "EV_DIAL", "EV_SETUP_CNF", "EV_ACCEPTB", "EV_DISCONNECT_IND", "EV_RELEASE", "EV_LEASED", "EV_LEASED_REL", "EV_SETUP_IND", "EV_ACCEPTD", "EV_SETUP_CMPL_IND", "EV_BC_EST", "EV_WRITEBUF", "EV_HANGUP", "EV_BC_REL", "EV_CINF", "EV_SUSPEND", "EV_RESUME", "EV_NOSETUP_RSP", "EV_SETUP_ERR", "EV_CONNECT_ERR", "EV_PROCEED", "EV_ALERT", "EV_REDIR",};static inline voidHL_LL(struct Channel *chanp, int command){ isdn_ctrl ic; ic.driver = chanp->cs->myid; ic.command = command; ic.arg = chanp->chan; chanp->cs->iif.statcallb(&ic);}static inline voidlli_deliver_cause(struct Channel *chanp){ isdn_ctrl ic; if (!chanp->proc) return; if (chanp->proc->para.cause == NO_CAUSE) return; ic.driver = chanp->cs->myid; ic.command = ISDN_STAT_CAUSE; ic.arg = chanp->chan; if (chanp->cs->protocol == ISDN_PTYPE_EURO) sprintf(ic.parm.num, "E%02X%02X", chanp->proc->para.loc & 0x7f, chanp->proc->para.cause & 0x7f); else sprintf(ic.parm.num, "%02X%02X", chanp->proc->para.loc & 0x7f, chanp->proc->para.cause & 0x7f); chanp->cs->iif.statcallb(&ic);}static inline voidlli_close(struct FsmInst *fi){ struct Channel *chanp = fi->userdata; FsmChangeState(fi, ST_NULL); chanp->Flags = 0; chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);}static voidlli_leased_in(struct FsmInst *fi, int event, void *arg){ struct Channel *chanp = fi->userdata; isdn_ctrl ic; int ret; if (!chanp->leased) return; chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan); FsmChangeState(fi, ST_IN_WAIT_LL); if (chanp->debug & 1) link_debug(chanp, 0, "STAT_ICALL_LEASED"); ic.driver = chanp->cs->myid; ic.command = ((chanp->chan < 2) ? ISDN_STAT_ICALL : ISDN_STAT_ICALLW); ic.arg = chanp->chan; ic.parm.setup.si1 = 7; ic.parm.setup.si2 = 0; ic.parm.setup.plan = 0; ic.parm.setup.screen = 0; sprintf(ic.parm.setup.eazmsn,"%d", chanp->chan + 1); sprintf(ic.parm.setup.phone,"LEASED%d", chanp->cs->myid); ret = chanp->cs->iif.statcallb(&ic); if (chanp->debug & 1) link_debug(chanp, 1, "statcallb ret=%d", ret); if (!ret) { chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan); FsmChangeState(fi, ST_NULL); }}/* * Dial out */static voidlli_init_bchan_out(struct FsmInst *fi, int event, void *arg){ struct Channel *chanp = fi->userdata; FsmChangeState(fi, ST_WAIT_BCONN); if (chanp->debug & 1) link_debug(chanp, 0, "STAT_DCONN"); HL_LL(chanp, ISDN_STAT_DCONN); init_b_st(chanp, 0); L4L3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL);}static voidlli_prep_dialout(struct FsmInst *fi, int event, void *arg){ struct Channel *chanp = fi->userdata; FsmDelTimer(&chanp->drel_timer, 60); FsmDelTimer(&chanp->dial_timer, 73); chanp->l2_active_protocol = chanp->l2_protocol; chanp->incoming = 0; chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan); if (chanp->leased) { lli_init_bchan_out(fi, event, arg); } else { FsmChangeState(fi, ST_OUT_DIAL); L4L3(chanp->d_st, CC_SETUP | REQUEST, chanp); }}static voidlli_resume(struct FsmInst *fi, int event, void *arg){ struct Channel *chanp = fi->userdata; FsmDelTimer(&chanp->drel_timer, 60); FsmDelTimer(&chanp->dial_timer, 73); chanp->l2_active_protocol = chanp->l2_protocol; chanp->incoming = 0; chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan); if (chanp->leased) { lli_init_bchan_out(fi, event, arg); } else { FsmChangeState(fi, ST_OUT_DIAL); L4L3(chanp->d_st, CC_RESUME | REQUEST, chanp); }}static voidlli_go_active(struct FsmInst *fi, int event, void *arg){ struct Channel *chanp = fi->userdata; isdn_ctrl ic; FsmChangeState(fi, ST_ACTIVE); chanp->data_open = !0; if (chanp->bcs->conmsg) strcpy(ic.parm.num, chanp->bcs->conmsg); else ic.parm.num[0] = 0; if (chanp->debug & 1) link_debug(chanp, 0, "STAT_BCONN %s", ic.parm.num); ic.driver = chanp->cs->myid; ic.command = ISDN_STAT_BCONN; ic.arg = chanp->chan; chanp->cs->iif.statcallb(&ic); chanp->cs->cardmsg(chanp->cs, MDL_INFO_CONN, (void *) (long)chanp->chan);}/* * RESUME *//* incoming call */static voidlli_deliver_call(struct FsmInst *fi, int event, void *arg){ struct Channel *chanp = fi->userdata; isdn_ctrl ic; int ret; chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan); /* * Report incoming calls only once to linklevel, use CallFlags * which is set to 3 with each broadcast message in isdnl1.c * and resetted if a interface answered the STAT_ICALL. */ if (1) { /* for only one TEI */ FsmChangeState(fi, ST_IN_WAIT_LL); if (chanp->debug & 1) link_debug(chanp, 0, (chanp->chan < 2) ? "STAT_ICALL" : "STAT_ICALLW"); ic.driver = chanp->cs->myid; ic.command = ((chanp->chan < 2) ? ISDN_STAT_ICALL : ISDN_STAT_ICALLW); ic.arg = chanp->chan; /* * No need to return "unknown" for calls without OAD, * cause that's handled in linklevel now (replaced by '0') */ memcpy(&ic.parm.setup, &chanp->proc->para.setup, sizeof(setup_parm)); ret = chanp->cs->iif.statcallb(&ic); if (chanp->debug & 1) link_debug(chanp, 1, "statcallb ret=%d", ret); switch (ret) { case 1: /* OK, someone likes this call */ FsmDelTimer(&chanp->drel_timer, 61); FsmChangeState(fi, ST_IN_ALERT_SENT); L4L3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc); break; case 5: /* direct redirect */ case 4: /* Proceeding desired */ FsmDelTimer(&chanp->drel_timer, 61); FsmChangeState(fi, ST_IN_PROCEED_SEND); L4L3(chanp->d_st, CC_PROCEED_SEND | REQUEST, chanp->proc); if (ret == 5) { memcpy(&chanp->setup, &ic.parm.setup, sizeof(setup_parm)); L4L3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc); } break; case 2: /* Rejecting Call */ break; case 3: /* incomplete number */ FsmDelTimer(&chanp->drel_timer, 61); L4L3(chanp->d_st, CC_MORE_INFO | REQUEST, chanp->proc); break; case 0: /* OK, nobody likes this call */ default: /* statcallb problems */ L4L3(chanp->d_st, CC_IGNORE | REQUEST, chanp->proc); chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan); FsmChangeState(fi, ST_NULL); break; } } else { L4L3(chanp->d_st, CC_IGNORE | REQUEST, chanp->proc); chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan); }}static voidlli_send_dconnect(struct FsmInst *fi, int event, void *arg){ struct Channel *chanp = fi->userdata; FsmChangeState(fi, ST_IN_WAIT_CONN_ACK); L4L3(chanp->d_st, CC_SETUP | RESPONSE, chanp->proc);}static voidlli_send_alert(struct FsmInst *fi, int event, void *arg){ struct Channel *chanp = fi->userdata; FsmChangeState(fi, ST_IN_ALERT_SENT); L4L3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);}static voidlli_send_redir(struct FsmInst *fi, int event, void *arg){ struct Channel *chanp = fi->userdata; L4L3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc);}static voidlli_init_bchan_in(struct FsmInst *fi, int event, void *arg){ struct Channel *chanp = fi->userdata; FsmChangeState(fi, ST_WAIT_BCONN); if (chanp->debug & 1) link_debug(chanp, 0, "STAT_DCONN"); HL_LL(chanp, ISDN_STAT_DCONN); chanp->l2_active_protocol = chanp->l2_protocol; chanp->incoming = !0; init_b_st(chanp, !0); L4L3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL);}static voidlli_setup_rsp(struct FsmInst *fi, int event, void *arg){ struct Channel *chanp = fi->userdata; if (chanp->leased) { lli_init_bchan_in(fi, event, arg); } else { FsmChangeState(fi, ST_IN_WAIT_CONN_ACK);#ifdef WANT_ALERT L4L3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);#endif L4L3(chanp->d_st, CC_SETUP | RESPONSE, chanp->proc); }}/* Call suspend */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -