2001-05-13 00:41:32 +08:00
/*
* libpri : An implementation of Primary Rate ISDN
*
* Written by Mark Spencer < markster @ linux - support . net >
*
* Copyright ( C ) 2001 , Linux Support Services , Inc .
* All Rights Reserved .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*
*/
# include "libpri.h"
# include "pri_internal.h"
# include "pri_q921.h"
# include "pri_q931.h"
# include <unistd.h>
# include <stdlib.h>
# include <string.h>
# include <stdio.h>
2003-09-25 14:13:14 +08:00
# define MAX_MAND_IES 10
2001-05-13 00:41:32 +08:00
struct msgtype {
int msgnum ;
unsigned char * name ;
2003-09-25 14:13:14 +08:00
int mandies [ MAX_MAND_IES ] ;
2001-07-17 20:12:42 +08:00
} ;
struct msgtype msgs [ ] = {
2001-05-13 00:41:32 +08:00
/* Call establishment messages */
{ Q931_ALERTING , " ALERTING " } ,
{ Q931_CALL_PROCEEDING , " CALL PROCEEDING " } ,
{ Q931_CONNECT , " CONNECT " } ,
{ Q931_CONNECT_ACKNOWLEDGE , " CONNECT ACKNOWLEDGE " } ,
2003-09-25 14:13:14 +08:00
{ Q931_PROGRESS , " PROGRESS " , { Q931_PROGRESS_INDICATOR } } ,
{ Q931_SETUP , " SETUP " , { Q931_BEARER_CAPABILITY , Q931_CHANNEL_IDENT } } ,
2002-03-18 22:04:47 +08:00
{ Q931_SETUP_ACKNOWLEDGE , " SETUP ACKNOWLEDGE " } ,
2001-05-13 00:41:32 +08:00
/* Call disestablishment messages */
2003-09-25 14:13:14 +08:00
{ Q931_DISCONNECT , " DISCONNECT " , { Q931_CAUSE } } ,
2001-05-13 00:41:32 +08:00
{ Q931_RELEASE , " RELEASE " } ,
{ Q931_RELEASE_COMPLETE , " RELEASE COMPLETE " } ,
2003-09-25 14:13:14 +08:00
{ Q931_RESTART , " RESTART " , { Q931_RESTART_INDICATOR } } ,
{ Q931_RESTART_ACKNOWLEDGE , " RESTART ACKNOWLEDGE " , { Q931_RESTART_INDICATOR } } ,
2001-05-13 00:41:32 +08:00
/* Miscellaneous */
2003-09-25 14:13:14 +08:00
{ Q931_STATUS , " STATUS " , { Q931_CAUSE , Q931_CALL_STATE } } ,
2001-05-13 00:41:32 +08:00
{ Q931_STATUS_ENQUIRY , " STATUS ENQUIRY " } ,
2001-07-17 20:12:42 +08:00
{ Q931_USER_INFORMATION , " USER_INFORMATION " } ,
{ Q931_SEGMENT , " SEGMENT " } ,
{ Q931_CONGESTION_CONTROL , " CONGESTION CONTROL " } ,
{ Q931_INFORMATION , " INFORMATION " } ,
2003-02-12 21:59:23 +08:00
{ Q931_FACILITY , " FACILITY " } ,
2003-09-25 14:13:14 +08:00
{ Q931_NOTIFY , " NOTIFY " , { Q931_IE_NOTIFY_IND } } ,
2001-07-17 20:12:42 +08:00
/* Call Management */
{ Q931_HOLD , " HOLD " } ,
{ Q931_HOLD_ACKNOWLEDGE , " HOLD ACKNOWLEDGE " } ,
{ Q931_HOLD_REJECT , " HOLD REJECT " } ,
{ Q931_RETRIEVE , " RETRIEVE " } ,
{ Q931_RETRIEVE_ACKNOWLEDGE , " RETRIEVE ACKNOWLEDGE " } ,
{ Q931_RETRIEVE_REJECT , " RETRIEVE REJECT " } ,
{ Q931_RESUME , " RESUME " } ,
2003-09-25 14:13:14 +08:00
{ Q931_RESUME_ACKNOWLEDGE , " RESUME ACKNOWLEDGE " , { Q931_CHANNEL_IDENT } } ,
{ Q931_RESUME_REJECT , " RESUME REJECT " , { Q931_CAUSE } } ,
2001-07-17 20:12:42 +08:00
{ Q931_SUSPEND , " SUSPEND " } ,
{ Q931_SUSPEND_ACKNOWLEDGE , " SUSPEND ACKNOWLEDGE " } ,
{ Q931_SUSPEND_REJECT , " SUSPEND REJECT " } ,
2001-05-13 00:41:32 +08:00
/* Maintenance */
{ NATIONAL_SERVICE , " SERVICE " } ,
{ NATIONAL_SERVICE_ACKNOWLEDGE , " SERVICE ACKNOWLEDGE " } ,
} ;
2001-07-17 20:12:42 +08:00
struct msgtype causes [ ] = {
{ PRI_CAUSE_UNALLOCATED , " Unallocated (unassigned) number " } ,
{ PRI_CAUSE_NO_ROUTE_TRANSIT_NET , " No route to specified transmit network " } ,
{ PRI_CAUSE_NO_ROUTE_DESTINATION , " No route to destination " } ,
{ PRI_CAUSE_CHANNEL_UNACCEPTABLE , " Channel unacceptable " } ,
{ PRI_CAUSE_CALL_AWARDED_DELIVERED , " Call awarded and being delivered in an established channel " } ,
{ PRI_CAUSE_NORMAL_CLEARING , " Normal Clearing " } ,
{ PRI_CAUSE_USER_BUSY , " User busy " } ,
{ PRI_CAUSE_NO_USER_RESPONSE , " No user responding " } ,
{ PRI_CAUSE_NO_ANSWER , " User alerting, no answer " } ,
{ PRI_CAUSE_CALL_REJECTED , " Call Rejected " } ,
2002-03-18 22:04:47 +08:00
{ PRI_CAUSE_NUMBER_CHANGED , " Number changed " } ,
2001-07-17 20:12:42 +08:00
{ PRI_CAUSE_DESTINATION_OUT_OF_ORDER , " Destination out of order " } ,
{ PRI_CAUSE_INVALID_NUMBER_FORMAT , " Invalid number format " } ,
2002-03-18 22:04:47 +08:00
{ PRI_CAUSE_FACILITY_REJECTED , " Facility rejected " } ,
2001-07-17 20:12:42 +08:00
{ PRI_CAUSE_RESPONSE_TO_STATUS_ENQUIRY , " Response to STATus ENQuiry " } ,
{ PRI_CAUSE_NORMAL_UNSPECIFIED , " Normal, unspecified " } ,
{ PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION , " Circuit/channel congestion " } ,
2002-03-18 22:04:47 +08:00
{ PRI_CAUSE_NETWORK_OUT_OF_ORDER , " Network out of order " } ,
2001-07-17 20:12:42 +08:00
{ PRI_CAUSE_NORMAL_TEMPORARY_FAILURE , " Temporary failure " } ,
{ PRI_CAUSE_SWITCH_CONGESTION , " Switching equipment congestion " } ,
{ PRI_CAUSE_ACCESS_INFO_DISCARDED , " Access information discarded " } ,
{ PRI_CAUSE_REQUESTED_CHAN_UNAVAIL , " Requested channel not available " } ,
2002-03-18 22:04:47 +08:00
{ PRI_CAUSE_PRE_EMPTED , " Pre-empted " } ,
{ PRI_CAUSE_FACILITY_NOT_SUBSCRIBED , " Facility not subscribed " } ,
{ PRI_CAUSE_OUTGOING_CALL_BARRED , " Outgoing call barred " } ,
{ PRI_CAUSE_INCOMING_CALL_BARRED , " Incoming call barred " } ,
2001-07-17 20:12:42 +08:00
{ PRI_CAUSE_BEARERCAPABILITY_NOTAUTH , " Bearer capability not authorized " } ,
2002-03-18 22:04:47 +08:00
{ PRI_CAUSE_BEARERCAPABILITY_NOTAVAIL , " Bearer capability not available " } ,
2001-07-17 20:12:42 +08:00
{ PRI_CAUSE_BEARERCAPABILITY_NOTIMPL , " Bearer capability not implemented " } ,
2002-03-18 22:04:47 +08:00
{ PRI_CAUSE_CHAN_NOT_IMPLEMENTED , " Channel not implemented " } ,
{ PRI_CAUSE_FACILITY_NOT_IMPLEMENTED , " Facility not implemented " } ,
2001-07-17 20:12:42 +08:00
{ PRI_CAUSE_INVALID_CALL_REFERENCE , " Invalid call reference value " } ,
{ PRI_CAUSE_INCOMPATIBLE_DESTINATION , " Incompatible destination " } ,
2002-03-18 22:04:47 +08:00
{ PRI_CAUSE_INVALID_MSG_UNSPECIFIED , " Invalid message unspecified " } ,
2001-07-17 20:12:42 +08:00
{ PRI_CAUSE_MANDATORY_IE_MISSING , " Mandatory information element is missing " } ,
{ PRI_CAUSE_MESSAGE_TYPE_NONEXIST , " Message type nonexist. " } ,
2002-03-18 22:04:47 +08:00
{ PRI_CAUSE_WRONG_MESSAGE , " Wrong message " } ,
2001-07-17 20:12:42 +08:00
{ PRI_CAUSE_IE_NONEXIST , " Info. element nonexist or not implemented " } ,
{ PRI_CAUSE_INVALID_IE_CONTENTS , " Invalid information element contents " } ,
{ PRI_CAUSE_WRONG_CALL_STATE , " Message not compatible with call state " } ,
{ PRI_CAUSE_RECOVERY_ON_TIMER_EXPIRE , " Recover on timer expiry " } ,
2002-03-18 22:04:47 +08:00
{ PRI_CAUSE_MANDATORY_IE_LENGTH_ERROR , " Mandatory IE length error " } ,
2001-07-17 20:12:42 +08:00
{ PRI_CAUSE_PROTOCOL_ERROR , " Protocol error, unspecified " } ,
{ PRI_CAUSE_INTERWORKING , " Interworking, unspecified " } ,
} ;
2001-05-13 00:41:32 +08:00
# define FLAG_PREFERRED 2
# define FLAG_EXCLUSIVE 4
# define RESET_INDICATOR_CHANNEL 0
# define RESET_INDICATOR_DS1 6
# define RESET_INDICATOR_PRI 7
# define TRANS_MODE_64_CIRCUIT 0x10
2001-07-17 20:12:42 +08:00
# define TRANS_MODE_2x64_CIRCUIT 0x11
2001-05-13 00:41:32 +08:00
# define TRANS_MODE_384_CIRCUIT 0x13
# define TRANS_MODE_1536_CIRCUIT 0x15
2001-07-17 20:12:42 +08:00
# define TRANS_MODE_1920_CIRCUIT 0x17
2001-05-13 00:41:32 +08:00
# define TRANS_MODE_MULTIRATE 0x18
# define TRANS_MODE_PACKET 0X40
# define RATE_ADAPT_56K 0x0f
# define LAYER_2_LAPB 0x46
# define LAYER_3_X25 0x66
/* The 4ESS uses a different audio field */
# define PRI_TRANS_CAP_AUDIO_4ESS 0x08
2002-03-18 22:04:47 +08:00
# define Q931_PROG_CALL_NOT_E2E_ISDN 0x011
# define Q931_PROG_CALLED_NOT_ISDN 0x02
# define Q931_PROG_CALLER_NOT_ISDN 0x03
# define Q931_PROG_INBAND_AVAILABLE 0x08
# define Q931_PROG_DELAY_AT_INTERF 0x0a
# define Q931_PROG_INTERWORKING_WITH_PUBLIC 0x10
# define Q931_PROG_INTERWORKING_NO_RELEASE 0x11
# define Q931_PROG_INTERWORKING_NO_RELEASE_PRE_ANSWER 0x12
# define Q931_PROG_INTERWORKING_NO_RELEASE_POST_ANSWER 0x13
2001-05-13 00:41:32 +08:00
2001-07-17 20:12:42 +08:00
# define CODE_CCITT 0x0
# define CODE_INTERNATIONAL 0x1
# define CODE_NATIONAL 0x2
# define CODE_NETWORK_SPECIFIC 0x3
2001-05-13 00:41:32 +08:00
# define LOC_USER 0x0
# define LOC_PRIV_NET_LOCAL_USER 0x1
# define LOC_PUB_NET_LOCAL_USER 0x2
# define LOC_TRANSIT_NET 0x3
# define LOC_PUB_NET_REMOTE_USER 0x4
# define LOC_PRIV_NET_REMOTE_USER 0X5
# define LOC_INTERNATIONAL_NETWORK 0x7
# define LOC_NETWORK_BEYOND_INTERWORKING 0xa
2003-09-25 14:13:14 +08:00
# define T_308 4000
# define T_305 30000
# define T_313 4000
2001-05-13 00:41:32 +08:00
struct q931_call {
2003-09-25 14:13:14 +08:00
struct pri * pri ; /* PRI */
2001-05-13 00:41:32 +08:00
int cr ; /* Call Reference */
2002-03-18 22:04:47 +08:00
int forceinvert ; /* Force inversion of call number even if 0 */
2001-05-13 00:41:32 +08:00
q931_call * next ;
2001-07-17 20:12:42 +08:00
/* Slotmap specified (bitmap of channels 31/24-1) (Channel Identifier IE) (-1 means not specified) */
2001-05-13 00:41:32 +08:00
int slotmap ;
/* An explicit channel (Channel Identifier IE) (-1 means not specified) */
int channelno ;
/* An explicit DS1 (-1 means not specified) */
int ds1no ;
/* Channel flags (0 means none retrieved) */
int chanflags ;
2003-02-12 21:59:23 +08:00
int alive ; /* Whether or not the call is alive */
int acked ; /* Whether setup has been acked or not */
2002-03-18 22:04:47 +08:00
int sendhangupack ; /* Whether or not to send a hangup ack */
2003-02-12 21:59:23 +08:00
int proc ; /* Whether we've sent a call proceeding / alerting */
2001-05-13 00:41:32 +08:00
int ri ; /* Restart Indicator (Restart Indicator IE) */
/* Bearer Capability */
int transcapability ;
int transmoderate ;
int transmultiple ;
int userl1 ;
int userl2 ;
int userl3 ;
int rateadaption ;
int sentchannel ;
int progcode ; /* Progress coding */
int progloc ; /* Progress Location */
int progress ; /* Progress indicator */
int causecode ; /* Cause Coding */
int causeloc ; /* Cause Location */
int cause ; /* Cause of clearing */
2003-08-05 09:00:45 +08:00
int peercallstate ; /* Call state of peer as reported */
2003-03-04 14:00:37 +08:00
int ourcallstate ; /* Our call state */
2003-09-25 14:13:14 +08:00
int sugcallstate ; /* Status call state */
2001-05-13 00:41:32 +08:00
int callerplan ;
int callerpres ; /* Caller presentation */
char callernum [ 256 ] ; /* Caller */
2003-02-12 21:59:23 +08:00
char callername [ 256 ] ;
2001-05-13 00:41:32 +08:00
int calledplan ;
int nonisdn ;
char callednum [ 256 ] ; /* Called Number */
2003-07-02 04:25:34 +08:00
int complete ; /* no more digits coming */
2003-09-25 14:13:14 +08:00
int newcall ; /* if the received message has a new call reference value */
2003-02-12 21:59:23 +08:00
2003-09-25 14:13:14 +08:00
int retranstimer ; /* Timer for retransmitting DISC */
int t308_timedout ; /* Whether t308 timed out once */
2003-02-12 21:59:23 +08:00
int redirectingplan ;
int redirectingpres ;
int redirectingreason ;
char redirectingnum [ 256 ] ;
int useruserprotocoldisc ;
char useruserinfo [ 256 ] ;
2001-05-13 00:41:32 +08:00
} ;
struct ie {
int ie ;
char * name ;
/* Dump an IE for debugging (preceed all lines by prefix) */
void ( * dump ) ( q931_ie * ie , int len , char prefix ) ;
/* Handle IE returns 0 on success, -1 on failure */
int ( * receive ) ( struct pri * pri , q931_call * call , int msgtype , q931_ie * ie , int len ) ;
/* Add IE to a message, return the # of bytes added or -1 on failure */
int ( * transmit ) ( struct pri * pri , q931_call * call , int msgtype , q931_ie * ie , int maxlen ) ;
} ;
2001-07-17 20:12:42 +08:00
static char * code2str ( int code , struct msgtype * codes , int max )
{
int x ;
for ( x = 0 ; x < max ; x + + )
if ( codes [ x ] . msgnum = = code )
return codes [ x ] . name ;
return " Unknown " ;
}
2001-05-13 00:41:32 +08:00
static void call_init ( struct q931_call * c )
{
memset ( c , 0 , sizeof ( * c ) ) ;
c - > alive = 0 ;
2001-12-08 03:45:45 +08:00
c - > sendhangupack = 0 ;
2002-03-18 22:04:47 +08:00
c - > forceinvert = - 1 ;
2001-05-13 00:41:32 +08:00
c - > cr = - 1 ;
c - > slotmap = - 1 ;
c - > channelno = - 1 ;
c - > ds1no = - 1 ;
c - > chanflags = 0 ;
c - > next = NULL ;
c - > sentchannel = 0 ;
2003-09-25 14:13:14 +08:00
c - > newcall = 1 ;
2003-03-04 14:00:37 +08:00
c - > ourcallstate = Q931_CALL_STATE_NULL ;
2003-08-05 09:00:45 +08:00
c - > peercallstate = Q931_CALL_STATE_NULL ;
2001-05-13 00:41:32 +08:00
}
static char * binary ( int b , int len ) {
static char res [ 33 ] ;
int x ;
memset ( res , 0 , sizeof ( res ) ) ;
if ( len > 32 )
len = 32 ;
for ( x = 1 ; x < = len ; x + + )
res [ x - 1 ] = b & ( 1 < < ( len - x ) ) ? ' 1 ' : ' 0 ' ;
return res ;
}
static int receive_channel_id ( struct pri * pri , q931_call * call , int msgtype , q931_ie * ie , int len )
{
int x ;
int pos = 0 ;
2003-02-12 21:59:23 +08:00
# ifdef NO_BRI_SUPPORT
if ( ! ie - > data [ 0 ] & 0x20 ) {
pri_error ( " !! Not PRI type!? \n " ) ;
return - 1 ;
}
# endif
# ifndef NOAUTO_CHANNEL_SELECTION_SUPPORT
2001-05-13 00:41:32 +08:00
if ( ( ie - > data [ 0 ] & 3 ) ! = 1 ) {
2003-02-12 21:59:23 +08:00
pri_error ( " !! Unexpected Channel selection %d \n " , ie - > data [ 0 ] & 3 ) ;
2001-05-13 00:41:32 +08:00
return - 1 ;
}
2003-02-12 21:59:23 +08:00
# endif
2001-05-13 00:41:32 +08:00
if ( ie - > data [ 0 ] & 0x08 )
call - > chanflags = FLAG_EXCLUSIVE ;
else
call - > chanflags = FLAG_PREFERRED ;
pos + + ;
if ( ie - > data [ 0 ] & 0x40 ) {
/* DS1 specified -- stop here */
call - > ds1no = ie - > data [ 1 ] & 0x7f ;
pos + + ;
}
2003-02-12 21:59:23 +08:00
if ( pos + 2 < len ) {
2001-05-13 00:41:32 +08:00
/* More coming */
if ( ( ie - > data [ pos ] & 0x0f ) ! = 3 ) {
2003-02-12 21:59:23 +08:00
pri_error ( " !! Unexpected Channel Type %d \n " , ie - > data [ 1 ] & 0x0f ) ;
2001-05-13 00:41:32 +08:00
return - 1 ;
}
if ( ( ie - > data [ pos ] & 0x60 ) ! = 0 ) {
2003-02-12 21:59:23 +08:00
pri_error ( " !! Invalid CCITT coding %d \n " , ( ie - > data [ 1 ] & 0x60 ) > > 5 ) ;
2001-05-13 00:41:32 +08:00
return - 1 ;
}
if ( ie - > data [ pos ] & 0x10 ) {
/* Expect Slot Map */
call - > slotmap = 0 ;
pos + + ;
for ( x = 0 ; x < 3 ; x + + ) {
call - > slotmap < < = 8 ;
call - > slotmap | = ie - > data [ x + pos ] ;
}
return 0 ;
} else {
pos + + ;
/* Only expect a particular channel */
call - > channelno = ie - > data [ pos ] & 0x7f ;
return 0 ;
}
} else
return 0 ;
return - 1 ;
}
static int transmit_channel_id ( struct pri * pri , q931_call * call , int msgtype , q931_ie * ie , int len )
{
int pos = 0 ;
/* Start with standard stuff */
ie - > data [ pos ] = 0xa1 ;
/* Add exclusive flag if necessary */
if ( call - > chanflags & FLAG_EXCLUSIVE )
ie - > data [ pos ] | = 0x08 ;
else if ( ! ( call - > chanflags & FLAG_PREFERRED ) ) {
/* Don't need this IE */
return 0 ;
}
if ( call - > ds1no > - 1 ) {
/* Note that we are specifying the identifier */
2002-03-18 22:04:47 +08:00
ie - > data [ pos + + ] | = 0x40 ;
2001-05-13 00:41:32 +08:00
/* We need to use the Channel Identifier Present thingy. Just specify it and we're done */
2002-03-18 22:04:47 +08:00
ie - > data [ pos + + ] = 0x80 | call - > ds1no ;
2001-05-13 00:41:32 +08:00
} else
pos + + ;
if ( ( call - > channelno > - 1 ) | | ( call - > slotmap ! = - 1 ) ) {
/* We'll have the octet 8.2 and 8.3's present */
ie - > data [ pos + + ] = 0x83 ;
if ( call - > channelno > - 1 ) {
/* Channel number specified */
ie - > data [ pos + + ] = 0x80 | call - > channelno ;
return pos + 2 ;
}
/* We have to send a channel map */
if ( call - > slotmap ! = - 1 ) {
ie - > data [ pos - 1 ] | = 0x10 ;
ie - > data [ pos + + ] = ( call - > slotmap & 0xff0000 ) > > 16 ;
ie - > data [ pos + + ] = ( call - > slotmap & 0xff00 ) > > 8 ;
ie - > data [ pos + + ] = ( call - > slotmap & 0xff ) ;
return pos + 2 ;
}
}
if ( call - > ds1no > - 1 ) {
/* We're done */
return pos + 2 ;
}
2003-02-12 21:59:23 +08:00
pri_error ( " !! No channel map, no channel, and no ds1? What am I supposed to identify? \n " ) ;
2001-05-13 00:41:32 +08:00
return - 1 ;
}
static void dump_channel_id ( q931_ie * ie , int len , char prefix )
{
int pos = 0 ;
int x ;
int res = 0 ;
2003-02-12 21:59:23 +08:00
static const char * msg_chan_sel [ ] = {
" No channel selected " , " B1 channel " , " B2 channel " , " Any channel selected "
" No channel selected " , " As indicated in following octets " , " Reserved " , " Any channel selected "
} ;
pri_message ( " %c Channel ID (len=%2d) [ Ext: %d IntID: %s, %s Spare: %d, %s Dchan: %d \n " ,
2001-05-13 00:41:32 +08:00
prefix , len , ( ie - > data [ 0 ] & 0x80 ) ? 1 : 0 , ( ie - > data [ 0 ] & 0x40 ) ? " Explicit " : " Implicit " ,
( ie - > data [ 0 ] & 0x20 ) ? " PRI " : " Other " , ( ie - > data [ 0 ] & 0x10 ) ? 1 : 0 ,
2003-02-12 21:59:23 +08:00
( ie - > data [ 0 ] & 0x08 ) ? " Exclusive " : " Preferred " , ( ie - > data [ 0 ] & 0x04 ) ? 1 : 0 ) ;
pri_message ( " %c ChanSel: %s \n " ,
prefix , msg_chan_sel [ ( ie - > data [ 0 ] & 0x3 ) + ( ( ie - > data [ 0 ] > > 3 ) & 0x4 ) ] ) ;
2001-05-13 00:41:32 +08:00
pos + + ;
len - - ;
if ( ie - > data [ 0 ] & 0x40 ) {
/* Explicitly defined DS1 */
2003-02-12 21:59:23 +08:00
pri_message ( " %c Ext: %d DS1 Identifier: %d \n " , prefix , ( ie - > data [ pos ] & 0x80 ) > > 7 , ie - > data [ pos ] & 0x7f ) ;
2001-05-13 00:41:32 +08:00
pos + + ;
len - - ;
} else {
/* Implicitly defined DS1 */
}
2003-02-12 21:59:23 +08:00
if ( pos + 2 < len ) {
2001-05-13 00:41:32 +08:00
/* Still more information here */
2003-02-12 21:59:23 +08:00
pri_message ( " %c Ext: %d Coding: %d %s Specified Channel Type: %d \n " ,
2001-05-13 00:41:32 +08:00
prefix , ( ie - > data [ pos ] & 0x80 ) > > 7 , ( ie - > data [ pos ] & 60 ) > > 5 ,
( ie - > data [ pos ] & 0x10 ) ? " Slot Map " : " Number " , ie - > data [ pos ] & 0x0f ) ;
if ( ! ( ie - > data [ pos ] & 0x10 ) ) {
/* Number specified */
pos + + ;
2003-02-12 21:59:23 +08:00
pri_message ( " %c Ext: %d Channel: %d ] \n " , prefix , ( ie - > data [ pos ] & 0x80 ) > > 7 ,
2001-05-13 00:41:32 +08:00
( ie - > data [ pos ] ) & 0x7f ) ;
} else {
pos + + ;
/* Map specified */
for ( x = 0 ; x < 3 ; x + + ) {
res < < = 8 ;
res | = ie - > data [ pos + + ] ;
}
2003-02-12 21:59:23 +08:00
pri_message ( " %c Map: %s ] \n " , prefix , binary ( res , 24 ) ) ;
2001-05-13 00:41:32 +08:00
}
2003-02-12 21:59:23 +08:00
} else pri_message ( " ] \n " ) ;
2001-05-13 00:41:32 +08:00
}
static char * ri2str ( int ri )
{
2001-07-17 20:12:42 +08:00
static struct msgtype ris [ ] = {
{ 0 , " Indicated Channel " } ,
{ 6 , " Single DS1 Facility " } ,
{ 7 , " All DS1 Facilities " } ,
} ;
return code2str ( ri , ris , sizeof ( ris ) / sizeof ( ris [ 0 ] ) ) ;
2001-05-13 00:41:32 +08:00
}
static void dump_restart_indicator ( q931_ie * ie , int len , char prefix )
{
2003-02-12 21:59:23 +08:00
pri_message ( " %c Restart Indentifier: [ Ext: %d Spare: %d Resetting %s (%d) ] \n " ,
2001-05-13 00:41:32 +08:00
prefix , ( ie - > data [ 0 ] & 0x80 ) > > 7 , ( ie - > data [ 0 ] & 0x78 ) > > 3 , ri2str ( ie - > data [ 0 ] & 0x7 ) , ie - > data [ 0 ] & 0x7 ) ;
}
static int receive_restart_indicator ( struct pri * pri , q931_call * call , int msgtype , q931_ie * ie , int len )
{
/* Pretty simple */
call - > ri = ie - > data [ 0 ] & 0x7 ;
return 0 ;
}
static int transmit_restart_indicator ( struct pri * pri , q931_call * call , int msgtype , q931_ie * ie , int maxlen )
{
/* Pretty simple */
switch ( call - > ri ) {
case 0 :
case 6 :
case 7 :
ie - > data [ 0 ] = 0x80 | ( call - > ri & 0x7 ) ;
break ;
case 5 :
/* Switch compatibility */
ie - > data [ 0 ] = 0xA0 | ( call - > ri & 0x7 ) ;
break ;
default :
2003-02-12 21:59:23 +08:00
pri_error ( " !! Invalid restart indicator value %d \n " , call - > ri ) ;
2001-05-13 00:41:32 +08:00
return - 1 ;
}
return 3 ;
}
2002-03-18 22:04:47 +08:00
static char * redirection_reason2str ( int mode )
{
static struct msgtype modes [ ] = {
{ PRI_REDIR_UNKNOWN , " Unknown " } ,
{ PRI_REDIR_FORWARD_ON_BUSY , " Forwarded on busy " } ,
{ PRI_REDIR_FORWARD_ON_NO_REPLY , " Forwarded on no reply " } ,
{ PRI_REDIR_DEFLECTION , " Call deflected " } ,
{ PRI_REDIR_DTE_OUT_OF_ORDER , " Called DTE out of order " } ,
{ PRI_REDIR_FORWARDED_BY_DTE , " Forwarded by called DTE " } ,
{ PRI_REDIR_UNCONDITIONAL , " Forwarded unconditionally " } ,
} ;
return code2str ( mode , modes , sizeof ( modes ) / sizeof ( modes [ 0 ] ) ) ;
}
2001-05-13 00:41:32 +08:00
static char * cap2str ( int mode )
{
2001-07-17 20:12:42 +08:00
static struct msgtype modes [ ] = {
{ PRI_TRANS_CAP_SPEECH , " Speech " } ,
{ PRI_TRANS_CAP_DIGITAL , " Unrestricted digital information " } ,
{ PRI_TRANS_CAP_RESTRICTED_DIGITAL , " Restricted digital information " } ,
{ PRI_TRANS_CAP_3_1K_AUDIO , " 3.1kHz audio " } ,
{ PRI_TRANS_CAP_7K_AUDIO , " 7kHz audio " } ,
{ PRI_TRANS_CAP_VIDEO , " Video " } ,
{ PRI_TRANS_CAP_AUDIO_4ESS , " 3.1khz audio (4ESS) " } ,
} ;
return code2str ( mode , modes , sizeof ( modes ) / sizeof ( modes [ 0 ] ) ) ;
2001-05-13 00:41:32 +08:00
}
static char * mode2str ( int mode )
{
2001-07-17 20:12:42 +08:00
static struct msgtype modes [ ] = {
{ TRANS_MODE_64_CIRCUIT , " 64kbps, circuit-mode " } ,
{ TRANS_MODE_2x64_CIRCUIT , " 2x64kbps, circuit-mode " } ,
{ TRANS_MODE_384_CIRCUIT , " 384kbps, circuit-mode " } ,
{ TRANS_MODE_1536_CIRCUIT , " 1536kbps, circuit-mode " } ,
{ TRANS_MODE_1920_CIRCUIT , " 1920kbps, circuit-mode " } ,
{ TRANS_MODE_MULTIRATE , " Multirate (Nx64kbps) " } ,
{ TRANS_MODE_PACKET , " Packet Mode " } ,
} ;
return code2str ( mode , modes , sizeof ( modes ) / sizeof ( modes [ 0 ] ) ) ;
2001-05-13 00:41:32 +08:00
}
static char * l12str ( int proto )
{
2001-07-17 20:12:42 +08:00
static struct msgtype protos [ ] = {
2001-12-08 03:45:45 +08:00
{ PRI_LAYER_1_ITU_RATE_ADAPT , " ITU Rate Adaption " } ,
{ PRI_LAYER_1_ULAW , " u-Law " } ,
{ PRI_LAYER_1_ALAW , " A-Law " } ,
{ PRI_LAYER_1_G721 , " G.721 ADPCM " } ,
{ PRI_LAYER_1_G722_G725 , " G.722/G.725 7kHz Audio " } ,
{ PRI_LAYER_1_G7XX_384K , " G.7xx 384k Video " } ,
{ PRI_LAYER_1_NON_ITU_ADAPT , " Non-ITU Rate Adaption " } ,
{ PRI_LAYER_1_V120_RATE_ADAPT , " V.120 Rate Adaption " } ,
{ PRI_LAYER_1_X31_RATE_ADAPT , " X.31 Rate Adaption " } ,
2001-07-17 20:12:42 +08:00
} ;
return code2str ( proto , protos , sizeof ( protos ) / sizeof ( protos [ 0 ] ) ) ;
2001-05-13 00:41:32 +08:00
}
static char * ra2str ( int proto )
{
2001-07-17 20:12:42 +08:00
static struct msgtype protos [ ] = {
{ RATE_ADAPT_56K , " from 56kbps " } ,
} ;
return code2str ( proto , protos , sizeof ( protos ) / sizeof ( protos [ 0 ] ) ) ;
2001-05-13 00:41:32 +08:00
}
static char * l22str ( int proto )
{
2001-07-17 20:12:42 +08:00
static struct msgtype protos [ ] = {
{ LAYER_2_LAPB , " LAPB " } ,
} ;
return code2str ( proto , protos , sizeof ( protos ) / sizeof ( protos [ 0 ] ) ) ;
2001-05-13 00:41:32 +08:00
}
static char * l32str ( int proto )
{
2001-07-17 20:12:42 +08:00
static struct msgtype protos [ ] = {
{ LAYER_3_X25 , " X.25 " } ,
} ;
return code2str ( proto , protos , sizeof ( protos ) / sizeof ( protos [ 0 ] ) ) ;
2001-05-13 00:41:32 +08:00
}
static void dump_bearer_capability ( q931_ie * ie , int len , char prefix )
{
int pos = 2 ;
2003-02-12 21:59:23 +08:00
pri_message ( " %c Bearer Capability (len=%2d) [ Ext: %d Q.931 Std: %d Info transfer capability: %s (%d) \n " ,
2002-03-18 22:04:47 +08:00
prefix , ie - > len , ( ie - > data [ 0 ] & 0x80 ) > > 7 , ( ie - > data [ 0 ] & 0x60 ) > > 5 , cap2str ( ie - > data [ 0 ] & 0x1f ) , ( ie - > data [ 0 ] & 0x1f ) ) ;
2003-02-12 21:59:23 +08:00
pri_message ( " %c Ext: %d Trans mode/rate: %s (%d) \n " , prefix , ( ie - > data [ 1 ] & 0x80 ) > > 7 , mode2str ( ie - > data [ 1 ] & 0x7f ) , ie - > data [ 1 ] & 0x7f ) ;
2001-05-13 00:41:32 +08:00
if ( ( ie - > data [ 1 ] & 0x7f ) = = 0x18 ) {
2003-02-12 21:59:23 +08:00
pri_message ( " %c Ext: %d Transfer rate multiplier: %d x 64 \n " , prefix , ( ie - > data [ 2 ] & 0x80 ) > > 7 , ie - > data [ 2 ] & 0x7f ) ;
2001-05-13 00:41:32 +08:00
pos + + ;
}
/* Stop here if no more */
if ( pos > = len )
return ;
if ( ( ie - > data [ 1 ] & 0x7f ) ! = TRANS_MODE_PACKET ) {
/* Look for octets 5 and 5.a if present */
2003-02-12 21:59:23 +08:00
pri_message ( " %c Ext: %d User information layer 1: %s (%d) \n " , prefix , ( ie - > data [ pos ] > > 7 ) , l12str ( ie - > data [ pos ] & 0x7f ) , ie - > data [ pos ] & 0x7f ) ;
2001-12-08 03:45:45 +08:00
if ( ( ie - > data [ pos ] & 0x7f ) = = PRI_LAYER_1_ITU_RATE_ADAPT )
2003-02-12 21:59:23 +08:00
pri_message ( " %c Ext: %d Rate adaptatation: %s (%d) \n " , prefix , ie - > data [ pos ] > > 7 , ra2str ( ie - > data [ pos ] & 0x7f ) , ie - > data [ pos ] & 0x7f ) ;
2001-05-13 00:41:32 +08:00
pos + + ;
} else {
/* Look for octets 6 and 7 but not 5 and 5.a */
2003-02-12 21:59:23 +08:00
pri_message ( " %c Ext: %d User information layer 2: %s (%d) \n " , prefix , ie - > data [ pos ] > > 7 , l22str ( ie - > data [ pos ] & 0x7f ) , ie - > data [ pos ] & 0x7f ) ;
2001-05-13 00:41:32 +08:00
pos + + ;
2003-02-12 21:59:23 +08:00
pri_message ( " %c Ext: %d User information layer 3: %s (%d) \n " , prefix , ie - > data [ pos ] > > 7 , l32str ( ie - > data [ pos ] & 0x7f ) , ie - > data [ pos ] & 0x7f ) ;
2001-05-13 00:41:32 +08:00
pos + + ;
}
}
static int receive_bearer_capability ( struct pri * pri , q931_call * call , int msgtype , q931_ie * ie , int len )
{
int pos = 2 ;
if ( ie - > data [ 0 ] & 0x60 ) {
2003-02-12 21:59:23 +08:00
pri_error ( " !! non-standard Q.931 standard field \n " ) ;
2001-05-13 00:41:32 +08:00
return - 1 ;
}
call - > transcapability = ie - > data [ 0 ] & 0x1f ;
call - > transmoderate = ie - > data [ 1 ] & 0x7f ;
if ( call - > transmoderate = = PRI_TRANS_CAP_AUDIO_4ESS )
2001-07-17 20:12:42 +08:00
call - > transmoderate = PRI_TRANS_CAP_3_1K_AUDIO ;
2001-05-13 00:41:32 +08:00
if ( call - > transmoderate ! = TRANS_MODE_PACKET ) {
call - > userl1 = ie - > data [ pos ] & 0x7f ;
2001-12-08 03:45:45 +08:00
if ( call - > userl1 = = PRI_LAYER_1_ITU_RATE_ADAPT ) {
2001-05-13 00:41:32 +08:00
call - > rateadaption = ie - > data [ + + pos ] & 0x7f ;
}
pos + + ;
} else {
/* Get 6 and 7 */
call - > userl2 = ie - > data [ pos + + ] & 0x7f ;
call - > userl3 = ie - > data [ pos ] & 0x7f ;
}
return 0 ;
}
static int transmit_bearer_capability ( struct pri * pri , q931_call * call , int msgtype , q931_ie * ie , int len )
{
int tc ;
tc = call - > transcapability ;
if ( pri - > switchtype = = PRI_SWITCH_ATT4ESS ) {
/* 4ESS uses a different trans capability for 3.1khz audio */
2001-07-17 20:12:42 +08:00
if ( tc = = PRI_TRANS_CAP_3_1K_AUDIO )
2001-05-13 00:41:32 +08:00
tc = PRI_TRANS_CAP_AUDIO_4ESS ;
}
ie - > data [ 0 ] = 0x80 | tc ;
ie - > data [ 1 ] = call - > transmoderate | 0x80 ;
2004-04-17 02:05:41 +08:00
if ( ( tc & PRI_TRANS_CAP_DIGITAL ) & & ( pri - > switchtype = = PRI_SWITCH_EUROISDN_E1 ) ) {
/* Apparently EuroISDN switches don't seem to like user layer 2/3 */
return 4 ;
}
2001-05-13 00:41:32 +08:00
if ( call - > transmoderate ! = TRANS_MODE_PACKET ) {
/* If you have an AT&T 4ESS, you don't send any more info */
2004-02-08 08:20:18 +08:00
if ( ( pri - > switchtype ! = PRI_SWITCH_ATT4ESS ) & & ( call - > userl1 > - 1 ) ) {
ie - > data [ 2 ] = call - > userl1 | 0x80 ; /* XXX Ext bit? XXX */
if ( call - > userl1 = = PRI_LAYER_1_ITU_RATE_ADAPT ) {
ie - > data [ 3 ] = call - > rateadaption | 0x80 ;
return 6 ;
}
return 5 ;
} else
2001-05-13 00:41:32 +08:00
return 4 ;
} else {
ie - > data [ 2 ] = 0x80 | call - > userl2 ;
ie - > data [ 3 ] = 0x80 | call - > userl3 ;
return 6 ;
}
}
char * pri_plan2str ( int plan )
{
2001-07-17 20:12:42 +08:00
static struct msgtype plans [ ] = {
{ PRI_INTERNATIONAL_ISDN , " International number in ISDN " } ,
{ PRI_NATIONAL_ISDN , " National number in ISDN " } ,
{ PRI_LOCAL_ISDN , " Local number in ISDN " } ,
{ PRI_PRIVATE , " Private numbering plan " } ,
{ PRI_UNKNOWN , " Unknown numbering plan " } ,
} ;
return code2str ( plan , plans , sizeof ( plans ) / sizeof ( plans [ 0 ] ) ) ;
2001-05-13 00:41:32 +08:00
}
2002-03-18 22:04:47 +08:00
static char * npi2str ( int plan )
{
static struct msgtype plans [ ] = {
{ PRI_NPI_UNKNOWN , " Unknown Number Plan " } ,
{ PRI_NPI_E163_E164 , " ISDN/Telephony Numbering Plan (E.164/E.163) " } ,
{ PRI_NPI_X121 , " Data Numbering Plan (X.121) " } ,
{ PRI_NPI_F69 , " Telex Numbering Plan (F.69) " } ,
{ PRI_NPI_NATIONAL , " National Standard Numbering Plan " } ,
{ PRI_NPI_PRIVATE , " Private Numbering Plan " } ,
{ PRI_NPI_RESERVED , " Reserved Number Plan " } ,
} ;
return code2str ( plan , plans , sizeof ( plans ) / sizeof ( plans [ 0 ] ) ) ;
}
static char * ton2str ( int plan )
{
static struct msgtype plans [ ] = {
{ PRI_TON_UNKNOWN , " Unknown Number Type " } ,
{ PRI_TON_INTERNATIONAL , " International Number " } ,
{ PRI_TON_NATIONAL , " National Number " } ,
{ PRI_TON_NET_SPECIFIC , " Network Specific Number " } ,
{ PRI_TON_SUBSCRIBER , " Subscriber Number " } ,
{ PRI_TON_ABBREVIATED , " Abbreviated number " } ,
{ PRI_TON_RESERVED , " Reserved Number " } ,
} ;
return code2str ( plan , plans , sizeof ( plans ) / sizeof ( plans [ 0 ] ) ) ;
}
static char * subaddrtype2str ( int plan )
{
static struct msgtype plans [ ] = {
{ 0 , " NSAP (X.213/ISO 8348 AD2) " } ,
{ 2 , " User Specified " } ,
} ;
return code2str ( plan , plans , sizeof ( plans ) / sizeof ( plans [ 0 ] ) ) ;
}
2001-05-13 00:41:32 +08:00
char * pri_pres2str ( int pres )
{
2001-07-17 20:12:42 +08:00
static struct msgtype press [ ] = {
{ PRES_ALLOWED_USER_NUMBER_NOT_SCREENED , " Presentation permitted, user number not screened " } ,
{ PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN , " Presentation permitted, user number passed network screening " } ,
{ PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN , " Presentation permitted, user number failed network screening " } ,
{ PRES_ALLOWED_NETWORK_NUMBER , " Presentation allowed of network provided number " } ,
{ PRES_PROHIB_USER_NUMBER_NOT_SCREENED , " Presentation prohibited, user number not screened " } ,
{ PRES_PROHIB_USER_NUMBER_PASSED_SCREEN , " Presentation prohibited, user number passed network screening " } ,
{ PRES_PROHIB_USER_NUMBER_FAILED_SCREEN , " Presentation prohibited, user number failed network screening " } ,
2003-08-13 11:08:22 +08:00
{ PRES_PROHIB_NETWORK_NUMBER , " Presentation prohibited of network provided number " } ,
2001-07-17 20:12:42 +08:00
} ;
return code2str ( pres , press , sizeof ( press ) / sizeof ( press [ 0 ] ) ) ;
2001-05-13 00:41:32 +08:00
}
static void q931_get_number ( unsigned char * num , int maxlen , unsigned char * src , int len )
{
if ( len > maxlen - 1 ) {
num [ 0 ] = 0 ;
return ;
}
memcpy ( num , src , len ) ;
num [ len ] = 0 ;
}
static void dump_called_party_number ( q931_ie * ie , int len , char prefix )
2002-03-18 22:04:47 +08:00
{
char cnum [ 256 ] ;
q931_get_number ( cnum , sizeof ( cnum ) , ie - > data + 1 , len - 3 ) ;
2003-02-12 21:59:23 +08:00
pri_message ( " %c Called Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d) '%s' ] \n " ,
2002-03-18 22:04:47 +08:00
prefix , len , ie - > data [ 0 ] > > 7 , ton2str ( ( ie - > data [ 0 ] > > 4 ) & 0x07 ) , ( ie - > data [ 0 ] > > 4 ) & 0x07 , npi2str ( ie - > data [ 0 ] & 0x0f ) , ie - > data [ 0 ] & 0x0f , cnum ) ;
}
static void dump_called_party_subaddr ( q931_ie * ie , int len , char prefix )
2001-05-13 00:41:32 +08:00
{
char cnum [ 256 ] ;
q931_get_number ( cnum , sizeof ( cnum ) , ie - > data + 1 , len - 3 ) ;
2003-02-12 21:59:23 +08:00
pri_message ( " %c Called Sub-Address (len=%2d) [ Ext: %d Type: %s (%d) O: %d '%s' ] \n " ,
2002-03-18 22:04:47 +08:00
prefix , len , ie - > data [ 0 ] > > 7 ,
subaddrtype2str ( ( ie - > data [ 0 ] & 0x70 ) > > 4 ) , ( ie - > data [ 0 ] & 0x70 ) > > 4 ,
( ie - > data [ 0 ] & 0x08 ) > > 3 , cnum ) ;
2001-05-13 00:41:32 +08:00
}
static void dump_calling_party_number ( q931_ie * ie , int len , char prefix )
{
char cnum [ 256 ] ;
2002-03-18 22:04:47 +08:00
q931_get_number ( cnum , sizeof ( cnum ) , ie - > data + 2 , len - 4 ) ;
2003-02-12 21:59:23 +08:00
pri_message ( " %c Calling Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d) \n " , prefix , len , ie - > data [ 0 ] > > 7 , ton2str ( ( ie - > data [ 0 ] > > 4 ) & 0x07 ) , ( ie - > data [ 0 ] > > 4 ) & 0x07 , npi2str ( ie - > data [ 0 ] & 0x0f ) , ie - > data [ 0 ] & 0x0f ) ;
2003-08-13 11:08:22 +08:00
pri_message ( " %c Presentation: %s (%d) '%s' ] \n " , prefix , pri_pres2str ( ie - > data [ 1 ] & 0x7f ) , ie - > data [ 1 ] & 0x7f , cnum ) ;
2002-03-18 22:04:47 +08:00
}
2001-05-13 00:41:32 +08:00
2002-03-18 22:04:47 +08:00
static void dump_calling_party_subaddr ( q931_ie * ie , int len , char prefix )
{
char cnum [ 256 ] ;
2001-05-13 00:41:32 +08:00
q931_get_number ( cnum , sizeof ( cnum ) , ie - > data + 2 , len - 4 ) ;
2003-02-12 21:59:23 +08:00
pri_message ( " %c Calling Sub-Address (len=%2d) [ Ext: %d Type: %s (%d) O: %d '%s' ] \n " ,
2002-03-18 22:04:47 +08:00
prefix , len , ie - > data [ 0 ] > > 7 ,
subaddrtype2str ( ( ie - > data [ 0 ] & 0x70 ) > > 4 ) , ( ie - > data [ 0 ] & 0x70 ) > > 4 ,
( ie - > data [ 0 ] & 0x08 ) > > 3 , cnum ) ;
2001-05-13 00:41:32 +08:00
}
2002-03-18 22:04:47 +08:00
static void dump_redirecting_number ( q931_ie * ie , int len , char prefix )
{
char cnum [ 256 ] ;
q931_get_number ( cnum , sizeof ( cnum ) , ie - > data + 3 , len - 5 ) ;
2003-02-12 21:59:23 +08:00
pri_message ( " %c Redirecting Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d) \n " , prefix , len , ie - > data [ 0 ] > > 7 , ton2str ( ( ie - > data [ 0 ] > > 4 ) & 0x07 ) , ( ie - > data [ 0 ] > > 4 ) & 0x07 , npi2str ( ie - > data [ 0 ] & 0x0f ) , ie - > data [ 0 ] & 0x0f ) ;
2003-08-13 11:08:22 +08:00
pri_message ( " %c Presentation: %s (%d) Reason: %s (%d) '%s' ] \n " , prefix , pri_pres2str ( ie - > data [ 1 ] & 0x7f ) , ie - > data [ 1 ] & 0x7f , redirection_reason2str ( ie - > data [ 2 ] ) , ie - > data [ 2 ] , cnum ) ;
2003-02-12 21:59:23 +08:00
}
static int receive_redirecting_number ( struct pri * pri , q931_call * call , int msgtype , q931_ie * ie , int len )
{
call - > redirectingplan = ie - > data [ 0 ] & 0x7f ;
call - > redirectingpres = ie - > data [ 1 ] & 0x7f ;
call - > redirectingreason = ie - > data [ 2 ] & 0x0f ;
q931_get_number ( call - > redirectingnum , sizeof ( call - > redirectingnum ) , ie - > data + 3 , len - 5 ) ;
return 0 ;
2002-03-18 22:04:47 +08:00
}
2003-02-12 21:59:23 +08:00
2002-03-18 22:04:47 +08:00
static void dump_redirecting_subaddr ( q931_ie * ie , int len , char prefix )
{
char cnum [ 256 ] ;
q931_get_number ( cnum , sizeof ( cnum ) , ie - > data + 2 , len - 4 ) ;
2003-02-12 21:59:23 +08:00
pri_message ( " %c Redirecting Sub-Address (len=%2d) [ Ext: %d Type: %s (%d) O: %d '%s' ] \n " ,
2002-03-18 22:04:47 +08:00
prefix , len , ie - > data [ 0 ] > > 7 ,
subaddrtype2str ( ( ie - > data [ 0 ] & 0x70 ) > > 4 ) , ( ie - > data [ 0 ] & 0x70 ) > > 4 ,
( ie - > data [ 0 ] & 0x08 ) > > 3 , cnum ) ;
}
2001-12-08 03:45:45 +08:00
2001-05-13 00:41:32 +08:00
static int receive_called_party_number ( struct pri * pri , q931_call * call , int msgtype , q931_ie * ie , int len )
{
2003-02-12 21:59:23 +08:00
/* copy digits to call->callednum */
q931_get_number ( call - > callednum , sizeof ( call - > callednum ) , ie - > data + 1 , len - 3 ) ;
2001-05-13 00:41:32 +08:00
call - > calledplan = ie - > data [ 0 ] & 0x7f ;
return 0 ;
}
static int transmit_called_party_number ( struct pri * pri , q931_call * call , int msgtype , q931_ie * ie , int len )
{
ie - > data [ 0 ] = 0x80 | call - > calledplan ;
if ( strlen ( call - > callednum ) )
memcpy ( ie - > data + 1 , call - > callednum , strlen ( call - > callednum ) ) ;
return strlen ( call - > callednum ) + 3 ;
}
static int receive_calling_party_number ( struct pri * pri , q931_call * call , int msgtype , q931_ie * ie , int len )
{
2003-02-12 21:59:23 +08:00
int extbit ;
call - > callerplan = ie - > data [ 0 ] & 0x7f ;
extbit = ( ie - > data [ 0 ] > > 7 ) & 0x01 ;
if ( extbit ) {
q931_get_number ( call - > callernum , sizeof ( call - > callernum ) , ie - > data + 1 , len - 3 ) ;
call - > callerpres = 0 ; /* PI presentation allowed
SI user - provided , not screened */
} else {
q931_get_number ( call - > callernum , sizeof ( call - > callernum ) , ie - > data + 2 , len - 4 ) ;
call - > callerpres = ie - > data [ 1 ] & 0x7f ;
}
2001-05-13 00:41:32 +08:00
return 0 ;
}
static int transmit_calling_party_number ( struct pri * pri , q931_call * call , int msgtype , q931_ie * ie , int len )
{
ie - > data [ 0 ] = call - > callerplan ;
ie - > data [ 1 ] = 0x80 | call - > callerpres ;
if ( strlen ( call - > callednum ) )
memcpy ( ie - > data + 2 , call - > callernum , strlen ( call - > callernum ) ) ;
return strlen ( call - > callernum ) + 4 ;
}
2003-02-12 21:59:23 +08:00
static void dump_user_user ( q931_ie * ie , int len , char prefix )
{
2004-01-29 05:02:23 +08:00
int x ;
pri_message ( " %c User-User Information (len=%2d) [ " , prefix , ie - > len ) ;
for ( x = 0 ; x < ie - > len ; x + + )
pri_message ( " %c " , ie - > data [ x ] & 0x7f ) ;
pri_message ( " ] \n " ) ;
2003-02-12 21:59:23 +08:00
}
static int receive_user_user ( struct pri * pri , q931_call * call , int msgtype , q931_ie * ie , int len )
{
call - > useruserprotocoldisc = ie - > data [ 0 ] & 0xff ;
if ( call - > useruserprotocoldisc = = 4 ) /* IA5 */
q931_get_number ( call - > useruserinfo , sizeof ( call - > useruserinfo ) , ie - > data + 1 , len - 3 ) ;
return 0 ;
}
2001-05-13 00:41:32 +08:00
static char * prog2str ( int prog )
{
2001-07-17 20:12:42 +08:00
static struct msgtype progs [ ] = {
2002-03-18 22:04:47 +08:00
{ Q931_PROG_CALL_NOT_E2E_ISDN , " Call is not end-to-end ISDN; further call progress information may be available inband. " } ,
{ Q931_PROG_CALLED_NOT_ISDN , " Called equipment is non-ISDN. " } ,
{ Q931_PROG_CALLER_NOT_ISDN , " Calling equipment is non-ISDN. " } ,
{ Q931_PROG_INBAND_AVAILABLE , " Inband information or appropriate pattern now available. " } ,
{ Q931_PROG_DELAY_AT_INTERF , " Delay in response at called Interface. " } ,
{ Q931_PROG_INTERWORKING_WITH_PUBLIC , " Interworking with a public network. " } ,
{ Q931_PROG_INTERWORKING_NO_RELEASE , " Interworking with a network unable to supply a release signal. " } ,
{ Q931_PROG_INTERWORKING_NO_RELEASE_PRE_ANSWER , " Interworking with a network unable to supply a release signal before answer. " } ,
{ Q931_PROG_INTERWORKING_NO_RELEASE_POST_ANSWER , " Interworking with a network unable to supply a release signal after answer. " } ,
2001-07-17 20:12:42 +08:00
} ;
return code2str ( prog , progs , sizeof ( progs ) / sizeof ( progs [ 0 ] ) ) ;
2001-05-13 00:41:32 +08:00
}
static char * coding2str ( int cod )
{
2001-07-17 20:12:42 +08:00
static struct msgtype cods [ ] = {
{ CODE_CCITT , " CCITT (ITU) standard " } ,
{ CODE_INTERNATIONAL , " Non-ITU international standard " } ,
{ CODE_NATIONAL , " National standard " } ,
{ CODE_NETWORK_SPECIFIC , " Network specific standard " } ,
} ;
return code2str ( cod , cods , sizeof ( cods ) / sizeof ( cods [ 0 ] ) ) ;
2001-05-13 00:41:32 +08:00
}
static char * loc2str ( int loc )
{
2001-07-17 20:12:42 +08:00
static struct msgtype locs [ ] = {
{ LOC_USER , " User " } ,
{ LOC_PRIV_NET_LOCAL_USER , " Private network serving the local user " } ,
{ LOC_PUB_NET_LOCAL_USER , " Public network serving the local user " } ,
{ LOC_TRANSIT_NET , " Transit network " } ,
{ LOC_PUB_NET_REMOTE_USER , " Public network serving the remote user " } ,
{ LOC_PRIV_NET_REMOTE_USER , " Private network serving the remote user " } ,
{ LOC_INTERNATIONAL_NETWORK , " International network " } ,
{ LOC_NETWORK_BEYOND_INTERWORKING , " Network beyond the interworking point " } ,
} ;
return code2str ( loc , locs , sizeof ( locs ) / sizeof ( locs [ 0 ] ) ) ;
2001-05-13 00:41:32 +08:00
}
static void dump_progress_indicator ( q931_ie * ie , int len , char prefix )
{
2003-02-12 21:59:23 +08:00
pri_message ( " %c Progress Indicator (len=%2d) [ Ext: %d Coding: %s (%d) 0: %d Location: %s (%d) \n " ,
2002-03-18 22:04:47 +08:00
prefix , ie - > len , ie - > data [ 0 ] > > 7 , coding2str ( ( ie - > data [ 0 ] & 0x60 ) > > 5 ) , ( ie - > data [ 0 ] & 0x60 ) > > 5 ,
2001-05-13 00:41:32 +08:00
( ie - > data [ 0 ] & 0x10 ) > > 4 , loc2str ( ie - > data [ 0 ] & 0xf ) , ie - > data [ 0 ] & 0xf ) ;
2003-02-12 21:59:23 +08:00
pri_message ( " %c Ext: %d Progress Description: %s (%d) ] \n " ,
2001-05-13 00:41:32 +08:00
prefix , ie - > data [ 1 ] > > 7 , prog2str ( ie - > data [ 1 ] & 0x7f ) , ie - > data [ 1 ] & 0x7f ) ;
}
2003-02-12 21:59:23 +08:00
static int receive_display ( struct pri * pri , q931_call * call , int msgtype , q931_ie * ie , int len )
{
unsigned char * data ;
data = ie - > data ;
if ( data [ 0 ] & 0x80 ) {
/* Skip over character set */
data + + ;
len - - ;
}
q931_get_number ( call - > callername , sizeof ( call - > callername ) , data , len - 2 ) ;
return 0 ;
}
static int transmit_display ( struct pri * pri , q931_call * call , int msgtype , q931_ie * ie , int len )
{
2003-09-25 14:13:14 +08:00
if ( ( pri - > switchtype ! = PRI_SWITCH_NI1 ) & & strlen ( call - > callername ) ) {
2003-05-29 06:34:59 +08:00
ie - > data [ 0 ] = 0xb1 ;
memcpy ( ie - > data + 1 , call - > callername , strlen ( call - > callername ) ) ;
return 3 + strlen ( call - > callername ) ;
}
return 0 ;
2003-02-12 21:59:23 +08:00
}
2001-05-13 00:41:32 +08:00
static int receive_progress_indicator ( struct pri * pri , q931_call * call , int msgtype , q931_ie * ie , int len )
{
call - > progloc = ie - > data [ 0 ] & 0xf ;
2002-03-18 22:04:47 +08:00
call - > progcode = ( ie - > data [ 0 ] & 0x60 ) > > 5 ;
2001-05-13 00:41:32 +08:00
call - > progress = ( ie - > data [ 1 ] & 0x7f ) ;
return 0 ;
}
2003-02-12 21:59:23 +08:00
static int receive_facility ( struct pri * pri , q931_call * call , int msgtype , q931_ie * ie , int len )
{
if ( ie - > len < 14 ) {
pri_error ( " !! Facility message shorter than 14 bytes \n " ) ;
return 0 ;
}
if ( ie - > data [ 13 ] + 14 = = ie - > len ) {
q931_get_number ( call - > callername , sizeof ( call - > callername ) - 1 , ie - > data + 14 , ie - > len - 14 ) ;
}
return 0 ;
}
2001-05-13 00:41:32 +08:00
static int transmit_progress_indicator ( struct pri * pri , q931_call * call , int msgtype , q931_ie * ie , int len )
{
if ( call - > progress > 0 ) {
ie - > data [ 0 ] = 0x80 | ( call - > progcode < < 5 ) | ( call - > progloc ) ;
ie - > data [ 1 ] = 0x80 | ( call - > progress ) ;
return 4 ;
} else {
/* Leave off */
return 0 ;
}
}
2003-03-04 14:00:37 +08:00
static int transmit_call_state ( struct pri * pri , q931_call * call , int msgtype , q931_ie * ie , int len )
{
if ( call - > ourcallstate > - 1 ) {
ie - > data [ 0 ] = call - > ourcallstate ;
return 3 ;
}
return 0 ;
}
static int receive_call_state ( struct pri * pri , q931_call * call , int msgtype , q931_ie * ie , int len )
{
2003-09-25 14:13:14 +08:00
call - > sugcallstate = ie - > data [ 0 ] & 0x3f ;
2003-03-04 14:00:37 +08:00
return 0 ;
}
2001-05-13 00:41:32 +08:00
2002-03-18 22:04:47 +08:00
static char * callstate2str ( int callstate )
{
static struct msgtype callstates [ ] = {
{ 0 , " Null " } ,
{ 1 , " Call Initiated " } ,
{ 2 , " Overlap sending " } ,
{ 3 , " Outgoing call Proceeding " } ,
{ 4 , " Call Delivered " } ,
{ 6 , " Call Present " } ,
{ 7 , " Call Received " } ,
{ 8 , " Connect Request " } ,
{ 9 , " Incoming Call Proceeding " } ,
{ 10 , " Active " } ,
{ 11 , " Disconnect Request " } ,
{ 12 , " Disconnect Indication " } ,
{ 15 , " Suspend Request " } ,
{ 17 , " Resume Request " } ,
{ 19 , " Release Request " } ,
{ 22 , " Call Abort " } ,
{ 25 , " Overlap Receiving " } ,
{ 61 , " Restart Request " } ,
{ 62 , " Restart " } ,
} ;
return code2str ( callstate , callstates , sizeof ( callstates ) / sizeof ( callstates [ 0 ] ) ) ;
}
static void dump_call_state ( q931_ie * ie , int len , char prefix )
{
2003-02-12 21:59:23 +08:00
pri_message ( " %c Call State (len=%2d) [ Ext: %d Coding: %s (%d) Call state: %s (%d) \n " ,
2002-03-18 22:04:47 +08:00
prefix , ie - > len , ie - > data [ 0 ] > > 7 , coding2str ( ( ie - > data [ 0 ] & 0xC0 ) > > 6 ) , ( ie - > data [ 0 ] & 0xC0 ) > > 6 ,
callstate2str ( ie - > data [ 0 ] & 0x3f ) , ie - > data [ 0 ] & 0x3f ) ;
}
static void dump_call_identity ( q931_ie * ie , int len , char prefix )
{
int x ;
2003-02-12 21:59:23 +08:00
pri_message ( " %c Call Identity (len=%2d) [ " , prefix , ie - > len ) ;
2002-03-18 22:04:47 +08:00
for ( x = 0 ; x < ie - > len ; x + + )
2003-02-12 21:59:23 +08:00
pri_message ( " 0x%02X " , ie - > data [ x ] ) ;
pri_message ( " ] \n " ) ;
2002-03-18 22:04:47 +08:00
}
static void dump_time_date ( q931_ie * ie , int len , char prefix )
{
2003-02-12 21:59:23 +08:00
pri_message ( " %c Time Date (len=%2d) [ " , prefix , ie - > len ) ;
2002-03-18 22:04:47 +08:00
if ( ie - > len > 0 )
2003-02-12 21:59:23 +08:00
pri_message ( " %02d " , ie - > data [ 0 ] ) ;
2002-03-18 22:04:47 +08:00
if ( ie - > len > 1 )
2003-02-12 21:59:23 +08:00
pri_message ( " -%02d " , ie - > data [ 1 ] ) ;
2002-03-18 22:04:47 +08:00
if ( ie - > len > 2 )
2003-02-12 21:59:23 +08:00
pri_message ( " -%02d " , ie - > data [ 2 ] ) ;
2002-03-18 22:04:47 +08:00
if ( ie - > len > 3 )
2003-02-12 21:59:23 +08:00
pri_message ( " %02d " , ie - > data [ 3 ] ) ;
2002-03-18 22:04:47 +08:00
if ( ie - > len > 4 )
2003-02-12 21:59:23 +08:00
pri_message ( " :%02d " , ie - > data [ 4 ] ) ;
2002-03-18 22:04:47 +08:00
if ( ie - > len > 5 )
2003-02-12 21:59:23 +08:00
pri_message ( " :%02d " , ie - > data [ 5 ] ) ;
pri_message ( " ] \n " ) ;
2002-03-18 22:04:47 +08:00
}
static void dump_display ( q931_ie * ie , int len , char prefix )
{
int x ;
2003-02-12 21:59:23 +08:00
pri_message ( " %c Display (len=%2d) [ " , prefix , ie - > len ) ;
2002-03-18 22:04:47 +08:00
for ( x = 0 ; x < ie - > len ; x + + )
2003-02-12 21:59:23 +08:00
pri_message ( " %c " , ie - > data [ x ] & 0x7f ) ;
pri_message ( " ] \n " ) ;
}
static void dump_ie_data ( unsigned char * c , int len )
{
char tmp [ 1024 ] = " " ;
int x = 0 ;
int lastascii = 0 ;
while ( len ) {
if ( ( ( * c > = ' A ' ) & & ( * c < = ' Z ' ) ) | |
( ( * c > = ' a ' ) & & ( * c < = ' z ' ) ) | |
( ( * c > = ' 0 ' ) & & ( * c < = ' 9 ' ) ) ) {
if ( ! lastascii ) {
if ( strlen ( tmp ) ) {
tmp [ x + + ] = ' , ' ;
tmp [ x + + ] = ' ' ;
}
tmp [ x + + ] = ' \' ' ;
}
tmp [ x + + ] = * c ;
lastascii = 1 ;
} else {
if ( lastascii ) {
tmp [ x + + ] = ' \' ' ;
}
if ( strlen ( tmp ) ) {
tmp [ x + + ] = ' , ' ;
tmp [ x + + ] = ' ' ;
}
sprintf ( tmp + x , " 0x%02x " , * c ) ;
x + = 4 ;
lastascii = 0 ;
}
c + + ;
len - - ;
}
if ( lastascii )
tmp [ x + + ] = ' \' ' ;
pri_message ( tmp ) ;
}
static void dump_facility ( q931_ie * ie , int len , char prefix )
{
pri_message ( " %c Facility (len=%2d) [ " , prefix , ie - > len ) ;
dump_ie_data ( ie - > data , ie - > len ) ;
pri_message ( " ] \n " ) ;
2002-03-18 22:04:47 +08:00
}
2001-05-13 00:41:32 +08:00
char * pri_cause2str ( int cause )
{
2001-07-17 20:12:42 +08:00
return code2str ( cause , causes , sizeof ( causes ) / sizeof ( causes [ 0 ] ) ) ;
2001-05-13 00:41:32 +08:00
}
static char * pri_causeclass2str ( int cause )
{
2001-07-17 20:12:42 +08:00
static struct msgtype causeclasses [ ] = {
{ 0 , " Normal Event " } ,
{ 1 , " Normal Event " } ,
{ 2 , " Network Congestion " } ,
{ 3 , " Service or Option not Available " } ,
{ 4 , " Service or Option not Implemented " } ,
{ 5 , " Invalid message " } ,
{ 6 , " Protocol Error " } ,
{ 7 , " Interworking " } ,
} ;
return code2str ( cause , causeclasses , sizeof ( causeclasses ) / sizeof ( causeclasses [ 0 ] ) ) ;
2001-05-13 00:41:32 +08:00
}
static void dump_cause ( q931_ie * ie , int len , char prefix )
{
int x ;
2003-02-12 21:59:23 +08:00
pri_message ( " %c Cause (len=%2d) [ Ext: %d Coding: %s (%d) 0: %d Location: %s (%d) \n " ,
2002-03-18 22:04:47 +08:00
prefix , ie - > len , ie - > data [ 0 ] > > 7 , coding2str ( ( ie - > data [ 0 ] & 0x60 ) > > 5 ) , ( ie - > data [ 0 ] & 0x60 ) > > 5 ,
2001-05-13 00:41:32 +08:00
( ie - > data [ 0 ] & 0x10 ) > > 4 , loc2str ( ie - > data [ 0 ] & 0xf ) , ie - > data [ 0 ] & 0xf ) ;
2003-02-12 21:59:23 +08:00
pri_message ( " %c Ext: %d Cause: %s (%d), class = %s (%d) ] \n " ,
2001-05-13 00:41:32 +08:00
prefix , ( ie - > data [ 1 ] > > 7 ) , pri_cause2str ( ie - > data [ 1 ] & 0x7f ) , ie - > data [ 1 ] & 0x7f ,
pri_causeclass2str ( ( ie - > data [ 1 ] & 0x7f ) > > 4 ) , ( ie - > data [ 1 ] & 0x7f ) > > 4 ) ;
for ( x = 4 ; x < len ; x + + )
2003-02-12 21:59:23 +08:00
pri_message ( " %c Cause data %d: %02x (%d) \n " , prefix , x - 4 , ie - > data [ x ] , ie - > data [ x ] ) ;
2001-05-13 00:41:32 +08:00
}
static int receive_cause ( struct pri * pri , q931_call * call , int msgtype , q931_ie * ie , int len )
{
call - > causeloc = ie - > data [ 0 ] & 0xf ;
2002-03-18 22:04:47 +08:00
call - > causecode = ( ie - > data [ 0 ] & 0x60 ) > > 5 ;
2001-05-13 00:41:32 +08:00
call - > cause = ( ie - > data [ 1 ] & 0x7f ) ;
return 0 ;
}
static int transmit_cause ( struct pri * pri , q931_call * call , int msgtype , q931_ie * ie , int len )
{
if ( call - > cause > 0 ) {
ie - > data [ 0 ] = 0x80 | ( call - > causecode < < 5 ) | ( call - > causeloc ) ;
ie - > data [ 1 ] = 0x80 | ( call - > cause ) ;
return 4 ;
} else {
/* Leave off */
return 0 ;
}
}
2002-03-18 22:04:47 +08:00
static void dump_sending_complete ( q931_ie * ie , int len , char prefix )
{
2004-04-11 09:55:54 +08:00
pri_message ( " %c Sending Complete (len=%2d) \n " , prefix , ie - > len ) ;
2002-03-18 22:04:47 +08:00
}
static int receive_sending_complete ( struct pri * pri , q931_call * call , int msgtype , q931_ie * ie , int len )
{
2003-07-02 04:25:34 +08:00
/* We've got a "Complete" message: Exect no further digits. */
call - > complete = 1 ;
2002-03-18 22:04:47 +08:00
return 0 ;
}
2001-12-08 03:45:45 +08:00
static int transmit_sending_complete ( struct pri * pri , q931_call * call , int msgtype , q931_ie * ie , int len )
{
2003-05-16 03:35:05 +08:00
if ( ! pri - > overlapdial & & ( ( pri - > switchtype = = PRI_SWITCH_EUROISDN_E1 ) | | ( pri - > switchtype = = PRI_SWITCH_EUROISDN_T1 ) ) ) {
2001-12-08 03:45:45 +08:00
/* Include this single-byte IE */
ie - > f = 1 ;
return 1 ;
}
return 0 ;
}
2001-05-13 00:41:32 +08:00
struct ie ies [ ] = {
{ NATIONAL_CHANGE_STATUS , " Change Status " } ,
{ Q931_LOCKING_SHIFT , " Locking Shift " } ,
{ Q931_BEARER_CAPABILITY , " Bearer Capability " , dump_bearer_capability , receive_bearer_capability , transmit_bearer_capability } ,
{ Q931_CAUSE , " Cause " , dump_cause , receive_cause , transmit_cause } ,
2003-03-04 14:00:37 +08:00
{ Q931_CALL_STATE , " Call State " , dump_call_state , receive_call_state , transmit_call_state } ,
2001-05-13 00:41:32 +08:00
{ Q931_CHANNEL_IDENT , " Channel Identification " , dump_channel_id , receive_channel_id , transmit_channel_id } ,
{ Q931_PROGRESS_INDICATOR , " Progress Indicator " , dump_progress_indicator , receive_progress_indicator , transmit_progress_indicator } ,
{ Q931_NETWORK_SPEC_FAC , " Network-Specific Facilities " } ,
{ Q931_INFORMATION_RATE , " Information Rate " } ,
{ Q931_TRANSIT_DELAY , " End-to-End Transit Delay " } ,
{ Q931_TRANS_DELAY_SELECT , " Transmit Delay Selection and Indication " } ,
{ Q931_BINARY_PARAMETERS , " Packet-layer Binary Parameters " } ,
{ Q931_WINDOW_SIZE , " Packet-layer Window Size " } ,
{ Q931_CLOSED_USER_GROUP , " Closed User Group " } ,
{ Q931_REVERSE_CHARGE_INDIC , " Reverse Charging Indication " } ,
{ Q931_CALLING_PARTY_NUMBER , " Calling Party Number " , dump_calling_party_number , receive_calling_party_number , transmit_calling_party_number } ,
2002-03-18 22:04:47 +08:00
{ Q931_CALLING_PARTY_SUBADDR , " Calling Party Subaddress " , dump_calling_party_subaddr } ,
2001-05-13 00:41:32 +08:00
{ Q931_CALLED_PARTY_NUMBER , " Called Party Number " , dump_called_party_number , receive_called_party_number , transmit_called_party_number } ,
2002-03-18 22:04:47 +08:00
{ Q931_CALLED_PARTY_SUBADDR , " Called Party Subaddress " , dump_called_party_subaddr } ,
2003-02-12 21:59:23 +08:00
{ Q931_REDIRECTING_NUMBER , " Redirecting Number " , dump_redirecting_number , receive_redirecting_number } ,
2002-03-18 22:04:47 +08:00
{ Q931_REDIRECTING_SUBADDR , " Redirecting Subaddress " , dump_redirecting_subaddr } ,
2001-05-13 00:41:32 +08:00
{ Q931_TRANSIT_NET_SELECT , " Transit Network Selection " } ,
{ Q931_RESTART_INDICATOR , " Restart Indicator " , dump_restart_indicator , receive_restart_indicator , transmit_restart_indicator } ,
{ Q931_LOW_LAYER_COMPAT , " Low-layer Compatibility " } ,
{ Q931_HIGH_LAYER_COMPAT , " High-layer Compatibility " } ,
2001-07-17 20:12:42 +08:00
{ Q931_PACKET_SIZE , " Packet Size " } ,
2003-02-12 21:59:23 +08:00
{ Q931_IE_FACILITY , " Facility " , dump_facility , receive_facility } ,
2001-07-17 20:12:42 +08:00
{ Q931_IE_REDIRECTION_NUMBER , " Redirection Number " } ,
{ Q931_IE_REDIRECTION_SUBADDR , " Redirection Subaddress " } ,
{ Q931_IE_FEATURE_ACTIVATE , " Feature Activation " } ,
{ Q931_IE_INFO_REQUEST , " Feature Request " } ,
{ Q931_IE_FEATURE_IND , " Feature Indication " } ,
{ Q931_IE_SEGMENTED_MSG , " Segmented Message " } ,
2002-03-18 22:04:47 +08:00
{ Q931_IE_CALL_IDENTITY , " Call Identity " , dump_call_identity } ,
2001-07-17 20:12:42 +08:00
{ Q931_IE_ENDPOINT_ID , " Endpoint Identification " } ,
{ Q931_IE_NOTIFY_IND , " Notification Indicator " } ,
2003-02-12 21:59:23 +08:00
{ Q931_DISPLAY , " Display " , dump_display , receive_display , transmit_display } ,
2002-03-18 22:04:47 +08:00
{ Q931_IE_TIME_DATE , " Date/Time " , dump_time_date } ,
2001-07-17 20:12:42 +08:00
{ Q931_IE_KEYPAD_FACILITY , " Keypad Facility " } ,
{ Q931_IE_SIGNAL , " Signal " } ,
{ Q931_IE_SWITCHHOOK , " Switch-hook " } ,
2003-02-12 21:59:23 +08:00
{ Q931_IE_USER_USER , " User-User " , dump_user_user , receive_user_user } ,
2001-07-17 20:12:42 +08:00
{ Q931_IE_ESCAPE_FOR_EXT , " Escape for Extension " } ,
{ Q931_IE_CALL_STATUS , " Call Status " } ,
{ Q931_IE_CHANGE_STATUS , " Change Status " } ,
{ Q931_IE_CONNECTED_NUM , " Connected Number " } ,
{ Q931_IE_ORIGINAL_CALLED_NUMBER , " Original Called Number " } ,
{ Q931_IE_USER_USER_FACILITY , " User-User Facility " } ,
{ Q931_IE_UPDATE , " Update " } ,
2002-03-18 22:04:47 +08:00
{ Q931_SENDING_COMPLETE , " Sending Complete " , dump_sending_complete , receive_sending_complete , transmit_sending_complete } ,
2001-05-13 00:41:32 +08:00
} ;
static char * ie2str ( int ie )
{
2003-08-06 23:20:49 +08:00
unsigned int x ;
2001-05-13 00:41:32 +08:00
for ( x = 0 ; x < sizeof ( ies ) / sizeof ( ies [ 0 ] ) ; x + + )
if ( ies [ x ] . ie = = ie )
return ies [ x ] . name ;
return " Unknown Information Element " ;
}
static inline int ielen ( q931_ie * ie )
{
if ( ie - > f )
return 1 ;
else
return 2 + ie - > len ;
}
static char * msg2str ( int msg )
{
2003-08-06 23:20:49 +08:00
unsigned int x ;
2001-05-13 00:41:32 +08:00
for ( x = 0 ; x < sizeof ( msgs ) / sizeof ( msgs [ 0 ] ) ; x + + )
if ( msgs [ x ] . msgnum = = msg )
return msgs [ x ] . name ;
return " Unknown Message Type " ;
}
static inline int q931_cr ( q931_h * h )
{
int cr = 0 ;
int x ;
if ( h - > crlen > 3 ) {
2003-02-12 21:59:23 +08:00
pri_error ( " Call Reference Length Too long: %d \n " , h - > crlen ) ;
2001-05-13 00:41:32 +08:00
return - 1 ;
}
2003-10-14 06:34:05 +08:00
switch ( h - > crlen ) {
case 2 :
for ( x = 0 ; x < h - > crlen ; x + + ) {
cr < < = 8 ;
cr | = h - > crv [ x ] ;
}
break ;
case 1 :
cr = h - > crv [ 0 ] ;
if ( cr & 0x80 ) {
cr & = ~ 0x80 ;
cr | = 0x8000 ;
}
2003-10-14 06:36:07 +08:00
break ;
2003-10-14 06:34:05 +08:00
default :
pri_error ( " Call Reference Length not supported: %d \n " , h - > crlen ) ;
2001-05-13 00:41:32 +08:00
}
return cr ;
}
static inline void q931_dumpie ( q931_ie * ie , char prefix )
{
2003-08-06 23:20:49 +08:00
unsigned int x ;
2001-05-13 00:41:32 +08:00
for ( x = 0 ; x < sizeof ( ies ) / sizeof ( ies [ 0 ] ) ; x + + )
if ( ies [ x ] . ie = = ie - > ie ) {
if ( ies [ x ] . dump )
ies [ x ] . dump ( ie , ielen ( ie ) , prefix ) ;
else
2003-02-12 21:59:23 +08:00
pri_message ( " %c IE: %s (len = %d) \n " , prefix , ies [ x ] . name , ielen ( ie ) ) ;
2001-05-13 00:41:32 +08:00
return ;
}
2003-02-12 21:59:23 +08:00
pri_error ( " !! %c Unknown IE %d (len = %d) \n " , prefix , ie - > ie , ielen ( ie ) ) ;
2001-05-13 00:41:32 +08:00
}
static q931_call * q931_getcall ( struct pri * pri , int cr )
{
q931_call * cur , * prev ;
cur = pri - > calls ;
prev = NULL ;
while ( cur ) {
if ( cur - > cr = = cr )
return cur ;
prev = cur ;
cur = cur - > next ;
}
/* No call exists, make a new one */
if ( pri - > debug & PRI_DEBUG_Q931_STATE )
2003-02-12 21:59:23 +08:00
pri_message ( " -- Making new call for cr %d \n " , cr ) ;
2001-05-13 00:41:32 +08:00
cur = malloc ( sizeof ( struct q931_call ) ) ;
if ( cur ) {
call_init ( cur ) ;
/* Call reference */
cur - > cr = cr ;
2003-09-25 14:13:14 +08:00
cur - > pri = pri ;
2001-05-13 00:41:32 +08:00
/* Append to end of list */
if ( prev )
prev - > next = cur ;
else
pri - > calls = cur ;
}
return cur ;
}
q931_call * q931_new_call ( struct pri * pri )
{
q931_call * cur ;
do {
cur = pri - > calls ;
pri - > cref + + ;
if ( pri - > cref > 32767 )
pri - > cref = 1 ;
while ( cur ) {
if ( cur - > cr = = ( 0x8000 | pri - > cref ) )
break ;
cur = cur - > next ;
}
} while ( cur ) ;
return q931_getcall ( pri , pri - > cref | 0x8000 ) ;
}
static void q931_destroycall ( struct pri * pri , int cr )
{
q931_call * cur , * prev ;
prev = NULL ;
cur = pri - > calls ;
while ( cur ) {
if ( cur - > cr = = cr ) {
if ( prev )
prev - > next = cur - > next ;
else
pri - > calls = cur - > next ;
2003-08-05 09:00:45 +08:00
if ( pri - > debug & PRI_DEBUG_Q931_STATE )
pri_message ( " NEW_HANGUP DEBUG: Destroying the call, ourstate %s, peerstate %s \n " , callstate2str ( cur - > ourcallstate ) , callstate2str ( cur - > peercallstate ) ) ;
2003-09-25 14:13:14 +08:00
if ( cur - > retranstimer )
pri_schedule_del ( pri , cur - > retranstimer ) ;
2001-05-13 00:41:32 +08:00
free ( cur ) ;
return ;
}
prev = cur ;
cur = cur - > next ;
}
2003-02-12 21:59:23 +08:00
pri_error ( " Can't destroy call %d! \n " , cr ) ;
2001-05-13 00:41:32 +08:00
}
2003-08-13 04:16:55 +08:00
void __q931_destroycall ( struct pri * pri , q931_call * c ) {
if ( pri & & c )
q931_destroycall ( pri , c - > cr ) ;
return ;
}
2001-05-13 00:41:32 +08:00
static int add_ie ( struct pri * pri , q931_call * call , int msgtype , int ie , q931_ie * iet , int maxlen )
{
2003-08-06 23:20:49 +08:00
unsigned int x ;
2001-05-13 00:41:32 +08:00
int res ;
for ( x = 0 ; x < sizeof ( ies ) / sizeof ( ies [ 0 ] ) ; x + + ) {
if ( ies [ x ] . ie = = ie ) {
/* This is our baby */
iet - > f = 0 ;
iet - > ie = ie ;
if ( ies [ x ] . transmit ) {
res = ies [ x ] . transmit ( pri , call , msgtype , iet , maxlen ) ;
if ( res < 0 )
return res ;
2001-12-08 03:45:45 +08:00
if ( ! iet - > f )
iet - > len = res - 2 ;
2001-05-13 00:41:32 +08:00
return res ;
} else {
2003-02-12 21:59:23 +08:00
pri_error ( " !! Don't know how to add an IE %s (%d) \n " , ie2str ( ie ) , ie ) ;
2001-05-13 00:41:32 +08:00
return - 1 ;
}
}
}
2003-02-12 21:59:23 +08:00
pri_error ( " !! Unknown IE %d (%s) \n " , ie , ie2str ( ie ) ) ;
2001-05-13 00:41:32 +08:00
return - 1 ;
}
static char * disc2str ( int disc )
{
2001-07-17 20:12:42 +08:00
static struct msgtype discs [ ] = {
{ Q931_PROTOCOL_DISCRIMINATOR , " Q.931 " } ,
{ 0x3 , " AT&T Maintenance " } ,
} ;
return code2str ( disc , discs , sizeof ( discs ) / sizeof ( discs [ 0 ] ) ) ;
2001-05-13 00:41:32 +08:00
}
2002-03-18 22:04:47 +08:00
void q931_dump ( q931_h * h , int len , int txrx )
2001-05-13 00:41:32 +08:00
{
q931_mh * mh ;
char c ;
int x = 0 , r ;
2002-03-18 22:04:47 +08:00
c = txrx ? ' > ' : ' < ' ;
2003-02-12 21:59:23 +08:00
pri_message ( " %c Protocol Discriminator: %s (%d) len=%d \n " , c , disc2str ( h - > pd ) , h - > pd , len ) ;
2004-04-11 09:55:54 +08:00
pri_message ( " %c Call Ref: len=%2d (reference %d/0x%X) (%s) \n " , c , h - > crlen , q931_cr ( h ) , q931_cr ( h ) , ( h - > crv [ 0 ] & 0x80 ) ? " Terminator " : " Originator " ) ;
2001-05-13 00:41:32 +08:00
/* Message header begins at the end of the call reference number */
mh = ( q931_mh * ) ( h - > contents + h - > crlen ) ;
2003-02-12 21:59:23 +08:00
pri_message ( " %c Message type: %s (%d) \n " , c , msg2str ( mh - > msg ) , mh - > msg ) ;
2001-05-13 00:41:32 +08:00
/* Drop length of header, including call reference */
len - = ( h - > crlen + 3 ) ;
while ( x < len ) {
r = ielen ( ( q931_ie * ) ( mh - > data + x ) ) ;
q931_dumpie ( ( q931_ie * ) ( mh - > data + x ) , c ) ;
x + = r ;
}
if ( x > len )
2003-02-12 21:59:23 +08:00
pri_error ( " XXX Message longer than it should be?? XXX \n " ) ;
2001-05-13 00:41:32 +08:00
}
static int q931_handle_ie ( struct pri * pri , q931_call * c , int msg , q931_ie * ie )
{
2003-08-07 00:53:40 +08:00
unsigned int x ;
2001-05-13 00:41:32 +08:00
if ( pri - > debug & PRI_DEBUG_Q931_STATE )
2003-02-12 21:59:23 +08:00
pri_message ( " -- Processing IE %d (%s) \n " , ie - > ie , ie2str ( ie - > ie ) ) ;
2001-05-13 00:41:32 +08:00
for ( x = 0 ; x < sizeof ( ies ) / sizeof ( ies [ 0 ] ) ; x + + ) {
if ( ie - > ie = = ies [ x ] . ie ) {
if ( ies [ x ] . receive )
return ies [ x ] . receive ( pri , c , msg , ie , ielen ( ie ) ) ;
else {
2001-07-17 20:12:42 +08:00
if ( pri - > debug & PRI_DEBUG_Q931_ANOMALY )
2003-02-12 21:59:23 +08:00
pri_error ( " !! No handler for IE %d (%s) \n " , ie - > ie , ie2str ( ie - > ie ) ) ;
2001-05-13 00:41:32 +08:00
return - 1 ;
}
}
}
2003-02-12 21:59:23 +08:00
pri_message ( " !! Unknown IE %d (%s) \n " , ie - > ie , ie2str ( ie - > ie ) ) ;
2001-05-13 00:41:32 +08:00
return - 1 ;
}
static void init_header ( q931_call * call , char * buf , q931_h * * hb , q931_mh * * mhb , int * len )
{
/* Returns header and message header and modifies length in place */
q931_h * h = ( q931_h * ) buf ;
q931_mh * mh = ( q931_mh * ) ( h - > contents + 2 ) ;
h - > pd = Q931_PROTOCOL_DISCRIMINATOR ;
h - > x0 = 0 ; /* Reserved 0 */
h - > crlen = 2 ; /* Two bytes of Call Reference. Invert the top bit to make it from our sense */
2002-03-18 22:04:47 +08:00
if ( call - > cr | | call - > forceinvert ) {
2001-05-13 00:41:32 +08:00
h - > crv [ 0 ] = ( ( call - > cr ^ 0x8000 ) & 0xff00 ) > > 8 ;
h - > crv [ 1 ] = ( call - > cr & 0xff ) ;
} else {
/* Unless of course this has no call reference */
h - > crv [ 0 ] = 0 ;
h - > crv [ 1 ] = 0 ;
}
mh - > f = 0 ;
* hb = h ;
* mhb = mh ;
* len - = 5 ;
}
static int q931_xmit ( struct pri * pri , q931_h * h , int len , int cr )
{
2002-03-18 22:04:47 +08:00
q921_transmit_iframe ( pri , h , len , cr ) ;
/* The transmit operation might dump the q921 header, so logging the q931
message body after the transmit puts the sections of the message in the
right order in the log */
2001-05-13 00:41:32 +08:00
if ( pri - > debug & PRI_DEBUG_Q931_DUMP )
q931_dump ( h , len , 1 ) ;
2004-03-15 13:53:25 +08:00
# ifdef LIBPRI_COUNTERS
pri - > q931_txcount + + ;
# endif
2001-05-13 00:41:32 +08:00
return 0 ;
}
static int send_message ( struct pri * pri , q931_call * c , int msgtype , int ies [ ] )
{
unsigned char buf [ 1024 ] ;
q931_h * h ;
q931_mh * mh ;
int len ;
int res ;
int offset = 0 ;
int x ;
memset ( buf , 0 , sizeof ( buf ) ) ;
len = sizeof ( buf ) ;
init_header ( c , buf , & h , & mh , & len ) ;
mh - > msg = msgtype ;
x = 0 ;
while ( ies [ x ] > - 1 ) {
res = add_ie ( pri , c , mh - > msg , ies [ x ] , ( q931_ie * ) ( mh - > data + offset ) , len ) ;
if ( res < 0 ) {
2003-02-12 21:59:23 +08:00
pri_error ( " !! Unable to add IE '%s' \n " , ie2str ( ies [ x ] ) ) ;
2001-05-13 00:41:32 +08:00
return - 1 ;
}
offset + = res ;
len - = res ;
x + + ;
}
/* Invert the logic */
len = sizeof ( buf ) - len ;
q931_xmit ( pri , h , len , 1 ) ;
2003-02-12 21:59:23 +08:00
c - > acked = 1 ;
2001-05-13 00:41:32 +08:00
return 0 ;
}
2003-03-04 14:00:37 +08:00
static int status_ies [ ] = { Q931_CAUSE , Q931_CALL_STATE , - 1 } ;
2003-09-25 14:13:14 +08:00
static int q931_status ( struct pri * pri , q931_call * c , int cause )
2003-03-04 14:00:37 +08:00
{
q931_call * cur = NULL ;
2003-09-25 14:13:14 +08:00
if ( ! cause )
cause = PRI_CAUSE_RESPONSE_TO_STATUS_ENQUIRY ;
2003-03-04 14:00:37 +08:00
if ( c - > cr > - 1 )
cur = pri - > calls ;
while ( cur ) {
if ( cur - > cr = = c - > cr ) {
2003-09-25 14:13:14 +08:00
cur - > cause = cause ;
2003-03-04 14:00:37 +08:00
cur - > causecode = CODE_CCITT ;
2003-09-25 14:13:14 +08:00
cur - > causeloc = LOC_USER ;
2003-03-04 14:00:37 +08:00
break ;
}
cur = cur - > next ;
}
if ( ! cur ) {
2003-09-25 14:13:14 +08:00
pri_message ( " YYY Here we get reset YYY \n " ) ;
2003-03-04 14:00:37 +08:00
/* something went wrong, respond with "no such call" */
c - > ourcallstate = Q931_CALL_STATE_NULL ;
2003-08-05 09:00:45 +08:00
c - > peercallstate = Q931_CALL_STATE_NULL ;
2003-03-04 14:00:37 +08:00
cur = c ;
}
return send_message ( pri , cur , Q931_STATUS , status_ies ) ;
}
2003-03-25 05:52:51 +08:00
static int information_ies [ ] = { Q931_CALLED_PARTY_NUMBER , - 1 } ;
int q931_information ( struct pri * pri , q931_call * c , char digit )
{
2003-03-26 01:02:23 +08:00
c - > callednum [ 0 ] = digit ;
2003-03-25 05:52:51 +08:00
c - > callednum [ 1 ] = ' \0 ' ;
return send_message ( pri , c , Q931_INFORMATION , information_ies ) ;
}
2001-05-13 00:41:32 +08:00
static int restart_ack_ies [ ] = { Q931_CHANNEL_IDENT , Q931_RESTART_INDICATOR , - 1 } ;
static int restart_ack ( struct pri * pri , q931_call * c )
{
2003-08-05 09:00:45 +08:00
c - > ourcallstate = Q931_CALL_STATE_NULL ;
c - > peercallstate = Q931_CALL_STATE_NULL ;
2001-05-13 00:41:32 +08:00
return send_message ( pri , c , Q931_RESTART_ACKNOWLEDGE , restart_ack_ies ) ;
}
static int call_proceeding_ies [ ] = { Q931_CHANNEL_IDENT , - 1 } ;
int q931_call_proceeding ( struct pri * pri , q931_call * c )
{
2003-03-04 14:00:37 +08:00
c - > ourcallstate = Q931_CALL_STATE_INCOMING_CALL_PROCEEDING ;
2003-08-05 09:00:45 +08:00
c - > peercallstate = Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING ;
2001-05-13 00:41:32 +08:00
c - > proc = 1 ;
2003-08-07 08:45:04 +08:00
c - > alive = 1 ;
2001-05-13 00:41:32 +08:00
return send_message ( pri , c , Q931_CALL_PROCEEDING , call_proceeding_ies ) ;
}
2003-07-08 07:37:18 +08:00
# ifndef ALERTING_NO_PROGRESS
2001-05-13 00:41:32 +08:00
static int alerting_ies [ ] = { Q931_CHANNEL_IDENT , Q931_PROGRESS_INDICATOR , - 1 } ;
2003-07-08 07:37:18 +08:00
# else
static int alerting_ies [ ] = { Q931_CHANNEL_IDENT , - 1 } ;
# endif
2001-05-13 00:41:32 +08:00
int q931_alerting ( struct pri * pri , q931_call * c , int channel , int info )
{
if ( channel )
c - > channelno = channel ;
c - > chanflags & = ~ FLAG_PREFERRED ;
c - > chanflags | = FLAG_EXCLUSIVE ;
if ( info ) {
c - > progloc = LOC_PRIV_NET_LOCAL_USER ;
c - > progcode = CODE_CCITT ;
2002-03-18 22:04:47 +08:00
c - > progress = Q931_PROG_INBAND_AVAILABLE ;
2001-05-13 00:41:32 +08:00
} else
c - > progress = - 1 ;
if ( ! c - > proc )
q931_call_proceeding ( pri , c ) ;
2003-03-04 14:00:37 +08:00
c - > ourcallstate = Q931_CALL_STATE_CALL_RECEIVED ;
2003-08-05 09:00:45 +08:00
c - > peercallstate = Q931_CALL_STATE_CALL_DELIVERED ;
2003-08-07 08:45:04 +08:00
c - > alive = 1 ;
2001-05-13 00:41:32 +08:00
return send_message ( pri , c , Q931_ALERTING , alerting_ies ) ;
}
static int connect_ies [ ] = { Q931_CHANNEL_IDENT , Q931_PROGRESS_INDICATOR , - 1 } ;
2003-02-12 21:59:23 +08:00
int q931_setup_ack ( struct pri * pri , q931_call * c , int channel , int nonisdn )
{
if ( channel )
c - > channelno = channel ;
c - > chanflags & = ~ FLAG_PREFERRED ;
c - > chanflags | = FLAG_EXCLUSIVE ;
if ( nonisdn & & ( pri - > switchtype ! = PRI_SWITCH_DMS100 ) ) {
c - > progloc = LOC_PRIV_NET_LOCAL_USER ;
c - > progcode = CODE_CCITT ;
c - > progress = Q931_PROG_CALLED_NOT_ISDN ;
} else
c - > progress = - 1 ;
2003-03-04 14:00:37 +08:00
c - > ourcallstate = Q931_CALL_STATE_OVERLAP_RECEIVING ;
2003-08-05 09:00:45 +08:00
c - > peercallstate = Q931_CALL_STATE_OVERLAP_SENDING ;
2003-08-07 08:45:04 +08:00
c - > alive = 1 ;
2003-02-12 21:59:23 +08:00
return send_message ( pri , c , Q931_SETUP_ACKNOWLEDGE , connect_ies ) ;
}
2001-05-13 00:41:32 +08:00
2003-09-25 14:13:14 +08:00
static void pri_connect_timeout ( void * data )
{
struct q931_call * c = data ;
struct pri * pri = c - > pri ;
if ( pri - > debug & PRI_DEBUG_Q931_STATE )
pri_message ( " Timed out looking for connect acknowledge \n " ) ;
q931_disconnect ( pri , c , PRI_CAUSE_NORMAL_CLEARING ) ;
}
static void pri_release_timeout ( void * data )
{
struct q931_call * c = data ;
struct pri * pri = c - > pri ;
if ( pri - > debug & PRI_DEBUG_Q931_STATE )
pri_message ( " Timed out looking for release complete \n " ) ;
c - > t308_timedout + + ;
c - > alive = 1 ;
q931_release ( pri , c , PRI_CAUSE_NORMAL_CLEARING ) ;
}
static void pri_release_finaltimeout ( void * data )
{
struct q931_call * c = data ;
struct pri * pri = c - > pri ;
c - > alive = 1 ;
if ( pri - > debug & PRI_DEBUG_Q931_STATE )
pri_message ( " Final time-out looking for release complete \n " ) ;
c - > t308_timedout + + ;
2004-04-06 22:50:19 +08:00
c - > ourcallstate = Q931_CALL_STATE_NULL ;
c - > peercallstate = Q931_CALL_STATE_NULL ;
pri - > schedev = 1 ;
pri - > ev . e = PRI_EVENT_HANGUP_ACK ;
pri - > ev . hangup . channel = c - > channelno ;
pri - > ev . hangup . cref = c - > cr ;
pri - > ev . hangup . cause = c - > cause ;
pri - > ev . hangup . call = c ;
q931_hangup ( pri , c , c - > cause ) ;
2003-09-25 14:13:14 +08:00
}
static void pri_disconnect_timeout ( void * data )
{
struct q931_call * c = data ;
struct pri * pri = c - > pri ;
if ( pri - > debug & PRI_DEBUG_Q931_STATE )
pri_message ( " Timed out looking for release \n " ) ;
c - > alive = 1 ;
q931_release ( pri , c , PRI_CAUSE_NORMAL_CLEARING ) ;
}
2001-05-13 00:41:32 +08:00
int q931_connect ( struct pri * pri , q931_call * c , int channel , int nonisdn )
{
if ( channel )
c - > channelno = channel ;
c - > chanflags & = ~ FLAG_PREFERRED ;
c - > chanflags | = FLAG_EXCLUSIVE ;
if ( nonisdn & & ( pri - > switchtype ! = PRI_SWITCH_DMS100 ) ) {
c - > progloc = LOC_PRIV_NET_LOCAL_USER ;
c - > progcode = CODE_CCITT ;
2002-03-18 22:04:47 +08:00
c - > progress = Q931_PROG_CALLED_NOT_ISDN ;
2001-05-13 00:41:32 +08:00
} else
c - > progress = - 1 ;
2003-03-04 14:00:37 +08:00
c - > ourcallstate = Q931_CALL_STATE_CONNECT_REQUEST ;
2003-08-05 09:00:45 +08:00
c - > peercallstate = Q931_CALL_STATE_ACTIVE ;
2003-08-07 08:45:04 +08:00
c - > alive = 1 ;
2003-09-25 14:13:14 +08:00
/* Setup timer */
if ( c - > retranstimer )
pri_schedule_del ( pri , c - > retranstimer ) ;
2003-12-09 23:55:48 +08:00
if ( pri - > localtype = = PRI_CPE )
c - > retranstimer = pri_schedule_event ( pri , T_313 , pri_connect_timeout , c ) ;
2001-05-13 00:41:32 +08:00
return send_message ( pri , c , Q931_CONNECT , connect_ies ) ;
}
static int release_ies [ ] = { Q931_CAUSE , - 1 } ;
int q931_release ( struct pri * pri , q931_call * c , int cause )
{
2003-03-04 14:00:37 +08:00
c - > ourcallstate = Q931_CALL_STATE_RELEASE_REQUEST ;
2003-08-05 09:00:45 +08:00
/* c->peercallstate stays the same */
2001-05-13 00:41:32 +08:00
if ( c - > alive ) {
c - > alive = 0 ;
c - > cause = cause ;
c - > causecode = CODE_CCITT ;
c - > causeloc = LOC_PRIV_NET_LOCAL_USER ;
2003-09-25 14:13:14 +08:00
if ( c - > acked ) {
if ( c - > retranstimer )
pri_schedule_del ( pri , c - > retranstimer ) ;
if ( ! c - > t308_timedout ) {
c - > retranstimer = pri_schedule_event ( pri , T_308 , pri_release_timeout , c ) ;
} else {
c - > retranstimer = pri_schedule_event ( pri , T_308 , pri_release_finaltimeout , c ) ;
}
2003-02-12 21:59:23 +08:00
return send_message ( pri , c , Q931_RELEASE , release_ies ) ;
2003-09-25 14:13:14 +08:00
} else
2003-02-12 21:59:23 +08:00
return send_message ( pri , c , Q931_RELEASE_COMPLETE , release_ies ) ; /* Yes, release_ies, not release_complete_ies */
2001-05-13 00:41:32 +08:00
} else
return 0 ;
}
2002-04-25 11:51:36 +08:00
static int restart_ies [ ] = { Q931_CHANNEL_IDENT , Q931_RESTART_INDICATOR , - 1 } ;
int q931_restart ( struct pri * pri , int channel )
{
struct q931_call * c ;
c = q931_getcall ( pri , 0 | 0x8000 ) ;
if ( ! c )
return - 1 ;
if ( ! channel )
return - 1 ;
c - > ri = 0 ;
c - > channelno = channel ;
c - > chanflags & = ~ FLAG_PREFERRED ;
c - > chanflags | = FLAG_EXCLUSIVE ;
2003-03-05 14:00:35 +08:00
c - > ourcallstate = Q931_CALL_STATE_RESTART ;
2003-08-05 09:00:45 +08:00
c - > peercallstate = Q931_CALL_STATE_RESTART_REQUEST ;
2002-04-25 11:51:36 +08:00
return send_message ( pri , c , Q931_RESTART , restart_ies ) ;
}
2001-05-13 00:41:32 +08:00
static int disconnect_ies [ ] = { Q931_CAUSE , - 1 } ;
int q931_disconnect ( struct pri * pri , q931_call * c , int cause )
{
2003-03-04 14:00:37 +08:00
c - > ourcallstate = Q931_CALL_STATE_DISCONNECT_REQUEST ;
2003-08-05 09:00:45 +08:00
c - > peercallstate = Q931_CALL_STATE_DISCONNECT_INDICATION ;
2001-05-13 00:41:32 +08:00
if ( c - > alive ) {
c - > alive = 0 ;
c - > cause = cause ;
c - > causecode = CODE_CCITT ;
c - > causeloc = LOC_PRIV_NET_LOCAL_USER ;
2001-12-08 03:45:45 +08:00
c - > sendhangupack = 1 ;
2003-09-25 14:13:14 +08:00
if ( c - > retranstimer )
pri_schedule_del ( pri , c - > retranstimer ) ;
c - > retranstimer = pri_schedule_event ( pri , T_305 , pri_disconnect_timeout , c ) ;
2001-05-13 00:41:32 +08:00
return send_message ( pri , c , Q931_DISCONNECT , disconnect_ies ) ;
} else
return 0 ;
}
2003-02-12 21:59:23 +08:00
static int setup_ies [ ] = { Q931_BEARER_CAPABILITY , Q931_CHANNEL_IDENT , Q931_DISPLAY , Q931_PROGRESS_INDICATOR ,
2001-12-08 03:45:45 +08:00
Q931_CALLING_PARTY_NUMBER , Q931_CALLED_PARTY_NUMBER , Q931_SENDING_COMPLETE , - 1 } ;
2001-05-13 00:41:32 +08:00
int q931_setup ( struct pri * pri , q931_call * c , int transmode , int channel , int exclusive ,
2003-02-12 21:59:23 +08:00
int nonisdn , char * caller , int callerplan , char * callername , int callerpres , char * called ,
2001-12-08 03:45:45 +08:00
int calledplan , int userl1 )
2001-05-13 00:41:32 +08:00
{
int res ;
if ( ! channel )
return - 1 ;
c - > transcapability = transmode ;
c - > transmoderate = TRANS_MODE_64_CIRCUIT ;
2001-12-08 03:45:45 +08:00
if ( ! userl1 )
userl1 = PRI_LAYER_1_ULAW ;
c - > userl1 = userl1 ;
2001-05-13 00:41:32 +08:00
c - > channelno = channel ;
c - > slotmap = - 1 ;
c - > ds1no = - 1 ;
c - > nonisdn = nonisdn ;
2003-09-25 14:13:14 +08:00
c - > newcall = 0 ;
2001-05-13 00:41:32 +08:00
if ( exclusive )
c - > chanflags = FLAG_EXCLUSIVE ;
else
c - > chanflags = FLAG_PREFERRED ;
if ( caller ) {
2001-12-08 03:45:45 +08:00
strncpy ( c - > callernum , caller , sizeof ( c - > callernum ) - 1 ) ;
2001-05-13 00:41:32 +08:00
c - > callerplan = callerplan ;
2003-02-12 21:59:23 +08:00
if ( callername )
strncpy ( c - > callername , callername , sizeof ( c - > callername ) - 1 ) ;
else
strcpy ( c - > callername , " " ) ;
2001-05-13 00:41:32 +08:00
if ( ( pri - > switchtype = = PRI_SWITCH_DMS100 ) | |
( pri - > switchtype = = PRI_SWITCH_ATT4ESS ) ) {
/* Doesn't like certain presentation types */
if ( ! ( callerpres & 0x7c ) )
callerpres = PRES_ALLOWED_NETWORK_NUMBER ;
}
c - > callerpres = callerpres ;
} else {
strcpy ( c - > callernum , " " ) ;
2003-02-12 21:59:23 +08:00
strcpy ( c - > callername , " " ) ;
2001-05-13 00:41:32 +08:00
c - > callerplan = PRI_UNKNOWN ;
c - > callerpres = PRES_NUMBER_NOT_AVAILABLE ;
}
if ( called ) {
2001-12-08 03:45:45 +08:00
strncpy ( c - > callednum , called , sizeof ( c - > callednum ) - 1 ) ;
2001-05-13 00:41:32 +08:00
c - > calledplan = calledplan ;
} else
return - 1 ;
if ( nonisdn & & ( pri - > switchtype = = PRI_SWITCH_NI2 ) )
2002-03-18 22:04:47 +08:00
c - > progress = Q931_PROG_CALLER_NOT_ISDN ;
2001-05-13 00:41:32 +08:00
else
c - > progress = - 1 ;
res = send_message ( pri , c , Q931_SETUP , setup_ies ) ;
2003-02-12 21:59:23 +08:00
if ( ! res ) {
2001-05-13 00:41:32 +08:00
c - > alive = 1 ;
2003-08-07 08:45:04 +08:00
/* make sure we call PRI_EVENT_HANGUP_ACK once we send/receive RELEASE_COMPLETE */
c - > sendhangupack = 1 ;
c - > ourcallstate = Q931_CALL_STATE_CALL_INITIATED ;
c - > peercallstate = Q931_CALL_STATE_OVERLAP_SENDING ;
2003-02-12 21:59:23 +08:00
}
2001-05-13 00:41:32 +08:00
return res ;
}
static int release_complete_ies [ ] = { - 1 } ;
2003-08-05 09:00:45 +08:00
static int q931_release_complete ( struct pri * pri , q931_call * c , int cause )
2001-05-13 00:41:32 +08:00
{
2003-08-05 09:00:45 +08:00
int res = 0 ;
2003-03-04 14:00:37 +08:00
c - > ourcallstate = Q931_CALL_STATE_NULL ;
2003-08-05 09:00:45 +08:00
c - > peercallstate = Q931_CALL_STATE_NULL ;
if ( cause > - 1 ) {
c - > cause = cause ;
c - > causecode = CODE_CCITT ;
c - > causeloc = LOC_PRIV_NET_LOCAL_USER ;
2003-08-06 03:26:07 +08:00
/* release_ies has CAUSE in it */
res = send_message ( pri , c , Q931_RELEASE_COMPLETE , release_ies ) ;
} else
res = send_message ( pri , c , Q931_RELEASE_COMPLETE , release_complete_ies ) ;
2003-08-05 09:00:45 +08:00
c - > alive = 0 ;
/* release the structure */
res + = q931_hangup ( pri , c , cause ) ;
return res ;
2001-05-13 00:41:32 +08:00
}
static int connect_acknowledge_ies [ ] = { - 1 } ;
static int q931_connect_acknowledge ( struct pri * pri , q931_call * c )
{
return send_message ( pri , c , Q931_CONNECT_ACKNOWLEDGE , connect_acknowledge_ies ) ;
}
2003-08-05 09:00:45 +08:00
int q931_hangup ( struct pri * pri , q931_call * c , int cause )
{
int disconnect = 1 ;
int release_compl = 0 ;
if ( pri - > debug & PRI_DEBUG_Q931_STATE )
pri_message ( " NEW_HANGUP DEBUG: Calling q931_hangup, ourstate %s, peerstate %s \n " , callstate2str ( c - > ourcallstate ) , callstate2str ( c - > peercallstate ) ) ;
if ( ! pri | | ! c )
return - 1 ;
2003-08-06 02:42:55 +08:00
if ( cause = = 34 | | cause = = 44 | | cause = = 82 | | cause = = 1 ) {
2003-08-06 04:37:32 +08:00
/* We'll send RELEASE_COMPLETE with these causes */
2003-08-05 09:00:45 +08:00
disconnect = 0 ;
release_compl = 1 ;
}
2003-08-06 04:37:32 +08:00
if ( cause = = 6 | | cause = = 7 | | cause = = 26 ) {
/* We'll send RELEASE with these causes */
2003-08-05 09:00:45 +08:00
disconnect = 0 ;
}
2003-08-06 04:37:32 +08:00
/* All other causes we send with DISCONNECT */
2003-08-05 09:00:45 +08:00
switch ( c - > ourcallstate ) {
case Q931_CALL_STATE_NULL :
if ( c - > peercallstate = = Q931_CALL_STATE_NULL )
/* free the resources if we receive or send REL_COMPL */
q931_destroycall ( pri , c - > cr ) ;
else if ( c - > peercallstate = = Q931_CALL_STATE_RELEASE_REQUEST )
q931_release_complete ( pri , c , cause ) ;
break ;
case Q931_CALL_STATE_CALL_INITIATED :
/* we sent SETUP */
case Q931_CALL_STATE_OVERLAP_SENDING :
/* received SETUP_ACKNOWLEDGE */
case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING :
/* received CALL_PROCEEDING */
case Q931_CALL_STATE_CALL_DELIVERED :
/* received ALERTING */
case Q931_CALL_STATE_CALL_PRESENT :
/* received SETUP */
case Q931_CALL_STATE_CALL_RECEIVED :
/* sent ALERTING */
case Q931_CALL_STATE_CONNECT_REQUEST :
/* sent CONNECT */
case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING :
/* we sent CALL_PROCEEDING */
case Q931_CALL_STATE_ACTIVE :
/* received CONNECT */
case Q931_CALL_STATE_OVERLAP_RECEIVING :
/* received SETUP_ACKNOWLEDGE */
/* send DISCONNECT in general */
2003-09-10 07:49:10 +08:00
if ( c - > peercallstate ! = Q931_CALL_STATE_NULL & & c - > peercallstate ! = Q931_CALL_STATE_DISCONNECT_REQUEST & & c - > peercallstate ! = Q931_CALL_STATE_DISCONNECT_INDICATION & & c - > peercallstate ! = Q931_CALL_STATE_RELEASE_REQUEST & & c - > peercallstate ! = Q931_CALL_STATE_RESTART_REQUEST & & c - > peercallstate ! = Q931_CALL_STATE_RESTART ) {
if ( disconnect )
q931_disconnect ( pri , c , cause ) ;
else if ( release_compl )
q931_release_complete ( pri , c , cause ) ;
else
q931_release ( pri , c , cause ) ;
} else
2003-08-05 09:00:45 +08:00
pri_error ( " Wierd, doing nothing but this shouldn't happen, ourstate %s, peerstate %s \n " , callstate2str ( c - > ourcallstate ) , callstate2str ( c - > peercallstate ) ) ;
break ;
case Q931_CALL_STATE_DISCONNECT_REQUEST :
/* sent DISCONNECT */
2003-09-25 14:13:14 +08:00
q931_release ( pri , c , cause ) ;
2003-08-05 09:00:45 +08:00
break ;
case Q931_CALL_STATE_DISCONNECT_INDICATION :
/* received DISCONNECT */
2003-09-25 14:13:14 +08:00
if ( c - > peercallstate = = Q931_CALL_STATE_DISCONNECT_REQUEST ) {
c - > alive = 1 ;
2003-08-05 09:00:45 +08:00
q931_release ( pri , c , cause ) ;
2003-09-25 14:13:14 +08:00
}
break ;
2003-08-05 09:00:45 +08:00
case Q931_CALL_STATE_RELEASE_REQUEST :
/* sent RELEASE */
/* don't do anything, waiting for RELEASE_COMPLETE */
break ;
case Q931_CALL_STATE_RESTART :
case Q931_CALL_STATE_RESTART_REQUEST :
/* sent RESTART */
pri_error ( " q931_hangup shouldn't be called in this state, ourstate %s, peerstate %s \n " , callstate2str ( c - > ourcallstate ) , callstate2str ( c - > peercallstate ) ) ;
break ;
default :
pri_error ( " We're not yet handling hanging up when our state is %d, contact support@digium.com, ourstate %s, peerstate %s \n " , callstate2str ( c - > ourcallstate ) , callstate2str ( c - > peercallstate ) ) ;
return - 1 ;
}
/* we did handle hangup properly at this point */
return 0 ;
}
2001-05-13 00:41:32 +08:00
int q931_receive ( struct pri * pri , q931_h * h , int len )
{
q931_mh * mh ;
q931_call * c ;
q931_ie * ie ;
2003-10-06 13:15:16 +08:00
unsigned int x ;
int y ;
2001-05-13 00:41:32 +08:00
int res ;
int r ;
2003-09-25 14:13:14 +08:00
int mandies [ MAX_MAND_IES ] ;
int missingmand ;
2001-05-13 00:41:32 +08:00
if ( pri - > debug & PRI_DEBUG_Q931_DUMP )
q931_dump ( h , len , 0 ) ;
2004-03-15 13:53:25 +08:00
# ifdef LIBPRI_COUNTERS
pri - > q931_rxcount + + ;
# endif
2001-05-13 00:41:32 +08:00
mh = ( q931_mh * ) ( h - > contents + h - > crlen ) ;
if ( h - > pd = = 0x3 ) {
/* This is the weird maintenance stuff. We majorly
KLUDGE this by changing byte 4 from a 0xf ( SERVICE )
to a 0x7 ( SERVICE ACKNOWLEDGE ) */
2004-01-17 23:14:11 +08:00
h - > raw [ h - > crlen + 2 ] - = 0x8 ;
2001-05-13 00:41:32 +08:00
q931_xmit ( pri , h , len , 1 ) ;
return 0 ;
2003-11-20 04:11:11 +08:00
} else if ( h - > pd ! = Q931_PROTOCOL_DISCRIMINATOR ) {
pri_error ( " Warning: unknown protocol discriminator received \n " ) ;
return 0 ;
2001-05-13 00:41:32 +08:00
}
c = q931_getcall ( pri , q931_cr ( h ) ) ;
if ( ! c ) {
2003-02-12 21:59:23 +08:00
pri_error ( " Unable to locate call %d \n " , q931_cr ( h ) ) ;
2001-05-13 00:41:32 +08:00
return - 1 ;
}
/* Preliminary handling */
switch ( mh - > msg ) {
case Q931_RESTART :
if ( pri - > debug & PRI_DEBUG_Q931_STATE )
2003-02-12 21:59:23 +08:00
pri_message ( " -- Processing Q.931 Restart \n " ) ;
2001-05-13 00:41:32 +08:00
/* Reset information */
c - > channelno = - 1 ;
c - > slotmap = - 1 ;
c - > chanflags = 0 ;
c - > ds1no = - 1 ;
c - > ri = - 1 ;
break ;
2003-02-12 21:59:23 +08:00
case Q931_FACILITY :
strcpy ( c - > callername , " " ) ;
break ;
2001-05-13 00:41:32 +08:00
case Q931_SETUP :
if ( pri - > debug & PRI_DEBUG_Q931_STATE )
2003-02-12 21:59:23 +08:00
pri_message ( " -- Processing Q.931 Call Setup \n " ) ;
2001-05-13 00:41:32 +08:00
c - > channelno = - 1 ;
c - > slotmap = - 1 ;
c - > chanflags = 0 ;
c - > ds1no = - 1 ;
c - > ri = - 1 ;
c - > transcapability = - 1 ;
c - > transmoderate = - 1 ;
c - > transmultiple = - 1 ;
c - > userl1 = - 1 ;
c - > userl2 = - 1 ;
c - > userl3 = - 1 ;
c - > rateadaption = - 1 ;
c - > calledplan = - 1 ;
c - > callerplan = - 1 ;
c - > callerpres = - 1 ;
strcpy ( c - > callernum , " " ) ;
strcpy ( c - > callednum , " " ) ;
2003-02-12 21:59:23 +08:00
strcpy ( c - > callername , " " ) ;
c - > redirectingplan = - 1 ;
c - > redirectingpres = - 1 ;
c - > redirectingreason = - 1 ;
strcpy ( c - > redirectingnum , " " ) ;
c - > useruserprotocoldisc = - 1 ;
strcpy ( c - > useruserinfo , " " ) ;
2003-07-26 23:14:44 +08:00
c - > complete = 0 ;
2001-05-13 00:41:32 +08:00
break ;
case Q931_CONNECT :
case Q931_ALERTING :
case Q931_PROGRESS :
c - > progress = - 1 ;
break ;
case Q931_CONNECT_ACKNOWLEDGE :
2003-09-25 14:13:14 +08:00
if ( c - > retranstimer )
pri_schedule_del ( pri , c - > retranstimer ) ;
c - > retranstimer = 0 ;
/* Fall through */
case Q931_CALL_PROCEEDING :
2001-05-13 00:41:32 +08:00
/* Do nothing */
break ;
case Q931_RELEASE :
case Q931_DISCONNECT :
c - > cause = - 1 ;
c - > causecode = - 1 ;
c - > causeloc = - 1 ;
2003-09-25 14:13:14 +08:00
if ( c - > retranstimer )
pri_schedule_del ( pri , c - > retranstimer ) ;
c - > retranstimer = 0 ;
2001-05-13 00:41:32 +08:00
break ;
case Q931_RELEASE_COMPLETE :
2003-09-25 14:13:14 +08:00
if ( c - > retranstimer )
pri_schedule_del ( pri , c - > retranstimer ) ;
c - > retranstimer = 0 ;
2001-05-13 00:41:32 +08:00
case Q931_STATUS :
c - > cause = - 1 ;
c - > causecode = - 1 ;
c - > causeloc = - 1 ;
2003-09-25 14:13:14 +08:00
c - > sugcallstate = - 1 ;
2001-05-13 00:41:32 +08:00
break ;
2001-07-17 20:12:42 +08:00
case Q931_RESTART_ACKNOWLEDGE :
2002-04-25 11:51:36 +08:00
c - > channelno = - 1 ;
break ;
2003-02-12 21:59:23 +08:00
case Q931_INFORMATION :
break ;
2001-07-17 20:12:42 +08:00
case Q931_STATUS_ENQUIRY :
2003-03-04 14:00:37 +08:00
break ;
case Q931_SETUP_ACKNOWLEDGE :
2003-03-25 05:52:51 +08:00
break ;
2003-09-25 14:13:14 +08:00
case Q931_NOTIFY :
break ;
2001-07-17 20:12:42 +08:00
case Q931_USER_INFORMATION :
case Q931_SEGMENT :
case Q931_CONGESTION_CONTROL :
case Q931_HOLD :
case Q931_HOLD_ACKNOWLEDGE :
case Q931_HOLD_REJECT :
case Q931_RETRIEVE :
case Q931_RETRIEVE_ACKNOWLEDGE :
case Q931_RETRIEVE_REJECT :
case Q931_RESUME :
case Q931_RESUME_ACKNOWLEDGE :
case Q931_RESUME_REJECT :
case Q931_SUSPEND :
case Q931_SUSPEND_ACKNOWLEDGE :
case Q931_SUSPEND_REJECT :
2003-02-12 21:59:23 +08:00
pri_error ( " !! Not yet handling pre-handle message type %s (%d) \n " , msg2str ( mh - > msg ) , mh - > msg ) ;
2003-09-25 14:13:14 +08:00
/* Fall through */
2001-05-13 00:41:32 +08:00
default :
2003-09-25 14:13:14 +08:00
pri_error ( " !! Don't know how to post-handle message type %s (%d) \n " , msg2str ( mh - > msg ) , mh - > msg ) ;
q931_status ( pri , c , PRI_CAUSE_MESSAGE_TYPE_NONEXIST ) ;
if ( c - > newcall )
q931_destroycall ( pri , c - > cr ) ;
2001-05-13 00:41:32 +08:00
return - 1 ;
}
2003-09-25 14:13:14 +08:00
memset ( mandies , 0 , sizeof ( mandies ) ) ;
missingmand = 0 ;
for ( x = 0 ; x < sizeof ( msgs ) / sizeof ( msgs [ 0 ] ) ; x + + ) {
if ( msgs [ x ] . msgnum = = mh - > msg ) {
memcpy ( mandies , msgs [ x ] . mandies , sizeof ( mandies ) ) ;
}
}
2001-05-13 00:41:32 +08:00
x = 0 ;
/* Do real IE processing */
len - = ( h - > crlen + 3 ) ;
while ( len ) {
ie = ( q931_ie * ) ( mh - > data + x ) ;
2003-09-25 14:13:14 +08:00
for ( y = 0 ; y < MAX_MAND_IES ; y + + ) {
if ( mandies [ y ] = = ie - > ie )
mandies [ y ] = 0 ;
}
2001-05-13 00:41:32 +08:00
r = ielen ( ie ) ;
if ( r > len ) {
2003-02-12 21:59:23 +08:00
pri_error ( " XXX Message longer than it should be?? XXX \n " ) ;
2001-05-13 00:41:32 +08:00
return - 1 ;
}
2003-09-25 14:13:14 +08:00
y = q931_handle_ie ( pri , c , mh - > msg , ie ) ;
if ( ! ( ie - > ie & 0xf0 ) & & ( y < 0 ) )
mandies [ MAX_MAND_IES - 1 ] = ie - > ie ;
2001-05-13 00:41:32 +08:00
x + = r ;
len - = r ;
}
2003-09-25 14:13:14 +08:00
missingmand = 0 ;
for ( x = 0 ; x < MAX_MAND_IES ; x + + ) {
if ( mandies [ x ] ) {
pri_error ( " XXX Missing mandatory IE %d/%s XXX \n " , mandies [ x ] , ie2str ( mandies [ x ] ) ) ;
missingmand + + ;
}
}
2003-12-06 07:10:33 +08:00
/* check if there is no channel identyfication when we're configured as network -> that's not an error */
if ( missingmand & & pri - > localtype = = PRI_NETWORK & & mh - > msg = = Q931_SETUP ) {
for ( x = 0 ; x < MAX_MAND_IES ; x + + ) {
if ( mandies [ x ] = = Q931_CHANNEL_IDENT ) {
missingmand - - ;
break ;
}
}
}
2003-09-25 14:13:14 +08:00
2001-05-13 00:41:32 +08:00
/* Post handling */
switch ( mh - > msg ) {
case Q931_RESTART :
2003-09-25 14:13:14 +08:00
if ( missingmand ) {
q931_status ( pri , c , PRI_CAUSE_MANDATORY_IE_MISSING ) ;
q931_destroycall ( pri , c - > cr ) ;
break ;
}
2003-08-05 09:00:45 +08:00
c - > ourcallstate = Q931_CALL_STATE_RESTART ;
c - > peercallstate = Q931_CALL_STATE_RESTART_REQUEST ;
2001-05-13 00:41:32 +08:00
/* Send back the Restart Acknowledge */
restart_ack ( pri , c ) ;
/* Notify user of restart event */
pri - > ev . e = PRI_EVENT_RESTART ;
pri - > ev . restart . channel = c - > channelno ;
return Q931_RES_HAVEEVENT ;
case Q931_SETUP :
2003-09-25 14:13:14 +08:00
if ( missingmand ) {
q931_release_complete ( pri , c , PRI_CAUSE_MANDATORY_IE_MISSING ) ;
break ;
}
/* Must be new call */
if ( ! c - > newcall ) {
break ;
}
c - > newcall = 0 ;
2003-03-04 14:00:37 +08:00
c - > ourcallstate = Q931_CALL_STATE_CALL_PRESENT ;
2003-08-05 09:00:45 +08:00
c - > peercallstate = Q931_CALL_STATE_CALL_INITIATED ;
2003-08-07 08:45:04 +08:00
/* it's not yet a call since higher level can respond with RELEASE or RELEASE_COMPLETE */
c - > alive = 0 ;
2001-05-13 00:41:32 +08:00
pri - > ev . e = PRI_EVENT_RING ;
pri - > ev . ring . channel = c - > channelno ;
pri - > ev . ring . callingpres = c - > callerpres ;
pri - > ev . ring . callingplan = c - > callerplan ;
2001-12-08 03:45:45 +08:00
strncpy ( pri - > ev . ring . callingnum , c - > callernum , sizeof ( pri - > ev . ring . callingnum ) - 1 ) ;
2003-02-12 21:59:23 +08:00
strncpy ( pri - > ev . ring . callingname , c - > callername , sizeof ( pri - > ev . ring . callingname ) - 1 ) ;
2001-05-13 00:41:32 +08:00
pri - > ev . ring . calledplan = c - > calledplan ;
2001-12-08 03:45:45 +08:00
strncpy ( pri - > ev . ring . callednum , c - > callednum , sizeof ( pri - > ev . ring . callednum ) - 1 ) ;
2003-02-12 21:59:23 +08:00
strncpy ( pri - > ev . ring . redirectingnum , c - > redirectingnum , sizeof ( pri - > ev . ring . redirectingnum ) - 1 ) ;
strncpy ( pri - > ev . ring . useruserinfo , c - > useruserinfo , sizeof ( pri - > ev . ring . useruserinfo ) - 1 ) ;
2001-05-13 00:41:32 +08:00
pri - > ev . ring . flexible = ! ( c - > chanflags & FLAG_EXCLUSIVE ) ;
pri - > ev . ring . cref = c - > cr ;
pri - > ev . ring . call = c ;
2001-12-08 03:45:45 +08:00
pri - > ev . ring . layer1 = c - > userl1 ;
2003-07-26 23:14:44 +08:00
pri - > ev . ring . complete = c - > complete ;
2003-11-24 22:36:46 +08:00
pri - > ev . ring . ctype = c - > transcapability ;
2001-05-13 00:41:32 +08:00
if ( c - > transmoderate ! = TRANS_MODE_64_CIRCUIT ) {
2003-09-25 14:13:14 +08:00
q931_release_complete ( pri , c , PRI_CAUSE_BEARERCAPABILITY_NOTIMPL ) ;
2001-05-13 00:41:32 +08:00
break ;
}
return Q931_RES_HAVEEVENT ;
case Q931_ALERTING :
2003-09-25 14:13:14 +08:00
if ( c - > newcall ) {
q931_release_complete ( pri , c , PRI_CAUSE_INVALID_CALL_REFERENCE ) ;
break ;
}
2003-03-04 14:00:37 +08:00
c - > ourcallstate = Q931_CALL_STATE_CALL_DELIVERED ;
2003-08-05 09:00:45 +08:00
c - > peercallstate = Q931_CALL_STATE_CALL_RECEIVED ;
2001-05-13 00:41:32 +08:00
pri - > ev . e = PRI_EVENT_RINGING ;
pri - > ev . ringing . channel = c - > channelno ;
pri - > ev . ringing . cref = c - > cr ;
pri - > ev . ringing . call = c ;
return Q931_RES_HAVEEVENT ;
case Q931_CONNECT :
2003-09-25 14:13:14 +08:00
if ( c - > newcall ) {
q931_release_complete ( pri , c , PRI_CAUSE_INVALID_CALL_REFERENCE ) ;
break ;
}
if ( c - > ourcallstate = = Q931_CALL_STATE_ACTIVE ) {
q931_status ( pri , c , PRI_CAUSE_WRONG_MESSAGE ) ;
break ;
}
2003-03-04 14:00:37 +08:00
c - > ourcallstate = Q931_CALL_STATE_ACTIVE ;
2003-08-05 09:00:45 +08:00
c - > peercallstate = Q931_CALL_STATE_CONNECT_REQUEST ;
2001-05-13 00:41:32 +08:00
pri - > ev . e = PRI_EVENT_ANSWER ;
pri - > ev . answer . channel = c - > channelno ;
pri - > ev . answer . cref = c - > cr ;
pri - > ev . answer . call = c ;
q931_connect_acknowledge ( pri , c ) ;
return Q931_RES_HAVEEVENT ;
2003-02-12 21:59:23 +08:00
case Q931_FACILITY :
2003-09-25 14:13:14 +08:00
if ( c - > newcall ) {
q931_release_complete ( pri , c , PRI_CAUSE_INVALID_CALL_REFERENCE ) ;
break ;
}
2003-02-12 21:59:23 +08:00
pri - > ev . e = PRI_EVENT_FACNAME ;
strncpy ( pri - > ev . facname . callingname , c - > callername , sizeof ( pri - > ev . facname . callingname ) - 1 ) ;
strncpy ( pri - > ev . facname . callingnum , c - > callernum , sizeof ( pri - > ev . facname . callingname ) - 1 ) ;
pri - > ev . facname . channel = c - > channelno ;
pri - > ev . facname . cref = c - > cr ;
pri - > ev . facname . call = c ;
#if 0
pri_message ( " Sending facility event (%s/%s) \n " , pri - > ev . facname . callingname , pri - > ev . facname . callingnum ) ;
# endif
return Q931_RES_HAVEEVENT ;
2001-05-13 00:41:32 +08:00
case Q931_PROGRESS :
2003-09-25 14:13:14 +08:00
if ( missingmand ) {
q931_status ( pri , c , PRI_CAUSE_MANDATORY_IE_MISSING ) ;
q931_destroycall ( pri , c - > cr ) ;
break ;
}
/* Fall through */
2003-04-18 23:56:38 +08:00
case Q931_CALL_PROCEEDING :
2003-09-25 14:13:14 +08:00
if ( c - > newcall ) {
q931_release_complete ( pri , c , PRI_CAUSE_INVALID_CALL_REFERENCE ) ;
break ;
}
if ( ( c - > ourcallstate ! = Q931_CALL_STATE_CALL_INITIATED ) & &
2003-10-10 15:04:19 +08:00
( c - > ourcallstate ! = Q931_CALL_STATE_OVERLAP_SENDING ) & &
2003-10-15 21:56:10 +08:00
( c - > ourcallstate ! = Q931_CALL_STATE_CALL_DELIVERED ) & &
2003-10-10 15:04:19 +08:00
( c - > ourcallstate ! = Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING ) ) {
2003-09-25 14:13:14 +08:00
q931_status ( pri , c , PRI_CAUSE_WRONG_MESSAGE ) ;
break ;
}
2003-04-18 23:56:38 +08:00
pri - > ev . e = PRI_EVENT_PROCEEDING ;
pri - > ev . proceeding . channel = c - > channelno ;
2003-09-25 14:13:14 +08:00
if ( mh - > msg = = Q931_CALL_PROCEEDING ) {
c - > ourcallstate = Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING ;
c - > peercallstate = Q931_CALL_STATE_INCOMING_CALL_PROCEEDING ;
}
2003-04-18 23:56:38 +08:00
return Q931_RES_HAVEEVENT ;
2001-05-13 00:41:32 +08:00
case Q931_CONNECT_ACKNOWLEDGE :
2003-09-25 14:13:14 +08:00
if ( c - > newcall ) {
q931_release_complete ( pri , c , PRI_CAUSE_INVALID_CALL_REFERENCE ) ;
break ;
}
if ( c - > ourcallstate ! = Q931_CALL_STATE_CONNECT_REQUEST ) {
q931_status ( pri , c , PRI_CAUSE_WRONG_MESSAGE ) ;
break ;
}
2003-03-04 14:00:37 +08:00
c - > ourcallstate = Q931_CALL_STATE_ACTIVE ;
2003-08-05 09:00:45 +08:00
c - > peercallstate = Q931_CALL_STATE_ACTIVE ;
2003-04-18 23:56:38 +08:00
break ;
2001-05-13 00:41:32 +08:00
case Q931_STATUS :
2003-09-25 14:13:14 +08:00
if ( missingmand ) {
q931_status ( pri , c , PRI_CAUSE_MANDATORY_IE_MISSING ) ;
q931_destroycall ( pri , c - > cr ) ;
break ;
}
if ( c - > newcall ) {
2004-02-26 04:02:04 +08:00
if ( c - > cr & 0x7fff )
q931_release_complete ( pri , c , PRI_CAUSE_WRONG_CALL_STATE ) ;
2003-09-25 14:13:14 +08:00
break ;
}
2001-05-13 00:41:32 +08:00
/* Do nothing */
2003-09-25 14:13:14 +08:00
/* Also when the STATUS asks for the call of an unexisting reference send RELEASE_COMPL */
2001-07-17 20:12:42 +08:00
if ( ( pri - > debug & PRI_DEBUG_Q931_ANOMALY ) & &
2003-09-25 14:13:14 +08:00
( c - > cause ! = PRI_CAUSE_INTERWORKING ) )
2003-02-12 21:59:23 +08:00
pri_error ( " Received unsolicited status: %s \n " , pri_cause2str ( c - > cause ) ) ;
2003-09-25 14:13:14 +08:00
if ( ! c - > sugcallstate ) {
pri - > ev . hangup . channel = c - > channelno ;
pri - > ev . hangup . cref = c - > cr ;
pri - > ev . hangup . cause = c - > cause ;
pri - > ev . hangup . call = c ;
/* Free resources */
c - > ourcallstate = Q931_CALL_STATE_NULL ;
c - > peercallstate = Q931_CALL_STATE_NULL ;
if ( c - > alive ) {
pri - > ev . e = PRI_EVENT_HANGUP ;
res = Q931_RES_HAVEEVENT ;
c - > alive = 0 ;
} else if ( c - > sendhangupack ) {
res = Q931_RES_HAVEEVENT ;
pri - > ev . e = PRI_EVENT_HANGUP_ACK ;
q931_hangup ( pri , c , c - > cause ) ;
} else {
q931_hangup ( pri , c , c - > cause ) ;
res = 0 ;
}
if ( res )
return res ;
}
2001-05-13 00:41:32 +08:00
break ;
case Q931_RELEASE_COMPLETE :
2003-03-04 14:00:37 +08:00
c - > ourcallstate = Q931_CALL_STATE_NULL ;
2003-08-05 09:00:45 +08:00
c - > peercallstate = Q931_CALL_STATE_NULL ;
2003-08-07 08:45:04 +08:00
pri - > ev . hangup . channel = c - > channelno ;
pri - > ev . hangup . cref = c - > cr ;
pri - > ev . hangup . cause = c - > cause ;
pri - > ev . hangup . call = c ;
2001-05-13 00:41:32 +08:00
/* Free resources */
if ( c - > alive ) {
pri - > ev . e = PRI_EVENT_HANGUP ;
res = Q931_RES_HAVEEVENT ;
c - > alive = 0 ;
2003-08-07 08:45:04 +08:00
} else if ( c - > sendhangupack ) {
res = Q931_RES_HAVEEVENT ;
pri - > ev . e = PRI_EVENT_HANGUP_ACK ;
pri_hangup ( pri , c , c - > cause ) ;
2001-05-13 00:41:32 +08:00
} else
res = 0 ;
if ( res )
return res ;
2003-08-05 09:00:45 +08:00
else
q931_hangup ( pri , c , c - > cause ) ;
2001-05-13 00:41:32 +08:00
break ;
case Q931_RELEASE :
2003-09-25 14:13:14 +08:00
if ( missingmand ) {
q931_release_complete ( pri , c , PRI_CAUSE_MANDATORY_IE_MISSING ) ;
break ;
}
if ( c - > ourcallstate = = Q931_CALL_STATE_RELEASE_REQUEST )
c - > peercallstate = Q931_CALL_STATE_NULL ;
else {
c - > peercallstate = Q931_CALL_STATE_RELEASE_REQUEST ;
}
2003-03-04 14:00:37 +08:00
c - > ourcallstate = Q931_CALL_STATE_NULL ;
2001-05-13 00:41:32 +08:00
pri - > ev . e = PRI_EVENT_HANGUP ;
pri - > ev . hangup . channel = c - > channelno ;
pri - > ev . hangup . cref = c - > cr ;
pri - > ev . hangup . cause = c - > cause ;
pri - > ev . hangup . call = c ;
2003-09-25 14:13:14 +08:00
/* Don't send release complete if they send us release
while we sent it , assume a NULL state */
if ( c - > newcall )
q931_release_complete ( pri , c , PRI_CAUSE_INVALID_CALL_REFERENCE ) ;
else
return Q931_RES_HAVEEVENT ;
break ;
2001-05-13 00:41:32 +08:00
case Q931_DISCONNECT :
2003-09-25 14:13:14 +08:00
if ( missingmand ) {
q931_release ( pri , c , PRI_CAUSE_MANDATORY_IE_MISSING ) ;
break ;
}
if ( c - > newcall ) {
q931_release_complete ( pri , c , PRI_CAUSE_INVALID_CALL_REFERENCE ) ;
break ;
}
2003-03-04 14:00:37 +08:00
c - > ourcallstate = Q931_CALL_STATE_DISCONNECT_INDICATION ;
2003-08-05 09:00:45 +08:00
c - > peercallstate = Q931_CALL_STATE_DISCONNECT_REQUEST ;
2003-08-07 08:45:04 +08:00
c - > sendhangupack = 1 ;
2001-05-13 00:41:32 +08:00
/* Return such an event */
2003-08-07 08:45:04 +08:00
pri - > ev . e = PRI_EVENT_HANGUP_REQ ;
2001-05-13 00:41:32 +08:00
pri - > ev . hangup . channel = c - > channelno ;
pri - > ev . hangup . cref = c - > cr ;
pri - > ev . hangup . cause = c - > cause ;
pri - > ev . hangup . call = c ;
2003-08-05 09:00:45 +08:00
if ( c - > alive )
return Q931_RES_HAVEEVENT ;
else
2003-08-07 08:45:04 +08:00
q931_hangup ( pri , c , c - > cause ) ;
break ;
2001-07-17 20:12:42 +08:00
case Q931_RESTART_ACKNOWLEDGE :
2003-03-04 14:00:37 +08:00
c - > ourcallstate = Q931_CALL_STATE_NULL ;
2003-08-05 09:00:45 +08:00
c - > peercallstate = Q931_CALL_STATE_NULL ;
2002-04-25 11:51:36 +08:00
pri - > ev . e = PRI_EVENT_RESTART_ACK ;
pri - > ev . restartack . channel = c - > channelno ;
return Q931_RES_HAVEEVENT ;
2003-02-12 21:59:23 +08:00
case Q931_INFORMATION :
2003-03-19 14:00:31 +08:00
/* XXX We're handling only INFORMATION messages that contain
overlap dialing received digit
2003-07-02 04:25:34 +08:00
+ the " Complete " msg which is basically an EOF on further digits
2003-03-19 14:00:31 +08:00
XXX */
2003-09-25 14:13:14 +08:00
if ( c - > newcall ) {
q931_release_complete ( pri , c , PRI_CAUSE_INVALID_CALL_REFERENCE ) ;
break ;
}
2003-03-19 14:00:31 +08:00
if ( c - > ourcallstate ! = Q931_CALL_STATE_OVERLAP_RECEIVING )
break ;
2003-02-12 21:59:23 +08:00
pri - > ev . e = PRI_EVENT_INFO_RECEIVED ;
pri - > ev . ring . call = c ;
2003-03-25 05:52:51 +08:00
pri - > ev . ring . channel = c - > channelno ;
2003-02-12 21:59:23 +08:00
strncpy ( pri - > ev . ring . callednum , c - > callednum , sizeof ( pri - > ev . ring . callednum ) - 1 ) ;
2003-07-02 04:25:34 +08:00
pri - > ev . ring . complete = c - > complete ; /* this covers IE 33 (Sending Complete) */
2003-02-12 21:59:23 +08:00
return Q931_RES_HAVEEVENT ;
2003-09-25 14:13:14 +08:00
break ;
2001-07-17 20:12:42 +08:00
case Q931_STATUS_ENQUIRY :
2003-09-25 14:13:14 +08:00
if ( c - > newcall ) {
q931_release_complete ( pri , c , PRI_CAUSE_INVALID_CALL_REFERENCE ) ;
} else
q931_status ( pri , c , 0 ) ;
2003-03-04 14:00:37 +08:00
break ;
case Q931_SETUP_ACKNOWLEDGE :
2003-09-25 14:13:14 +08:00
if ( c - > newcall ) {
q931_release_complete ( pri , c , PRI_CAUSE_INVALID_CALL_REFERENCE ) ;
break ;
}
2003-03-04 14:00:37 +08:00
c - > ourcallstate = Q931_CALL_STATE_OVERLAP_SENDING ;
2003-08-05 09:00:45 +08:00
c - > peercallstate = Q931_CALL_STATE_OVERLAP_RECEIVING ;
2003-05-16 06:15:38 +08:00
pri - > ev . e = PRI_EVENT_SETUP_ACK ;
pri - > ev . setup_ack . channel = c - > channelno ;
return Q931_RES_HAVEEVENT ;
2003-09-25 14:13:14 +08:00
case Q931_NOTIFY :
/* Do nothing */
break ;
2001-07-17 20:12:42 +08:00
case Q931_USER_INFORMATION :
case Q931_SEGMENT :
case Q931_CONGESTION_CONTROL :
case Q931_HOLD :
case Q931_HOLD_ACKNOWLEDGE :
case Q931_HOLD_REJECT :
case Q931_RETRIEVE :
case Q931_RETRIEVE_ACKNOWLEDGE :
case Q931_RETRIEVE_REJECT :
case Q931_RESUME :
case Q931_RESUME_ACKNOWLEDGE :
case Q931_RESUME_REJECT :
case Q931_SUSPEND :
case Q931_SUSPEND_ACKNOWLEDGE :
case Q931_SUSPEND_REJECT :
2003-02-12 21:59:23 +08:00
pri_error ( " !! Not yet handling post-handle message type %s (%d) \n " , msg2str ( mh - > msg ) , mh - > msg ) ;
2003-09-25 14:13:14 +08:00
/* Fall through */
2001-05-13 00:41:32 +08:00
default :
2003-09-25 14:13:14 +08:00
2003-02-12 21:59:23 +08:00
pri_error ( " !! Don't know how to post-handle message type %s (%d) \n " , msg2str ( mh - > msg ) , mh - > msg ) ;
2003-09-25 14:13:14 +08:00
q931_status ( pri , c , PRI_CAUSE_MESSAGE_TYPE_NONEXIST ) ;
if ( c - > newcall )
q931_destroycall ( pri , c - > cr ) ;
2001-05-13 00:41:32 +08:00
return - 1 ;
}
return 0 ;
}