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 .
*
*/
2004-12-16 04:15:28 +08:00
# include "compat.h"
2001-05-13 00:41:32 +08:00
# include "libpri.h"
# include "pri_internal.h"
# include "pri_q921.h"
# include "pri_q931.h"
2004-10-28 04:43:23 +08:00
# include "pri_facility.h"
2001-05-13 00:41:32 +08:00
# include <unistd.h>
# include <stdlib.h>
# include <string.h>
# include <stdio.h>
2005-01-17 20:58:05 +08:00
# include <limits.h>
2001-05-13 00:41:32 +08:00
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 ;
2005-04-04 07:07:55 +08:00
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 " } ,
} ;
2004-06-26 12:37:09 +08:00
struct msgtype facilities [ ] = {
{ PRI_NSF_SID_PREFERRED , " CPN (SID) preferred " } ,
{ PRI_NSF_ANI_PREFERRED , " BN (ANI) preferred " } ,
{ PRI_NSF_SID_ONLY , " CPN (SID) only " } ,
{ PRI_NSF_ANI_ONLY , " BN (ANI) only " } ,
{ PRI_NSF_CALL_ASSOC_TSC , " Call Associated TSC " } ,
{ PRI_NSF_NOTIF_CATSC_CLEARING , " Notification of CATSC Clearing or Resource Unavailable " } ,
{ PRI_NSF_OPERATOR , " Operator " } ,
{ PRI_NSF_PCCO , " Pre-subscribed Common Carrier Operator (PCCO) " } ,
{ PRI_NSF_SDN , " SDN (including GSDN) " } ,
{ PRI_NSF_TOLL_FREE_MEGACOM , " Toll Free MEGACOM " } ,
{ PRI_NSF_MEGACOM , " MEGACOM " } ,
{ PRI_NSF_ACCUNET , " ACCUNET Switched Digital Service " } ,
{ PRI_NSF_LONG_DISTANCE_SERVICE , " Long Distance Service " } ,
{ PRI_NSF_INTERNATIONAL_TOLL_FREE , " International Toll Free Service " } ,
{ PRI_NSF_ATT_MULTIQUEST , " AT&T MultiQuest " } ,
{ PRI_NSF_CALL_REDIRECTION_SERVICE , " Call Redirection Service " }
} ;
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
2004-04-22 05:21:29 +08:00
# define TRANS_MODE_PACKET 0x40
2001-05-13 00:41:32 +08:00
# 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
2005-01-17 20:58:05 +08:00
/* Don't forget to update PRI_PROG_xxx at libpri.h */
2004-05-23 03:06:54 +08:00
# define Q931_PROG_CALL_NOT_E2E_ISDN 0x01
2002-03-18 22:04:47 +08:00
# define Q931_PROG_CALLED_NOT_ISDN 0x02
# define Q931_PROG_CALLER_NOT_ISDN 0x03
2005-04-06 05:54:15 +08:00
# define Q931_PROG_CALLER_RETURNED_TO_ISDN 0x04
2002-03-18 22:04:47 +08:00
# 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
2004-04-22 05:21:29 +08:00
# define LOC_PRIV_NET_REMOTE_USER 0x5
2001-05-13 00:41:32 +08:00
# define LOC_INTERNATIONAL_NETWORK 0x7
# define LOC_NETWORK_BEYOND_INTERWORKING 0xa
2005-01-25 04:57:04 +08:00
static char * ie2str ( int ie ) ;
2005-01-29 06:11:24 +08:00
static char * msg2str ( int msg ) ;
2005-01-25 04:57:04 +08:00
2001-05-13 00:41:32 +08:00
2004-06-15 06:21:05 +08:00
# define FUNC_DUMP(name) void ((name))(int full_ie, q931_ie *ie, int len, char prefix)
# define FUNC_RECV(name) int ((name))(int full_ie, struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len)
2005-01-17 20:58:05 +08:00
# define FUNC_SEND(name) int ((name))(int full_ie, struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
2004-06-15 06:21:05 +08:00
2001-05-13 00:41:32 +08:00
struct ie {
2005-01-17 20:58:05 +08:00
/* Maximal count of same IEs at the message (0 - any, 1..n - limited) */
int max_count ;
/* IE code */
2001-05-13 00:41:32 +08:00
int ie ;
2005-01-17 20:58:05 +08:00
/* IE friendly name */
2001-05-13 00:41:32 +08:00
char * name ;
/* Dump an IE for debugging (preceed all lines by prefix) */
2004-06-15 06:21:05 +08:00
FUNC_DUMP ( * dump ) ;
2001-05-13 00:41:32 +08:00
/* Handle IE returns 0 on success, -1 on failure */
2004-06-15 06:21:05 +08:00
FUNC_RECV ( * receive ) ;
2001-05-13 00:41:32 +08:00
/* Add IE to a message, return the # of bytes added or -1 on failure */
2004-06-15 06:21:05 +08:00
FUNC_SEND ( * transmit ) ;
2001-05-13 00:41:32 +08:00
} ;
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 ;
2004-06-05 14:50:55 +08:00
c - > ds1no = 0 ;
2001-05-13 00:41:32 +08:00
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 ;
}
2004-06-15 06:21:05 +08:00
static FUNC_RECV ( receive_channel_id )
2001-05-13 00:41:32 +08:00
{
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
2005-03-02 23:56:11 +08:00
switch ( ie - > data [ 0 ] & 3 ) {
case 0 :
call - > justsignalling = 1 ;
break ;
case 1 :
break ;
default :
pri_error ( " !! Unexpected Channel selection %d \n " , ie - > data [ 0 ] & 3 ) ;
return - 1 ;
2001-05-13 00:41:32 +08:00
}
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 ;
}
2004-06-15 06:21:05 +08:00
static FUNC_SEND ( transmit_channel_id )
2001-05-13 00:41:32 +08:00
{
int pos = 0 ;
2005-01-17 20:58:05 +08:00
2005-03-02 23:56:11 +08:00
2005-01-17 20:58:05 +08:00
/* We are ready to transmit single IE only */
if ( order > 1 )
return 0 ;
2005-03-02 23:56:11 +08:00
if ( call - > justsignalling ) {
ie - > data [ pos + + ] = 0xac ; /* Read the standards docs to figure this out
ECMA - 165 section 7.3 */
return pos + 2 ;
}
2001-05-13 00:41:32 +08:00
/* Start with standard stuff */
2004-06-05 14:50:55 +08:00
if ( pri - > switchtype = = PRI_SWITCH_GR303_TMC )
2004-06-06 09:21:41 +08:00
ie - > data [ pos ] = 0x69 ;
2004-06-05 14:50:55 +08:00
else
ie - > data [ pos ] = 0xa1 ;
2001-05-13 00:41:32 +08:00
/* 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 ;
}
2004-06-05 14:50:55 +08:00
if ( call - > ds1no > 0 ) {
2001-05-13 00:41:32 +08:00
/* 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 ;
}
}
2004-06-05 14:50:55 +08:00
if ( call - > ds1no > 0 ) {
2001-05-13 00:41:32 +08:00
/* 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 ;
}
2004-06-15 06:21:05 +08:00
static FUNC_DUMP ( dump_channel_id )
2001-05-13 00:41:32 +08:00
{
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 + + ;
} 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
}
2004-06-15 06:21:05 +08:00
static FUNC_DUMP ( dump_restart_indicator )
2001-05-13 00:41:32 +08:00
{
2004-06-14 11:29:19 +08:00
pri_message ( " %c Restart Indentifier (len=%2d) [ Ext: %d Spare: %d Resetting %s (%d) ] \n " ,
prefix , len , ( ie - > data [ 0 ] & 0x80 ) > > 7 , ( ie - > data [ 0 ] & 0x78 ) > > 3 , ri2str ( ie - > data [ 0 ] & 0x7 ) , ie - > data [ 0 ] & 0x7 ) ;
2001-05-13 00:41:32 +08:00
}
2004-06-15 06:21:05 +08:00
static FUNC_RECV ( receive_restart_indicator )
2001-05-13 00:41:32 +08:00
{
/* Pretty simple */
call - > ri = ie - > data [ 0 ] & 0x7 ;
return 0 ;
}
2004-06-15 06:21:05 +08:00
static FUNC_SEND ( transmit_restart_indicator )
2001-05-13 00:41:32 +08:00
{
/* 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 " } ,
2005-02-28 14:34:24 +08:00
{ PRI_TRANS_CAP_DIGITAL_W_TONES , " Unrestricted digital information with tones/announcements " } ,
2001-07-17 20:12:42 +08:00
{ 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
}
2004-06-15 06:21:05 +08:00
static FUNC_DUMP ( dump_bearer_capability )
2001-05-13 00:41:32 +08:00
{
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 " ,
2004-06-14 11:29:19 +08:00
prefix , 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 + + ;
}
}
2004-06-15 06:21:05 +08:00
static FUNC_RECV ( receive_bearer_capability )
2001-05-13 00:41:32 +08:00
{
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 ;
}
2004-06-15 06:21:05 +08:00
static FUNC_SEND ( transmit_bearer_capability )
2001-05-13 00:41:32 +08:00
{
int tc ;
2005-01-17 20:58:05 +08:00
/* We are ready to transmit single IE only */
if ( order > 1 )
return 0 ;
2001-05-13 00:41:32 +08:00
tc = call - > transcapability ;
2004-06-06 09:21:41 +08:00
if ( pri - > subchannel ) {
/* Bearer capability is *hard coded* in GR-303 */
ie - > data [ 0 ] = 0x88 ;
ie - > data [ 1 ] = 0x90 ;
return 4 ;
}
2005-03-02 23:56:11 +08:00
if ( call - > justsignalling ) {
ie - > data [ 0 ] = 0xa8 ;
ie - > data [ 1 ] = 0x80 ;
return 4 ;
}
2001-05-13 00:41:32 +08:00
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 " } ,
2004-10-04 22:41:02 +08:00
{ PRES_NUMBER_NOT_AVAILABLE , " Number not available " } ,
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 ;
}
2004-06-15 06:21:05 +08:00
static FUNC_DUMP ( dump_called_party_number )
2002-03-18 22:04:47 +08:00
{
2005-04-04 07:07:55 +08:00
unsigned char cnum [ 256 ] ;
2002-03-18 22:04:47 +08:00
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 ) ;
}
2004-06-15 06:21:05 +08:00
static FUNC_DUMP ( dump_called_party_subaddr )
2001-05-13 00:41:32 +08:00
{
2005-04-04 07:07:55 +08:00
unsigned char cnum [ 256 ] ;
2001-05-13 00:41:32 +08:00
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
}
2004-06-15 06:21:05 +08:00
static FUNC_DUMP ( dump_calling_party_number )
2001-05-13 00:41:32 +08:00
{
2005-04-04 07:07:55 +08:00
unsigned char cnum [ 256 ] ;
2004-06-14 11:29:19 +08:00
if ( ie - > data [ 0 ] & 0x80 )
2004-05-20 06:02:40 +08:00
q931_get_number ( cnum , sizeof ( cnum ) , ie - > data + 1 , len - 3 ) ;
2004-06-14 11:29:19 +08:00
else
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 ) ;
2004-06-14 11:29:19 +08:00
if ( ie - > data [ 0 ] & 0x80 )
pri_message ( " %c Presentation: %s (%d) '%s' ] \n " , prefix , pri_pres2str ( 0 ) , 0 , cnum ) ;
else
2004-05-20 06:02:40 +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
2004-06-15 06:21:05 +08:00
static FUNC_DUMP ( dump_calling_party_subaddr )
2002-03-18 22:04:47 +08:00
{
2005-04-04 07:07:55 +08:00
unsigned 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
}
2004-06-15 06:21:05 +08:00
static FUNC_DUMP ( dump_redirecting_number )
2002-03-18 22:04:47 +08:00
{
2005-04-04 07:07:55 +08:00
unsigned char cnum [ 256 ] ;
2004-06-14 11:29:19 +08:00
int i = 0 ;
/* To follow Q.931 (4.5.1), we must search for start of octet 4 by
walking through all bytes until one with ext bit ( 8 ) set to 1 */
do {
switch ( i ) {
case 0 : /* Octet 3 */
pri_message ( " %c Redirecting Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d) " ,
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 ) ;
break ;
case 1 : /* Octet 3a */
pri_message ( " \n %c Ext: %d Presentation: %s (%d) " ,
prefix , ie - > data [ 1 ] > > 7 , pri_pres2str ( ie - > data [ 1 ] & 0x7f ) , ie - > data [ 1 ] & 0x7f ) ;
break ;
case 2 : /* Octet 3b */
pri_message ( " \n %c Ext: %d Reason: %s (%d) " ,
prefix , ie - > data [ 2 ] > > 7 , redirection_reason2str ( ie - > data [ 2 ] & 0x7f ) , ie - > data [ 2 ] & 0x7f ) ;
break ;
}
}
while ( ! ( ie - > data [ i + + ] & 0x80 ) ) ;
q931_get_number ( cnum , sizeof ( cnum ) , ie - > data + i , ie - > len - i ) ;
pri_message ( " '%s' ] \n " , cnum ) ;
}
2004-06-15 06:21:05 +08:00
static FUNC_DUMP ( dump_connected_number )
2004-06-14 11:29:19 +08:00
{
2005-04-04 07:07:55 +08:00
unsigned char cnum [ 256 ] ;
2004-06-14 11:29:19 +08:00
int i = 0 ;
/* To follow Q.931 (4.5.1), we must search for start of octet 4 by
walking through all bytes until one with ext bit ( 8 ) set to 1 */
do {
switch ( i ) {
case 0 : /* Octet 3 */
pri_message ( " %c Connected Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d) " ,
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 ) ;
break ;
case 1 : /* Octet 3a */
pri_message ( " \n %c Ext: %d Presentation: %s (%d) " ,
prefix , ie - > data [ 1 ] > > 7 , pri_pres2str ( ie - > data [ 1 ] & 0x7f ) , ie - > data [ 1 ] & 0x7f ) ;
break ;
}
}
while ( ! ( ie - > data [ i + + ] & 0x80 ) ) ;
q931_get_number ( cnum , sizeof ( cnum ) , ie - > data + i , ie - > len - i ) ;
pri_message ( " '%s' ] \n " , cnum ) ;
2003-02-12 21:59:23 +08:00
}
2004-06-15 06:21:05 +08:00
static FUNC_RECV ( receive_redirecting_number )
2004-08-25 14:20:50 +08:00
{
int i = 0 ;
2003-02-12 21:59:23 +08:00
2004-08-25 14:20:50 +08:00
/* To follow Q.931 (4.5.1), we must search for start of octet 4 by
walking through all bytes until one with ext bit ( 8 ) set to 1 */
do {
switch ( i ) {
case 0 :
call - > redirectingplan = ie - > data [ i ] & 0x7f ;
break ;
case 1 :
call - > redirectingpres = ie - > data [ i ] & 0x7f ;
break ;
case 2 :
call - > redirectingreason = ie - > data [ i ] & 0x0f ;
break ;
}
}
while ( ! ( ie - > data [ i + + ] & 0x80 ) ) ;
2005-04-04 07:07:55 +08:00
q931_get_number ( ( unsigned char * ) call - > redirectingnum , sizeof ( call - > redirectingnum ) , ie - > data + i , ie - > len - i ) ;
2003-02-12 21:59:23 +08:00
return 0 ;
2002-03-18 22:04:47 +08:00
}
2004-10-31 04:13:20 +08:00
static FUNC_SEND ( transmit_redirecting_number )
{
2005-01-17 20:58:05 +08:00
if ( order > 1 )
return 0 ;
2004-10-31 04:13:20 +08:00
if ( call - > redirectingnum & & strlen ( call - > redirectingnum ) ) {
ie - > data [ 0 ] = call - > redirectingplan ;
ie - > data [ 1 ] = call - > redirectingpres ;
ie - > data [ 2 ] = ( call - > redirectingreason & 0x0f ) | 0x80 ;
memcpy ( ie - > data + 3 , call - > redirectingnum , strlen ( call - > redirectingnum ) ) ;
return strlen ( call - > redirectingnum ) + 3 + 2 ;
}
return 0 ;
}
2003-02-12 21:59:23 +08:00
2004-06-15 06:21:05 +08:00
static FUNC_DUMP ( dump_redirecting_subaddr )
2002-03-18 22:04:47 +08:00
{
2005-04-04 07:07:55 +08:00
unsigned 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 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
2004-06-26 03:33:12 +08:00
static FUNC_RECV ( receive_calling_party_subaddr )
{
/* copy digits to call->callingsubaddr */
2005-04-04 07:07:55 +08:00
q931_get_number ( ( unsigned char * ) call - > callingsubaddr , sizeof ( call - > callingsubaddr ) , ie - > data + 2 , len - 4 ) ;
2004-06-26 03:33:12 +08:00
return 0 ;
}
2004-06-15 06:21:05 +08:00
static FUNC_RECV ( receive_called_party_number )
2001-05-13 00:41:32 +08:00
{
2003-02-12 21:59:23 +08:00
/* copy digits to call->callednum */
2005-04-04 07:07:55 +08:00
q931_get_number ( ( unsigned char * ) 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 ;
}
2004-06-15 06:21:05 +08:00
static FUNC_SEND ( transmit_called_party_number )
2001-05-13 00:41:32 +08:00
{
ie - > data [ 0 ] = 0x80 | call - > calledplan ;
if ( strlen ( call - > callednum ) )
memcpy ( ie - > data + 1 , call - > callednum , strlen ( call - > callednum ) ) ;
return strlen ( call - > callednum ) + 3 ;
}
2004-06-15 06:21:05 +08:00
static FUNC_RECV ( receive_calling_party_number )
2001-05-13 00:41:32 +08:00
{
2003-02-12 21:59:23 +08:00
int extbit ;
call - > callerplan = ie - > data [ 0 ] & 0x7f ;
extbit = ( ie - > data [ 0 ] > > 7 ) & 0x01 ;
2005-04-01 04:56:52 +08:00
/* Somebody's broken PRI stack sent a calling
party number IE twice . One with the callernam
and one without . */
if ( strlen ( call - > callernum ) )
return 0 ;
2003-02-12 21:59:23 +08:00
if ( extbit ) {
2005-04-04 07:07:55 +08:00
q931_get_number ( ( unsigned char * ) call - > callernum , sizeof ( call - > callernum ) , ie - > data + 1 , len - 3 ) ;
2003-02-12 21:59:23 +08:00
call - > callerpres = 0 ; /* PI presentation allowed
SI user - provided , not screened */
} else {
2005-04-04 07:07:55 +08:00
q931_get_number ( ( unsigned char * ) call - > callernum , sizeof ( call - > callernum ) , ie - > data + 2 , len - 4 ) ;
2003-02-12 21:59:23 +08:00
call - > callerpres = ie - > data [ 1 ] & 0x7f ;
}
2001-05-13 00:41:32 +08:00
return 0 ;
}
2004-06-15 06:21:05 +08:00
static FUNC_SEND ( transmit_calling_party_number )
2001-05-13 00:41:32 +08:00
{
ie - > data [ 0 ] = call - > callerplan ;
ie - > data [ 1 ] = 0x80 | call - > callerpres ;
2004-09-17 04:38:13 +08:00
if ( strlen ( call - > callernum ) )
2001-05-13 00:41:32 +08:00
memcpy ( ie - > data + 2 , call - > callernum , strlen ( call - > callernum ) ) ;
return strlen ( call - > callernum ) + 4 ;
}
2004-06-15 06:21:05 +08:00
static FUNC_DUMP ( dump_user_user )
2003-02-12 21:59:23 +08:00
{
2004-01-29 05:02:23 +08:00
int x ;
2004-06-14 11:29:19 +08:00
pri_message ( " %c User-User Information (len=%2d) [ " , prefix , len ) ;
2004-01-29 05:02:23 +08:00
for ( x = 0 ; x < ie - > len ; x + + )
2004-06-14 11:29:19 +08:00
pri_message ( " %02x " , ie - > data [ x ] & 0x7f ) ;
2004-01-29 05:02:23 +08:00
pri_message ( " ] \n " ) ;
2003-02-12 21:59:23 +08:00
}
2004-06-15 06:21:05 +08:00
static FUNC_RECV ( receive_user_user )
2003-02-12 21:59:23 +08:00
{
call - > useruserprotocoldisc = ie - > data [ 0 ] & 0xff ;
if ( call - > useruserprotocoldisc = = 4 ) /* IA5 */
2005-04-04 07:07:55 +08:00
q931_get_number ( ( unsigned char * ) call - > useruserinfo , sizeof ( call - > useruserinfo ) , ie - > data + 1 , len - 3 ) ;
2003-02-12 21:59:23 +08:00
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
}
2004-06-15 06:21:05 +08:00
static FUNC_DUMP ( dump_progress_indicator )
2001-05-13 00:41:32 +08:00
{
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 " ,
2004-06-14 11:29:19 +08:00
prefix , 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 ) ;
}
2004-06-15 06:21:05 +08:00
static FUNC_RECV ( receive_display )
2003-02-12 21:59:23 +08:00
{
unsigned char * data ;
data = ie - > data ;
if ( data [ 0 ] & 0x80 ) {
/* Skip over character set */
data + + ;
len - - ;
}
2005-04-04 07:07:55 +08:00
q931_get_number ( ( unsigned char * ) call - > callername , sizeof ( call - > callername ) , data , len - 2 ) ;
2003-02-12 21:59:23 +08:00
return 0 ;
}
2004-06-15 06:21:05 +08:00
static FUNC_SEND ( transmit_display )
2003-02-12 21:59:23 +08:00
{
2004-06-24 21:43:36 +08:00
int i ;
2003-09-25 14:13:14 +08:00
if ( ( pri - > switchtype ! = PRI_SWITCH_NI1 ) & & strlen ( call - > callername ) ) {
2004-06-24 21:43:36 +08:00
i = 0 ;
if ( pri - > switchtype ! = PRI_SWITCH_EUROISDN_E1 ) {
ie - > data [ 0 ] = 0xb1 ;
+ + i ;
}
memcpy ( ie - > data + i , call - > callername , strlen ( call - > callername ) ) ;
return 2 + i + strlen ( call - > callername ) ;
2003-05-29 06:34:59 +08:00
}
return 0 ;
2003-02-12 21:59:23 +08:00
}
2004-06-15 06:21:05 +08:00
static FUNC_RECV ( receive_progress_indicator )
2001-05-13 00:41:32 +08:00
{
call - > progloc = ie - > data [ 0 ] & 0xf ;
2002-03-18 22:04:47 +08:00
call - > progcode = ( ie - > data [ 0 ] & 0x60 ) > > 5 ;
2005-01-17 20:58:05 +08:00
switch ( call - > progress = ( ie - > data [ 1 ] & 0x7f ) ) {
case Q931_PROG_CALL_NOT_E2E_ISDN :
call - > progressmask | = PRI_PROG_CALL_NOT_E2E_ISDN ;
break ;
case Q931_PROG_CALLED_NOT_ISDN :
call - > progressmask | = PRI_PROG_CALLED_NOT_ISDN ;
break ;
case Q931_PROG_CALLER_NOT_ISDN :
call - > progressmask | = PRI_PROG_CALLER_NOT_ISDN ;
break ;
2005-04-06 05:54:15 +08:00
case Q931_PROG_CALLER_RETURNED_TO_ISDN :
call - > progressmask | = PRI_PROG_CALLER_RETURNED_TO_ISDN ;
break ;
2005-01-17 20:58:05 +08:00
case Q931_PROG_INBAND_AVAILABLE :
call - > progressmask | = PRI_PROG_INBAND_AVAILABLE ;
break ;
case Q931_PROG_DELAY_AT_INTERF :
call - > progressmask | = PRI_PROG_DELAY_AT_INTERF ;
break ;
case Q931_PROG_INTERWORKING_WITH_PUBLIC :
call - > progressmask | = PRI_PROG_INTERWORKING_WITH_PUBLIC ;
break ;
case Q931_PROG_INTERWORKING_NO_RELEASE :
call - > progressmask | = PRI_PROG_INTERWORKING_NO_RELEASE ;
break ;
case Q931_PROG_INTERWORKING_NO_RELEASE_PRE_ANSWER :
call - > progressmask | = PRI_PROG_INTERWORKING_NO_RELEASE_PRE_ANSWER ;
break ;
case Q931_PROG_INTERWORKING_NO_RELEASE_POST_ANSWER :
call - > progressmask | = PRI_PROG_INTERWORKING_NO_RELEASE_POST_ANSWER ;
break ;
default :
pri_error ( " XXX Invalid Progress indicator value received: %02x \n " , ( ie - > data [ 1 ] & 0x7f ) ) ;
break ;
}
2001-05-13 00:41:32 +08:00
return 0 ;
}
2005-03-02 23:56:11 +08:00
static FUNC_SEND ( transmit_facility )
{
struct apdu_event * tmp ;
int i = 0 ;
for ( tmp = call - > apdus ; tmp ; tmp = tmp - > next ) {
if ( tmp - > message = = msgtype )
break ;
}
if ( ! tmp ) /* No APDU found */
return 0 ;
if ( tmp - > apdu_len > 235 ) { /* TODO: find out how much sapce we can use */
pri_message ( " Requested ADPU (%d bytes) is too long \n " , tmp - > apdu_len ) ;
return 0 ;
}
memcpy ( ie - > data , tmp - > apdu , tmp - > apdu_len ) ;
i + = tmp - > apdu_len ;
return i + 2 ;
}
#if 0
2004-10-28 04:43:23 +08:00
static FUNC_SEND ( transmit_facility )
{
2005-02-04 06:14:44 +08:00
int i = 0 , j , first_i , compsp = 0 ;
struct rose_component * comp , * compstk [ 10 ] ;
2004-10-28 04:43:23 +08:00
unsigned char namelen = strlen ( call - > callername ) ;
2005-02-04 06:14:44 +08:00
if ( ( pri - > switchtype = = PRI_SWITCH_NI2 ) & & ( namelen > 15 ) )
2004-12-28 00:22:30 +08:00
namelen = 15 ; /* According to GR-1367, for NI2 switches it can't be > 15 characters */
2004-12-23 02:46:23 +08:00
if ( ( namelen > 0 ) & & ( ( pri - > switchtype = = PRI_SWITCH_QSIG ) | |
2005-01-25 08:36:34 +08:00
( ( pri - > switchtype = = PRI_SWITCH_NI2 ) & & ( pri - > localtype = = PRI_NETWORK ) ) ) ) {
2005-02-04 06:14:44 +08:00
do {
first_i = i ;
ie - > data [ i ] = 0x80 | Q932_PROTOCOL_EXTENSIONS ;
i + + ;
/* Interpretation component */
ASN1_ADD_BYTECOMP ( comp , COMP_TYPE_INTERPRETATION , ie - > data , i , 0x00 /* Discard unrecognized invokes */ ) ;
/* Invoke ID */
ASN1_ADD_SIMPLE ( comp , COMP_TYPE_INVOKE , ie - > data , i ) ;
ASN1_PUSH ( compstk , compsp , comp ) ;
/* Invoke component contents */
/* Invoke ID */
ASN1_ADD_BYTECOMP ( comp , ASN1_INTEGER , ie - > data , i , + + pri - > last_invoke ) ;
/* Operation Tag */
ASN1_ADD_BYTECOMP ( comp , ASN1_INTEGER , ie - > data , i , SS_CNID_CALLINGNAME ) ;
/* Arugement Tag */
j = asn1_string_encode ( ROSE_NAME_PRESENTATION_ALLOWED_SIMPLE , & ie - > data [ i ] , len - i , 15 , call - > callername , namelen ) ;
if ( j < 0 ) {
i = first_i ;
break ;
}
i + = j ;
2004-10-28 04:43:23 +08:00
2005-02-04 06:14:44 +08:00
/* Fix length of stacked components */
while ( compsp > 0 ) {
ASN1_FIXUP ( compstk , compsp , ie - > data , i ) ;
}
} while ( 0 ) ;
2004-10-28 04:43:23 +08:00
}
2005-02-04 06:14:44 +08:00
if ( /*(pri->switchtype == PRI_SWITCH_EUROISDN_E1) &&*/ call - > redirectingnum & & strlen ( call - > redirectingnum ) ) {
if ( ! ( first_i = i ) ) {
/* Add protocol information header */
ie - > data [ i + + ] = 0x80 | Q932_PROTOCOL_ROSE ;
}
2004-10-28 04:43:23 +08:00
2005-02-04 06:14:44 +08:00
/* ROSE invoke component */
ASN1_ADD_SIMPLE ( comp , COMP_TYPE_INVOKE , ie - > data , i ) ;
ASN1_PUSH ( compstk , compsp , comp ) ;
/* ROSE invokeId component */
ASN1_ADD_BYTECOMP ( comp , ASN1_INTEGER , ie - > data , i , + + pri - > last_invoke ) ;
/* ROSE operationId component */
ASN1_ADD_BYTECOMP ( comp , ASN1_INTEGER , ie - > data , i , ROSE_DIVERTING_LEG_INFORMATION2 ) ;
/* ROSE ARGUMENT component */
ASN1_ADD_SIMPLE ( comp , 0x30 , ie - > data , i ) ;
2005-02-06 00:54:52 +08:00
ASN1_PUSH ( compstk , compsp , comp ) ;
2005-02-04 06:14:44 +08:00
/* ROSE DivertingLegInformation2.diversionCounter component */
/* Always is 1 because other isn't available in the current design */
ASN1_ADD_BYTECOMP ( comp , ASN1_INTEGER , ie - > data , i , 1 ) ;
/* ROSE DivertingLegInformation2.diversionReason component */
ASN1_ADD_BYTECOMP ( comp , ASN1_ENUMERATED , ie - > data , i , redirectingreason_from_q931 ( pri , call - > redirectingreason ) ) ;
/* ROSE DivertingLegInformation2.divertingNr component */
ASN1_ADD_SIMPLE ( comp , 0xA1 , ie - > data , i ) ;
ASN1_PUSH ( compstk , compsp , comp ) ;
/* Redirecting information always not screened */
switch ( call - > redirectingpres ) {
case PRES_ALLOWED_USER_NUMBER_NOT_SCREENED :
case PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN :
if ( call - > redirectingnum & & strlen ( call - > redirectingnum ) ) {
ASN1_ADD_SIMPLE ( comp , 0xA0 , ie - > data , i ) ;
ASN1_PUSH ( compstk , compsp , comp ) ;
/* NPI of redirected number is not supported in the current design */
ASN1_ADD_SIMPLE ( comp , 0xA1 , ie - > data , i ) ;
ASN1_PUSH ( compstk , compsp , comp ) ;
ASN1_ADD_BYTECOMP ( comp , ASN1_ENUMERATED , ie - > data , i , typeofnumber_from_q931 ( pri , call - > redirectingplan > > 4 ) ) ;
j = asn1_string_encode ( ASN1_NUMERICSTRING , & ie - > data [ i ] , len - i , 20 , call - > redirectingnum , strlen ( call - > redirectingnum ) ) ;
if ( j < 0 ) {
i = first_i ;
goto finish2 ;
}
i + = j ;
ASN1_FIXUP ( compstk , compsp , ie - > data , i ) ;
ASN1_FIXUP ( compstk , compsp , ie - > data , i ) ;
break ;
}
/* fall through */
case PRES_PROHIB_USER_NUMBER_PASSED_SCREEN :
case PRES_PROHIB_USER_NUMBER_NOT_SCREENED :
ASN1_ADD_SIMPLE ( comp , 0x81 , ie - > data , i ) ;
break ;
/* Don't know how to handle this */
case PRES_ALLOWED_NETWORK_NUMBER :
case PRES_PROHIB_NETWORK_NUMBER :
case PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN :
case PRES_PROHIB_USER_NUMBER_FAILED_SCREEN :
ASN1_ADD_SIMPLE ( comp , 0x81 , ie - > data , i ) ;
break ;
default :
pri_message ( " !! Undefined presentation value for redirecting number: %d \n " , call - > redirectingpres ) ;
case PRES_NUMBER_NOT_AVAILABLE :
ASN1_ADD_SIMPLE ( comp , 0x82 , ie - > data , i ) ;
break ;
}
ASN1_FIXUP ( compstk , compsp , ie - > data , i ) ;
/* ROSE DivertingLegInformation2.originalCalledNr component */
/* This information isn't supported by current design - duplicate divertingNr */
ASN1_ADD_SIMPLE ( comp , 0xA2 , ie - > data , i ) ;
ASN1_PUSH ( compstk , compsp , comp ) ;
/* Redirecting information always not screened */
switch ( call - > redirectingpres ) {
case PRES_ALLOWED_USER_NUMBER_NOT_SCREENED :
case PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN :
if ( call - > redirectingnum & & strlen ( call - > redirectingnum ) ) {
ASN1_ADD_SIMPLE ( comp , 0xA0 , ie - > data , i ) ;
ASN1_PUSH ( compstk , compsp , comp ) ;
ASN1_ADD_SIMPLE ( comp , 0xA1 , ie - > data , i ) ;
ASN1_PUSH ( compstk , compsp , comp ) ;
ASN1_ADD_BYTECOMP ( comp , ASN1_ENUMERATED , ie - > data , i , typeofnumber_from_q931 ( pri , call - > redirectingplan > > 4 ) ) ;
j = asn1_string_encode ( ASN1_NUMERICSTRING , & ie - > data [ i ] , len - i , 20 , call - > redirectingnum , strlen ( call - > redirectingnum ) ) ;
if ( j < 0 ) {
i = first_i ;
goto finish2 ;
}
i + = j ;
ASN1_FIXUP ( compstk , compsp , ie - > data , i ) ;
ASN1_FIXUP ( compstk , compsp , ie - > data , i ) ;
break ;
}
/* fall through */
case PRES_PROHIB_USER_NUMBER_PASSED_SCREEN :
case PRES_PROHIB_USER_NUMBER_NOT_SCREENED :
ASN1_ADD_SIMPLE ( comp , 0x81 , ie - > data , i ) ;
break ;
/* Don't know how to handle this */
case PRES_ALLOWED_NETWORK_NUMBER :
case PRES_PROHIB_NETWORK_NUMBER :
case PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN :
case PRES_PROHIB_USER_NUMBER_FAILED_SCREEN :
ASN1_ADD_SIMPLE ( comp , 0x81 , ie - > data , i ) ;
break ;
default :
pri_message ( " !! Undefined presentation value for redirecting number: %d \n " , call - > redirectingpres ) ;
case PRES_NUMBER_NOT_AVAILABLE :
ASN1_ADD_SIMPLE ( comp , 0x82 , ie - > data , i ) ;
break ;
}
ASN1_FIXUP ( compstk , compsp , ie - > data , i ) ;
/* Fix length of stacked components */
while ( compsp > 0 ) {
ASN1_FIXUP ( compstk , compsp , ie - > data , i ) ;
}
}
finish2 :
return ( i ? i + 2 : 0 ) ;
2004-10-28 04:43:23 +08:00
}
2005-03-02 23:56:11 +08:00
# endif
2004-10-28 04:43:23 +08:00
2004-06-15 06:21:05 +08:00
static FUNC_RECV ( receive_facility )
2003-02-12 21:59:23 +08:00
{
2004-10-28 04:43:23 +08:00
int i = 0 ;
2005-02-04 06:14:44 +08:00
int protocol , next_protocol ;
2004-10-28 04:43:23 +08:00
struct rose_component * comp = NULL ;
2005-02-04 06:14:44 +08:00
enum {
Q932_STATE_NFE , /* Network facility extension */
Q932_STATE_NPP , /* Network protocol profile */
Q932_STATE_INTERPRETATION , /* Interpretation component */
Q932_STATE_SERVICE /* Service component(s) */
} state = Q932_STATE_SERVICE ;
# define Q932_HANDLE_PROC(component, my_state, name, handler) \
case component : \
if ( state > my_state ) { \
pri_error ( " !! %s component received in wrong place \n " ) ; \
break ; \
} \
state = my_state ; \
if ( pri - > debug ) \
pri_message ( " Handle Q.932 %s component \n " , name ) ; \
( handler ) ( pri , call , comp - > data , comp - > len ) ; \
break ;
# define Q932_HANDLE_NULL(component, my_state, name, handle) \
case component : \
if ( state > my_state ) { \
pri_error ( " !! %s component received in wrong place \n " ) ; \
break ; \
} \
state = my_state ; \
2005-03-03 00:03:22 +08:00
if ( pri - > debug & PRI_DEBUG_APDU ) \
2005-02-04 06:14:44 +08:00
pri_message ( " Q.932 %s component is not handled \n " , name ) ; \
break ;
2004-10-28 04:43:23 +08:00
if ( ie - > len < 1 )
return - 1 ;
2005-02-04 06:14:44 +08:00
if ( ( ie - > data [ i ] & 0xe0 ) ! = 0x80 ) {
pri_error ( " !! Invalid Protocol Profile field 0x%X \n " , ie - > data [ i ] ) ;
return - 1 ;
}
switch ( next_protocol = protocol = ( ie - > data [ i ] & 0x1f ) ) {
case Q932_PROTOCOL_CMIP :
case Q932_PROTOCOL_ACSE :
2005-03-03 00:03:22 +08:00
if ( pri - > debug & PRI_DEBUG_APDU )
2005-02-04 06:14:44 +08:00
pri_message ( " !! Don't know how to handle Q.932 Protocol Profile of type 0x%X \n " , protocol ) ;
return - 1 ;
case Q932_PROTOCOL_EXTENSIONS :
state = Q932_STATE_NFE ;
next_protocol = Q932_PROTOCOL_ROSE ;
break ;
case Q932_PROTOCOL_ROSE :
break ;
default :
pri_error ( " !! Invalid Q.932 Protocol Profile of type 0x%X received \n " , protocol ) ;
2004-10-28 04:43:23 +08:00
return - 1 ;
2003-02-12 21:59:23 +08:00
}
2004-10-28 04:43:23 +08:00
i + + ;
if ( ie - > len < 3 )
return - 1 ;
while ( ( i + 1 < ie - > len ) & & ( & ie - > data [ i ] ) ) {
comp = ( struct rose_component * ) & ie - > data [ i ] ;
if ( comp - > type ) {
2005-02-04 06:14:44 +08:00
if ( protocol = = Q932_PROTOCOL_EXTENSIONS ) {
switch ( comp - > type ) {
Q932_HANDLE_NULL ( COMP_TYPE_INTERPRETATION , Q932_STATE_INTERPRETATION , " Interpretation " , NULL ) ;
Q932_HANDLE_NULL ( COMP_TYPE_NFE , Q932_STATE_NFE , " Network facility extensions " , NULL ) ;
Q932_HANDLE_NULL ( COMP_TYPE_NETWORK_PROTOCOL_PROFILE , Q932_STATE_NPP , " Network protocol profile " , NULL ) ;
default :
protocol = next_protocol ;
2004-10-28 04:43:23 +08:00
break ;
2005-02-04 06:14:44 +08:00
}
}
switch ( protocol ) {
case Q932_PROTOCOL_ROSE :
switch ( comp - > type ) {
Q932_HANDLE_PROC ( COMP_TYPE_INVOKE , Q932_STATE_SERVICE , " ROSE Invoke " , rose_invoke_decode ) ;
Q932_HANDLE_NULL ( COMP_TYPE_RETURN_RESULT , Q932_STATE_SERVICE , " ROSE return result " , NULL ) ;
Q932_HANDLE_NULL ( COMP_TYPE_RETURN_ERROR , Q932_STATE_SERVICE , " ROSE return error " , NULL ) ;
Q932_HANDLE_NULL ( COMP_TYPE_REJECT , Q932_STATE_SERVICE , " ROSE reject " , NULL ) ;
default :
2005-03-03 00:03:22 +08:00
if ( pri - > debug & PRI_DEBUG_APDU )
2005-02-04 06:14:44 +08:00
pri_message ( " Don't know how to handle ROSE component of type 0x%X \n " , comp - > type ) ;
break ;
}
break ;
case Q932_PROTOCOL_CMIP :
switch ( comp - > type ) {
default :
2005-03-03 00:03:22 +08:00
if ( pri - > debug & PRI_DEBUG_APDU )
2005-02-04 06:14:44 +08:00
pri_message ( " Don't know how to handle CMIP component of type 0x%X \n " , comp - > type ) ;
2004-10-28 04:43:23 +08:00
break ;
2005-02-04 06:14:44 +08:00
}
break ;
case Q932_PROTOCOL_ACSE :
switch ( comp - > type ) {
2004-10-28 04:43:23 +08:00
default :
2005-03-03 00:03:22 +08:00
if ( pri - > debug & PRI_DEBUG_APDU )
2005-02-04 06:14:44 +08:00
pri_message ( " Don't know how to handle ACSE component of type 0x%X \n " , comp - > type ) ;
2004-10-28 04:43:23 +08:00
break ;
2005-02-04 06:14:44 +08:00
}
break ;
2004-10-28 04:43:23 +08:00
}
}
i + = ( comp - > len + 2 ) ;
}
2005-02-04 06:14:44 +08:00
# undef Q932_HANDLE
2004-10-28 04:43:23 +08:00
2003-02-12 21:59:23 +08:00
return 0 ;
}
2004-06-15 06:21:05 +08:00
static FUNC_SEND ( transmit_progress_indicator )
2001-05-13 00:41:32 +08:00
{
2005-01-17 20:58:05 +08:00
int code , mask ;
2004-06-05 14:50:55 +08:00
/* Can't send progress indicator on GR-303 -- EVER! */
2005-01-17 20:58:05 +08:00
if ( pri - > subchannel )
2001-05-13 00:41:32 +08:00
return 0 ;
2005-01-17 20:58:05 +08:00
if ( call - > progressmask > 0 ) {
if ( call - > progressmask & ( mask = PRI_PROG_CALL_NOT_E2E_ISDN ) )
code = Q931_PROG_CALL_NOT_E2E_ISDN ;
else if ( call - > progressmask & ( mask = PRI_PROG_CALLED_NOT_ISDN ) )
code = Q931_PROG_CALLED_NOT_ISDN ;
else if ( call - > progressmask & ( mask = PRI_PROG_CALLER_NOT_ISDN ) )
code = Q931_PROG_CALLER_NOT_ISDN ;
else if ( call - > progressmask & ( mask = PRI_PROG_INBAND_AVAILABLE ) )
code = Q931_PROG_INBAND_AVAILABLE ;
else if ( call - > progressmask & ( mask = PRI_PROG_DELAY_AT_INTERF ) )
code = Q931_PROG_DELAY_AT_INTERF ;
else if ( call - > progressmask & ( mask = PRI_PROG_INTERWORKING_WITH_PUBLIC ) )
code = Q931_PROG_INTERWORKING_WITH_PUBLIC ;
else if ( call - > progressmask & ( mask = PRI_PROG_INTERWORKING_NO_RELEASE ) )
code = Q931_PROG_INTERWORKING_NO_RELEASE ;
else if ( call - > progressmask & ( mask = PRI_PROG_INTERWORKING_NO_RELEASE_PRE_ANSWER ) )
code = Q931_PROG_INTERWORKING_NO_RELEASE_PRE_ANSWER ;
else if ( call - > progressmask & ( mask = PRI_PROG_INTERWORKING_NO_RELEASE_POST_ANSWER ) )
code = Q931_PROG_INTERWORKING_NO_RELEASE_POST_ANSWER ;
else {
code = 0 ;
pri_error ( " XXX Undefined progress bit: %x \n " , call - > progressmask ) ;
}
if ( code ) {
ie - > data [ 0 ] = 0x80 | ( call - > progcode < < 5 ) | ( call - > progloc ) ;
ie - > data [ 1 ] = 0x80 | code ;
call - > progressmask & = ~ mask ;
return 4 ;
}
2001-05-13 00:41:32 +08:00
}
2005-01-17 20:58:05 +08:00
/* Leave off */
return 0 ;
2001-05-13 00:41:32 +08:00
}
2004-06-15 06:21:05 +08:00
static FUNC_SEND ( transmit_call_state )
2003-03-04 14:00:37 +08:00
{
if ( call - > ourcallstate > - 1 ) {
ie - > data [ 0 ] = call - > ourcallstate ;
return 3 ;
}
return 0 ;
}
2004-06-15 06:21:05 +08:00
static FUNC_RECV ( receive_call_state )
2003-03-04 14:00:37 +08:00
{
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 ] ) ) ;
}
2004-06-15 06:21:05 +08:00
static FUNC_DUMP ( dump_call_state )
2002-03-18 22:04:47 +08:00
{
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 " ,
2004-06-14 11:29:19 +08:00
prefix , len , ie - > data [ 0 ] > > 7 , coding2str ( ( ie - > data [ 0 ] & 0xC0 ) > > 6 ) , ( ie - > data [ 0 ] & 0xC0 ) > > 6 ,
2002-03-18 22:04:47 +08:00
callstate2str ( ie - > data [ 0 ] & 0x3f ) , ie - > data [ 0 ] & 0x3f ) ;
}
2004-06-15 06:21:05 +08:00
static FUNC_DUMP ( dump_call_identity )
2002-03-18 22:04:47 +08:00
{
int x ;
2004-06-14 11:29:19 +08:00
pri_message ( " %c Call Identity (len=%2d) [ " , prefix , 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
}
2004-06-15 06:21:05 +08:00
static FUNC_DUMP ( dump_time_date )
2002-03-18 22:04:47 +08:00
{
2004-06-14 11:29:19 +08:00
pri_message ( " %c Time Date (len=%2d) [ " , prefix , 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
}
2005-03-02 23:56:11 +08:00
static FUNC_DUMP ( dump_keypad_facility )
{
char tmp [ 64 ] = " " ;
if ( ie - > len = = 0 | | ie - > len > sizeof ( tmp ) )
return ;
2005-04-04 07:07:55 +08:00
strncpy ( tmp , ( char * ) ie - > data , sizeof ( tmp ) ) ;
2005-03-02 23:56:11 +08:00
pri_message ( " %c Keypad Facility (len=%2d) [ %s ] \n " , prefix , ie - > len , tmp ) ;
}
static FUNC_RECV ( receive_keypad_facility )
{
int mylen = 0 ;
if ( ie - > len = = 0 )
return - 1 ;
if ( ie - > len > sizeof ( call - > digitbuf ) )
mylen = sizeof ( call - > digitbuf ) - 1 ;
else
mylen = ie - > len ;
2005-04-04 07:07:55 +08:00
strncpy ( call - > digitbuf , ( char * ) ie - > data , mylen ) ;
2005-03-02 23:56:11 +08:00
/* I must be really neurotic */
call - > digitbuf [ sizeof ( call - > digitbuf ) - 1 ] = ' \0 ' ;
return 0 ;
}
2004-06-15 06:21:05 +08:00
static FUNC_DUMP ( dump_display )
2002-03-18 22:04:47 +08:00
{
2004-06-17 02:25:35 +08:00
int x , y ;
2004-06-10 14:51:01 +08:00
char * buf = malloc ( len + 1 ) ;
2004-06-14 11:29:19 +08:00
char tmp [ 80 ] = " " ;
2004-06-10 14:51:01 +08:00
if ( buf ) {
2004-06-17 02:25:35 +08:00
x = y = 0 ;
2004-06-14 11:29:19 +08:00
if ( ( x < ie - > len ) & & ( ie - > data [ x ] & 0x80 ) ) {
sprintf ( tmp , " Charset: %02x " , ie - > data [ x ] & 0x7f ) ;
+ + x ;
}
2004-06-17 02:25:35 +08:00
for ( y = x ; x < ie - > len ; x + + )
buf [ x ] = ie - > data [ x ] & 0x7f ;
buf [ x ] = ' \0 ' ;
pri_message ( " %c Display (len=%2d) %s[ %s ] \n " , prefix , ie - > len , tmp , & buf [ y ] ) ;
2004-06-10 14:51:01 +08:00
free ( buf ) ;
}
2003-02-12 21:59:23 +08:00
}
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 ) ;
}
2004-06-15 06:21:05 +08:00
static FUNC_DUMP ( dump_facility )
2003-02-12 21:59:23 +08:00
{
2004-06-15 06:21:05 +08:00
pri_message ( " %c Facility (len=%2d, codeset=%d) [ " , prefix , len , Q931_IE_CODESET ( full_ie ) ) ;
2003-02-12 21:59:23 +08:00
dump_ie_data ( ie - > data , ie - > len ) ;
pri_message ( " ] \n " ) ;
2002-03-18 22:04:47 +08:00
}
2004-06-26 12:37:09 +08:00
static FUNC_DUMP ( dump_network_spec_fac )
{
2005-01-17 20:58:05 +08:00
pri_message ( " %c Network-Specific Facilities (len=%2d) [ " , prefix , ie - > len ) ;
if ( ie - > data [ 0 ] = = 0x00 ) {
pri_message ( code2str ( ie - > data [ 1 ] , facilities , sizeof ( facilities ) / sizeof ( facilities [ 0 ] ) ) ) ;
}
else
dump_ie_data ( ie - > data , ie - > len ) ;
pri_message ( " ] \n " ) ;
2004-06-26 12:37:09 +08:00
}
static FUNC_RECV ( receive_network_spec_fac )
{
2005-01-17 20:58:05 +08:00
return 0 ;
2004-06-26 12:37:09 +08:00
}
static FUNC_SEND ( transmit_network_spec_fac )
{
2005-01-17 20:58:05 +08:00
/* We are ready to transmit single IE only */
if ( order > 1 )
return 0 ;
if ( pri - > nsf ! = PRI_NSF_NONE ) {
ie - > data [ 0 ] = 0x00 ;
ie - > data [ 1 ] = pri - > nsf ;
return 4 ;
}
/* Leave off */
return 0 ;
2004-06-26 12:37:09 +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
}
2004-06-15 06:21:05 +08:00
static FUNC_DUMP ( dump_cause )
2001-05-13 00:41:32 +08:00
{
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 " ,
2004-06-14 11:29:19 +08:00
prefix , 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 ) ;
2005-01-28 04:47:10 +08:00
if ( ie - > len < 3 )
return ;
2005-01-27 14:05:09 +08:00
/* Dump cause data in readable form */
switch ( ie - > data [ 1 ] & 0x7f ) {
case PRI_CAUSE_IE_NONEXIST :
2005-01-25 04:57:04 +08:00
for ( x = 2 ; x < ie - > len ; x + + )
pri_message ( " %c Cause data %d: %02x (%d, %s IE) \n " , prefix , x - 1 , ie - > data [ x ] , ie - > data [ x ] , ie2str ( ie - > data [ x ] ) ) ;
2005-01-27 14:05:09 +08:00
break ;
2005-01-29 06:11:24 +08:00
case PRI_CAUSE_WRONG_CALL_STATE :
for ( x = 2 ; x < ie - > len ; x + + )
pri_message ( " %c Cause data %d: %02x (%d, %s message) \n " , prefix , x - 1 , ie - > data [ x ] , ie - > data [ x ] , msg2str ( ie - > data [ x ] ) ) ;
break ;
2005-01-27 14:05:09 +08:00
case PRI_CAUSE_RECOVERY_ON_TIMER_EXPIRE :
pri_message ( " %c Cause data: " , prefix ) ;
for ( x = 2 ; x < ie - > len ; x + + )
pri_message ( " %02x " , ie - > data [ x ] ) ;
pri_message ( " (Timer T " ) ;
for ( x = 2 ; x < ie - > len ; x + + )
pri_message ( " %c " , ( ( ie - > data [ x ] > = ' ' ) & & ( ie - > data [ x ] < 0x7f ) ) ? ie - > data [ x ] : ' . ' ) ;
pri_message ( " ) \n " ) ;
break ;
default :
2005-01-25 04:57:04 +08:00
for ( x = 2 ; x < ie - > len ; x + + )
pri_message ( " %c Cause data %d: %02x (%d) \n " , prefix , x - 1 , ie - > data [ x ] , ie - > data [ x ] ) ;
2005-01-27 14:05:09 +08:00
break ;
2005-01-25 04:57:04 +08:00
}
2001-05-13 00:41:32 +08:00
}
2004-06-15 06:21:05 +08:00
static FUNC_RECV ( receive_cause )
2001-05-13 00:41:32 +08:00
{
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 ;
}
2004-06-15 06:21:05 +08:00
static FUNC_SEND ( transmit_cause )
2001-05-13 00:41:32 +08:00
{
2005-01-17 20:58:05 +08:00
/* We are ready to transmit single IE only */
if ( order > 1 )
return 0 ;
2001-05-13 00:41:32 +08:00
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 ;
}
}
2004-06-15 06:21:05 +08:00
static FUNC_DUMP ( dump_sending_complete )
2002-03-18 22:04:47 +08:00
{
2004-06-14 11:29:19 +08:00
pri_message ( " %c Sending Complete (len=%2d) \n " , prefix , len ) ;
2002-03-18 22:04:47 +08:00
}
2004-06-15 06:21:05 +08:00
static FUNC_RECV ( receive_sending_complete )
2002-03-18 22:04:47 +08:00
{
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 ;
}
2004-06-15 06:21:05 +08:00
static FUNC_SEND ( transmit_sending_complete )
2001-12-08 03:45:45 +08:00
{
2004-06-17 01:16:37 +08:00
if ( ( pri - > overlapdial & & call - > complete ) | | /* Explicit */
( ! pri - > overlapdial & & ( ( pri - > switchtype = = PRI_SWITCH_EUROISDN_E1 ) | |
/* Implicit */ ( pri - > switchtype = = PRI_SWITCH_EUROISDN_T1 ) ) ) ) {
2001-12-08 03:45:45 +08:00
/* Include this single-byte IE */
return 1 ;
}
return 0 ;
}
2004-06-14 10:48:24 +08:00
static char * notify2str ( int info )
{
/* ITU-T Q.763 */
static struct msgtype notifies [ ] = {
{ PRI_NOTIFY_USER_SUSPENDED , " User suspended " } ,
{ PRI_NOTIFY_USER_RESUMED , " User resumed " } ,
{ PRI_NOTIFY_BEARER_CHANGE , " Bearer service change (DSS1) " } ,
{ PRI_NOTIFY_ASN1_COMPONENT , " ASN.1 encoded component (DSS1) " } ,
{ PRI_NOTIFY_COMPLETION_DELAY , " Call completion delay " } ,
{ PRI_NOTIFY_CONF_ESTABLISHED , " Conference established " } ,
{ PRI_NOTIFY_CONF_DISCONNECTED , " Conference disconnected " } ,
{ PRI_NOTIFY_CONF_PARTY_ADDED , " Other party added " } ,
{ PRI_NOTIFY_CONF_ISOLATED , " Isolated " } ,
{ PRI_NOTIFY_CONF_REATTACHED , " Reattached " } ,
{ PRI_NOTIFY_CONF_OTHER_ISOLATED , " Other party isolated " } ,
{ PRI_NOTIFY_CONF_OTHER_REATTACHED , " Other party reattached " } ,
{ PRI_NOTIFY_CONF_OTHER_SPLIT , " Other party split " } ,
{ PRI_NOTIFY_CONF_OTHER_DISCONNECTED , " Other party disconnected " } ,
{ PRI_NOTIFY_CONF_FLOATING , " Conference floating " } ,
{ PRI_NOTIFY_WAITING_CALL , " Call is waiting call " } ,
{ PRI_NOTIFY_DIVERSION_ACTIVATED , " Diversion activated (DSS1) " } ,
{ PRI_NOTIFY_TRANSFER_ALERTING , " Call transfer, alerting " } ,
{ PRI_NOTIFY_TRANSFER_ACTIVE , " Call transfer, active " } ,
{ PRI_NOTIFY_REMOTE_HOLD , " Remote hold " } ,
{ PRI_NOTIFY_REMOTE_RETRIEVAL , " Remote retrieval " } ,
{ PRI_NOTIFY_CALL_DIVERTING , " Call is diverting " } ,
} ;
return code2str ( info , notifies , sizeof ( notifies ) / sizeof ( notifies [ 0 ] ) ) ;
}
2004-06-15 06:21:05 +08:00
static FUNC_DUMP ( dump_notify )
2004-06-14 10:48:24 +08:00
{
pri_message ( " %c Notification indicator (len=%2d): Ext: %d %s (%d) \n " , prefix , len , ie - > data [ 0 ] > > 7 , notify2str ( ie - > data [ 0 ] & 0x7f ) , ie - > data [ 0 ] & 0x7f ) ;
}
2004-06-15 06:21:05 +08:00
static FUNC_RECV ( receive_notify )
2004-06-14 10:48:24 +08:00
{
call - > notify = ie - > data [ 0 ] & 0x7F ;
return 0 ;
}
2004-06-15 06:21:05 +08:00
static FUNC_SEND ( transmit_notify )
2004-06-14 10:48:24 +08:00
{
if ( call - > notify > = 0 ) {
ie - > data [ 0 ] = 0x80 | call - > notify ;
return 3 ;
}
return 0 ;
}
2004-06-17 02:25:35 +08:00
static FUNC_DUMP ( dump_shift )
{
pri_message ( " %c %sLocking Shift (len=%02d): Requested codeset %d \n " , prefix , ( full_ie & 8 ) ? " Non- " : " " , len , full_ie & 7 ) ;
}
static char * lineinfo2str ( int info )
{
/* NAPNA ANI II digits */
static struct msgtype lineinfo [ ] = {
{ 0 , " Plain Old Telephone Service (POTS) " } ,
{ 1 , " Multiparty line (more than 2) " } ,
{ 2 , " ANI failure " } ,
{ 6 , " Station Level Rating " } ,
{ 7 , " Special Operator Handling Required " } ,
{ 20 , " Automatic Identified Outward Dialing (AIOD) " } ,
{ 23 , " Coing or Non-Coin " } ,
{ 24 , " Toll free translated to POTS originated for non-pay station " } ,
{ 25 , " Toll free translated to POTS originated from pay station " } ,
{ 27 , " Pay station with coin control signalling " } ,
{ 29 , " Prison/Inmate Service " } ,
{ 30 , " Intercept (blank) " } ,
{ 31 , " Intercept (trouble) " } ,
{ 32 , " Intercept (regular) " } ,
{ 34 , " Telco Operator Handled Call " } ,
{ 52 , " Outward Wide Area Telecommunications Service (OUTWATS) " } ,
{ 60 , " TRS call from unrestricted line " } ,
{ 61 , " Cellular/Wireless PCS (Type 1) " } ,
{ 62 , " Cellular/Wireless PCS (Type 2) " } ,
{ 63 , " Cellular/Wireless PCS (Roaming) " } ,
{ 66 , " TRS call from hotel/motel " } ,
{ 67 , " TRS call from restricted line " } ,
{ 70 , " Line connected to pay station " } ,
{ 93 , " Private virtual network call " } ,
} ;
return code2str ( info , lineinfo , sizeof ( lineinfo ) / sizeof ( lineinfo [ 0 ] ) ) ;
}
static FUNC_DUMP ( dump_line_information )
{
pri_message ( " %c Originating Line Information (len=%02d): %s (%d) \n " , prefix , len , lineinfo2str ( ie - > data [ 0 ] ) , ie - > data [ 0 ] ) ;
}
static FUNC_RECV ( receive_line_information )
{
2004-09-17 12:02:16 +08:00
call - > ani2 = ie - > data [ 0 ] ;
2004-06-17 02:25:35 +08:00
return 0 ;
}
static FUNC_SEND ( transmit_line_information )
{
2005-01-17 20:58:05 +08:00
#if 0 /* XXX Is this IE possible for 4ESS only? XXX */
2004-06-17 02:25:35 +08:00
if ( pri - > switchtype = = PRI_SWITCH_ATT4ESS ) {
ie - > data [ 0 ] = 0 ;
return 3 ;
}
# endif
return 0 ;
}
2004-11-05 10:12:02 +08:00
static char * gdencoding2str ( int encoding )
{
static struct msgtype gdencoding [ ] = {
{ 0 , " BCD even " } ,
{ 1 , " BCD odd " } ,
{ 2 , " IA5 " } ,
{ 3 , " Binary " } ,
} ;
return code2str ( encoding , gdencoding , sizeof ( gdencoding ) / sizeof ( gdencoding [ 0 ] ) ) ;
}
static char * gdtype2str ( int type )
{
static struct msgtype gdtype [ ] = {
{ 0 , " Account Code " } ,
{ 1 , " Auth Code " } ,
{ 2 , " Customer ID " } ,
{ 3 , " Universal Access " } ,
{ 4 , " Info Digits " } ,
{ 5 , " Callid " } ,
{ 6 , " Opart " } ,
{ 7 , " TCN " } ,
{ 9 , " Adin " } ,
} ;
return code2str ( type , gdtype , sizeof ( gdtype ) / sizeof ( gdtype [ 0 ] ) ) ;
}
static FUNC_DUMP ( dump_generic_digits )
{
int encoding ;
int type ;
int idx ;
int value ;
if ( len < 3 ) {
pri_message ( " %c Generic Digits (len=%02d): Invalid length \n " , prefix , len ) ;
return ;
}
encoding = ( ie - > data [ 0 ] > > 5 ) & 7 ;
type = ie - > data [ 0 ] & 0x1F ;
pri_message ( " %c Generic Digits (len=%02d): Encoding %s Type %s \n " , prefix , len , gdencoding2str ( encoding ) , gdtype2str ( type ) ) ;
if ( encoding = = 3 ) { /* Binary */
pri_message ( " %c Don't know how to handle binary encoding \n " ) ;
return ;
}
if ( len = = 3 ) /* No number information */
return ;
pri_message ( " %c Digits: " ) ;
value = 0 ;
for ( idx = 3 ; idx < len ; + + idx ) {
switch ( encoding ) {
case 0 : /* BCD even */
case 1 : /* BCD odd */
2005-01-27 13:39:17 +08:00
pri_message ( " %d " , ie - > data [ idx - 2 ] & 0x0f ) ;
value = value * 10 + ( ie - > data [ idx - 2 ] & 0x0f ) ;
2004-11-05 10:12:02 +08:00
if ( ! encoding | | ( idx + 1 < len ) ) { /* Special handling for BCD odd */
2005-01-27 13:39:17 +08:00
pri_message ( " %d " , ( ie - > data [ idx - 2 ] > > 4 ) & 0x0f ) ;
value = value * 10 + ( ( ie - > data [ idx - 2 ] > > 4 ) & 0x0f ) ;
2004-11-05 10:12:02 +08:00
}
break ;
case 2 : /* IA5 */
pri_message ( " %c " , ie - > data [ idx - 2 ] ) ;
value = value * 10 + ie - > data [ idx - 2 ] - ' 0 ' ;
break ;
}
}
switch ( type ) {
case 4 : /* Info Digits */
pri_message ( " - %s " , lineinfo2str ( value ) ) ;
break ;
}
pri_message ( " \n " ) ;
}
static FUNC_RECV ( receive_generic_digits )
{
int encoding ;
int type ;
int idx ;
int value ;
int num_idx ;
char number [ 260 ] ;
if ( len < 3 ) {
pri_error ( " Invalid length of Generic Digits IE \n " ) ;
return - 1 ;
}
encoding = ( ie - > data [ 0 ] > > 5 ) & 7 ;
type = ie - > data [ 0 ] & 0x1F ;
if ( encoding = = 3 ) { /* Binary */
pri_message ( " !! Unable to handle binary encoded Generic Digits IE \n " ) ;
return 0 ;
}
if ( len = = 3 ) /* No number information */
return 0 ;
2005-03-17 23:46:23 +08:00
value = 0 ;
2004-11-05 10:12:02 +08:00
switch ( type ) {
/* Integer value handling */
case 4 : /* Info Digits */
for ( idx = 3 ; idx < len ; + + idx ) {
switch ( encoding ) {
case 0 : /* BCD even */
case 1 : /* BCD odd */
2005-01-27 13:39:17 +08:00
value = value * 10 + ( ie - > data [ idx - 2 ] & 0x0f ) ;
2004-11-05 10:12:02 +08:00
if ( ! encoding | | ( idx + 1 < len ) ) /* Special handling for BCD odd */
2005-01-27 13:39:17 +08:00
value = value * 10 + ( ( ie - > data [ idx - 2 ] > > 4 ) & 0x0f ) ;
2004-11-05 10:12:02 +08:00
break ;
case 2 : /* IA5 */
value = value * 10 + ( ie - > data [ idx - 2 ] - ' 0 ' ) ;
break ;
}
}
break ;
/* String value handling */
case 5 : /* Callid */
num_idx = 0 ;
for ( idx = 3 ; ( idx < len ) & & ( num_idx < sizeof ( number ) - 4 ) ; + + idx ) {
switch ( encoding ) {
case 0 : /* BCD even */
case 1 : /* BCD odd */
number [ num_idx + + ] = ' 0 ' + ( ie - > data [ idx - 2 ] & 0x0f ) ;
if ( ! encoding | | ( idx + 1 < len ) ) /* Special handling for BCD odd */
number [ num_idx + + ] = ' 0 ' + ( ( ie - > data [ idx - 2 ] > > 4 ) & 0x0f ) ;
break ;
case 2 :
number [ num_idx + + ] = ie - > data [ idx - 2 ] ;
break ;
}
}
number [ num_idx ] = ' \0 ' ;
break ;
}
switch ( type ) {
case 4 : /* Info Digits */
call - > ani2 = value ;
break ;
#if 0
case 5 : /* Callid */
if ( ! call - > callernum [ 0 ] ) {
memcpy ( call - > callernum , number , sizeof ( call - > callernum ) - 1 ) ;
call - > callerpres = 0 ;
call - > callerplan = 0 ;
}
break ;
# endif
}
return 0 ;
}
static FUNC_SEND ( transmit_generic_digits )
{
#if 0 /* XXX Is this IE possible for other switches? XXX */
2005-01-17 20:58:05 +08:00
if ( order > 1 )
return 0 ;
2004-11-05 10:12:02 +08:00
if ( pri - > switchtype = = PRI_SWITCH_NI1 ) {
ie - > data [ 0 ] = 0x04 ; /* BCD even, Info Digits */
ie - > data [ 1 ] = 0x00 ; /* POTS */
return 4 ;
}
# endif
return 0 ;
}
2005-01-17 20:58:05 +08:00
static char * signal2str ( int signal )
{
/* From Q.931 4.5.8 Table 4-24 */
static struct msgtype mtsignal [ ] = {
{ 0 , " Dial tone " } ,
{ 1 , " Ring back tone " } ,
{ 2 , " Intercept tone " } ,
{ 3 , " Network congestion tone " } ,
{ 4 , " Busy tone " } ,
{ 5 , " Confirm tone " } ,
{ 6 , " Answer tone " } ,
{ 7 , " Call waiting tone " } ,
{ 8 , " Off-hook warning tone " } ,
{ 9 , " Pre-emption tone " } ,
{ 63 , " Tones off " } ,
{ 64 , " Alerting on - pattern 0 " } ,
{ 65 , " Alerting on - pattern 1 " } ,
{ 66 , " Alerting on - pattern 2 " } ,
{ 67 , " Alerting on - pattern 3 " } ,
{ 68 , " Alerting on - pattern 4 " } ,
{ 69 , " Alerting on - pattern 5 " } ,
{ 70 , " Alerting on - pattern 6 " } ,
{ 71 , " Alerting on - pattern 7 " } ,
{ 79 , " Alerting off " } ,
} ;
return code2str ( signal , mtsignal , sizeof ( mtsignal ) / sizeof ( mtsignal [ 0 ] ) ) ;
}
static FUNC_DUMP ( dump_signal )
{
pri_message ( " %c Signal (len=%02d): " , prefix , len ) ;
if ( len < 3 ) {
pri_message ( " Invalid length \n " ) ;
return ;
}
pri_message ( " Signal %s (%d) \n " , signal2str ( ie - > data [ 0 ] ) , ie - > data [ 0 ] ) ;
}
2001-05-13 00:41:32 +08:00
struct ie ies [ ] = {
2004-06-17 02:25:35 +08:00
/* Codeset 0 - Common */
2005-01-17 20:58:05 +08:00
{ 1 , NATIONAL_CHANGE_STATUS , " Change Status " } ,
{ 0 , Q931_LOCKING_SHIFT , " Locking Shift " , dump_shift } ,
{ 0 , Q931_BEARER_CAPABILITY , " Bearer Capability " , dump_bearer_capability , receive_bearer_capability , transmit_bearer_capability } ,
{ 0 , Q931_CAUSE , " Cause " , dump_cause , receive_cause , transmit_cause } ,
{ 1 , Q931_CALL_STATE , " Call State " , dump_call_state , receive_call_state , transmit_call_state } ,
{ 0 , Q931_CHANNEL_IDENT , " Channel Identification " , dump_channel_id , receive_channel_id , transmit_channel_id } ,
{ 0 , Q931_PROGRESS_INDICATOR , " Progress Indicator " , dump_progress_indicator , receive_progress_indicator , transmit_progress_indicator } ,
{ 0 , Q931_NETWORK_SPEC_FAC , " Network-Specific Facilities " , dump_network_spec_fac , receive_network_spec_fac , transmit_network_spec_fac } ,
{ 1 , Q931_INFORMATION_RATE , " Information Rate " } ,
{ 1 , Q931_TRANSIT_DELAY , " End-to-End Transit Delay " } ,
{ 1 , Q931_TRANS_DELAY_SELECT , " Transmit Delay Selection and Indication " } ,
{ 1 , Q931_BINARY_PARAMETERS , " Packet-layer Binary Parameters " } ,
{ 1 , Q931_WINDOW_SIZE , " Packet-layer Window Size " } ,
{ 1 , Q931_CLOSED_USER_GROUP , " Closed User Group " } ,
{ 1 , Q931_REVERSE_CHARGE_INDIC , " Reverse Charging Indication " } ,
{ 1 , Q931_CALLING_PARTY_NUMBER , " Calling Party Number " , dump_calling_party_number , receive_calling_party_number , transmit_calling_party_number } ,
{ 1 , Q931_CALLING_PARTY_SUBADDR , " Calling Party Subaddress " , dump_calling_party_subaddr , receive_calling_party_subaddr } ,
{ 1 , Q931_CALLED_PARTY_NUMBER , " Called Party Number " , dump_called_party_number , receive_called_party_number , transmit_called_party_number } ,
{ 1 , Q931_CALLED_PARTY_SUBADDR , " Called Party Subaddress " , dump_called_party_subaddr } ,
{ 0 , Q931_REDIRECTING_NUMBER , " Redirecting Number " , dump_redirecting_number , receive_redirecting_number , transmit_redirecting_number } ,
{ 1 , Q931_REDIRECTING_SUBADDR , " Redirecting Subaddress " , dump_redirecting_subaddr } ,
{ 0 , Q931_TRANSIT_NET_SELECT , " Transit Network Selection " } ,
{ 1 , Q931_RESTART_INDICATOR , " Restart Indicator " , dump_restart_indicator , receive_restart_indicator , transmit_restart_indicator } ,
{ 0 , Q931_LOW_LAYER_COMPAT , " Low-layer Compatibility " } ,
{ 0 , Q931_HIGH_LAYER_COMPAT , " High-layer Compatibility " } ,
{ 1 , Q931_PACKET_SIZE , " Packet Size " } ,
{ 1 , Q931_IE_FACILITY , " Facility " , dump_facility , receive_facility , transmit_facility } ,
{ 1 , Q931_IE_REDIRECTION_NUMBER , " Redirection Number " } ,
{ 1 , Q931_IE_REDIRECTION_SUBADDR , " Redirection Subaddress " } ,
{ 1 , Q931_IE_FEATURE_ACTIVATE , " Feature Activation " } ,
{ 1 , Q931_IE_INFO_REQUEST , " Feature Request " } ,
{ 1 , Q931_IE_FEATURE_IND , " Feature Indication " } ,
{ 1 , Q931_IE_SEGMENTED_MSG , " Segmented Message " } ,
{ 1 , Q931_IE_CALL_IDENTITY , " Call Identity " , dump_call_identity } ,
{ 1 , Q931_IE_ENDPOINT_ID , " Endpoint Identification " } ,
{ 1 , Q931_IE_NOTIFY_IND , " Notification Indicator " , dump_notify , receive_notify , transmit_notify } ,
{ 1 , Q931_DISPLAY , " Display " , dump_display , receive_display , transmit_display } ,
{ 1 , Q931_IE_TIME_DATE , " Date/Time " , dump_time_date } ,
2005-03-02 23:56:11 +08:00
{ 1 , Q931_IE_KEYPAD_FACILITY , " Keypad Facility " , dump_keypad_facility , receive_keypad_facility } ,
2005-01-17 20:58:05 +08:00
{ 0 , Q931_IE_SIGNAL , " Signal " , dump_signal } ,
{ 1 , Q931_IE_SWITCHHOOK , " Switch-hook " } ,
{ 1 , Q931_IE_USER_USER , " User-User " , dump_user_user , receive_user_user } ,
{ 1 , Q931_IE_ESCAPE_FOR_EXT , " Escape for Extension " } ,
{ 1 , Q931_IE_CALL_STATUS , " Call Status " } ,
{ 1 , Q931_IE_CHANGE_STATUS , " Change Status " } ,
{ 1 , Q931_IE_CONNECTED_ADDR , " Connected Number " , dump_connected_number } ,
{ 1 , Q931_IE_CONNECTED_NUM , " Connected Number " , dump_connected_number } ,
{ 1 , Q931_IE_ORIGINAL_CALLED_NUMBER , " Original Called Number " , dump_redirecting_number , receive_redirecting_number , transmit_redirecting_number } ,
{ 1 , Q931_IE_USER_USER_FACILITY , " User-User Facility " } ,
{ 1 , Q931_IE_UPDATE , " Update " } ,
{ 1 , Q931_SENDING_COMPLETE , " Sending Complete " , dump_sending_complete , receive_sending_complete , transmit_sending_complete } ,
2004-06-17 02:25:35 +08:00
/* Codeset 6 - Network specific */
2005-01-17 20:58:05 +08:00
{ 1 , Q931_IE_ORIGINATING_LINE_INFO , " Originating Line Information " , dump_line_information , receive_line_information , transmit_line_information } ,
{ 1 , Q931_IE_FACILITY | Q931_CODESET ( 6 ) , " Facility " , dump_facility , receive_facility , transmit_facility } ,
{ 1 , Q931_DISPLAY | Q931_CODESET ( 6 ) , " Display (CS6) " , dump_display , receive_display , transmit_display } ,
{ 0 , Q931_IE_GENERIC_DIGITS , " Generic Digits " , dump_generic_digits , receive_generic_digits , transmit_generic_digits } ,
2004-06-15 06:21:05 +08:00
/* Codeset 7 */
2001-05-13 00:41:32 +08:00
} ;
static char * ie2str ( int ie )
{
2003-08-06 23:20:49 +08:00
unsigned int x ;
2004-06-15 06:21:05 +08:00
/* Special handling for Locking/Non-Locking Shifts */
switch ( ie & 0xf8 ) {
case Q931_LOCKING_SHIFT :
switch ( ie & 7 ) {
case 0 :
return " !! INVALID Locking Shift To Codeset 0 " ;
case 1 :
return " Locking Shift To Codeset 1 " ;
case 2 :
return " Locking Shift To Codeset 2 " ;
case 3 :
return " Locking Shift To Codeset 3 " ;
case 4 :
return " Locking Shift To Codeset 4 " ;
case 5 :
return " Locking Shift To Codeset 5 " ;
case 6 :
return " Locking Shift To Codeset 6 " ;
case 7 :
return " Locking Shift To Codeset 7 " ;
}
case Q931_NON_LOCKING_SHIFT :
switch ( ie & 7 ) {
case 0 :
return " Non-Locking Shift To Codeset 0 " ;
case 1 :
return " Non-Locking Shift To Codeset 1 " ;
case 2 :
return " Non-Locking Shift To Codeset 2 " ;
case 3 :
return " Non-Locking Shift To Codeset 3 " ;
case 4 :
return " Non-Locking Shift To Codeset 4 " ;
case 5 :
return " Non-Locking Shift To Codeset 5 " ;
case 6 :
return " Non-Locking Shift To Codeset 6 " ;
case 7 :
return " Non-Locking Shift To Codeset 7 " ;
}
default :
for ( x = 0 ; x < sizeof ( ies ) / sizeof ( ies [ 0 ] ) ; x + + )
if ( ie = = ies [ x ] . ie )
return ies [ x ] . name ;
return " Unknown Information Element " ;
}
2001-05-13 00:41:32 +08:00
}
2004-07-24 00:20:06 +08:00
static inline unsigned int ielen ( q931_ie * ie )
2001-05-13 00:41:32 +08:00
{
2004-06-15 06:21:05 +08:00
if ( ( ie - > ie & 0x80 ) ! = 0 )
2001-05-13 00:41:32 +08:00
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 ;
}
2004-06-15 06:21:05 +08:00
static inline void q931_dumpie ( int codeset , q931_ie * ie , char prefix )
2001-05-13 00:41:32 +08:00
{
2003-08-06 23:20:49 +08:00
unsigned int x ;
2004-06-15 06:21:05 +08:00
int full_ie = Q931_FULL_IE ( codeset , ie - > ie ) ;
2004-06-17 02:25:35 +08:00
int base_ie ;
2004-06-14 11:29:19 +08:00
pri_message ( " %c [ " , prefix ) ;
2004-06-15 06:21:05 +08:00
pri_message ( " %02x " , ie - > ie ) ;
if ( ! ( ie - > ie & 0x80 ) ) {
2004-06-14 11:29:19 +08:00
pri_message ( " %02x " , ielen ( ie ) - 2 ) ;
2004-06-15 06:21:05 +08:00
for ( x = 0 ; x + 2 < ielen ( ie ) ; + + x )
2004-06-14 11:29:19 +08:00
pri_message ( " %02x " , ie - > data [ x ] ) ;
}
pri_message ( " ] \n " ) ;
2004-06-17 02:25:35 +08:00
/* Special treatment for shifts */
if ( ( full_ie & 0xf0 ) = = Q931_LOCKING_SHIFT )
full_ie & = 0xff ;
base_ie = ( ( ( full_ie & ~ 0x7f ) = = Q931_FULL_IE ( 0 , 0x80 ) ) & & ( ( full_ie & 0x70 ) ! = 0x20 ) ) ? full_ie & ~ 0x0f : full_ie ;
2001-05-13 00:41:32 +08:00
for ( x = 0 ; x < sizeof ( ies ) / sizeof ( ies [ 0 ] ) ; x + + )
2004-06-17 02:25:35 +08:00
if ( ies [ x ] . ie = = base_ie ) {
2001-05-13 00:41:32 +08:00
if ( ies [ x ] . dump )
2004-06-15 06:21:05 +08:00
ies [ x ] . dump ( full_ie , ie , ielen ( ie ) , prefix ) ;
2001-05-13 00:41:32 +08:00
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 ;
}
2004-06-17 02:25:35 +08:00
pri_error ( " !! %c Unknown IE %d (len = %d) \n " , prefix , base_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 ;
2004-06-07 11:33:51 +08:00
cur = * pri - > callpool ;
2001-05-13 00:41:32 +08:00
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
2004-06-07 11:33:51 +08:00
* pri - > callpool = cur ;
2001-05-13 00:41:32 +08:00
}
return cur ;
}
q931_call * q931_new_call ( struct pri * pri )
{
q931_call * cur ;
do {
2004-06-07 11:33:51 +08:00
cur = * pri - > callpool ;
2001-05-13 00:41:32 +08:00
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 ) ;
}
2004-06-07 07:26:43 +08:00
static void q931_destroy ( struct pri * pri , int cr , q931_call * c )
2001-05-13 00:41:32 +08:00
{
q931_call * cur , * prev ;
prev = NULL ;
2004-06-07 11:33:51 +08:00
cur = * pri - > callpool ;
2001-05-13 00:41:32 +08:00
while ( cur ) {
2004-06-07 07:26:43 +08:00
if ( ( c & & ( cur = = c ) ) | | ( ! c & & ( cur - > cr = = cr ) ) ) {
2001-05-13 00:41:32 +08:00
if ( prev )
prev - > next = cur - > next ;
else
2004-06-07 11:33:51 +08:00
* pri - > callpool = 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 ) ;
2005-03-02 23:56:11 +08:00
pri_call_apdu_queue_cleanup ( cur ) ;
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
}
2004-06-07 07:26:43 +08:00
static void q931_destroycall ( struct pri * pri , int cr )
{
return q931_destroy ( pri , cr , NULL ) ;
}
void __q931_destroycall ( struct pri * pri , q931_call * c )
{
2003-08-13 04:16:55 +08:00
if ( pri & & c )
2004-06-07 07:26:43 +08:00
q931_destroy ( pri , 0 , c ) ;
2003-08-13 04:16:55 +08:00
return ;
}
2004-06-07 07:26:43 +08:00
2004-06-15 06:21:05 +08:00
static int add_ie ( struct pri * pri , q931_call * call , int msgtype , int ie , q931_ie * iet , int maxlen , int * codeset )
2001-05-13 00:41:32 +08:00
{
2003-08-06 23:20:49 +08:00
unsigned int x ;
2005-01-17 20:58:05 +08:00
int res , total_res ;
2004-06-15 06:21:05 +08:00
int have_shift ;
2005-01-17 20:58:05 +08:00
int ies_count , order ;
2001-05-13 00:41:32 +08:00
for ( x = 0 ; x < sizeof ( ies ) / sizeof ( ies [ 0 ] ) ; x + + ) {
if ( ies [ x ] . ie = = ie ) {
/* This is our baby */
if ( ies [ x ] . transmit ) {
2004-06-15 06:21:05 +08:00
/* Prepend with CODE SHIFT IE if required */
if ( * codeset ! = Q931_IE_CODESET ( ies [ x ] . ie ) ) {
/* Locking shift to codeset 0 isn't possible */
iet - > ie = Q931_IE_CODESET ( ies [ x ] . ie ) | ( Q931_IE_CODESET ( ies [ x ] . ie ) ? Q931_LOCKING_SHIFT : Q931_NON_LOCKING_SHIFT ) ;
have_shift = 1 ;
iet = ( q931_ie * ) ( ( char * ) iet + 1 ) ;
maxlen - - ;
}
else
have_shift = 0 ;
2005-01-17 20:58:05 +08:00
ies_count = ies [ x ] . max_count ;
if ( ies_count = = 0 )
ies_count = INT_MAX ;
order = 0 ;
total_res = 0 ;
do {
iet - > ie = ie ;
res = ies [ x ] . transmit ( ie , pri , call , msgtype , iet , maxlen , + + order ) ;
/* Error if res < 0 or ignored if res == 0 */
if ( res < 0 )
return res ;
if ( res > 0 ) {
if ( ( iet - > ie & 0x80 ) = = 0 ) /* Multibyte IE */
iet - > len = res - 2 ;
total_res + = res ;
maxlen - = res ;
iet = ( q931_ie * ) ( ( char * ) iet + res ) ;
}
}
while ( res > 0 & & order < ies_count ) ;
if ( have_shift & & total_res ) {
2004-06-15 06:21:05 +08:00
if ( Q931_IE_CODESET ( ies [ x ] . ie ) )
* codeset = Q931_IE_CODESET ( ies [ x ] . ie ) ;
2005-01-17 20:58:05 +08:00
return total_res + 1 ; /* Shift is single-byte IE */
2004-06-15 06:21:05 +08:00
}
2005-01-17 20:58:05 +08:00
return total_res ;
2001-05-13 00:41:32 +08:00
} 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 " } ,
2004-06-05 14:50:55 +08:00
{ GR303_PROTOCOL_DISCRIMINATOR , " GR-303 " } ,
2001-07-17 20:12:42 +08:00
{ 0x3 , " AT&T Maintenance " } ,
2004-06-10 11:57:43 +08:00
{ 0x43 , " New AT&T Maintenance " } ,
2001-07-17 20:12:42 +08:00
} ;
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 ;
2004-06-15 06:21:05 +08:00
int cur_codeset ;
int codeset ;
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-10-31 04:22:04 +08:00
pri_message ( " %c Call Ref: len=%2d (reference %d/0x%X) (%s) \n " , c , h - > crlen , q931_cr ( h ) & 0x7FFF , q931_cr ( h ) & 0x7FFF , ( 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 ) ;
2004-06-15 06:21:05 +08:00
codeset = cur_codeset = 0 ;
2001-05-13 00:41:32 +08:00
while ( x < len ) {
r = ielen ( ( q931_ie * ) ( mh - > data + x ) ) ;
2004-06-15 06:21:05 +08:00
q931_dumpie ( cur_codeset , ( q931_ie * ) ( mh - > data + x ) , c ) ;
switch ( mh - > data [ x ] & 0xf8 ) {
case Q931_LOCKING_SHIFT :
if ( ( mh - > data [ x ] & 7 ) > 0 )
codeset = cur_codeset = mh - > data [ x ] & 7 ;
break ;
case Q931_NON_LOCKING_SHIFT :
cur_codeset = mh - > data [ x ] & 7 ;
break ;
default :
/* Reset temporary codeset change */
cur_codeset = codeset ;
}
2001-05-13 00:41:32 +08:00
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
}
2004-06-15 06:21:05 +08:00
static int q931_handle_ie ( int codeset , struct pri * pri , q931_call * c , int msg , q931_ie * ie )
2001-05-13 00:41:32 +08:00
{
2003-08-07 00:53:40 +08:00
unsigned int x ;
2004-06-15 06:21:05 +08:00
int full_ie = Q931_FULL_IE ( codeset , ie - > ie ) ;
2001-05-13 00:41:32 +08:00
if ( pri - > debug & PRI_DEBUG_Q931_STATE )
2004-06-17 02:25:35 +08:00
pri_message ( " -- Processing IE %d (cs%d, %s) \n " , ie - > ie , codeset , ie2str ( full_ie ) ) ;
2001-05-13 00:41:32 +08:00
for ( x = 0 ; x < sizeof ( ies ) / sizeof ( ies [ 0 ] ) ; x + + ) {
2004-06-15 06:21:05 +08:00
if ( full_ie = = ies [ x ] . ie ) {
2001-05-13 00:41:32 +08:00
if ( ies [ x ] . receive )
2004-06-15 06:21:05 +08:00
return ies [ x ] . receive ( full_ie , pri , c , msg , ie , ielen ( ie ) ) ;
2001-05-13 00:41:32 +08:00
else {
2001-07-17 20:12:42 +08:00
if ( pri - > debug & PRI_DEBUG_Q931_ANOMALY )
2004-06-17 02:25:35 +08:00
pri_error ( " !! No handler for IE %d (cs%d, %s) \n " , ie - > ie , codeset , ie2str ( full_ie ) ) ;
2001-05-13 00:41:32 +08:00
return - 1 ;
}
}
}
2004-06-17 02:25:35 +08:00
pri_message ( " !! Unknown IE %d (cs%d, %s) \n " , ie - > ie , codeset , ie2str ( full_ie ) ) ;
2001-05-13 00:41:32 +08:00
return - 1 ;
}
2005-04-04 07:07:55 +08:00
static void init_header ( struct pri * pri , q931_call * call , unsigned char * buf , q931_h * * hb , q931_mh * * mhb , int * len )
2001-05-13 00:41:32 +08:00
{
/* Returns header and message header and modifies length in place */
q931_h * h = ( q931_h * ) buf ;
q931_mh * mh = ( q931_mh * ) ( h - > contents + 2 ) ;
2004-06-05 14:50:55 +08:00
h - > pd = pri - > protodisc ;
2001-05-13 00:41:32 +08:00
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 ;
}
2004-06-05 14:50:55 +08:00
if ( pri - > subchannel ) {
/* On GR-303, top bit is always 0 */
h - > crv [ 0 ] & = 0x7f ;
}
2001-05-13 00:41:32 +08:00
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 ;
2004-06-15 06:21:05 +08:00
int codeset ;
2005-03-02 23:56:11 +08:00
struct apdu_event * facevent = c - > apdus ;
2001-05-13 00:41:32 +08:00
memset ( buf , 0 , sizeof ( buf ) ) ;
len = sizeof ( buf ) ;
2004-06-05 14:50:55 +08:00
init_header ( pri , c , buf , & h , & mh , & len ) ;
2001-05-13 00:41:32 +08:00
mh - > msg = msgtype ;
x = 0 ;
2004-06-15 06:21:05 +08:00
codeset = 0 ;
2001-05-13 00:41:32 +08:00
while ( ies [ x ] > - 1 ) {
2005-03-02 23:56:11 +08:00
if ( ies [ x ] = = Q931_IE_FACILITY ) {
res = 0 ;
while ( facevent ) {
if ( ! facevent - > sent & & ( facevent - > message = = msgtype ) ) {
int tmpres ;
tmpres = add_ie ( pri , c , mh - > msg , ies [ x ] , ( q931_ie * ) ( mh - > data + offset ) , len , & codeset ) ;
if ( tmpres < 0 ) {
pri_error ( " !! Unable to add IE '%s' \n " , ie2str ( ies [ x ] ) ) ;
return - 1 ;
}
res + = tmpres ;
facevent - > sent = 1 ;
}
facevent = facevent - > next ;
}
} else {
res = add_ie ( pri , c , mh - > msg , ies [ x ] , ( q931_ie * ) ( mh - > data + offset ) , len , & codeset ) ;
}
2001-05-13 00:41:32 +08:00
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 ;
}
2005-03-02 23:56:11 +08:00
2001-05-13 00:41:32 +08:00
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 )
2004-06-07 11:33:51 +08:00
cur = * pri - > callpool ;
2003-03-04 14:00:37 +08:00
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 ) ;
}
2005-03-02 23:56:11 +08:00
static int facility_ies [ ] = { Q931_IE_FACILITY , - 1 } ;
int q931_facility ( struct pri * pri , q931_call * c )
{
return send_message ( pri , c , Q931_FACILITY , facility_ies ) ;
}
2004-06-14 10:48:24 +08:00
static int notify_ies [ ] = { Q931_IE_NOTIFY_IND , - 1 } ;
int q931_notify ( struct pri * pri , q931_call * c , int channel , int info )
{
if ( info > = 0 )
c - > notify = info & 0x7F ;
else
c - > notify = - 1 ;
return send_message ( pri , c , Q931_NOTIFY , notify_ies ) ;
}
2004-05-19 23:34:43 +08:00
# ifdef ALERTING_NO_PROGRESS
2004-05-20 08:21:16 +08:00
static int call_progress_ies [ ] = { - 1 } ;
2004-05-19 23:34:43 +08:00
# else
2004-05-20 08:21:16 +08:00
static int call_progress_ies [ ] = { Q931_PROGRESS_INDICATOR , - 1 } ;
2004-05-19 23:34:43 +08:00
# endif
2004-05-20 05:01:36 +08:00
int q931_call_progress ( struct pri * pri , q931_call * c , int channel , int info )
2004-05-19 23:34:43 +08:00
{
2004-06-17 02:04:22 +08:00
if ( channel ) {
c - > ds1no = ( channel & 0xff00 ) > > 8 ;
channel & = 0xff ;
c - > channelno = channel ;
}
2004-05-19 23:34:43 +08:00
if ( info ) {
c - > progloc = LOC_PRIV_NET_LOCAL_USER ;
c - > progcode = CODE_CCITT ;
2005-01-17 20:58:05 +08:00
c - > progressmask = PRI_PROG_INBAND_AVAILABLE ;
} else {
/* PI is mandatory IE for PROGRESS message - Q.931 3.1.8 */
pri_error ( " XXX Progress message requested but no information is provided \n " ) ;
c - > progressmask = 0 ;
}
2004-05-19 23:34:43 +08:00
c - > alive = 1 ;
return send_message ( pri , c , Q931_PROGRESS , call_progress_ies ) ;
}
2004-05-19 23:26:16 +08:00
# ifdef ALERTING_NO_PROGRESS
2001-05-13 00:41:32 +08:00
static int call_proceeding_ies [ ] = { Q931_CHANNEL_IDENT , - 1 } ;
2004-05-19 23:26:16 +08:00
# else
static int call_proceeding_ies [ ] = { Q931_CHANNEL_IDENT , Q931_PROGRESS_INDICATOR , - 1 } ;
# endif
2001-05-13 00:41:32 +08:00
2004-05-20 05:01:36 +08:00
int q931_call_proceeding ( struct pri * pri , q931_call * c , int channel , int info )
2001-05-13 00:41:32 +08:00
{
2004-06-05 14:50:55 +08:00
if ( channel ) {
c - > ds1no = ( channel & 0xff00 ) > > 8 ;
channel & = 0xff ;
2004-05-20 05:01:36 +08:00
c - > channelno = channel ;
2004-06-05 14:50:55 +08:00
}
2004-05-20 05:01:36 +08:00
c - > chanflags & = ~ FLAG_PREFERRED ;
c - > chanflags | = FLAG_EXCLUSIVE ;
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 ;
2004-05-19 23:21:15 +08:00
if ( info ) {
c - > progloc = LOC_PRIV_NET_LOCAL_USER ;
c - > progcode = CODE_CCITT ;
2005-01-17 20:58:05 +08:00
c - > progressmask = PRI_PROG_INBAND_AVAILABLE ;
2004-05-19 23:21:15 +08:00
} else
2005-01-17 20:58:05 +08:00
c - > progressmask = 0 ;
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
2004-05-20 08:21:16 +08:00
static int alerting_ies [ ] = { Q931_PROGRESS_INDICATOR , - 1 } ;
2003-07-08 07:37:18 +08:00
# else
2004-05-20 08:21:16 +08:00
static int alerting_ies [ ] = { - 1 } ;
2003-07-08 07:37:18 +08:00
# endif
2001-05-13 00:41:32 +08:00
int q931_alerting ( struct pri * pri , q931_call * c , int channel , int info )
{
2004-05-20 05:01:36 +08:00
if ( ! c - > proc )
q931_call_proceeding ( pri , c , channel , 0 ) ;
2001-05-13 00:41:32 +08:00
if ( info ) {
c - > progloc = LOC_PRIV_NET_LOCAL_USER ;
c - > progcode = CODE_CCITT ;
2005-01-17 20:58:05 +08:00
c - > progressmask = PRI_PROG_INBAND_AVAILABLE ;
2001-05-13 00:41:32 +08:00
} else
2005-01-17 20:58:05 +08:00
c - > progressmask = 0 ;
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 )
{
2004-06-05 14:50:55 +08:00
if ( channel ) {
c - > ds1no = ( channel & 0xff00 ) > > 8 ;
channel & = 0xff ;
c - > channelno = channel ;
}
2003-02-12 21:59:23 +08:00
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 ;
2005-01-17 20:58:05 +08:00
c - > progressmask = PRI_PROG_CALLED_NOT_ISDN ;
2003-02-12 21:59:23 +08:00
} else
2005-01-17 20:58:05 +08:00
c - > progressmask = 0 ;
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 )
{
2004-06-05 14:50:55 +08:00
if ( channel ) {
c - > ds1no = ( channel & 0xff00 ) > > 8 ;
channel & = 0xff ;
c - > channelno = channel ;
}
2001-05-13 00:41:32 +08:00
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 ;
2005-01-17 20:58:05 +08:00
c - > progressmask = PRI_PROG_CALLED_NOT_ISDN ;
2001-05-13 00:41:32 +08:00
} else
2005-01-17 20:58:05 +08:00
c - > progressmask = 0 ;
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 ) ;
2004-09-20 21:29:37 +08:00
c - > retranstimer = 0 ;
2004-06-28 04:29:53 +08:00
if ( ( pri - > localtype = = PRI_CPE ) & & ( ! pri - > subchannel ) )
2004-10-02 22:55:20 +08:00
c - > retranstimer = pri_schedule_event ( pri , pri - > timers [ PRI_TIMER_T313 ] , 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 ) {
2004-10-02 22:55:20 +08:00
c - > retranstimer = pri_schedule_event ( pri , pri - > timers [ PRI_TIMER_T308 ] , pri_release_timeout , c ) ;
2003-09-25 14:13:14 +08:00
} else {
2004-10-02 22:55:20 +08:00
c - > retranstimer = pri_schedule_event ( pri , pri - > timers [ PRI_TIMER_T308 ] , pri_release_finaltimeout , c ) ;
2003-09-25 14:13:14 +08:00
}
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 ;
2004-06-05 14:50:55 +08:00
c - > ds1no = ( channel & 0xff00 ) > > 8 ;
channel & = 0xff ;
c - > channelno = channel ;
2002-04-25 11:51:36 +08:00
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 ) ;
2004-10-02 22:55:20 +08:00
c - > retranstimer = pri_schedule_event ( pri , pri - > timers [ PRI_TIMER_T305 ] , pri_disconnect_timeout , c ) ;
2001-05-13 00:41:32 +08:00
return send_message ( pri , c , Q931_DISCONNECT , disconnect_ies ) ;
} else
return 0 ;
}
2004-10-28 04:43:23 +08:00
static int setup_ies [ ] = { Q931_BEARER_CAPABILITY , Q931_CHANNEL_IDENT , Q931_IE_FACILITY , Q931_PROGRESS_INDICATOR , Q931_NETWORK_SPEC_FAC , Q931_DISPLAY ,
2004-11-05 10:12:02 +08:00
Q931_CALLING_PARTY_NUMBER , Q931_CALLED_PARTY_NUMBER , Q931_REDIRECTING_NUMBER , Q931_SENDING_COMPLETE , Q931_IE_ORIGINATING_LINE_INFO , Q931_IE_GENERIC_DIGITS , - 1 } ;
2001-05-13 00:41:32 +08:00
2004-06-06 09:21:41 +08:00
static int gr303_setup_ies [ ] = { Q931_BEARER_CAPABILITY , Q931_CHANNEL_IDENT , - 1 } ;
2005-03-02 23:56:11 +08:00
static int cis_setup_ies [ ] = { Q931_BEARER_CAPABILITY , Q931_CHANNEL_IDENT , Q931_IE_FACILITY , Q931_CALLED_PARTY_NUMBER , - 1 } ;
2004-06-16 23:33:58 +08:00
int q931_setup ( struct pri * pri , q931_call * c , struct pri_sr * req )
2001-05-13 00:41:32 +08:00
{
int res ;
2004-06-16 23:33:58 +08:00
c - > transcapability = req - > transmode ;
2001-05-13 00:41:32 +08:00
c - > transmoderate = TRANS_MODE_64_CIRCUIT ;
2004-06-16 23:33:58 +08:00
if ( ! req - > userl1 )
req - > userl1 = PRI_LAYER_1_ULAW ;
c - > userl1 = req - > userl1 ;
c - > ds1no = ( req - > channel & 0xff00 ) > > 8 ;
req - > channel & = 0xff ;
2004-06-29 12:28:34 +08:00
if ( ( pri - > localtype = = PRI_CPE ) & & pri - > subchannel ) {
req - > channel = 0 ;
req - > exclusive = 0 ;
}
2004-06-16 23:33:58 +08:00
c - > channelno = req - > channel ;
2001-05-13 00:41:32 +08:00
c - > slotmap = - 1 ;
2004-06-16 23:33:58 +08:00
c - > nonisdn = req - > nonisdn ;
2005-03-02 23:56:11 +08:00
c - > newcall = 0 ;
c - > justsignalling = req - > justsignalling ;
2004-06-17 01:16:37 +08:00
c - > complete = req - > numcomplete ;
2004-06-16 23:33:58 +08:00
if ( req - > exclusive )
2001-05-13 00:41:32 +08:00
c - > chanflags = FLAG_EXCLUSIVE ;
2004-06-29 12:28:34 +08:00
else if ( c - > channelno )
2001-05-13 00:41:32 +08:00
c - > chanflags = FLAG_PREFERRED ;
2004-06-16 23:33:58 +08:00
if ( req - > caller ) {
strncpy ( c - > callernum , req - > caller , sizeof ( c - > callernum ) - 1 ) ;
c - > callerplan = req - > callerplan ;
if ( req - > callername )
strncpy ( c - > callername , req - > callername , sizeof ( c - > callername ) - 1 ) ;
2003-02-12 21:59:23 +08:00
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 */
2004-06-16 23:33:58 +08:00
if ( ! ( req - > callerpres & 0x7c ) )
req - > callerpres = PRES_ALLOWED_NETWORK_NUMBER ;
2001-05-13 00:41:32 +08:00
}
2004-06-16 23:33:58 +08:00
c - > callerpres = req - > callerpres ;
2001-05-13 00:41:32 +08:00
} 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 ;
}
2004-10-31 04:13:20 +08:00
if ( req - > redirectingnum ) {
strncpy ( c - > redirectingnum , req - > redirectingnum , sizeof ( c - > redirectingnum ) - 1 ) ;
c - > redirectingplan = req - > redirectingplan ;
if ( ( pri - > switchtype = = PRI_SWITCH_DMS100 ) | |
( pri - > switchtype = = PRI_SWITCH_ATT4ESS ) ) {
/* Doesn't like certain presentation types */
if ( ! ( req - > redirectingpres & 0x7c ) )
req - > redirectingpres = PRES_ALLOWED_NETWORK_NUMBER ;
}
c - > redirectingpres = req - > redirectingpres ;
c - > redirectingreason = req - > redirectingreason ;
} else {
strcpy ( c - > redirectingnum , " " ) ;
c - > redirectingplan = PRI_UNKNOWN ;
c - > redirectingpres = PRES_NUMBER_NOT_AVAILABLE ;
c - > redirectingreason = PRI_REDIR_UNKNOWN ;
}
2004-06-16 23:33:58 +08:00
if ( req - > called ) {
strncpy ( c - > callednum , req - > called , sizeof ( c - > callednum ) - 1 ) ;
c - > calledplan = req - > calledplan ;
2001-05-13 00:41:32 +08:00
} else
return - 1 ;
2004-06-16 23:33:58 +08:00
if ( req - > nonisdn & & ( pri - > switchtype = = PRI_SWITCH_NI2 ) )
2005-01-17 20:58:05 +08:00
c - > progressmask = PRI_PROG_CALLER_NOT_ISDN ;
2001-05-13 00:41:32 +08:00
else
2005-01-17 20:58:05 +08:00
c - > progressmask = 0 ;
2005-03-02 23:56:11 +08:00
pri_call_add_standard_apdus ( pri , c ) ;
2004-06-06 09:21:41 +08:00
if ( pri - > subchannel )
res = send_message ( pri , c , Q931_SETUP , gr303_setup_ies ) ;
2005-03-02 23:56:11 +08:00
else if ( c - > justsignalling )
res = send_message ( pri , c , Q931_SETUP , cis_setup_ies ) ;
2004-06-06 09:21:41 +08:00
else
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 } ;
2004-06-07 23:55:39 +08:00
static int gr303_connect_acknowledge_ies [ ] = { Q931_CHANNEL_IDENT , - 1 } ;
2001-05-13 00:41:32 +08:00
static int q931_connect_acknowledge ( struct pri * pri , q931_call * c )
{
2004-06-07 23:55:39 +08:00
if ( pri - > subchannel ) {
if ( pri - > localtype = = PRI_CPE )
return send_message ( pri , c , Q931_CONNECT_ACKNOWLEDGE , gr303_connect_acknowledge_ies ) ;
} else
return send_message ( pri , c , Q931_CONNECT_ACKNOWLEDGE , connect_acknowledge_ies ) ;
return 0 ;
2001-05-13 00:41:32 +08:00
}
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 ;
2004-06-17 06:19:11 +08:00
/* If mandatory IE was missing, insist upon that cause code */
if ( c - > cause = = PRI_CAUSE_MANDATORY_IE_MISSING )
cause = c - > cause ;
2004-06-06 09:21:41 +08:00
if ( cause = = 34 | | cause = = 44 | | cause = = 82 | | cause = = 1 | | cause = = 81 ) {
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 ;
2004-06-15 06:21:05 +08:00
int codeset , cur_codeset ;
int last_ie [ 8 ] ;
2005-03-02 23:56:11 +08:00
struct apdu_event * cur = NULL ;
2004-06-15 06:21:05 +08:00
memset ( last_ie , 0 , sizeof ( last_ie ) ) ;
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 ) ;
2004-06-10 11:57:43 +08:00
if ( ( h - > pd = = 0x3 ) | | ( h - > pd = = 0x43 ) ) {
2001-05-13 00:41:32 +08:00
/* 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 ;
2004-06-05 14:50:55 +08:00
} else if ( h - > pd ! = pri - > protodisc ) {
pri_error ( " Warning: unknown/inappropriate protocol discriminator received (%02x/%d) \n " , h - > pd , h - > pd ) ;
2003-11-20 04:11:11 +08:00
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 ;
2004-06-05 14:50:55 +08:00
c - > ds1no = 0 ;
2001-05-13 00:41:32 +08:00
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 ;
2004-06-05 14:50:55 +08:00
c - > ds1no = 0 ;
2001-05-13 00:41:32 +08:00
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 ;
2005-01-17 20:58:05 +08:00
c - > nonisdn = 0 ;
/* Fall through */
2001-05-13 00:41:32 +08:00
case Q931_CONNECT :
case Q931_ALERTING :
case Q931_PROGRESS :
2005-01-17 20:58:05 +08:00
case Q931_CALL_PROCEEDING :
2001-05-13 00:41:32 +08:00
c - > progress = - 1 ;
2005-01-17 20:58:05 +08:00
c - > progressmask = 0 ;
2001-05-13 00:41:32 +08:00
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 ;
2001-05-13 00:41:32 +08:00
break ;
case Q931_RELEASE :
case Q931_DISCONNECT :
c - > cause = - 1 ;
c - > causecode = - 1 ;
c - > causeloc = - 1 ;
2005-04-05 11:55:58 +08:00
c - > aoc_units = - 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 ;
2005-04-05 11:55:58 +08:00
c - > aoc_units = - 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 ) ;
2004-06-15 06:21:05 +08:00
codeset = cur_codeset = 0 ;
2001-05-13 00:41:32 +08:00
while ( len ) {
ie = ( q931_ie * ) ( mh - > data + x ) ;
2003-09-25 14:13:14 +08:00
for ( y = 0 ; y < MAX_MAND_IES ; y + + ) {
2004-06-15 06:21:05 +08:00
if ( mandies [ y ] = = Q931_FULL_IE ( cur_codeset , ie - > ie ) )
2003-09-25 14:13:14 +08:00
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 ;
}
2004-06-15 06:21:05 +08:00
/* Special processing for codeset shifts */
switch ( ie - > ie & 0xf8 ) {
case Q931_LOCKING_SHIFT :
y = ie - > ie & 7 ; /* Requested codeset */
/* Locking shifts couldn't go to lower codeset, and couldn't follows non-locking shifts - verify this */
if ( ( cur_codeset ! = codeset ) & & ( pri - > debug & PRI_DEBUG_Q931_ANOMALY ) )
pri_message ( " XXX Locking shift immediately follows non-locking shift (from %d through %d to %d) XXX \n " , codeset , cur_codeset , y ) ;
if ( y > 0 ) {
if ( ( y < codeset ) & & ( pri - > debug & PRI_DEBUG_Q931_ANOMALY ) )
pri_error ( " !! Trying to locked downshift codeset from %d to %d !! \n " , codeset , y ) ;
codeset = cur_codeset = y ;
}
else {
/* Locking shift to codeset 0 is forbidden by all specifications */
pri_error ( " !! Invalid locking shift to codeset 0 !! \n " ) ;
}
break ;
case Q931_NON_LOCKING_SHIFT :
cur_codeset = ie - > ie & 7 ;
break ;
default :
/* Sanity check for IE code order */
if ( ! ( ie - > ie & 0x80 ) ) {
if ( last_ie [ cur_codeset ] > ie - > ie ) {
if ( ( pri - > debug & PRI_DEBUG_Q931_ANOMALY ) )
pri_message ( " XXX Out-of-order IE %d at codeset %d (last was %d) \n " , ie - > ie , cur_codeset , last_ie [ cur_codeset ] ) ;
}
else
last_ie [ cur_codeset ] = ie - > ie ;
}
/* Ignore non-locking shifts for TR41459-based signalling */
switch ( pri - > switchtype ) {
case PRI_SWITCH_LUCENT5E :
case PRI_SWITCH_ATT4ESS :
if ( cur_codeset ! = codeset ) {
if ( ( pri - > debug & PRI_DEBUG_Q931_DUMP ) )
pri_message ( " XXX Ignoring IE %d for temporary codeset %d XXX \n " , ie - > ie , cur_codeset ) ;
break ;
}
/* Fall through */
default :
y = q931_handle_ie ( cur_codeset , pri , c , mh - > msg , ie ) ;
2004-06-17 02:25:35 +08:00
/* XXX Applicable to codeset 0 only? XXX */
if ( ! cur_codeset & & ! ( ie - > ie & 0xf0 ) & & ( y < 0 ) )
2004-06-15 06:21:05 +08:00
mandies [ MAX_MAND_IES - 1 ] = Q931_FULL_IE ( cur_codeset , ie - > ie ) ;
}
/* Reset current codeset */
cur_codeset = codeset ;
}
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 ] ) {
2004-06-05 14:50:55 +08:00
/* check if there is no channel identification when we're configured as network -> that's not an error */
2004-10-29 23:41:59 +08:00
if ( ( ( pri - > localtype ! = PRI_NETWORK ) | | ( mh - > msg ! = Q931_SETUP ) | | ( mandies [ x ] ! = Q931_CHANNEL_IDENT ) ) & &
( ( mh - > msg ! = Q931_PROGRESS ) | | ( mandies [ x ] ! = Q931_PROGRESS_INDICATOR ) ) ) {
2004-06-17 02:25:35 +08:00
pri_error ( " XXX Missing handling for mandatory IE %d (cs%d, %s) XXX \n " , Q931_IE_IE ( mandies [ x ] ) , Q931_IE_CODESET ( mandies [ x ] ) , ie2str ( mandies [ x ] ) ) ;
2004-06-05 14:50:55 +08:00
missingmand + + ;
2003-12-06 07:10:33 +08:00
}
}
}
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 ;
2004-06-11 03:28:14 +08:00
pri - > ev . restart . channel = c - > channelno | ( c - > ds1no < < 8 ) ;
2001-05-13 00:41:32 +08:00
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 ;
}
2005-01-17 20:58:05 +08:00
if ( c - > progressmask & PRI_PROG_CALLER_NOT_ISDN )
c - > nonisdn = 1 ;
2003-09-25 14:13:14 +08:00
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 ;
2005-01-17 20:58:05 +08:00
if ( c - > transmoderate ! = TRANS_MODE_64_CIRCUIT ) {
q931_release_complete ( pri , c , PRI_CAUSE_BEARERCAPABILITY_NOTIMPL ) ;
break ;
}
2001-05-13 00:41:32 +08:00
pri - > ev . e = PRI_EVENT_RING ;
2004-06-05 14:50:55 +08:00
pri - > ev . ring . channel = c - > channelno | ( c - > ds1no < < 8 ) ;
2001-05-13 00:41:32 +08:00
pri - > ev . ring . callingpres = c - > callerpres ;
pri - > ev . ring . callingplan = c - > callerplan ;
2004-09-17 12:02:16 +08:00
pri - > ev . ring . ani2 = c - > ani2 ;
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 ;
2004-06-26 03:33:12 +08:00
strncpy ( pri - > ev . ring . callingsubaddr , c - > callingsubaddr , sizeof ( pri - > ev . ring . callingsubaddr ) - 1 ) ;
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 ;
2004-12-16 03:48:15 +08:00
pri - > ev . ring . redirectingreason = c - > redirectingreason ;
2005-01-17 20:58:05 +08:00
pri - > ev . ring . progress = c - > progress ;
pri - > ev . ring . progressmask = c - > progressmask ;
2001-05-13 00:41:32 +08:00
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 ;
2004-06-05 14:50:55 +08:00
pri - > ev . ringing . channel = c - > channelno | ( c - > ds1no < < 8 ) ;
2001-05-13 00:41:32 +08:00
pri - > ev . ringing . cref = c - > cr ;
pri - > ev . ringing . call = c ;
2004-10-31 04:19:18 +08:00
pri - > ev . ringing . progress = c - > progress ;
2005-01-17 20:58:05 +08:00
pri - > ev . ringing . progressmask = c - > progressmask ;
2001-05-13 00:41:32 +08:00
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 ;
2004-06-05 14:50:55 +08:00
pri - > ev . answer . channel = c - > channelno | ( c - > ds1no < < 8 ) ;
2001-05-13 00:41:32 +08:00
pri - > ev . answer . cref = c - > cr ;
pri - > ev . answer . call = c ;
2004-10-31 04:19:18 +08:00
pri - > ev . answer . progress = c - > progress ;
2005-01-17 20:58:05 +08:00
pri - > ev . answer . progressmask = c - > progressmask ;
2001-05-13 00:41:32 +08:00
q931_connect_acknowledge ( pri , c ) ;
2005-03-04 23:56:37 +08:00
if ( c - > justsignalling ) { /* Make sure WE release when we initiatie a signalling only connection */
q931_release ( pri , c , PRI_CAUSE_NORMAL_CLEARING ) ;
break ;
} else
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 ) ;
2004-06-05 14:50:55 +08:00
pri - > ev . facname . channel = c - > channelno | ( c - > ds1no < < 8 ) ;
2003-02-12 21:59:23 +08:00
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 ;
}
2004-06-15 05:25:41 +08:00
pri - > ev . e = PRI_EVENT_PROGRESS ;
2003-09-25 14:13:14 +08:00
/* 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 ;
}
2004-06-05 14:50:55 +08:00
pri - > ev . proceeding . channel = c - > channelno | ( c - > ds1no < < 8 ) ;
2003-09-25 14:13:14 +08:00
if ( mh - > msg = = Q931_CALL_PROCEEDING ) {
2004-06-15 05:25:41 +08:00
pri - > ev . e = PRI_EVENT_PROCEEDING ;
2003-09-25 14:13:14 +08:00
c - > ourcallstate = Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING ;
c - > peercallstate = Q931_CALL_STATE_INCOMING_CALL_PROCEEDING ;
}
2004-11-06 04:27:56 +08:00
pri - > ev . proceeding . progress = c - > progress ;
2005-01-17 20:58:05 +08:00
pri - > ev . proceeding . progressmask = c - > progressmask ;
2004-10-31 04:19:18 +08:00
pri - > ev . proceeding . cref = c - > cr ;
pri - > ev . proceeding . call = c ;
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 ) ) ;
2005-01-25 04:57:04 +08:00
/* Workaround for S-12 ver 7.3 - it responds for invalid/non-implemented IEs at SETUP with null call state */
if ( ! c - > sugcallstate & & ( c - > ourcallstate ! = Q931_CALL_STATE_CALL_INITIATED ) ) {
2004-06-05 14:50:55 +08:00
pri - > ev . hangup . channel = c - > channelno | ( c - > ds1no < < 8 ) ;
2003-09-25 14:13:14 +08:00
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 ;
2004-06-05 14:50:55 +08:00
pri - > ev . hangup . channel = c - > channelno | ( c - > ds1no < < 8 ) ;
2003-08-07 08:45:04 +08:00
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 ) {
2004-06-17 06:19:11 +08:00
/* Force cause to be mandatory IE missing */
c - > cause = PRI_CAUSE_MANDATORY_IE_MISSING ;
2003-09-25 14:13:14 +08:00
}
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 ;
2004-06-05 14:50:55 +08:00
pri - > ev . hangup . channel = c - > channelno | ( c - > ds1no < < 8 ) ;
2001-05-13 00:41:32 +08:00
pri - > ev . hangup . cref = c - > cr ;
pri - > ev . hangup . cause = c - > cause ;
pri - > ev . hangup . call = c ;
2005-04-05 11:55:58 +08:00
pri - > ev . hangup . aoc_units = c - > aoc_units ;
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 ) {
2004-06-17 06:19:11 +08:00
/* Still let user call release */
c - > cause = PRI_CAUSE_MANDATORY_IE_MISSING ;
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_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 ;
2004-06-05 14:50:55 +08:00
pri - > ev . hangup . channel = c - > channelno | ( c - > ds1no < < 8 ) ;
2001-05-13 00:41:32 +08:00
pri - > ev . hangup . cref = c - > cr ;
pri - > ev . hangup . cause = c - > cause ;
pri - > ev . hangup . call = c ;
2005-04-05 11:55:58 +08:00
pri - > ev . hangup . aoc_units = c - > aoc_units ;
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 ;
2004-06-05 14:50:55 +08:00
pri - > ev . restartack . channel = c - > channelno | ( c - > ds1no < < 8 ) ;
2002-04-25 11:51:36 +08:00
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 ;
}
2005-03-02 23:56:11 +08:00
if ( c - > ourcallstate ! = Q931_CALL_STATE_OVERLAP_RECEIVING ) {
pri - > ev . e = PRI_EVENT_KEYPAD_DIGIT ;
pri - > ev . digit . call = c ;
pri - > ev . digit . channel = c - > channelno | ( c - > ds1no < < 8 ) ;
strncpy ( pri - > ev . digit . digits , c - > digitbuf , sizeof ( pri - > ev . digit . digits ) ) ;
return Q931_RES_HAVEEVENT ;
}
2003-02-12 21:59:23 +08:00
pri - > ev . e = PRI_EVENT_INFO_RECEIVED ;
pri - > ev . ring . call = c ;
2004-06-05 14:50:55 +08:00
pri - > ev . ring . channel = c - > channelno | ( c - > ds1no < < 8 ) ;
2003-02-12 21:59:23 +08:00
strncpy ( pri - > ev . ring . callednum , c - > callednum , sizeof ( pri - > ev . ring . callednum ) - 1 ) ;
2004-06-26 03:33:12 +08:00
strncpy ( pri - > ev . ring . callingsubaddr , c - > callingsubaddr , sizeof ( pri - > ev . ring . callingsubaddr ) - 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 ;
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 ;
2005-03-02 23:56:11 +08:00
cur = c - > apdus ;
while ( cur ) {
if ( ! cur - > sent & & cur - > message = = Q931_FACILITY ) {
q931_facility ( pri , c ) ;
break ;
}
cur = cur - > next ;
}
2003-05-16 06:15:38 +08:00
return Q931_RES_HAVEEVENT ;
2003-09-25 14:13:14 +08:00
case Q931_NOTIFY :
2004-06-14 10:48:24 +08:00
pri - > ev . e = PRI_EVENT_NOTIFY ;
pri - > ev . notify . channel = c - > channelno ;
pri - > ev . notify . info = c - > notify ;
return Q931_RES_HAVEEVENT ;
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 ;
}
2004-06-05 14:50:55 +08:00
int q931_call_getcrv ( struct pri * pri , q931_call * call , int * callmode )
{
if ( callmode )
* callmode = call - > cr & 0x7 ;
return ( ( call - > cr & 0x7fff ) > > 3 ) ;
}
int q931_call_setcrv ( struct pri * pri , q931_call * call , int crv , int callmode )
{
call - > cr = ( crv < < 3 ) & 0x7fff ;
call - > cr | = ( callmode & 0x7 ) ;
return 0 ;
}