📄 l3dss1.c
字号:
/* $Id: l3dss1.c,v 1.1.1.1 1999/11/15 13:42:18 vadim Exp $ * EURO/DSS1 D-channel protocol * * Author Karsten Keil (keil@temic-ech.spacenet.de) * based on the teles driver from Jan den Ouden * * This file is (c) under GNU PUBLIC LICENSE * For changes and modifications please read * ../../../Documentation/isdn/HiSax.cert * * Thanks to Jan den Ouden * Fritz Elfert * * $Log: l3dss1.c,v $ * Revision 1.1.1.1 1999/11/15 13:42:18 vadim * Initial import * * Revision 1.16.2.8 1998/11/03 00:07:14 keil * certification related changes * fixed logging for smaller stack use * * Revision 1.16.2.7 1998/10/25 18:16:25 fritz * Replaced some read-only variables by defines. * * Revision 1.16.2.6 1998/10/23 15:00:56 fritz * Eliminated a compiler warning. * * Revision 1.16.2.5 1998/09/27 13:06:48 keil * Apply most changes from 2.1.X (HiSax 3.1) * * Revision 1.16.2.4 1998/05/27 18:06:08 keil * HiSax 3.0 * * Revision 1.16.2.3 1998/02/03 23:16:06 keil * german AOC * * Revision 1.16.2.2 1997/11/15 18:54:15 keil * cosmetics * * Revision 1.16.2.1 1997/10/17 22:14:16 keil * update to last hisax version * * Revision 2.2 1997/08/07 17:44:36 keil * Fix RESTART * * Revision 2.1 1997/08/03 14:36:33 keil * Implement RESTART procedure * * Revision 2.0 1997/07/27 21:15:43 keil * New Callref based layer3 * * Revision 1.17 1997/06/26 11:11:46 keil * SET_SKBFREE now on creation of a SKB * * Revision 1.15 1997/04/17 11:50:48 keil * pa->loc was undefined, if it was not send by the exchange * * Old log removed /KKe * */#define __NO_VERSION__#include "hisax.h"#include "isdnl3.h"#include "l3dss1.h"#include <linux/ctype.h>extern char *HiSax_getrev(const char *revision);const char *dss1_revision = "$Revision: 1.1.1.1 $";#define EXT_BEARER_CAPS 1#define MsgHead(ptr, cref, mty) \ *ptr++ = 0x8; \ *ptr++ = 0x1; \ *ptr++ = cref^0x80; \ *ptr++ = mty#if HISAX_DE_AOCstatic voidl3dss1_parse_facility(struct l3_process *pc, u_char * p){ int qd_len = 0; p++; qd_len = *p++; if (qd_len == 0) { l3_debug(pc->st, "qd_len == 0"); return; } if ((*p & 0x1F) != 0x11) { /* Service discriminator, supplementary service */ l3_debug(pc->st, "supplementary service != 0x11"); return; } while (qd_len > 0 && !(*p & 0x80)) { /* extension ? */ p++; qd_len--; } if (qd_len < 2) { l3_debug(pc->st, "qd_len < 2"); return; } p++; qd_len--; if ((*p & 0xE0) != 0xA0) { /* class and form */ l3_debug(pc->st, "class and form != 0xA0"); return; } switch (*p & 0x1F) { /* component tag */ case 1: /* invoke */ { unsigned char nlen = 0, ilen; int ident; p++; qd_len--; if (qd_len < 1) { l3_debug(pc->st, "qd_len < 1"); break; } if (*p & 0x80) { /* length format */ l3_debug(pc->st, "*p & 0x80 length format"); break; } nlen = *p++; qd_len--; if (qd_len < nlen) { l3_debug(pc->st, "qd_len < nlen"); return; } qd_len -= nlen; if (nlen < 2) { l3_debug(pc->st, "nlen < 2"); return; } if (*p != 0x02) { /* invoke identifier tag */ l3_debug(pc->st, "invoke identifier tag !=0x02"); return; } p++; nlen--; if (*p & 0x80) { /* length format */ l3_debug(pc->st, "*p & 0x80 length format 2"); break; } ilen = *p++; nlen--; if (ilen > nlen || ilen == 0) { l3_debug(pc->st, "ilen > nlen || ilen == 0"); return; } nlen -= ilen; ident = 0; while (ilen > 0) { ident = (ident << 8) | (*p++ & 0xFF); /* invoke identifier */ ilen--; } if (nlen < 2) { l3_debug(pc->st, "nlen < 2 22"); return; } if (*p != 0x02) { /* operation value */ l3_debug(pc->st, "operation value !=0x02"); return; } p++; nlen--; ilen = *p++; nlen--; if (ilen > nlen || ilen == 0) { l3_debug(pc->st, "ilen > nlen || ilen == 0 22"); return; } nlen -= ilen; ident = 0; while (ilen > 0) { ident = (ident << 8) | (*p++ & 0xFF); ilen--; }#define FOO1(s,a,b) \ while(nlen > 1) { \ int ilen = p[1]; \ if(nlen < ilen+2) { \ l3_debug(pc->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) { default: break; 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; pc->st->l3.l3l4(pc->st, CC_CHARGE | INDICATION, pc); } if (pc->st->l3.debug & L3_DEB_CHARGE) { if (*(p + 2) == 0) { l3_debug(pc->st, "charging info during %d", pc->para.chargeinfo); } else { l3_debug(pc->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; pc->st->l3.l3l4(pc->st, CC_CHARGE | INDICATION, pc); } if (pc->st->l3.debug & L3_DEB_CHARGE) { l3_debug(pc->st, "charging info final %d", pc->para.chargeinfo); } } )))))) break; }#undef FOO1 } break; case 2: /* return result */ l3_debug(pc->st, "return result break"); break; case 3: /* return error */ l3_debug(pc->st, "return error break"); break; default: l3_debug(pc->st, "default break"); break; }}#endifstatic intl3dss1_check_messagetype_validity(int mt){/* verify if a message type exists */ switch (mt) { case MT_ALERTING: case MT_CALL_PROCEEDING: case MT_CONNECT: case MT_CONNECT_ACKNOWLEDGE: case MT_PROGRESS: case MT_SETUP: case MT_SETUP_ACKNOWLEDGE: case MT_RESUME: case MT_RESUME_ACKNOWLEDGE: case MT_RESUME_REJECT: case MT_SUSPEND: case MT_SUSPEND_ACKNOWLEDGE: case MT_SUSPEND_REJECT: case MT_USER_INFORMATION: case MT_DISCONNECT: case MT_RELEASE: case MT_RELEASE_COMPLETE: case MT_RESTART: case MT_RESTART_ACKNOWLEDGE: case MT_SEGMENT: case MT_CONGESTION_CONTROL: case MT_INFORMATION: case MT_FACILITY: case MT_NOTIFY: case MT_STATUS: case MT_STATUS_ENQUIRY: return(1); default: return(0); } return(0);}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_release_req(struct l3_process *pc, u_char pr, void *arg){ StopAllL3Timer(pc); newl3state(pc, 19); l3dss1_message(pc, MT_RELEASE); L3AddTimer(&pc->timer, T308, CC_T308_1);}static voidl3dss1_release_cmpl(struct l3_process *pc, u_char pr, void *arg){ u_char *p; struct sk_buff *skb = arg; int cause = -1; p = skb->data; pc->para.loc = 0; 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); StopAllL3Timer(pc); pc->para.cause = cause; newl3state(pc, 0); pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc); release_l3_process(pc);}#if EXT_BEARER_CAPSu_char *EncodeASyncParams(u_char * p, u_char si2){ // 7c 06 88 90 21 42 00 bb p[0] = p[1] = 0; p[2] = 0x80; if (si2 & 32) // 7 data bits p[2] += 16; else // 8 data bits p[2] += 24; if (si2 & 16) // 2 stop bits p[2] += 96; else // 1 stop bit p[2] = 32; if (si2 & 8) // even parity p[2] += 2; else // no parity p[2] += 3; switch (si2 & 0x07) { case 0: p[0] = 66; // 1200 bit/s break; case 1: p[0] = 88; // 1200/75 bit/s break; case 2: p[0] = 87; // 75/1200 bit/s break; case 3: p[0] = 67; // 2400 bit/s break; case 4: p[0] = 69; // 4800 bit/s break; case 5: p[0] = 72; // 9600 bit/s break; case 6: p[0] = 73; // 14400 bit/s break; case 7: p[0] = 75; // 19200 bit/s break; } return p + 3;}u_charEncodeSyncParams(u_char si2, u_char ai){ switch (si2) { case 0: return ai + 2; // 1200 bit/s case 1: return ai + 24; // 1200/75 bit/s case 2: return ai + 23; // 75/1200 bit/s case 3: return ai + 3; // 2400 bit/s case 4: return ai + 5; // 4800 bit/s case 5: return ai + 8; // 9600 bit/s case 6: return ai + 9; // 14400 bit/s case 7: return ai + 11; // 19200 bit/s case 8: return ai + 14; // 48000 bit/s case 9: return ai + 15; // 56000 bit/s case 15: return ai + 40; // negotiate bit/s default: break; } return ai;}static u_charDecodeASyncParams(u_char si2, u_char * p){ u_char info; switch (p[5]) { case 66: // 1200 bit/s break; // si2 don't change case 88: // 1200/75 bit/s si2 += 1; break; case 87: // 75/1200 bit/s si2 += 2; break; case 67: // 2400 bit/s si2 += 3; break; case 69: // 4800 bit/s si2 += 4; break; case 72: // 9600 bit/s si2 += 5; break; case 73: // 14400 bit/s si2 += 6; break; case 75: // 19200 bit/s si2 += 7; break; } info = p[7] & 0x7f; if ((info & 16) && (!(info & 8))) // 7 data bits si2 += 32; // else 8 data bits if ((info & 96) == 96) // 2 stop bits si2 += 16; // else 1 stop bit if ((info & 2) && (!(info & 1))) // even parity si2 += 8; // else no parity return si2;}static u_charDecodeSyncParams(u_char si2, u_char info){ info &= 0x7f; switch (info) { case 40: // bit/s negotiation failed ai := 165 not 175! return si2 + 15; case 15: // 56000 bit/s failed, ai := 0 not 169 ! return si2 + 9; case 14: // 48000 bit/s return si2 + 8; case 11: // 19200 bit/s return si2 + 7; case 9: // 14400 bit/s return si2 + 6; case 8: // 9600 bit/s return si2 + 5; case 5: // 4800 bit/s return si2 + 4; case 3: // 2400 bit/s return si2 + 3; case 23: // 75/1200 bit/s return si2 + 2; case 24: // 1200/75 bit/s return si2 + 1; default: // 1200 bit/s return si2; }}static u_charDecodeSI2(struct sk_buff *skb){ u_char *p; //, *pend=skb->data + skb->len; if ((p = findie(skb->data, skb->len, 0x7c, 0))) { switch (p[4] & 0x0f) { case 0x01: if (p[1] == 0x04) // sync. Bitratenadaption return DecodeSyncParams(160, p[5]); // V.110/X.30 else if (p[1] == 0x06) // async. Bitratenadaption return DecodeASyncParams(192, p); // V.110/X.30 break; case 0x08: // if (p[5] == 0x02) // sync. Bitratenadaption return DecodeSyncParams(176, p[5]); // V.120 break; } } return 0;}#endifstatic voidl3dss1_setup_req(struct l3_process *pc, u_char pr, void *arg){ struct sk_buff *skb; u_char tmp[128]; u_char *p = tmp; u_char channel = 0; u_char screen = 0x80; u_char *teln; u_char *msn; u_char *sub; u_char *sp; int l; MsgHead(p, pc->callref, MT_SETUP); /* * Set Bearer Capability, Map info from 1TR6-convention to EDSS1 */#if HISAX_EURO_SENDCOMPLETE *p++ = 0xa1; /* complete indicator */#endif switch (pc->para.setup.si1) { case 1: /* Telephony */ *p++ = 0x4; /* BC-IE-code */ *p++ = 0x3; /* Length */ *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */ *p++ = 0x90; /* Circuit-Mode 64kbps */ *p++ = 0xa3; /* A-Law Audio */ break; case 5: /* Datatransmission 64k, BTX */ case 7: /* Datatransmission 64k */ default: *p++ = 0x4; /* BC-IE-code */ *p++ = 0x2; /* Length */ *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */ *p++ = 0x90; /* Circuit-Mode 64kbps */ break; } /* * What about info2? Mapping to High-Layer-Compatibility? */ teln = pc->para.setup.phone; if (*teln) { /* parse number for special things */ if (!isdigit(*teln)) { switch (0x5f & *teln) { case 'C': channel = 0x08; case 'P': channel |= 0x80; teln++; if (*teln == '1') channel |= 0x01; else channel |= 0x02; break; case 'R': screen = 0xA0; break; case 'D': screen = 0x80; break; default: if (pc->debug & L3_DEB_WARN) l3_debug(pc->st, "Wrong MSN Code"); break; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -