📄 l3dss1.c
字号:
/* $Id: l3dss1.c,v 2.30.6.2 2001/09/23 22:24:49 kai Exp $ * * EURO/DSS1 D-channel protocol * * German 1TR6 D-channel protocol * * Author Karsten Keil * based on the teles driver from Jan den Ouden * 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 * * Thanks to Jan den Ouden * Fritz Elfert * */#define __NO_VERSION__#include "hisax.h"#include "isdnl3.h"#include "l3dss1.h"#include <linux/ctype.h>#include <linux/config.h>extern char *HiSax_getrev(const char *revision);const char *dss1_revision = "$Revision: 2.30.6.2 $";#define EXT_BEARER_CAPS 1#define MsgHead(ptr, cref, mty) \ *ptr++ = 0x8; \ if (cref == -1) { \ *ptr++ = 0x0; \ } else { \ *ptr++ = 0x1; \ *ptr++ = cref^0x80; \ } \ *ptr++ = mty/**********************************************//* get a new invoke id for remote operations. *//* Only a return value != 0 is valid *//**********************************************/static unsigned char new_invoke_id(struct PStack *p){ unsigned char retval; unsigned long flags; int i; i = 32; /* maximum search depth */ save_flags(flags); cli(); retval = p->prot.dss1.last_invoke_id + 1; /* try new id */ while ((i) && (p->prot.dss1.invoke_used[retval >> 3] == 0xFF)) { p->prot.dss1.last_invoke_id = (retval & 0xF8) + 8; i--; } if (i) { while (p->prot.dss1.invoke_used[retval >> 3] & (1 << (retval & 7))) retval++; } else retval = 0; p->prot.dss1.last_invoke_id = retval; p->prot.dss1.invoke_used[retval >> 3] |= (1 << (retval & 7)); restore_flags(flags); return(retval); } /* new_invoke_id *//*************************//* free a used invoke id *//*************************/static void free_invoke_id(struct PStack *p, unsigned char id){ unsigned long flags; if (!id) return; /* 0 = invalid value */ save_flags(flags); cli(); p->prot.dss1.invoke_used[id >> 3] &= ~(1 << (id & 7)); restore_flags(flags);} /* free_invoke_id */ /**********************************************************//* create a new l3 process and fill in dss1 specific data *//**********************************************************/static struct l3_process*dss1_new_l3_process(struct PStack *st, int cr){ struct l3_process *proc; if (!(proc = new_l3_process(st, cr))) return(NULL); proc->prot.dss1.invoke_id = 0; proc->prot.dss1.remote_operation = 0; proc->prot.dss1.uus1_data[0] = '\0'; return(proc);} /* dss1_new_l3_process *//************************************************//* free a l3 process and all dss1 specific data *//************************************************/ static voiddss1_release_l3_process(struct l3_process *p){ free_invoke_id(p->st,p->prot.dss1.invoke_id); release_l3_process(p);} /* dss1_release_l3_process */ /********************************************************//* search a process with invoke id id and dummy callref *//********************************************************/static struct l3_process *l3dss1_search_dummy_proc(struct PStack *st, int id){ struct l3_process *pc = st->l3.proc; /* start of processes */ if (!id) return(NULL); while (pc) { if ((pc->callref == -1) && (pc->prot.dss1.invoke_id == id)) return(pc); pc = pc->next; } return(NULL);} /* l3dss1_search_dummy_proc *//*******************************************************************//* called when a facility message with a dummy callref is received *//* and a return result is delivered. id specifies the invoke id. *//*******************************************************************/ static void l3dss1_dummy_return_result(struct PStack *st, int id, u_char *p, u_char nlen){ isdn_ctrl ic; struct IsdnCardState *cs; struct l3_process *pc = NULL; if ((pc = l3dss1_search_dummy_proc(st, id))) { L3DelTimer(&pc->timer); /* remove timer */ cs = pc->st->l1.hardware; ic.driver = cs->myid; ic.command = ISDN_STAT_PROT; ic.arg = DSS1_STAT_INVOKE_RES; ic.parm.dss1_io.hl_id = pc->prot.dss1.invoke_id; ic.parm.dss1_io.ll_id = pc->prot.dss1.ll_id; ic.parm.dss1_io.proc = pc->prot.dss1.proc; ic.parm.dss1_io.timeout= 0; ic.parm.dss1_io.datalen = nlen; ic.parm.dss1_io.data = p; free_invoke_id(pc->st, pc->prot.dss1.invoke_id); pc->prot.dss1.invoke_id = 0; /* reset id */ cs->iif.statcallb(&ic); dss1_release_l3_process(pc); } else l3_debug(st, "dummy return result id=0x%x result len=%d",id,nlen);} /* l3dss1_dummy_return_result *//*******************************************************************//* called when a facility message with a dummy callref is received *//* and a return error is delivered. id specifies the invoke id. *//*******************************************************************/ static void l3dss1_dummy_error_return(struct PStack *st, int id, ulong error){ isdn_ctrl ic; struct IsdnCardState *cs; struct l3_process *pc = NULL; if ((pc = l3dss1_search_dummy_proc(st, id))) { L3DelTimer(&pc->timer); /* remove timer */ cs = pc->st->l1.hardware; ic.driver = cs->myid; ic.command = ISDN_STAT_PROT; ic.arg = DSS1_STAT_INVOKE_ERR; ic.parm.dss1_io.hl_id = pc->prot.dss1.invoke_id; ic.parm.dss1_io.ll_id = pc->prot.dss1.ll_id; ic.parm.dss1_io.proc = pc->prot.dss1.proc; ic.parm.dss1_io.timeout= error; ic.parm.dss1_io.datalen = 0; ic.parm.dss1_io.data = NULL; free_invoke_id(pc->st, pc->prot.dss1.invoke_id); pc->prot.dss1.invoke_id = 0; /* reset id */ cs->iif.statcallb(&ic); dss1_release_l3_process(pc); } else l3_debug(st, "dummy return error id=0x%x error=0x%lx",id,error);} /* l3dss1_error_return *//*******************************************************************//* called when a facility message with a dummy callref is received *//* and a invoke is delivered. id specifies the invoke id. *//*******************************************************************/ static void l3dss1_dummy_invoke(struct PStack *st, int cr, int id, int ident, u_char *p, u_char nlen){ isdn_ctrl ic; struct IsdnCardState *cs; l3_debug(st, "dummy invoke %s id=0x%x ident=0x%x datalen=%d", (cr == -1) ? "local" : "broadcast",id,ident,nlen); if (cr >= -1) return; /* ignore local data */ cs = st->l1.hardware; ic.driver = cs->myid; ic.command = ISDN_STAT_PROT; ic.arg = DSS1_STAT_INVOKE_BRD; ic.parm.dss1_io.hl_id = id; ic.parm.dss1_io.ll_id = 0; ic.parm.dss1_io.proc = ident; ic.parm.dss1_io.timeout= 0; ic.parm.dss1_io.datalen = nlen; ic.parm.dss1_io.data = p; cs->iif.statcallb(&ic);} /* l3dss1_dummy_invoke */static voidl3dss1_parse_facility(struct PStack *st, struct l3_process *pc, int cr, u_char * p){ int qd_len = 0; unsigned char nlen = 0, ilen, cp_tag; int ident, id; ulong err_ret; if (pc) st = pc->st; /* valid Stack */ else if ((!st) || (cr >= 0)) return; /* neither pc nor st specified */ p++; qd_len = *p++; if (qd_len == 0) { l3_debug(st, "qd_len == 0"); return; } if ((*p & 0x1F) != 0x11) { /* Service discriminator, supplementary service */ l3_debug(st, "supplementary service != 0x11"); return; } while (qd_len > 0 && !(*p & 0x80)) { /* extension ? */ p++; qd_len--; } if (qd_len < 2) { l3_debug(st, "qd_len < 2"); return; } p++; qd_len--; if ((*p & 0xE0) != 0xA0) { /* class and form */ l3_debug(st, "class and form != 0xA0"); return; } cp_tag = *p & 0x1F; /* remember tag value */ p++; qd_len--; if (qd_len < 1) { l3_debug(st, "qd_len < 1"); return; } if (*p & 0x80) { /* length format indefinite or limited */ nlen = *p++ & 0x7F; /* number of len bytes or indefinite */ if ((qd_len-- < ((!nlen) ? 3 : (1 + nlen))) || (nlen > 1)) { l3_debug(st, "length format error or not implemented"); return; } if (nlen == 1) { nlen = *p++; /* complete length */ qd_len--; } else { qd_len -= 2; /* trailing null bytes */ if ((*(p+qd_len)) || (*(p+qd_len+1))) { l3_debug(st,"length format indefinite error"); return; } nlen = qd_len; } } else { nlen = *p++; qd_len--; } if (qd_len < nlen) { l3_debug(st, "qd_len < nlen"); return; } qd_len -= nlen; if (nlen < 2) { l3_debug(st, "nlen < 2"); return; } if (*p != 0x02) { /* invoke identifier tag */ l3_debug(st, "invoke identifier tag !=0x02"); return; } p++; nlen--; if (*p & 0x80) { /* length format */ l3_debug(st, "invoke id length format 2"); return; } ilen = *p++; nlen--; if (ilen > nlen || ilen == 0) { l3_debug(st, "ilen > nlen || ilen == 0"); return; } nlen -= ilen; id = 0; while (ilen > 0) { id = (id << 8) | (*p++ & 0xFF); /* invoke identifier */ ilen--; } switch (cp_tag) { /* component tag */ case 1: /* invoke */ if (nlen < 2) { l3_debug(st, "nlen < 2 22"); return; } if (*p != 0x02) { /* operation value */ l3_debug(st, "operation value !=0x02"); return; } p++; nlen--; ilen = *p++; nlen--; if (ilen > nlen || ilen == 0) { l3_debug(st, "ilen > nlen || ilen == 0 22"); return; } nlen -= ilen; ident = 0; while (ilen > 0) { ident = (ident << 8) | (*p++ & 0xFF); ilen--; } if (!pc) { l3dss1_dummy_invoke(st, cr, id, ident, p, nlen); return; } #if HISAX_DE_AOC {#define FOO1(s,a,b) \ while(nlen > 1) { \ int ilen = p[1]; \ if(nlen < ilen+2) { \ l3_debug(st, "FOO1 nlen < ilen+2"); \ return; \ } \ nlen -= ilen+2; \ if((*p & 0xFF) == (a)) { \ int nlen = ilen; \ p += 2; \ b; \ } else { \ p += ilen+2; \ } \ } switch (ident) { case 0x22: /* during */ FOO1("1A", 0x30, FOO1("1C", 0xA1, FOO1("1D", 0x30, FOO1("1E", 0x02, ( { ident = 0; nlen = (nlen)?nlen:0; /* Make gcc happy */ while (ilen > 0) { ident = (ident << 8) | *p++; ilen--; } if (ident > pc->para.chargeinfo) { pc->para.chargeinfo = ident; st->l3.l3l4(st, CC_CHARGE | INDICATION, pc); } if (st->l3.debug & L3_DEB_CHARGE) { if (*(p + 2) == 0) { l3_debug(st, "charging info during %d", pc->para.chargeinfo); } else { l3_debug(st, "charging info final %d", pc->para.chargeinfo); } } } ))))) break; case 0x24: /* final */ FOO1("2A", 0x30, FOO1("2B", 0x30, FOO1("2C", 0xA1, FOO1("2D", 0x30, FOO1("2E", 0x02, ( { ident = 0; nlen = (nlen)?nlen:0; /* Make gcc happy */ while (ilen > 0) { ident = (ident << 8) | *p++; ilen--; } if (ident > pc->para.chargeinfo) { pc->para.chargeinfo = ident; st->l3.l3l4(st, CC_CHARGE | INDICATION, pc); } if (st->l3.debug & L3_DEB_CHARGE) { l3_debug(st, "charging info final %d", pc->para.chargeinfo); } } )))))) break; default: l3_debug(st, "invoke break invalid ident %02x",ident); break; }#undef FOO1 }#else /* not HISAX_DE_AOC */ l3_debug(st, "invoke break");#endif /* not HISAX_DE_AOC */ break; case 2: /* return result */ /* if no process available handle separately */ if (!pc) { if (cr == -1) l3dss1_dummy_return_result(st, id, p, nlen); return; } if ((pc->prot.dss1.invoke_id) && (pc->prot.dss1.invoke_id == id)) { /* Diversion successful */ free_invoke_id(st,pc->prot.dss1.invoke_id); pc->prot.dss1.remote_result = 0; /* success */ pc->prot.dss1.invoke_id = 0; pc->redir_result = pc->prot.dss1.remote_result; L3L4(st, CC_REDIR | INDICATION, pc); } /* Diversion successful */ else l3_debug(st,"return error unknown identifier"); break; case 3: /* return error */ err_ret = 0; if (nlen < 2) { l3_debug(st, "return error nlen < 2"); return; } if (*p != 0x02) { /* result tag */ l3_debug(st, "invoke error tag !=0x02"); return; } p++; nlen--; if (*p > 4) { /* length format */ l3_debug(st, "invoke return errlen > 4 "); return; } ilen = *p++; nlen--; if (ilen > nlen || ilen == 0) { l3_debug(st, "error return ilen > nlen || ilen == 0"); return; } nlen -= ilen; while (ilen > 0) { err_ret = (err_ret << 8) | (*p++ & 0xFF); /* error value */ ilen--; } /* if no process available handle separately */ if (!pc) { if (cr == -1) l3dss1_dummy_error_return(st, id, err_ret); return; } if ((pc->prot.dss1.invoke_id) && (pc->prot.dss1.invoke_id == id)) { /* Deflection error */ free_invoke_id(st,pc->prot.dss1.invoke_id); pc->prot.dss1.remote_result = err_ret; /* result */ pc->prot.dss1.invoke_id = 0; pc->redir_result = pc->prot.dss1.remote_result; L3L4(st, CC_REDIR | INDICATION, pc); } /* Deflection error */ else l3_debug(st,"return result unknown identifier"); break; default: l3_debug(st, "facility default break tag=0x%02x",cp_tag); break; }}static voidl3dss1_message(struct l3_process *pc, u_char mt){ struct sk_buff *skb; u_char *p; if (!(skb = l3_alloc_skb(4))) return; p = skb_put(skb, 4); MsgHead(p, pc->callref, mt); l3_msg(pc->st, DL_DATA | REQUEST, skb);}static voidl3dss1_message_cause(struct l3_process *pc, u_char mt, u_char cause){ struct sk_buff *skb; u_char tmp[16]; u_char *p = tmp;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -