2005-04-17 02:20:36 +04:00
/* $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 1 TR6
*
*/
# 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 "
}
} ;
2009-07-24 20:26:08 +04:00
# define MTSIZE ARRAY_SIZE(mtlist)
2005-04-17 02:20:36 +04:00
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 " }
} ;
2009-07-24 20:26:08 +04:00
# define MT_N0_LEN ARRAY_SIZE(mt_n0)
2005-04-17 02:20:36 +04:00
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 " }
} ;
2009-07-24 20:26:08 +04:00
# define MT_N1_LEN ARRAY_SIZE(mt_n1)
2005-04-17 02:20:36 +04:00
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 " , " "
} ,
} ;
2009-07-24 20:26:08 +04:00
# define CVSIZE ARRAY_SIZE(cvlist)
2005-04-17 02:20:36 +04:00
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 " }
} ;
2009-07-24 20:26:08 +04:00
static int cause_1tr6_len = ARRAY_SIZE ( cause_1tr6 ) ;
2005-04-17 02:20:36 +04:00
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 + + & 80 ) ) {
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 " } ,
} ;
2009-07-24 20:26:08 +04:00
# define DTAGSIZE ARRAY_SIZE(dtaglist)
2005-04-17 02:20:36 +04:00
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 ) ;
}
2005-06-26 01:59:18 +04:00
static int
2005-04-17 02:20:36 +04:00
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
} ,
} ;
2009-07-24 20:26:08 +04:00
# define IESIZE ARRAY_SIZE(ielist)
2005-04-17 02:20:36 +04:00
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 } ,
} ;
2009-07-24 20:26:08 +04:00
# define IESIZE_NI1 ARRAY_SIZE(ielist_ni1)
2005-04-17 02:20:36 +04:00
static
struct InformationElement ielist_ni1_cs5 [ ] = {
{ 0x1d , " Operator system access " , general_ni1 } ,
{ 0x2a , " Display text " , disptext_ni1 } ,
} ;
2009-07-24 20:26:08 +04:00
# define IESIZE_NI1_CS5 ARRAY_SIZE(ielist_ni1_cs5)
2005-04-17 02:20:36 +04:00
static
struct InformationElement ielist_ni1_cs6 [ ] = {
{ 0x7b , " Call appearance " , general_ni1 } ,
} ;
2009-07-24 20:26:08 +04:00
# define IESIZE_NI1_CS6 ARRAY_SIZE(ielist_ni1_cs6)
2005-04-17 02:20:36 +04:00
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 }
} ;
2009-07-24 20:26:08 +04:00
# define WE_0_LEN ARRAY_SIZE(we_0)
2005-04-17 02:20:36 +04:00
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 }
} ;
2009-07-24 20:26:08 +04:00
# define WE_6_LEN ARRAY_SIZE(we_6)
2005-04-17 02:20:36 +04:00
int
QuickHex ( char * txt , u_char * p , int cnt )
{
register int i ;
register char * t = txt ;
for ( i = 0 ; i < cnt ; i + + ) {
* t + + = ' ' ;
2010-07-15 06:37:18 +04:00
* t + + = hex_asc_hi ( p [ i ] ) ;
* t + + = hex_asc_lo ( p [ i ] ) ;
2005-04-17 02:20:36 +04:00
}
* 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 , 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 , 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 ) {
2006-06-26 11:25:32 +04:00
for ( i = 0 ; i < IESIZE_NI1 ; i + + )
2005-04-17 02:20:36 +04:00
if ( * buf = = ielist_ni1 [ i ] . nr )
break ;
/* When not found, give appropriate msg */
2006-06-26 11:25:32 +04:00
if ( i ! = IESIZE_NI1 ) {
2005-04-17 02:20:36 +04:00
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 , cs - > dlog ) ;
}