X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=kernel%2Fdrivers%2Fisdn%2Fhisax%2Fq931.c;fp=kernel%2Fdrivers%2Fisdn%2Fhisax%2Fq931.c;h=b420f8bd862e454df2cc08f4da84b8bc7ef76e57;hb=9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00;hp=0000000000000000000000000000000000000000;hpb=98260f3884f4a202f9ca5eabed40b1354c489b29;p=kvmfornfv.git diff --git a/kernel/drivers/isdn/hisax/q931.c b/kernel/drivers/isdn/hisax/q931.c new file mode 100644 index 000000000..b420f8bd8 --- /dev/null +++ b/kernel/drivers/isdn/hisax/q931.c @@ -0,0 +1,1513 @@ +/* $Id: q931.c,v 1.12.2.3 2004/01/13 14:31:26 keil Exp $ + * + * code to decode ITU Q.931 call control messages + * + * Author Jan den Ouden + * Copyright by Jan den Ouden + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + * Changelog: + * + * Pauline Middelink general improvements + * Beat Doebeli cause texts, display information element + * Karsten Keil cause texts, display information element for 1TR6 + * + */ + + +#include "hisax.h" +#include "l3_1tr6.h" + +void +iecpy(u_char *dest, u_char *iestart, int ieoffset) +{ + u_char *p; + int l; + + p = iestart + ieoffset + 2; + l = iestart[1] - ieoffset; + while (l--) + *dest++ = *p++; + *dest++ = '\0'; +} + +/* + * According to Table 4-2/Q.931 + */ +static +struct MessageType { + u_char nr; + char *descr; +} mtlist[] = { + + { + 0x1, "ALERTING" + }, + { + 0x2, "CALL PROCEEDING" + }, + { + 0x7, "CONNECT" + }, + { + 0xf, "CONNECT ACKNOWLEDGE" + }, + { + 0x3, "PROGRESS" + }, + { + 0x5, "SETUP" + }, + { + 0xd, "SETUP ACKNOWLEDGE" + }, + { + 0x24, "HOLD" + }, + { + 0x28, "HOLD ACKNOWLEDGE" + }, + { + 0x30, "HOLD REJECT" + }, + { + 0x31, "RETRIEVE" + }, + { + 0x33, "RETRIEVE ACKNOWLEDGE" + }, + { + 0x37, "RETRIEVE REJECT" + }, + { + 0x26, "RESUME" + }, + { + 0x2e, "RESUME ACKNOWLEDGE" + }, + { + 0x22, "RESUME REJECT" + }, + { + 0x25, "SUSPEND" + }, + { + 0x2d, "SUSPEND ACKNOWLEDGE" + }, + { + 0x21, "SUSPEND REJECT" + }, + { + 0x20, "USER INFORMATION" + }, + { + 0x45, "DISCONNECT" + }, + { + 0x4d, "RELEASE" + }, + { + 0x5a, "RELEASE COMPLETE" + }, + { + 0x46, "RESTART" + }, + { + 0x4e, "RESTART ACKNOWLEDGE" + }, + { + 0x60, "SEGMENT" + }, + { + 0x79, "CONGESTION CONTROL" + }, + { + 0x7b, "INFORMATION" + }, + { + 0x62, "FACILITY" + }, + { + 0x6e, "NOTIFY" + }, + { + 0x7d, "STATUS" + }, + { + 0x75, "STATUS ENQUIRY" + } +}; + +#define MTSIZE ARRAY_SIZE(mtlist) + +static +struct MessageType mt_n0[] = +{ + {MT_N0_REG_IND, "REGister INDication"}, + {MT_N0_CANC_IND, "CANCel INDication"}, + {MT_N0_FAC_STA, "FACility STAtus"}, + {MT_N0_STA_ACK, "STAtus ACKnowledge"}, + {MT_N0_STA_REJ, "STAtus REJect"}, + {MT_N0_FAC_INF, "FACility INFormation"}, + {MT_N0_INF_ACK, "INFormation ACKnowledge"}, + {MT_N0_INF_REJ, "INFormation REJect"}, + {MT_N0_CLOSE, "CLOSE"}, + {MT_N0_CLO_ACK, "CLOse ACKnowledge"} +}; + +#define MT_N0_LEN ARRAY_SIZE(mt_n0) + +static +struct MessageType mt_n1[] = +{ + {MT_N1_ESC, "ESCape"}, + {MT_N1_ALERT, "ALERT"}, + {MT_N1_CALL_SENT, "CALL SENT"}, + {MT_N1_CONN, "CONNect"}, + {MT_N1_CONN_ACK, "CONNect ACKnowledge"}, + {MT_N1_SETUP, "SETUP"}, + {MT_N1_SETUP_ACK, "SETUP ACKnowledge"}, + {MT_N1_RES, "RESume"}, + {MT_N1_RES_ACK, "RESume ACKnowledge"}, + {MT_N1_RES_REJ, "RESume REJect"}, + {MT_N1_SUSP, "SUSPend"}, + {MT_N1_SUSP_ACK, "SUSPend ACKnowledge"}, + {MT_N1_SUSP_REJ, "SUSPend REJect"}, + {MT_N1_USER_INFO, "USER INFO"}, + {MT_N1_DET, "DETach"}, + {MT_N1_DISC, "DISConnect"}, + {MT_N1_REL, "RELease"}, + {MT_N1_REL_ACK, "RELease ACKnowledge"}, + {MT_N1_CANC_ACK, "CANCel ACKnowledge"}, + {MT_N1_CANC_REJ, "CANCel REJect"}, + {MT_N1_CON_CON, "CONgestion CONtrol"}, + {MT_N1_FAC, "FACility"}, + {MT_N1_FAC_ACK, "FACility ACKnowledge"}, + {MT_N1_FAC_CAN, "FACility CANcel"}, + {MT_N1_FAC_REG, "FACility REGister"}, + {MT_N1_FAC_REJ, "FACility REJect"}, + {MT_N1_INFO, "INFOrmation"}, + {MT_N1_REG_ACK, "REGister ACKnowledge"}, + {MT_N1_REG_REJ, "REGister REJect"}, + {MT_N1_STAT, "STATus"} +}; + +#define MT_N1_LEN ARRAY_SIZE(mt_n1) + + +static int +prbits(char *dest, u_char b, int start, int len) +{ + char *dp = dest; + + b = b << (8 - start); + while (len--) { + if (b & 0x80) + *dp++ = '1'; + else + *dp++ = '0'; + b = b << 1; + } + return (dp - dest); +} + +static +u_char * +skipext(u_char *p) +{ + while (!(*p++ & 0x80)); + return (p); +} + +/* + * Cause Values According to Q.850 + * edescr: English description + * ddescr: German description used by Swissnet II (Swiss Telecom + * not yet written... + */ + +static +struct CauseValue { + u_char nr; + char *edescr; + char *ddescr; +} cvlist[] = { + + { + 0x01, "Unallocated (unassigned) number", "Nummer nicht zugeteilt" + }, + { + 0x02, "No route to specified transit network", "" + }, + { + 0x03, "No route to destination", "" + }, + { + 0x04, "Send special information tone", "" + }, + { + 0x05, "Misdialled trunk prefix", "" + }, + { + 0x06, "Channel unacceptable", "Kanal nicht akzeptierbar" + }, + { + 0x07, "Channel awarded and being delivered in an established channel", "" + }, + { + 0x08, "Preemption", "" + }, + { + 0x09, "Preemption - circuit reserved for reuse", "" + }, + { + 0x10, "Normal call clearing", "Normale Ausloesung" + }, + { + 0x11, "User busy", "TNB besetzt" + }, + { + 0x12, "No user responding", "" + }, + { + 0x13, "No answer from user (user alerted)", "" + }, + { + 0x14, "Subscriber absent", "" + }, + { + 0x15, "Call rejected", "" + }, + { + 0x16, "Number changed", "" + }, + { + 0x1a, "non-selected user clearing", "" + }, + { + 0x1b, "Destination out of order", "" + }, + { + 0x1c, "Invalid number format (address incomplete)", "" + }, + { + 0x1d, "Facility rejected", "" + }, + { + 0x1e, "Response to Status enquiry", "" + }, + { + 0x1f, "Normal, unspecified", "" + }, + { + 0x22, "No circuit/channel available", "" + }, + { + 0x26, "Network out of order", "" + }, + { + 0x27, "Permanent frame mode connection out-of-service", "" + }, + { + 0x28, "Permanent frame mode connection operational", "" + }, + { + 0x29, "Temporary failure", "" + }, + { + 0x2a, "Switching equipment congestion", "" + }, + { + 0x2b, "Access information discarded", "" + }, + { + 0x2c, "Requested circuit/channel not available", "" + }, + { + 0x2e, "Precedence call blocked", "" + }, + { + 0x2f, "Resource unavailable, unspecified", "" + }, + { + 0x31, "Quality of service unavailable", "" + }, + { + 0x32, "Requested facility not subscribed", "" + }, + { + 0x35, "Outgoing calls barred within CUG", "" + }, + { + 0x37, "Incoming calls barred within CUG", "" + }, + { + 0x39, "Bearer capability not authorized", "" + }, + { + 0x3a, "Bearer capability not presently available", "" + }, + { + 0x3e, "Inconsistency in designated outgoing access information and subscriber class ", " " + }, + { + 0x3f, "Service or option not available, unspecified", "" + }, + { + 0x41, "Bearer capability not implemented", "" + }, + { + 0x42, "Channel type not implemented", "" + }, + { + 0x43, "Requested facility not implemented", "" + }, + { + 0x44, "Only restricted digital information bearer capability is available", "" + }, + { + 0x4f, "Service or option not implemented", "" + }, + { + 0x51, "Invalid call reference value", "" + }, + { + 0x52, "Identified channel does not exist", "" + }, + { + 0x53, "A suspended call exists, but this call identity does not", "" + }, + { + 0x54, "Call identity in use", "" + }, + { + 0x55, "No call suspended", "" + }, + { + 0x56, "Call having the requested call identity has been cleared", "" + }, + { + 0x57, "User not member of CUG", "" + }, + { + 0x58, "Incompatible destination", "" + }, + { + 0x5a, "Non-existent CUG", "" + }, + { + 0x5b, "Invalid transit network selection", "" + }, + { + 0x5f, "Invalid message, unspecified", "" + }, + { + 0x60, "Mandatory information element is missing", "" + }, + { + 0x61, "Message type non-existent or not implemented", "" + }, + { + 0x62, "Message not compatible with call state or message type non-existent or not implemented ", " " + }, + { + 0x63, "Information element/parameter non-existent or not implemented", "" + }, + { + 0x64, "Invalid information element contents", "" + }, + { + 0x65, "Message not compatible with call state", "" + }, + { + 0x66, "Recovery on timer expiry", "" + }, + { + 0x67, "Parameter non-existent or not implemented - passed on", "" + }, + { + 0x6e, "Message with unrecognized parameter discarded", "" + }, + { + 0x6f, "Protocol error, unspecified", "" + }, + { + 0x7f, "Interworking, unspecified", "" + }, +}; + +#define CVSIZE ARRAY_SIZE(cvlist) + +static +int +prcause(char *dest, u_char *p) +{ + u_char *end; + char *dp = dest; + int i, cause; + + end = p + p[1] + 1; + p += 2; + dp += sprintf(dp, " coding "); + dp += prbits(dp, *p, 7, 2); + dp += sprintf(dp, " location "); + dp += prbits(dp, *p, 4, 4); + *dp++ = '\n'; + p = skipext(p); + + cause = 0x7f & *p++; + + /* locate cause value */ + for (i = 0; i < CVSIZE; i++) + if (cvlist[i].nr == cause) + break; + + /* display cause value if it exists */ + if (i == CVSIZE) + dp += sprintf(dp, "Unknown cause type %x!\n", cause); + else + dp += sprintf(dp, " cause value %x : %s \n", cause, cvlist[i].edescr); + + while (!0) { + if (p > end) + break; + dp += sprintf(dp, " diag attribute %d ", *p++ & 0x7f); + dp += sprintf(dp, " rej %d ", *p & 0x7f); + if (*p & 0x80) { + *dp++ = '\n'; + break; + } else + dp += sprintf(dp, " av %d\n", (*++p) & 0x7f); + } + return (dp - dest); + +} + +static +struct MessageType cause_1tr6[] = +{ + {CAUSE_InvCRef, "Invalid Call Reference"}, + {CAUSE_BearerNotImpl, "Bearer Service Not Implemented"}, + {CAUSE_CIDunknown, "Caller Identity unknown"}, + {CAUSE_CIDinUse, "Caller Identity in Use"}, + {CAUSE_NoChans, "No Channels available"}, + {CAUSE_FacNotImpl, "Facility Not Implemented"}, + {CAUSE_FacNotSubscr, "Facility Not Subscribed"}, + {CAUSE_OutgoingBarred, "Outgoing calls barred"}, + {CAUSE_UserAccessBusy, "User Access Busy"}, + {CAUSE_NegativeGBG, "Negative GBG"}, + {CAUSE_UnknownGBG, "Unknown GBG"}, + {CAUSE_NoSPVknown, "No SPV known"}, + {CAUSE_DestNotObtain, "Destination not obtainable"}, + {CAUSE_NumberChanged, "Number changed"}, + {CAUSE_OutOfOrder, "Out Of Order"}, + {CAUSE_NoUserResponse, "No User Response"}, + {CAUSE_UserBusy, "User Busy"}, + {CAUSE_IncomingBarred, "Incoming Barred"}, + {CAUSE_CallRejected, "Call Rejected"}, + {CAUSE_NetworkCongestion, "Network Congestion"}, + {CAUSE_RemoteUser, "Remote User initiated"}, + {CAUSE_LocalProcErr, "Local Procedure Error"}, + {CAUSE_RemoteProcErr, "Remote Procedure Error"}, + {CAUSE_RemoteUserSuspend, "Remote User Suspend"}, + {CAUSE_RemoteUserResumed, "Remote User Resumed"}, + {CAUSE_UserInfoDiscarded, "User Info Discarded"} +}; + +static int cause_1tr6_len = ARRAY_SIZE(cause_1tr6); + +static int +prcause_1tr6(char *dest, u_char *p) +{ + char *dp = dest; + int i, cause; + + p++; + if (0 == *p) { + dp += sprintf(dp, " OK (cause length=0)\n"); + return (dp - dest); + } else if (*p > 1) { + dp += sprintf(dp, " coding "); + dp += prbits(dp, p[2], 7, 2); + dp += sprintf(dp, " location "); + dp += prbits(dp, p[2], 4, 4); + *dp++ = '\n'; + } + p++; + cause = 0x7f & *p; + + /* locate cause value */ + for (i = 0; i < cause_1tr6_len; i++) + if (cause_1tr6[i].nr == cause) + break; + + /* display cause value if it exists */ + if (i == cause_1tr6_len) + dp += sprintf(dp, "Unknown cause type %x!\n", cause); + else + dp += sprintf(dp, " cause value %x : %s \n", cause, cause_1tr6[i].descr); + + return (dp - dest); + +} + +static int +prchident(char *dest, u_char *p) +{ + char *dp = dest; + + p += 2; + dp += sprintf(dp, " octet 3 "); + dp += prbits(dp, *p, 8, 8); + *dp++ = '\n'; + return (dp - dest); +} + +static int +prcalled(char *dest, u_char *p) +{ + int l; + char *dp = dest; + + p++; + l = *p++ - 1; + dp += sprintf(dp, " octet 3 "); + dp += prbits(dp, *p++, 8, 8); + *dp++ = '\n'; + dp += sprintf(dp, " number digits "); + while (l--) + *dp++ = *p++; + *dp++ = '\n'; + return (dp - dest); +} +static int +prcalling(char *dest, u_char *p) +{ + int l; + char *dp = dest; + + p++; + l = *p++ - 1; + dp += sprintf(dp, " octet 3 "); + dp += prbits(dp, *p, 8, 8); + *dp++ = '\n'; + if (!(*p & 0x80)) { + dp += sprintf(dp, " octet 3a "); + dp += prbits(dp, *++p, 8, 8); + *dp++ = '\n'; + l--; + }; + p++; + + dp += sprintf(dp, " number digits "); + while (l--) + *dp++ = *p++; + *dp++ = '\n'; + return (dp - dest); +} + +static +int +prbearer(char *dest, u_char *p) +{ + char *dp = dest, ch; + + p += 2; + dp += sprintf(dp, " octet 3 "); + dp += prbits(dp, *p++, 8, 8); + *dp++ = '\n'; + dp += sprintf(dp, " octet 4 "); + dp += prbits(dp, *p, 8, 8); + *dp++ = '\n'; + if ((*p++ & 0x1f) == 0x18) { + dp += sprintf(dp, " octet 4.1 "); + dp += prbits(dp, *p++, 8, 8); + *dp++ = '\n'; + } + /* check for user information layer 1 */ + if ((*p & 0x60) == 0x20) { + ch = ' '; + do { + dp += sprintf(dp, " octet 5%c ", ch); + dp += prbits(dp, *p, 8, 8); + *dp++ = '\n'; + if (ch == ' ') + ch = 'a'; + else + ch++; + } + while (!(*p++ & 0x80)); + } + /* check for user information layer 2 */ + if ((*p & 0x60) == 0x40) { + dp += sprintf(dp, " octet 6 "); + dp += prbits(dp, *p++, 8, 8); + *dp++ = '\n'; + } + /* check for user information layer 3 */ + if ((*p & 0x60) == 0x60) { + dp += sprintf(dp, " octet 7 "); + dp += prbits(dp, *p++, 8, 8); + *dp++ = '\n'; + } + return (dp - dest); +} + + +static +int +prbearer_ni1(char *dest, u_char *p) +{ + char *dp = dest; + u_char len; + + p++; + len = *p++; + dp += sprintf(dp, " octet 3 "); + dp += prbits(dp, *p, 8, 8); + switch (*p++) { + case 0x80: + dp += sprintf(dp, " Speech"); + break; + case 0x88: + dp += sprintf(dp, " Unrestricted digital information"); + break; + case 0x90: + dp += sprintf(dp, " 3.1 kHz audio"); + break; + default: + dp += sprintf(dp, " Unknown information-transfer capability"); + } + *dp++ = '\n'; + dp += sprintf(dp, " octet 4 "); + dp += prbits(dp, *p, 8, 8); + switch (*p++) { + case 0x90: + dp += sprintf(dp, " 64 kbps, circuit mode"); + break; + case 0xc0: + dp += sprintf(dp, " Packet mode"); + break; + default: + dp += sprintf(dp, " Unknown transfer mode"); + } + *dp++ = '\n'; + if (len > 2) { + dp += sprintf(dp, " octet 5 "); + dp += prbits(dp, *p, 8, 8); + switch (*p++) { + case 0x21: + dp += sprintf(dp, " Rate adaption\n"); + dp += sprintf(dp, " octet 5a "); + dp += prbits(dp, *p, 8, 8); + break; + case 0xa2: + dp += sprintf(dp, " u-law"); + break; + default: + dp += sprintf(dp, " Unknown UI layer 1 protocol"); + } + *dp++ = '\n'; + } + return (dp - dest); +} + +static int +general(char *dest, u_char *p) +{ + char *dp = dest; + char ch = ' '; + int l, octet = 3; + + p++; + l = *p++; + /* Iterate over all octets in the information element */ + while (l--) { + dp += sprintf(dp, " octet %d%c ", octet, ch); + dp += prbits(dp, *p++, 8, 8); + *dp++ = '\n'; + + /* last octet in group? */ + if (*p & 0x80) { + octet++; + ch = ' '; + } else if (ch == ' ') + ch = 'a'; + else + ch++; + } + return (dp - dest); +} + +static int +general_ni1(char *dest, u_char *p) +{ + char *dp = dest; + char ch = ' '; + int l, octet = 3; + + p++; + l = *p++; + /* Iterate over all octets in the information element */ + while (l--) { + dp += sprintf(dp, " octet %d%c ", octet, ch); + dp += prbits(dp, *p, 8, 8); + *dp++ = '\n'; + + /* last octet in group? */ + if (*p++ & 0x80) { + octet++; + ch = ' '; + } else if (ch == ' ') + ch = 'a'; + else + ch++; + } + return (dp - dest); +} + +static int +prcharge(char *dest, u_char *p) +{ + char *dp = dest; + int l; + + p++; + l = *p++ - 1; + dp += sprintf(dp, " GEA "); + dp += prbits(dp, *p++, 8, 8); + dp += sprintf(dp, " Anzahl: "); + /* Iterate over all octets in the * information element */ + while (l--) + *dp++ = *p++; + *dp++ = '\n'; + return (dp - dest); +} +static int +prtext(char *dest, u_char *p) +{ + char *dp = dest; + int l; + + p++; + l = *p++; + dp += sprintf(dp, " "); + /* Iterate over all octets in the * information element */ + while (l--) + *dp++ = *p++; + *dp++ = '\n'; + return (dp - dest); +} + +static int +prfeatureind(char *dest, u_char *p) +{ + char *dp = dest; + + p += 2; /* skip id, len */ + dp += sprintf(dp, " octet 3 "); + dp += prbits(dp, *p, 8, 8); + *dp++ = '\n'; + if (!(*p++ & 0x80)) { + dp += sprintf(dp, " octet 4 "); + dp += prbits(dp, *p++, 8, 8); + *dp++ = '\n'; + } + dp += sprintf(dp, " Status: "); + switch (*p) { + case 0: + dp += sprintf(dp, "Idle"); + break; + case 1: + dp += sprintf(dp, "Active"); + break; + case 2: + dp += sprintf(dp, "Prompt"); + break; + case 3: + dp += sprintf(dp, "Pending"); + break; + default: + dp += sprintf(dp, "(Reserved)"); + break; + } + *dp++ = '\n'; + return (dp - dest); +} + +static +struct DTag { /* Display tags */ + u_char nr; + char *descr; +} dtaglist[] = { + { 0x82, "Continuation" }, + { 0x83, "Called address" }, + { 0x84, "Cause" }, + { 0x85, "Progress indicator" }, + { 0x86, "Notification indicator" }, + { 0x87, "Prompt" }, + { 0x88, "Accumlated digits" }, + { 0x89, "Status" }, + { 0x8a, "Inband" }, + { 0x8b, "Calling address" }, + { 0x8c, "Reason" }, + { 0x8d, "Calling party name" }, + { 0x8e, "Called party name" }, + { 0x8f, "Orignal called name" }, + { 0x90, "Redirecting name" }, + { 0x91, "Connected name" }, + { 0x92, "Originating restrictions" }, + { 0x93, "Date & time of day" }, + { 0x94, "Call Appearance ID" }, + { 0x95, "Feature address" }, + { 0x96, "Redirection name" }, + { 0x9e, "Text" }, +}; +#define DTAGSIZE ARRAY_SIZE(dtaglist) + +static int +disptext_ni1(char *dest, u_char *p) +{ + char *dp = dest; + int l, tag, len, i; + + p++; + l = *p++ - 1; + if (*p++ != 0x80) { + dp += sprintf(dp, " Unknown display type\n"); + return (dp - dest); + } + /* Iterate over all tag,length,text fields */ + while (l > 0) { + tag = *p++; + len = *p++; + l -= len + 2; + /* Don't space or skip */ + if ((tag == 0x80) || (tag == 0x81)) p++; + else { + for (i = 0; i < DTAGSIZE; i++) + if (tag == dtaglist[i].nr) + break; + + /* When not found, give appropriate msg */ + if (i != DTAGSIZE) { + dp += sprintf(dp, " %s: ", dtaglist[i].descr); + while (len--) + *dp++ = *p++; + } else { + dp += sprintf(dp, " (unknown display tag %2x): ", tag); + while (len--) + *dp++ = *p++; + } + dp += sprintf(dp, "\n"); + } + } + return (dp - dest); +} +static int +display(char *dest, u_char *p) +{ + char *dp = dest; + char ch = ' '; + int l, octet = 3; + + p++; + l = *p++; + /* Iterate over all octets in the * display-information element */ + dp += sprintf(dp, " \""); + while (l--) { + dp += sprintf(dp, "%c", *p++); + + /* last octet in group? */ + if (*p & 0x80) { + octet++; + ch = ' '; + } else if (ch == ' ') + ch = 'a'; + + else + ch++; + } + *dp++ = '\"'; + *dp++ = '\n'; + return (dp - dest); +} + +static int +prfacility(char *dest, u_char *p) +{ + char *dp = dest; + int l, l2; + + p++; + l = *p++; + dp += sprintf(dp, " octet 3 "); + dp += prbits(dp, *p++, 8, 8); + dp += sprintf(dp, "\n"); + l -= 1; + + while (l > 0) { + dp += sprintf(dp, " octet 4 "); + dp += prbits(dp, *p++, 8, 8); + dp += sprintf(dp, "\n"); + dp += sprintf(dp, " octet 5 %d\n", l2 = *p++ & 0x7f); + l -= 2; + dp += sprintf(dp, " contents "); + while (l2--) { + dp += sprintf(dp, "%2x ", *p++); + l--; + } + dp += sprintf(dp, "\n"); + } + + return (dp - dest); +} + +static +struct InformationElement { + u_char nr; + char *descr; + int (*f) (char *, u_char *); +} ielist[] = { + + { + 0x00, "Segmented message", general + }, + { + 0x04, "Bearer capability", prbearer + }, + { + 0x08, "Cause", prcause + }, + { + 0x10, "Call identity", general + }, + { + 0x14, "Call state", general + }, + { + 0x18, "Channel identification", prchident + }, + { + 0x1c, "Facility", prfacility + }, + { + 0x1e, "Progress indicator", general + }, + { + 0x20, "Network-specific facilities", general + }, + { + 0x27, "Notification indicator", general + }, + { + 0x28, "Display", display + }, + { + 0x29, "Date/Time", general + }, + { + 0x2c, "Keypad facility", general + }, + { + 0x34, "Signal", general + }, + { + 0x40, "Information rate", general + }, + { + 0x42, "End-to-end delay", general + }, + { + 0x43, "Transit delay selection and indication", general + }, + { + 0x44, "Packet layer binary parameters", general + }, + { + 0x45, "Packet layer window size", general + }, + { + 0x46, "Packet size", general + }, + { + 0x47, "Closed user group", general + }, + { + 0x4a, "Reverse charge indication", general + }, + { + 0x6c, "Calling party number", prcalling + }, + { + 0x6d, "Calling party subaddress", general + }, + { + 0x70, "Called party number", prcalled + }, + { + 0x71, "Called party subaddress", general + }, + { + 0x74, "Redirecting number", general + }, + { + 0x78, "Transit network selection", general + }, + { + 0x79, "Restart indicator", general + }, + { + 0x7c, "Low layer compatibility", general + }, + { + 0x7d, "High layer compatibility", general + }, + { + 0x7e, "User-user", general + }, + { + 0x7f, "Escape for extension", general + }, +}; + + +#define IESIZE ARRAY_SIZE(ielist) + +static +struct InformationElement ielist_ni1[] = { + { 0x04, "Bearer Capability", prbearer_ni1 }, + { 0x08, "Cause", prcause }, + { 0x14, "Call State", general_ni1 }, + { 0x18, "Channel Identification", prchident }, + { 0x1e, "Progress Indicator", general_ni1 }, + { 0x27, "Notification Indicator", general_ni1 }, + { 0x2c, "Keypad Facility", prtext }, + { 0x32, "Information Request", general_ni1 }, + { 0x34, "Signal", general_ni1 }, + { 0x38, "Feature Activation", general_ni1 }, + { 0x39, "Feature Indication", prfeatureind }, + { 0x3a, "Service Profile Identification (SPID)", prtext }, + { 0x3b, "Endpoint Identifier", general_ni1 }, + { 0x6c, "Calling Party Number", prcalling }, + { 0x6d, "Calling Party Subaddress", general_ni1 }, + { 0x70, "Called Party Number", prcalled }, + { 0x71, "Called Party Subaddress", general_ni1 }, + { 0x74, "Redirecting Number", general_ni1 }, + { 0x78, "Transit Network Selection", general_ni1 }, + { 0x7c, "Low Layer Compatibility", general_ni1 }, + { 0x7d, "High Layer Compatibility", general_ni1 }, +}; + + +#define IESIZE_NI1 ARRAY_SIZE(ielist_ni1) + +static +struct InformationElement ielist_ni1_cs5[] = { + { 0x1d, "Operator system access", general_ni1 }, + { 0x2a, "Display text", disptext_ni1 }, +}; + +#define IESIZE_NI1_CS5 ARRAY_SIZE(ielist_ni1_cs5) + +static +struct InformationElement ielist_ni1_cs6[] = { + { 0x7b, "Call appearance", general_ni1 }, +}; + +#define IESIZE_NI1_CS6 ARRAY_SIZE(ielist_ni1_cs6) + +static struct InformationElement we_0[] = +{ + {WE0_cause, "Cause", prcause_1tr6}, + {WE0_connAddr, "Connecting Address", prcalled}, + {WE0_callID, "Call IDentity", general}, + {WE0_chanID, "Channel IDentity", general}, + {WE0_netSpecFac, "Network Specific Facility", general}, + {WE0_display, "Display", general}, + {WE0_keypad, "Keypad", general}, + {WE0_origAddr, "Origination Address", prcalled}, + {WE0_destAddr, "Destination Address", prcalled}, + {WE0_userInfo, "User Info", general} +}; + +#define WE_0_LEN ARRAY_SIZE(we_0) + +static struct InformationElement we_6[] = +{ + {WE6_serviceInd, "Service Indicator", general}, + {WE6_chargingInfo, "Charging Information", prcharge}, + {WE6_date, "Date", prtext}, + {WE6_facSelect, "Facility Select", general}, + {WE6_facStatus, "Facility Status", general}, + {WE6_statusCalled, "Status Called", general}, + {WE6_addTransAttr, "Additional Transmission Attributes", general} +}; +#define WE_6_LEN ARRAY_SIZE(we_6) + +int +QuickHex(char *txt, u_char *p, int cnt) +{ + register int i; + register char *t = txt; + + for (i = 0; i < cnt; i++) { + *t++ = ' '; + *t++ = hex_asc_hi(p[i]); + *t++ = hex_asc_lo(p[i]); + } + *t++ = 0; + return (t - txt); +} + +void +LogFrame(struct IsdnCardState *cs, u_char *buf, int size) +{ + char *dp; + + if (size < 1) + return; + dp = cs->dlog; + if (size < MAX_DLOG_SPACE / 3 - 10) { + *dp++ = 'H'; + *dp++ = 'E'; + *dp++ = 'X'; + *dp++ = ':'; + dp += QuickHex(dp, buf, size); + dp--; + *dp++ = '\n'; + *dp = 0; + HiSax_putstatus(cs, NULL, "%s", cs->dlog); + } else + HiSax_putstatus(cs, "LogFrame: ", "warning Frame too big (%d)", size); +} + +void +dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir) +{ + u_char *bend, *buf; + char *dp; + unsigned char pd, cr_l, cr, mt; + unsigned char sapi, tei, ftyp; + int i, cset = 0, cs_old = 0, cs_fest = 0; + int size, finish = 0; + + if (skb->len < 3) + return; + /* display header */ + dp = cs->dlog; + dp += jiftime(dp, jiffies); + *dp++ = ' '; + sapi = skb->data[0] >> 2; + tei = skb->data[1] >> 1; + ftyp = skb->data[2]; + buf = skb->data; + dp += sprintf(dp, "frame %s ", dir ? "network->user" : "user->network"); + size = skb->len; + + if (tei == GROUP_TEI) { + if (sapi == CTRL_SAPI) { /* sapi 0 */ + if (ftyp == 3) { + dp += sprintf(dp, "broadcast\n"); + buf += 3; + size -= 3; + } else { + dp += sprintf(dp, "no UI broadcast\n"); + finish = 1; + } + } else if (sapi == TEI_SAPI) { + dp += sprintf(dp, "tei management\n"); + finish = 1; + } else { + dp += sprintf(dp, "unknown sapi %d broadcast\n", sapi); + finish = 1; + } + } else { + if (sapi == CTRL_SAPI) { + if (!(ftyp & 1)) { /* IFrame */ + dp += sprintf(dp, "with tei %d\n", tei); + buf += 4; + size -= 4; + } else { + dp += sprintf(dp, "SFrame with tei %d\n", tei); + finish = 1; + } + } else { + dp += sprintf(dp, "unknown sapi %d tei %d\n", sapi, tei); + finish = 1; + } + } + bend = skb->data + skb->len; + if (buf >= bend) { + dp += sprintf(dp, "frame too short\n"); + finish = 1; + } + if (finish) { + *dp = 0; + HiSax_putstatus(cs, NULL, "%s", cs->dlog); + return; + } + if ((0xfe & buf[0]) == PROTO_DIS_N0) { /* 1TR6 */ + /* locate message type */ + pd = *buf++; + cr_l = *buf++; + if (cr_l) + cr = *buf++; + else + cr = 0; + mt = *buf++; + if (pd == PROTO_DIS_N0) { /* N0 */ + for (i = 0; i < MT_N0_LEN; i++) + if (mt_n0[i].nr == mt) + break; + /* display message type if it exists */ + if (i == MT_N0_LEN) + dp += sprintf(dp, "callref %d %s size %d unknown message type N0 %x!\n", + cr & 0x7f, (cr & 0x80) ? "called" : "caller", + size, mt); + else + dp += sprintf(dp, "callref %d %s size %d message type %s\n", + cr & 0x7f, (cr & 0x80) ? "called" : "caller", + size, mt_n0[i].descr); + } else { /* N1 */ + for (i = 0; i < MT_N1_LEN; i++) + if (mt_n1[i].nr == mt) + break; + /* display message type if it exists */ + if (i == MT_N1_LEN) + dp += sprintf(dp, "callref %d %s size %d unknown message type N1 %x!\n", + cr & 0x7f, (cr & 0x80) ? "called" : "caller", + size, mt); + else + dp += sprintf(dp, "callref %d %s size %d message type %s\n", + cr & 0x7f, (cr & 0x80) ? "called" : "caller", + size, mt_n1[i].descr); + } + + /* display each information element */ + while (buf < bend) { + /* Is it a single octet information element? */ + if (*buf & 0x80) { + switch ((*buf >> 4) & 7) { + case 1: + dp += sprintf(dp, " Shift %x\n", *buf & 0xf); + cs_old = cset; + cset = *buf & 7; + cs_fest = *buf & 8; + break; + case 3: + dp += sprintf(dp, " Congestion level %x\n", *buf & 0xf); + break; + case 2: + if (*buf == 0xa0) { + dp += sprintf(dp, " More data\n"); + break; + } + if (*buf == 0xa1) { + dp += sprintf(dp, " Sending complete\n"); + } + break; + /* fall through */ + default: + dp += sprintf(dp, " Reserved %x\n", *buf); + break; + } + buf++; + continue; + } + /* No, locate it in the table */ + if (cset == 0) { + for (i = 0; i < WE_0_LEN; i++) + if (*buf == we_0[i].nr) + break; + + /* When found, give appropriate msg */ + if (i != WE_0_LEN) { + dp += sprintf(dp, " %s\n", we_0[i].descr); + dp += we_0[i].f(dp, buf); + } else + dp += sprintf(dp, " Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]); + } else if (cset == 6) { + for (i = 0; i < WE_6_LEN; i++) + if (*buf == we_6[i].nr) + break; + + /* When found, give appropriate msg */ + if (i != WE_6_LEN) { + dp += sprintf(dp, " %s\n", we_6[i].descr); + dp += we_6[i].f(dp, buf); + } else + dp += sprintf(dp, " Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]); + } else + dp += sprintf(dp, " Unknown Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]); + /* Skip to next element */ + if (cs_fest == 8) { + cset = cs_old; + cs_old = 0; + cs_fest = 0; + } + buf += buf[1] + 2; + } + } else if ((buf[0] == 8) && (cs->protocol == ISDN_PTYPE_NI1)) { /* NI-1 */ + /* locate message type */ + buf++; + cr_l = *buf++; + if (cr_l) + cr = *buf++; + else + cr = 0; + mt = *buf++; + for (i = 0; i < MTSIZE; i++) + if (mtlist[i].nr == mt) + break; + + /* display message type if it exists */ + if (i == MTSIZE) + dp += sprintf(dp, "callref %d %s size %d unknown message type %x!\n", + cr & 0x7f, (cr & 0x80) ? "called" : "caller", + size, mt); + else + dp += sprintf(dp, "callref %d %s size %d message type %s\n", + cr & 0x7f, (cr & 0x80) ? "called" : "caller", + size, mtlist[i].descr); + + /* display each information element */ + while (buf < bend) { + /* Is it a single octet information element? */ + if (*buf & 0x80) { + switch ((*buf >> 4) & 7) { + case 1: + dp += sprintf(dp, " Shift %x\n", *buf & 0xf); + cs_old = cset; + cset = *buf & 7; + cs_fest = *buf & 8; + break; + default: + dp += sprintf(dp, " Unknown single-octet IE %x\n", *buf); + break; + } + buf++; + continue; + } + /* No, locate it in the table */ + if (cset == 0) { + for (i = 0; i < IESIZE_NI1; i++) + if (*buf == ielist_ni1[i].nr) + break; + + /* When not found, give appropriate msg */ + if (i != IESIZE_NI1) { + dp += sprintf(dp, " %s\n", ielist_ni1[i].descr); + dp += ielist_ni1[i].f(dp, buf); + } else + dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); + } else if (cset == 5) { + for (i = 0; i < IESIZE_NI1_CS5; i++) + if (*buf == ielist_ni1_cs5[i].nr) + break; + + /* When not found, give appropriate msg */ + if (i != IESIZE_NI1_CS5) { + dp += sprintf(dp, " %s\n", ielist_ni1_cs5[i].descr); + dp += ielist_ni1_cs5[i].f(dp, buf); + } else + dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); + } else if (cset == 6) { + for (i = 0; i < IESIZE_NI1_CS6; i++) + if (*buf == ielist_ni1_cs6[i].nr) + break; + + /* When not found, give appropriate msg */ + if (i != IESIZE_NI1_CS6) { + dp += sprintf(dp, " %s\n", ielist_ni1_cs6[i].descr); + dp += ielist_ni1_cs6[i].f(dp, buf); + } else + dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); + } else + dp += sprintf(dp, " Unknown Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]); + + /* Skip to next element */ + if (cs_fest == 8) { + cset = cs_old; + cs_old = 0; + cs_fest = 0; + } + buf += buf[1] + 2; + } + } else if ((buf[0] == 8) && (cs->protocol == ISDN_PTYPE_EURO)) { /* EURO */ + /* locate message type */ + buf++; + cr_l = *buf++; + if (cr_l) + cr = *buf++; + else + cr = 0; + mt = *buf++; + for (i = 0; i < MTSIZE; i++) + if (mtlist[i].nr == mt) + break; + + /* display message type if it exists */ + if (i == MTSIZE) + dp += sprintf(dp, "callref %d %s size %d unknown message type %x!\n", + cr & 0x7f, (cr & 0x80) ? "called" : "caller", + size, mt); + else + dp += sprintf(dp, "callref %d %s size %d message type %s\n", + cr & 0x7f, (cr & 0x80) ? "called" : "caller", + size, mtlist[i].descr); + + /* display each information element */ + while (buf < bend) { + /* Is it a single octet information element? */ + if (*buf & 0x80) { + switch ((*buf >> 4) & 7) { + case 1: + dp += sprintf(dp, " Shift %x\n", *buf & 0xf); + break; + case 3: + dp += sprintf(dp, " Congestion level %x\n", *buf & 0xf); + break; + case 5: + dp += sprintf(dp, " Repeat indicator %x\n", *buf & 0xf); + break; + case 2: + if (*buf == 0xa0) { + dp += sprintf(dp, " More data\n"); + break; + } + if (*buf == 0xa1) { + dp += sprintf(dp, " Sending complete\n"); + } + break; + /* fall through */ + default: + dp += sprintf(dp, " Reserved %x\n", *buf); + break; + } + buf++; + continue; + } + /* No, locate it in the table */ + for (i = 0; i < IESIZE; i++) + if (*buf == ielist[i].nr) + break; + + /* When not found, give appropriate msg */ + if (i != IESIZE) { + dp += sprintf(dp, " %s\n", ielist[i].descr); + dp += ielist[i].f(dp, buf); + } else + dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); + + /* Skip to next element */ + buf += buf[1] + 2; + } + } else { + dp += sprintf(dp, "Unknown protocol %x!", buf[0]); + } + *dp = 0; + HiSax_putstatus(cs, NULL, "%s", cs->dlog); +}