2001-05-13 00:41:32 +08:00
/*
* libpri : An implementation of Primary Rate ISDN
*
2005-06-22 06:47:39 +08:00
* Written by Mark Spencer < markster @ digium . com >
2001-05-13 00:41:32 +08:00
*
2008-08-06 06:18:12 +08:00
* Copyright ( C ) 2001 - 2005 , Digium , Inc .
2001-05-13 00:41:32 +08:00
* All Rights Reserved .
2008-08-06 06:18:12 +08:00
*/
/*
* See http : //www.asterisk.org for more information about
* the Asterisk project . Please do not directly contact
* any of the maintainers of this project for assistance ;
* the project provides a web site , mailing lists and IRC
* channels for your use .
2001-05-13 00:41:32 +08:00
*
2008-08-06 06:18:12 +08:00
* This program is free software , distributed under the terms of
* the GNU General Public License Version 2 as published by the
* Free Software Foundation . See the LICENSE file included with
* this program for more details .
2001-05-13 00:41:32 +08:00
*
2008-08-06 06:18:12 +08:00
* In addition , when this program is distributed with Asterisk in
* any form that would qualify as a ' combined work ' or as a
* ' derivative work ' ( but not mere aggregation ) , you can redistribute
* and / or modify the combination under the terms of the license
* provided with that copy of Asterisk , instead of the license
* terms granted here .
2001-05-13 00:41:32 +08:00
*/
2005-06-22 06:47:39 +08:00
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"
2009-04-22 06:08:45 +08:00
# include "rose.h"
2001-05-13 00:41:32 +08:00
# include <unistd.h>
# include <stdlib.h>
# include <string.h>
2006-01-06 03:33:32 +08:00
# include <ctype.h>
2001-05-13 00:41:32 +08:00
# 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
} ;
2006-07-07 23:35:48 +08:00
static 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 " } ,
2009-04-14 23:05:21 +08:00
} ;
static int post_handle_q931_message ( struct pri * pri , struct q931_mh * mh , struct q931_call * c , int missingmand ) ;
2001-05-13 00:41:32 +08:00
2009-04-14 23:05:21 +08:00
struct msgtype maintenance_msgs [ ] = {
{ NATIONAL_SERVICE , " SERVICE " , { Q931_CHANNEL_IDENT } } ,
{ NATIONAL_SERVICE_ACKNOWLEDGE , " SERVICE ACKNOWLEDGE " , { Q931_CHANNEL_IDENT } } ,
2001-05-13 00:41:32 +08:00
} ;
2009-04-14 23:05:21 +08:00
static int post_handle_maintenance_message ( struct pri * pri , struct q931_mh * mh , struct q931_call * c ) ;
2001-05-13 00:41:32 +08:00
2006-07-07 23:35:48 +08:00
static struct msgtype causes [ ] = {
2001-07-17 20:12:42 +08:00
{ 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 " } ,
2006-02-18 05:19:37 +08:00
{ PRI_CAUSE_SERVICEOROPTION_NOTAVAIL , " Service or option not available, unspecified " } ,
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 " } ,
2006-02-18 05:19:37 +08:00
{ PRI_CAUSE_IDENTIFIED_CHANNEL_NOTEXIST , " Identified channel does not exist " } ,
2001-07-17 20:12:42 +08:00
{ 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 " } ,
} ;
2006-07-07 23:35:48 +08:00
static struct msgtype facilities [ ] = {
2004-06-26 12:37:09 +08:00
{ 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
2005-05-23 23:06:33 +08:00
# define FUNC_DUMP(name) void ((name))(int full_ie, struct pri *pri, q931_ie *ie, int len, char prefix)
2004-06-15 06:21:05 +08:00
# 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
2006-07-07 05:11:37 +08:00
# if 1
/* Update call state with transition trace. */
# define UPDATE_OURCALLSTATE(pri,c,newstate) do {\
if ( pri - > debug & ( PRI_DEBUG_Q931_STATE ) & & c - > ourcallstate ! = newstate ) \
pri_message ( pri , DBGHEAD " call %d on channel %d enters state %d (%s) \n " , DBGINFO , \
c - > cr , c - > channelno , newstate , callstate2str ( newstate ) ) ; \
c - > ourcallstate = newstate ; \
} while ( 0 )
# else
/* Update call state with no trace. */
# define UPDATE_OURCALLSTATE(pri,c,newstate) c->ourcallstate = newstate
# endif
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 " ;
}
2009-04-14 23:05:21 +08:00
static char * pritype ( int type )
{
switch ( type ) {
case PRI_CPE :
return " CPE " ;
break ;
case PRI_NETWORK :
return " NET " ;
break ;
default :
return " UNKNOWN " ;
}
}
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 ) {
2005-05-23 23:06:33 +08:00
pri_error ( pri , " !! Not PRI type!? \n " ) ;
2003-02-12 21:59:23 +08:00
return - 1 ;
}
# endif
# ifndef NOAUTO_CHANNEL_SELECTION_SUPPORT
2008-05-08 03:51:44 +08:00
if ( pri - > bri ) {
if ( ! ( ie - > data [ 0 ] & 3 ) )
2005-03-02 23:56:11 +08:00
call - > justsignalling = 1 ;
2008-05-08 03:51:44 +08:00
else
call - > channelno = ie - > data [ 0 ] & 3 ;
} else {
switch ( ie - > data [ 0 ] & 3 ) {
case 0 :
call - > justsignalling = 1 ;
break ;
case 1 :
break ;
default :
pri_error ( pri , " !! 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 ;
2005-05-19 22:06:43 +08:00
call - > ds1explicit = 1 ;
2001-05-13 00:41:32 +08:00
pos + + ;
2005-05-19 22:06:43 +08:00
} else
call - > ds1explicit = 0 ;
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 ) {
2005-05-23 23:06:33 +08:00
pri_error ( pri , " !! 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 ) {
2005-05-23 23:06:33 +08:00
pri_error ( pri , " !! 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 ;
2008-10-18 00:13:42 +08:00
if ( pri - > chan_mapping_logical & & call - > channelno > 15 )
call - > channelno + + ;
2001-05-13 00:41:32 +08:00
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 ;
2008-05-08 03:51:44 +08:00
else if ( pri - > bri ) {
ie - > data [ pos ] = 0x80 ;
if ( call - > channelno > - 1 )
ie - > data [ pos ] | = ( call - > channelno & 0x3 ) ;
} else
2004-06-05 14:50:55 +08:00
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 ;
}
2005-09-17 01:15:57 +08:00
if ( ( ( pri - > switchtype ! = PRI_SWITCH_QSIG ) & & ( call - > ds1no > 0 ) ) | | call - > ds1explicit ) {
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 + + ;
2008-05-08 03:51:44 +08:00
if ( pri - > bri )
return pos + 2 ;
2001-05-13 00:41:32 +08:00
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 */
2008-10-18 00:13:42 +08:00
if ( pri - > chan_mapping_logical & & call - > channelno > 16 )
ie - > data [ pos + + ] = 0x80 | ( call - > channelno - 1 ) ;
else
ie - > data [ pos + + ] = 0x80 | call - > channelno ;
2001-05-13 00:41:32 +08:00
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 ;
}
2005-05-23 23:06:33 +08:00
pri_error ( pri , " !! 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 [ ] = {
2008-06-05 01:02:12 +08:00
" No channel selected " , " B1 channel " , " B2 channel " , " Any channel selected " ,
2003-02-12 21:59:23 +08:00
" No channel selected " , " As indicated in following octets " , " Reserved " , " Any channel selected "
} ;
2006-07-21 23:55:54 +08:00
pri_message ( pri , " %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 ) ;
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %c ChanSel: %s \n " ,
2003-02-12 21:59:23 +08:00
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 */
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %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 */
2006-07-21 23:55:54 +08:00
pri_message ( pri , " %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 + + ;
2009-04-14 23:05:21 +08:00
pri_message ( pri , " %c Ext: %d Channel: %d Type: %s] \n " , prefix , ( ie - > data [ pos ] & 0x80 ) > > 7 ,
( ie - > data [ pos ] ) & 0x7f , pritype ( pri - > localtype ) ) ;
2001-05-13 00:41:32 +08:00
} else {
pos + + ;
/* Map specified */
for ( x = 0 ; x < 3 ; x + + ) {
res < < = 8 ;
res | = ie - > data [ pos + + ] ;
}
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %c Map: %s ] \n " , prefix , binary ( res , 24 ) ) ;
2001-05-13 00:41:32 +08:00
}
2005-05-23 23:06:33 +08:00
} else pri_message ( pri , " ] \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
{
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %c Restart Indentifier (len=%2d) [ Ext: %d Spare: %d Resetting %s (%d) ] \n " ,
2004-06-14 11:29:19 +08:00
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 :
2005-05-23 23:06:33 +08:00
pri_error ( pri , " !! 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 [ ] = {
2008-02-19 04:31:38 +08:00
{ PRI_LAYER_1_ITU_RATE_ADAPT , " V.110 Rate Adaption " } ,
2001-12-08 03:45:45 +08:00
{ 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 " } ,
2008-02-19 04:31:38 +08:00
{ PRI_LAYER_1_H223_H245 , " H.223/H.245 Multimedia " } ,
2001-12-08 03:45:45 +08:00
{ 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 [ ] = {
2008-02-19 04:31:38 +08:00
{ PRI_RATE_ADAPT_9K6 , " 9.6 kbit/s " } ,
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 * 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
}
2008-02-19 04:31:38 +08:00
static char * int_rate2str ( int proto )
{
static struct msgtype protos [ ] = {
{ PRI_INT_RATE_8K , " 8 kbit/s " } ,
{ PRI_INT_RATE_16K , " 16 kbit/s " } ,
{ PRI_INT_RATE_32K , " 32 kbit/s " } ,
} ;
return code2str ( proto , protos , sizeof ( protos ) / sizeof ( protos [ 0 ] ) ) ;
}
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 ;
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %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 ) ) ;
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %c Ext: %d Trans mode/rate: %s (%d) \n " , prefix , ( ie - > data [ 1 ] & 0x80 ) > > 7 , mode2str ( ie - > data [ 1 ] & 0x7f ) , ie - > data [ 1 ] & 0x7f ) ;
2008-02-19 04:31:38 +08:00
/* octet 4.1 exists iff mode/rate is multirate */
2001-05-13 00:41:32 +08:00
if ( ( ie - > data [ 1 ] & 0x7f ) = = 0x18 ) {
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %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 + + ;
}
2008-01-12 00:34:44 +08:00
2008-02-19 04:31:38 +08:00
/* don't count the IE num and length as part of the data */
len - = 2 ;
/* Look for octet 5; this is identified by bits 5,6 == 01 */
if ( pos < len & &
( ie - > data [ pos ] & 0x60 ) = = 0x20 ) {
/* although the layer1 is only the bottom 5 bits of the byte,
previous versions of this library passed bits 5 & 6 through
too , so we have to do the same for binary compatability */
u_int8_t layer1 = ie - > data [ pos ] & 0x7f ;
pri_message ( pri , " %c User information layer 1: %s (%d) \n " ,
prefix , l12str ( layer1 ) , layer1 ) ;
2001-05-13 00:41:32 +08:00
pos + + ;
2008-02-19 04:31:38 +08:00
/* octet 5a? */
if ( pos < len & & ! ( ie - > data [ pos - 1 ] & 0x80 ) ) {
int ra = ie - > data [ pos ] & 0x7f ;
pri_message ( pri , " %c Async: %d, Negotiation: %d, "
" User rate: %s (%#x) \n " ,
prefix ,
ra & PRI_RATE_ADAPT_ASYNC ? 1 : 0 ,
ra & PRI_RATE_ADAPT_NEGOTIATION_POSS ? 1 : 0 ,
ra2str ( ra & PRI_RATE_USER_RATE_MASK ) ,
ra & PRI_RATE_USER_RATE_MASK ) ;
pos + + ;
}
/* octet 5b? */
if ( pos < len & & ! ( ie - > data [ pos - 1 ] & 0x80 ) ) {
u_int8_t data = ie - > data [ pos ] ;
if ( layer1 = = PRI_LAYER_1_ITU_RATE_ADAPT ) {
pri_message ( pri , " %c Intermediate rate: %s (%d), "
" NIC on Tx: %d, NIC on Rx: %d, "
" Flow control on Tx: %d, "
" Flow control on Rx: %d \n " ,
prefix , int_rate2str ( ( data & 0x60 ) > > 5 ) ,
( data & 0x60 ) > > 5 ,
( data & 0x10 ) ? 1 : 0 ,
( data & 0x08 ) ? 1 : 0 ,
( data & 0x04 ) ? 1 : 0 ,
( data & 0x02 ) ? 1 : 0 ) ;
} else if ( layer1 = = PRI_LAYER_1_V120_RATE_ADAPT ) {
pri_message ( pri , " %c Hdr: %d, Multiframe: %d, Mode: %d, "
" LLI negot: %d, Assignor: %d, "
" In-band neg: %d \n " , prefix ,
( data & 0x40 ) ? 1 : 0 ,
( data & 0x20 ) ? 1 : 0 ,
( data & 0x10 ) ? 1 : 0 ,
( data & 0x08 ) ? 1 : 0 ,
( data & 0x04 ) ? 1 : 0 ,
( data & 0x02 ) ? 1 : 0 ) ;
} else {
pri_message ( pri , " %c Unknown octet 5b: 0x%x \n " , data ) ;
}
pos + + ;
}
/* octet 5c? */
if ( pos < len & & ! ( ie - > data [ pos - 1 ] & 0x80 ) ) {
u_int8_t data = ie - > data [ pos ] ;
const char * stop_bits [ ] = { " ? " , " 1 " , " 1.5 " , " 2 " } ;
const char * data_bits [ ] = { " ? " , " 5 " , " 7 " , " 8 " } ;
const char * parity [ ] = { " Odd " , " ? " , " Even " , " None " ,
" zero " , " one " , " ? " , " ? " } ;
pri_message ( pri , " %c Stop bits: %s, data bits: %s, "
" parity: %s \n " , prefix ,
stop_bits [ ( data & 0x60 ) > > 5 ] ,
data_bits [ ( data & 0x18 ) > > 3 ] ,
parity [ ( data & 0x7 ) ] ) ;
pos + + ;
}
/* octet 5d? */
if ( pos < len & & ! ( ie - > data [ pos - 1 ] & 0x80 ) ) {
u_int8_t data = ie - > data [ pos ] ;
pri_message ( pri , " %c Duplex mode: %d, modem type: %d \n " ,
prefix , ( data & 0x40 ) ? 1 : 0 , data & 0x3F ) ;
pos + + ;
}
}
/* Look for octet 6; this is identified by bits 5,6 == 10 */
if ( pos < len & &
( ie - > data [ pos ] & 0x60 ) = = 0x40 ) {
pri_message ( pri , " %c User information layer 2: %s (%d) \n " ,
prefix , l22str ( ie - > data [ pos ] & 0x1f ) ,
ie - > data [ pos ] & 0x1f ) ;
2001-05-13 00:41:32 +08:00
pos + + ;
2008-02-19 04:31:38 +08:00
}
/* Look for octet 7; this is identified by bits 5,6 == 11 */
if ( pos < len & & ( ie - > data [ pos ] & 0x60 ) = = 0x60 ) {
pri_message ( pri , " %c User information layer 3: %s (%d) \n " ,
prefix , l32str ( ie - > data [ pos ] & 0x1f ) ,
ie - > data [ pos ] & 0x1f ) ;
2001-05-13 00:41:32 +08:00
pos + + ;
2008-02-19 04:31:38 +08:00
/* octets 7a and 7b? */
if ( pos + 1 < len & & ! ( ie - > data [ pos - 1 ] & 0x80 ) & &
! ( ie - > data [ pos ] & 0x80 ) ) {
unsigned int proto ;
proto = ( ( ie - > data [ pos ] & 0xF ) < < 4 ) |
( ie - > data [ pos + 1 ] & 0xF ) ;
pri_message ( pri , " %c Network layer: 0x%x \n " , prefix ,
proto ) ;
pos + = 2 ;
}
2001-05-13 00:41:32 +08:00
}
}
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 ) {
2005-05-23 23:06:33 +08:00
pri_error ( pri , " !! 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 ;
2008-02-19 04:31:38 +08:00
/* octet 4.1 exists iff mode/rate is multirate */
if ( call - > transmoderate = = TRANS_MODE_MULTIRATE ) {
call - > transmultiple = ie - > data [ pos + + ] & 0x7f ;
}
/* Look for octet 5; this is identified by bits 5,6 == 01 */
if ( pos < len & &
( ie - > data [ pos ] & 0x60 ) = = 0x20 ) {
/* although the layer1 is only the bottom 5 bits of the byte,
previous versions of this library passed bits 5 & 6 through
too , so we have to do the same for binary compatability */
2001-05-13 00:41:32 +08:00
call - > userl1 = ie - > data [ pos ] & 0x7f ;
pos + + ;
2008-02-19 04:31:38 +08:00
/* octet 5a? */
if ( pos < len & & ! ( ie - > data [ pos - 1 ] & 0x80 ) ) {
call - > rateadaption = ie - > data [ pos ] & 0x7f ;
pos + + ;
}
/* octets 5b through 5d? */
while ( pos < len & & ! ( ie - > data [ pos - 1 ] & 0x80 ) ) {
pos + + ;
}
}
/* Look for octet 6; this is identified by bits 5,6 == 10 */
if ( pos < len & &
( ie - > data [ pos ] & 0x60 ) = = 0x40 ) {
call - > userl2 = ie - > data [ pos + + ] & 0x1f ;
}
/* Look for octet 7; this is identified by bits 5,6 == 11 */
if ( pos < len & &
( ie - > data [ pos ] & 0x60 ) = = 0x60 ) {
call - > userl3 = ie - > data [ pos + + ] & 0x1f ;
2001-05-13 00:41:32 +08:00
}
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 ;
2008-02-19 04:31:38 +08:00
int pos ;
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 ;
2008-05-08 03:51:44 +08:00
if ( pri - > subchannel & & ! pri - > bri ) {
2004-06-06 09:21:41 +08:00
/* 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
ie - > data [ 0 ] = 0x80 | tc ;
ie - > data [ 1 ] = call - > transmoderate | 0x80 ;
2008-02-19 04:31:38 +08:00
pos = 2 ;
/* octet 4.1 exists iff mode/rate is multirate */
if ( call - > transmoderate = = TRANS_MODE_MULTIRATE ) {
ie - > data [ pos + + ] = call - > transmultiple | 0x80 ;
}
if ( ( tc & PRI_TRANS_CAP_DIGITAL ) & & ( pri - > switchtype = = PRI_SWITCH_EUROISDN_E1 ) & &
( call - > transmoderate = = TRANS_MODE_PACKET ) ) {
2004-04-17 02:05:41 +08:00
/* Apparently EuroISDN switches don't seem to like user layer 2/3 */
return 4 ;
}
2009-03-05 04:31:20 +08:00
if ( ( tc & PRI_TRANS_CAP_DIGITAL ) & & ( call - > transmoderate = = TRANS_MODE_64_CIRCUIT ) ) {
/* Unrestricted digital 64k data calls don't use 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 ) ) {
2008-02-19 04:31:38 +08:00
ie - > data [ pos + + ] = call - > userl1 | 0x80 ; /* XXX Ext bit? XXX */
2004-02-08 08:20:18 +08:00
if ( call - > userl1 = = PRI_LAYER_1_ITU_RATE_ADAPT ) {
2008-02-19 04:31:38 +08:00
ie - > data [ pos + + ] = call - > rateadaption | 0x80 ;
2004-02-08 08:20:18 +08:00
}
2008-02-19 04:31:38 +08:00
return pos + 2 ;
}
ie - > data [ pos + + ] = 0xa0 | ( call - > userl1 & 0x1f ) ;
if ( call - > userl1 = = PRI_LAYER_1_ITU_RATE_ADAPT ) {
ie - > data [ pos - 1 ] & = ~ 0x80 ; /* clear EXT bit in octet 5 */
ie - > data [ pos + + ] = call - > rateadaption | 0x80 ;
}
}
if ( call - > userl2 ! = - 1 )
ie - > data [ pos + + ] = 0xc0 | ( call - > userl2 & 0x1f ) ;
if ( call - > userl3 ! = - 1 )
ie - > data [ pos + + ] = 0xe0 | ( call - > userl3 & 0x1f ) ;
return pos + 2 ;
2001-05-13 00:41:32 +08:00
}
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 )
{
2006-02-18 02:54:20 +08:00
if ( ( len < 0 ) | | ( len > maxlen - 1 ) ) {
2001-05-13 00:41:32 +08:00
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 ) ;
2006-07-21 23:55:54 +08:00
pri_message ( pri , " %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 ) ;
2006-07-21 23:55:54 +08:00
pri_message ( pri , " %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 ) ;
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %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 )
2006-07-21 23:55:54 +08:00
pri_message ( pri , " %c Presentation: %s (%d) '%s' ] \n " , prefix , pri_pres2str ( 0 ) , 0 , cnum ) ;
2004-06-14 11:29:19 +08:00
else
2006-07-21 23:55:54 +08:00
pri_message ( pri , " %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 ] ;
2006-02-18 02:54:20 +08:00
q931_get_number ( cnum , sizeof ( cnum ) , ie - > data + 1 , len - 3 ) ;
2006-07-21 23:55:54 +08:00
pri_message ( pri , " %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 */
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %c Redirecting Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d) " ,
2004-06-14 11:29:19 +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 ) ;
break ;
case 1 : /* Octet 3a */
2006-07-21 23:55:54 +08:00
pri_message ( pri , " \n %c Ext: %d Presentation: %s (%d) " ,
2004-06-14 11:29:19 +08:00
prefix , ie - > data [ 1 ] > > 7 , pri_pres2str ( ie - > data [ 1 ] & 0x7f ) , ie - > data [ 1 ] & 0x7f ) ;
break ;
case 2 : /* Octet 3b */
2006-07-21 23:55:54 +08:00
pri_message ( pri , " \n %c Ext: %d Reason: %s (%d) " ,
2004-06-14 11:29:19 +08:00
prefix , ie - > data [ 2 ] > > 7 , redirection_reason2str ( ie - > data [ 2 ] & 0x7f ) , ie - > data [ 2 ] & 0x7f ) ;
break ;
}
2009-04-22 06:08:45 +08:00
} while ( ! ( ie - > data [ i + + ] & 0x80 ) ) ;
2004-06-14 11:29:19 +08:00
q931_get_number ( cnum , sizeof ( cnum ) , ie - > data + i , ie - > len - i ) ;
2006-07-21 23:55:54 +08:00
pri_message ( pri , " '%s' ] \n " , cnum ) ;
2004-06-14 11:29:19 +08:00
}
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 */
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %c Connected Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d) " ,
2004-06-14 11:29:19 +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 ) ;
break ;
case 1 : /* Octet 3a */
2006-07-21 23:55:54 +08:00
pri_message ( pri , " \n %c Ext: %d Presentation: %s (%d) " ,
2004-06-14 11:29:19 +08:00
prefix , ie - > data [ 1 ] > > 7 , pri_pres2str ( ie - > data [ 1 ] & 0x7f ) , ie - > data [ 1 ] & 0x7f ) ;
break ;
}
2009-04-22 06:08:45 +08:00
} while ( ! ( ie - > data [ i + + ] & 0x80 ) ) ;
2004-06-14 11:29:19 +08:00
q931_get_number ( cnum , sizeof ( cnum ) , ie - > data + i , ie - > len - i ) ;
2006-07-21 23:55:54 +08:00
pri_message ( pri , " '%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 ;
}
2009-04-22 06:08:45 +08:00
} 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 ;
2005-06-22 04:37:22 +08:00
if ( call - > redirectingnum & & * call - > redirectingnum ) {
2004-10-31 04:13:20 +08:00
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 ) ;
2006-07-21 23:55:54 +08:00
pri_message ( pri , " %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 */
2006-02-18 02:54:20 +08:00
q931_get_number ( ( unsigned char * ) call - > callingsubaddr , sizeof ( call - > callingsubaddr ) , ie - > data + 1 , len - 3 ) ;
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 ;
2005-06-22 04:37:22 +08:00
if ( * call - > callednum )
2001-05-13 00:41:32 +08:00
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
{
2005-06-22 04:37:22 +08:00
u_int8_t * data ;
size_t length ;
2003-02-12 21:59:23 +08:00
2005-07-12 10:33:25 +08:00
if ( ie - > data [ 0 ] & 0x80 ) {
2005-06-22 04:37:22 +08:00
data = ie - > data + 1 ;
length = len - 3 ;
2005-07-12 10:33:25 +08:00
call - > callerpres = 0 ; /* PI presentation allowed SI user-provided, not screened */
} else {
2005-06-22 04:37:22 +08:00
data = ie - > data + 2 ;
length = len - 4 ;
call - > callerpres = ie - > data [ 1 ] & 0x7f ;
}
if ( call - > callerpres = = PRES_ALLOWED_NETWORK_NUMBER | |
call - > callerpres = = PRES_PROHIB_NETWORK_NUMBER ) {
q931_get_number ( ( u_int8_t * ) call - > callerani , sizeof ( call - > callerani ) , data , length ) ;
2005-07-12 10:33:25 +08:00
call - > callerplanani = ie - > data [ 0 ] & 0x7f ;
2005-06-22 04:37:22 +08:00
2005-07-12 10:33:25 +08:00
if ( ! * call - > callernum ) { /*Copy ANI to CallerID if CallerID is not already set */
2005-06-22 06:47:39 +08:00
libpri_copy_string ( call - > callernum , call - > callerani , sizeof ( call - > callernum ) ) ;
2005-07-12 10:33:25 +08:00
call - > callerplan = call - > callerplanani ;
}
} else {
2005-06-22 04:37:22 +08:00
q931_get_number ( ( u_int8_t * ) call - > callernum , sizeof ( call - > callernum ) , data , length ) ;
2005-07-12 10:33:25 +08:00
call - > callerplan = ie - > data [ 0 ] & 0x7f ;
}
2005-04-01 04:56:52 +08:00
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 ;
2005-06-22 04:37:22 +08:00
if ( * 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 ;
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %c User-User Information (len=%2d) [ " , prefix , len ) ;
2004-01-29 05:02:23 +08:00
for ( x = 0 ; x < ie - > len ; x + + )
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %02x " , ie - > data [ x ] & 0x7f ) ;
pri_message ( pri , " ] \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 ;
}
2005-10-22 04:20:22 +08:00
static FUNC_SEND ( transmit_user_user )
{
int datalen = strlen ( call - > useruserinfo ) ;
if ( datalen > 0 ) {
/* Restricted to 35 characters */
if ( msgtype = = Q931_USER_INFORMATION ) {
if ( datalen > 260 )
datalen = 260 ;
} else {
if ( datalen > 35 )
datalen = 35 ;
}
ie - > data [ 0 ] = 4 ; /* IA5 characters */
memcpy ( & ie - > data [ 1 ] , call - > useruserinfo , datalen ) ;
call - > useruserinfo [ 0 ] = ' \0 ' ;
return datalen + 3 ;
}
return 0 ;
}
2009-04-14 23:05:21 +08:00
static FUNC_DUMP ( dump_change_status )
{
int x ;
pri_message ( pri , " %c Change Status Information (len=%2d) [ " , prefix , len ) ;
for ( x = 0 ; x < ie - > len ; x + + ) {
pri_message ( pri , " %02x " , ie - > data [ x ] & 0x7f ) ;
}
pri_message ( pri , " ] \n " ) ;
}
static FUNC_RECV ( receive_change_status )
{
call - > changestatus = ie - > data [ 0 ] & 0x0f ;
return 0 ;
}
static FUNC_SEND ( transmit_change_status )
{
ie - > data [ 0 ] = 0xc0 | call - > changestatus ;
return 3 ;
}
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
{
2006-07-21 23:55:54 +08:00
pri_message ( pri , " %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 ) ;
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %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 ;
2006-04-01 06:37:46 +08:00
2006-06-09 06:34:25 +08:00
if ( ( pri - > switchtype = = PRI_SWITCH_QSIG ) | |
( ( pri - > switchtype = = PRI_SWITCH_EUROISDN_E1 ) & & ( pri - > localtype = = PRI_CPE ) ) | |
! call - > callername [ 0 ] )
2006-04-01 06:37:46 +08:00
return 0 ;
i = 0 ;
if ( pri - > switchtype ! = PRI_SWITCH_EUROISDN_E1 ) {
ie - > data [ 0 ] = 0xb1 ;
+ + i ;
2003-05-29 06:34:59 +08:00
}
2006-04-01 06:37:46 +08:00
memcpy ( ie - > data + i , call - > callername , strlen ( call - > callername ) ) ;
return 2 + i + strlen ( call - > callername ) ;
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 :
2005-05-23 23:06:33 +08:00
pri_error ( pri , " XXX Invalid Progress indicator value received: %02x \n " , ( ie - > data [ 1 ] & 0x7f ) ) ;
2005-01-17 20:58:05 +08:00
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 ) {
2006-01-06 04:50:51 +08:00
if ( ( tmp - > message = = msgtype ) & & ! tmp - > sent )
2005-03-02 23:56:11 +08:00
break ;
}
if ( ! tmp ) /* No APDU found */
return 0 ;
2009-04-22 06:08:45 +08:00
if ( pri - > debug & PRI_DEBUG_APDU ) {
pri_message ( pri , " Adding facility ie contents to send message: \n " ) ;
facility_decode_dump ( pri , tmp - > apdu , tmp - > apdu_len ) ;
}
2006-01-06 04:50:51 +08:00
if ( tmp - > apdu_len > 235 ) { /* TODO: find out how much space we can use */
pri_message ( pri , " Requested APDU (%d bytes) is too long \n " , tmp - > apdu_len ) ;
2005-03-02 23:56:11 +08:00
return 0 ;
}
2009-04-22 06:08:45 +08:00
2006-01-06 04:50:51 +08:00
memcpy ( & ie - > data [ i ] , tmp - > apdu , tmp - > apdu_len ) ;
2005-03-02 23:56:11 +08:00
i + = tmp - > apdu_len ;
2006-01-06 04:50:51 +08:00
tmp - > sent = 1 ;
2005-03-02 23:56:11 +08:00
return i + 2 ;
}
2009-04-22 06:08:45 +08:00
static int receive_facility ( int full_ie , struct pri * ctrl , q931_call * call , int msgtype , q931_ie * ie , int len )
2003-02-12 21:59:23 +08:00
{
2009-04-22 06:08:45 +08:00
struct fac_extension_header header ;
struct rose_message rose ;
const unsigned char * pos ;
const unsigned char * end ;
2004-10-28 04:43:23 +08:00
2009-04-22 06:08:45 +08:00
pos = ie - > data ;
end = ie - > data + ie - > len ;
/* Make sure we have enough room for the protocol profile ie octet(s) */
if ( end < pos + 2 ) {
2006-01-20 06:18:01 +08:00
return - 1 ;
2009-04-22 06:08:45 +08:00
}
switch ( * pos & Q932_PROTOCOL_MASK ) {
2006-01-20 06:18:01 +08:00
case Q932_PROTOCOL_ROSE :
2009-04-22 06:08:45 +08:00
case Q932_PROTOCOL_EXTENSIONS :
2006-01-20 06:18:01 +08:00
break ;
default :
2009-04-22 06:08:45 +08:00
case Q932_PROTOCOL_CMIP :
case Q932_PROTOCOL_ACSE :
if ( ctrl - > debug & PRI_DEBUG_APDU ) {
pri_message ( ctrl ,
" !! Don't know how to handle Q.932 Protocol Profile type 0x%X \n " ,
* pos & Q932_PROTOCOL_MASK ) ;
}
2006-01-20 06:18:01 +08:00
return - 1 ;
2003-02-12 21:59:23 +08:00
}
2009-04-22 06:08:45 +08:00
if ( ! ( * pos & 0x80 ) ) {
/* DMS-100 Service indicator octet - Just ignore for now */
+ + pos ;
}
+ + pos ;
2004-10-28 04:43:23 +08:00
2009-04-22 06:08:45 +08:00
if ( ctrl - > debug & PRI_DEBUG_APDU ) {
asn1_dump ( ctrl , pos , end ) ;
}
pos = fac_dec_extension_header ( ctrl , pos , end , & header ) ;
if ( ! pos ) {
2004-10-28 04:43:23 +08:00
return - 1 ;
2009-04-22 06:08:45 +08:00
}
if ( header . npp_present ) {
if ( ctrl - > debug & PRI_DEBUG_APDU ) {
pri_message ( ctrl ,
" !! Don't know how to handle Network Protocol Profile type 0x%X \n " ,
header . npp ) ;
2004-10-28 04:43:23 +08:00
}
2009-04-22 06:08:45 +08:00
return - 1 ;
2004-10-28 04:43:23 +08:00
}
2009-04-22 06:08:45 +08:00
pos = rose_decode ( ctrl , pos , end , & rose ) ;
if ( ! pos ) {
return - 1 ;
}
switch ( rose . type ) {
case ROSE_COMP_TYPE_INVOKE :
rose_handle_invoke ( ctrl , call , ie , & header , & rose . component . invoke ) ;
break ;
case ROSE_COMP_TYPE_RESULT :
rose_handle_result ( ctrl , call , ie , & header , & rose . component . result ) ;
break ;
case ROSE_COMP_TYPE_ERROR :
rose_handle_error ( ctrl , call , ie , & header , & rose . component . error ) ;
break ;
case ROSE_COMP_TYPE_REJECT :
rose_handle_reject ( ctrl , call , ie , & header , & rose . component . reject ) ;
break ;
default :
return - 1 ;
}
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! */
2008-05-08 03:51:44 +08:00
if ( pri - > subchannel & & ! pri - > bri )
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 ;
2005-05-23 23:06:33 +08:00
pri_error ( pri , " XXX Undefined progress bit: %x \n " , call - > progressmask ) ;
2005-01-17 20:58:05 +08:00
}
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
{
2006-07-21 23:55:54 +08:00
pri_message ( pri , " %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 ;
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %c Call Identity (len=%2d) [ " , prefix , len ) ;
2002-03-18 22:04:47 +08:00
for ( x = 0 ; x < ie - > len ; x + + )
2005-05-23 23:06:33 +08:00
pri_message ( pri , " 0x%02X " , ie - > data [ x ] ) ;
pri_message ( pri , " ] \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
{
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %c Time Date (len=%2d) [ " , prefix , len ) ;
2002-03-18 22:04:47 +08:00
if ( ie - > len > 0 )
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %02d " , ie - > data [ 0 ] ) ;
2002-03-18 22:04:47 +08:00
if ( ie - > len > 1 )
2005-05-23 23:06:33 +08:00
pri_message ( pri , " -%02d " , ie - > data [ 1 ] ) ;
2002-03-18 22:04:47 +08:00
if ( ie - > len > 2 )
2005-05-23 23:06:33 +08:00
pri_message ( pri , " -%02d " , ie - > data [ 2 ] ) ;
2002-03-18 22:04:47 +08:00
if ( ie - > len > 3 )
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %02d " , ie - > data [ 3 ] ) ;
2002-03-18 22:04:47 +08:00
if ( ie - > len > 4 )
2005-05-23 23:06:33 +08:00
pri_message ( pri , " :%02d " , ie - > data [ 4 ] ) ;
2002-03-18 22:04:47 +08:00
if ( ie - > len > 5 )
2005-05-23 23:06:33 +08:00
pri_message ( pri , " :%02d " , ie - > data [ 5 ] ) ;
pri_message ( pri , " ] \n " ) ;
2002-03-18 22:04:47 +08:00
}
2005-03-02 23:56:11 +08:00
static FUNC_DUMP ( dump_keypad_facility )
{
2005-06-22 06:47:39 +08:00
char tmp [ 64 ] ;
2005-03-02 23:56:11 +08:00
if ( ie - > len = = 0 | | ie - > len > sizeof ( tmp ) )
return ;
2005-12-02 01:59:56 +08:00
memcpy ( tmp , ie - > data , ie - > len ) ;
tmp [ ie - > len ] = ' \0 ' ;
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %c Keypad Facility (len=%2d) [ %s ] \n " , prefix , ie - > len , tmp ) ;
2005-03-02 23:56:11 +08:00
}
static FUNC_RECV ( receive_keypad_facility )
{
2005-06-22 06:47:39 +08:00
int mylen ;
2005-03-02 23:56:11 +08:00
if ( ie - > len = = 0 )
return - 1 ;
2005-12-02 01:59:56 +08:00
if ( ie - > len > ( sizeof ( call - > keypad_digits ) - 1 ) )
mylen = ( sizeof ( call - > keypad_digits ) - 1 ) ;
2005-03-02 23:56:11 +08:00
else
mylen = ie - > len ;
2005-12-02 01:59:56 +08:00
memcpy ( call - > keypad_digits , ie - > data , mylen ) ;
call - > keypad_digits [ mylen ] = 0 ;
2005-03-02 23:56:11 +08:00
return 0 ;
}
2005-12-02 01:59:56 +08:00
static FUNC_SEND ( transmit_keypad_facility )
{
int sublen ;
sublen = strlen ( call - > keypad_digits ) ;
if ( sublen > 32 ) {
sublen = 32 ;
call - > keypad_digits [ 32 ] = ' \0 ' ;
}
if ( sublen ) {
2005-12-02 11:59:41 +08:00
libpri_copy_string ( ( char * ) ie - > data , ( char * ) call - > keypad_digits , sizeof ( call - > keypad_digits ) ) ;
2005-12-02 01:59:56 +08:00
/* Make sure we clear the field */
call - > keypad_digits [ 0 ] = ' \0 ' ;
return sublen + 2 ;
} else
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 ) ;
2006-07-13 03:04:12 +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 ' ;
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %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
}
2006-01-06 04:50:51 +08:00
# define CHECK_OVERFLOW(limit) \
if ( tmpptr - tmp + limit > = sizeof ( tmp ) ) { \
* tmpptr = ' \0 ' ; \
pri_message ( pri , " %s " , tmpptr = tmp ) ; \
}
static void dump_ie_data ( struct pri * pri , unsigned char * c , int len )
2003-02-12 21:59:23 +08:00
{
2006-01-06 04:50:51 +08:00
static char hexs [ 16 ] = " 0123456789ABCDEF " ;
char tmp [ 1024 ] , * tmpptr ;
2003-02-12 21:59:23 +08:00
int lastascii = 0 ;
2006-01-06 04:50:51 +08:00
tmpptr = tmp ;
for ( ; len ; - - len , + + c ) {
CHECK_OVERFLOW ( 7 ) ;
2006-01-06 03:33:32 +08:00
if ( isprint ( * c ) ) {
2003-02-12 21:59:23 +08:00
if ( ! lastascii ) {
2006-01-06 04:50:51 +08:00
if ( tmpptr ! = tmp ) {
* tmpptr + + = ' , ' ;
* tmpptr + + = ' ' ;
2003-02-12 21:59:23 +08:00
}
2006-01-06 04:50:51 +08:00
* tmpptr + + = ' \' ' ;
lastascii = 1 ;
2003-02-12 21:59:23 +08:00
}
2006-01-06 04:50:51 +08:00
* tmpptr + + = * c ;
2003-02-12 21:59:23 +08:00
} else {
if ( lastascii ) {
2006-01-06 04:50:51 +08:00
* tmpptr + + = ' \' ' ;
lastascii = 0 ;
2003-02-12 21:59:23 +08:00
}
2006-01-06 04:50:51 +08:00
if ( tmpptr ! = tmp ) {
* tmpptr + + = ' , ' ;
* tmpptr + + = ' ' ;
2003-02-12 21:59:23 +08:00
}
2006-01-06 04:50:51 +08:00
* tmpptr + + = ' 0 ' ;
* tmpptr + + = ' x ' ;
* tmpptr + + = hexs [ ( * c > > 4 ) & 0x0f ] ;
* tmpptr + + = hexs [ ( * c ) & 0x0f ] ;
2003-02-12 21:59:23 +08:00
}
}
if ( lastascii )
2006-01-06 04:50:51 +08:00
* tmpptr + + = ' \' ' ;
* tmpptr = ' \0 ' ;
pri_message ( pri , " %s " , tmp ) ;
2003-02-12 21:59:23 +08:00
}
2004-06-15 06:21:05 +08:00
static FUNC_DUMP ( dump_facility )
2003-02-12 21:59:23 +08:00
{
2006-01-20 06:24:41 +08:00
int dataat = ( ie - > data [ 0 ] & 0x80 ) ? 1 : 2 ;
2009-04-22 06:08:45 +08:00
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %c Facility (len=%2d, codeset=%d) [ " , prefix , len , Q931_IE_CODESET ( full_ie ) ) ;
2006-01-06 04:50:51 +08:00
dump_ie_data ( pri , ie - > data , ie - > len ) ;
2005-05-24 02:15:06 +08:00
pri_message ( NULL , " ] \n " ) ;
2006-01-06 04:50:51 +08:00
if ( ie - > len > 1 ) {
2009-04-22 06:08:45 +08:00
pri_message ( pri , " PROTOCOL %02X \n " , ie - > data [ 0 ] & Q932_PROTOCOL_MASK ) ;
asn1_dump ( pri , ie - > data + dataat , ie - > data + ie - > len ) ;
2006-01-06 04:50:51 +08:00
}
2002-03-18 22:04:47 +08:00
}
2004-06-26 12:37:09 +08:00
static FUNC_DUMP ( dump_network_spec_fac )
{
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %c Network-Specific Facilities (len=%2d) [ " , prefix , ie - > len ) ;
2005-01-17 20:58:05 +08:00
if ( ie - > data [ 0 ] = = 0x00 ) {
2009-04-22 06:08:45 +08:00
pri_message ( pri , " %s " , code2str ( ie - > data [ 1 ] , facilities , ARRAY_LEN ( facilities ) ) ) ;
2005-01-17 20:58:05 +08:00
}
else
2006-01-06 04:50:51 +08:00
dump_ie_data ( pri , ie - > data , ie - > len ) ;
2005-05-23 23:06:33 +08:00
pri_message ( pri , " ] \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 " } ,
2006-02-18 05:19:37 +08:00
{ 2 , " Network Congestion (resource unavailable) " } ,
2001-07-17 20:12:42 +08:00
{ 3 , " Service or Option not Available " } ,
{ 4 , " Service or Option not Implemented " } ,
2006-02-18 05:19:37 +08:00
{ 5 , " Invalid message (e.g. parameter out of range) " } ,
{ 6 , " Protocol Error (e.g. unknown message) " } ,
2001-07-17 20:12:42 +08:00
{ 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 ;
2006-07-21 23:55:54 +08:00
pri_message ( pri , " %c Cause (len=%2d) [ Ext: %d Coding: %s (%d) Spare: %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 ) ;
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %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 + + )
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %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 + + )
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %c Cause data %d: %02x (%d, %s message) \n " , prefix , x - 1 , ie - > data [ x ] , ie - > data [ x ] , msg2str ( ie - > data [ x ] ) ) ;
2005-01-29 06:11:24 +08:00
break ;
2005-01-27 14:05:09 +08:00
case PRI_CAUSE_RECOVERY_ON_TIMER_EXPIRE :
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %c Cause data: " , prefix ) ;
2005-01-27 14:05:09 +08:00
for ( x = 2 ; x < ie - > len ; x + + )
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %02x " , ie - > data [ x ] ) ;
pri_message ( pri , " (Timer T " ) ;
2005-01-27 14:05:09 +08:00
for ( x = 2 ; x < ie - > len ; x + + )
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %c " , ( ( ie - > data [ x ] > = ' ' ) & & ( ie - > data [ x ] < 0x7f ) ) ? ie - > data [ x ] : ' . ' ) ;
pri_message ( pri , " ) \n " ) ;
2005-01-27 14:05:09 +08:00
break ;
default :
2005-01-25 04:57:04 +08:00
for ( x = 2 ; x < ie - > len ; x + + )
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %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
{
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %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
{
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %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-14 10:48:24 +08:00
}
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 )
{
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %c %sLocking Shift (len=%02d): Requested codeset %d \n " , prefix , ( full_ie & 8 ) ? " Non- " : " " , len , full_ie & 7 ) ;
2004-06-17 02:25:35 +08:00
}
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 )
{
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %c Originating Line Information (len=%02d): %s (%d) \n " , prefix , len , lineinfo2str ( ie - > data [ 0 ] ) , ie - > data [ 0 ] ) ;
2004-06-17 02:25:35 +08:00
}
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 ) {
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %c Generic Digits (len=%02d): Invalid length \n " , prefix , len ) ;
2004-11-05 10:12:02 +08:00
return ;
}
encoding = ( ie - > data [ 0 ] > > 5 ) & 7 ;
type = ie - > data [ 0 ] & 0x1F ;
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %c Generic Digits (len=%02d): Encoding %s Type %s \n " , prefix , len , gdencoding2str ( encoding ) , gdtype2str ( type ) ) ;
2004-11-05 10:12:02 +08:00
if ( encoding = = 3 ) { /* Binary */
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %c Don't know how to handle binary encoding \n " ) ;
2004-11-05 10:12:02 +08:00
return ;
}
if ( len = = 3 ) /* No number information */
return ;
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %c Digits: " ) ;
2004-11-05 10:12:02 +08:00
value = 0 ;
for ( idx = 3 ; idx < len ; + + idx ) {
switch ( encoding ) {
case 0 : /* BCD even */
case 1 : /* BCD odd */
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %d " , ie - > data [ idx - 2 ] & 0x0f ) ;
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-05-23 23:06:33 +08:00
pri_message ( pri , " %d " , ( ie - > data [ idx - 2 ] > > 4 ) & 0x0f ) ;
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 */
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %c " , ie - > data [ idx - 2 ] ) ;
2004-11-05 10:12:02 +08:00
value = value * 10 + ie - > data [ idx - 2 ] - ' 0 ' ;
break ;
}
}
switch ( type ) {
case 4 : /* Info Digits */
2005-05-23 23:06:33 +08:00
pri_message ( pri , " - %s " , lineinfo2str ( value ) ) ;
2004-11-05 10:12:02 +08:00
break ;
}
2005-05-23 23:06:33 +08:00
pri_message ( pri , " \n " ) ;
2004-11-05 10:12:02 +08:00
}
static FUNC_RECV ( receive_generic_digits )
{
int encoding ;
int type ;
int idx ;
int value ;
int num_idx ;
char number [ 260 ] ;
if ( len < 3 ) {
2005-05-23 23:06:33 +08:00
pri_error ( pri , " Invalid length of Generic Digits IE \n " ) ;
2004-11-05 10:12:02 +08:00
return - 1 ;
}
encoding = ( ie - > data [ 0 ] > > 5 ) & 7 ;
type = ie - > data [ 0 ] & 0x1F ;
if ( encoding = = 3 ) { /* Binary */
2005-05-23 23:06:33 +08:00
pri_message ( pri , " !! Unable to handle binary encoded Generic Digits IE \n " ) ;
2004-11-05 10:12:02 +08:00
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 )
{
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %c Signal (len=%02d): " , prefix , len ) ;
2005-01-17 20:58:05 +08:00
if ( len < 3 ) {
2005-05-23 23:06:33 +08:00
pri_message ( pri , " Invalid length \n " ) ;
2005-01-17 20:58:05 +08:00
return ;
}
2005-05-23 23:06:33 +08:00
pri_message ( pri , " Signal %s (%d) \n " , signal2str ( ie - > data [ 0 ] ) , ie - > data [ 0 ] ) ;
2005-01-17 20:58:05 +08:00
}
2006-01-06 04:50:51 +08:00
static FUNC_DUMP ( dump_transit_count )
{
/* Defined in ECMA-225 */
pri_message ( pri , " %c Transit Count (len=%02d): " , prefix , len ) ;
if ( len < 3 ) {
pri_message ( pri , " Invalid length \n " ) ;
return ;
}
pri_message ( pri , " Count=%d (0x%02x) \n " , ie - > data [ 0 ] & 0x1f , ie - > data [ 0 ] & 0x1f ) ;
}
2005-01-17 20:58:05 +08:00
2006-07-07 23:35:48 +08:00
static struct ie ies [ ] = {
2004-06-17 02:25:35 +08:00
/* Codeset 0 - Common */
2009-04-14 23:05:21 +08:00
{ 1 , NATIONAL_CHANGE_STATUS , " Change Status " , dump_change_status , receive_change_status , transmit_change_status } ,
2005-01-17 20:58:05 +08:00
{ 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 " } ,
2006-01-06 04:50:51 +08:00
{ 0 , Q931_IE_FACILITY , " Facility " , dump_facility , receive_facility , transmit_facility } ,
2005-01-17 20:58:05 +08:00
{ 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-12-02 01:59:56 +08:00
{ 1 , Q931_IE_KEYPAD_FACILITY , " Keypad Facility " , dump_keypad_facility , receive_keypad_facility , transmit_keypad_facility } ,
2005-01-17 20:58:05 +08:00
{ 0 , Q931_IE_SIGNAL , " Signal " , dump_signal } ,
{ 1 , Q931_IE_SWITCHHOOK , " Switch-hook " } ,
2005-10-22 04:20:22 +08:00
{ 1 , Q931_IE_USER_USER , " User-User " , dump_user_user , receive_user_user , transmit_user_user } ,
2005-01-17 20:58:05 +08:00
{ 1 , Q931_IE_ESCAPE_FOR_EXT , " Escape for Extension " } ,
{ 1 , Q931_IE_CALL_STATUS , " Call Status " } ,
2009-04-14 23:05:21 +08:00
{ 1 , Q931_IE_CHANGE_STATUS , " Change Status " , dump_change_status , receive_change_status , transmit_change_status } ,
2005-01-17 20:58:05 +08:00
{ 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 } ,
2006-01-06 04:50:51 +08:00
/* Codeset 4 - Q.SIG specific */
{ 1 , QSIG_IE_TRANSIT_COUNT | Q931_CODESET ( 4 ) , " Transit Count " , dump_transit_count } ,
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 " ;
}
2009-04-14 23:05:21 +08:00
static char * maintenance_msg2str ( int msg )
{
unsigned int x ;
for ( x = 0 ; x < sizeof ( maintenance_msgs ) / sizeof ( maintenance_msgs [ 0 ] ) ; x + + ) {
if ( maintenance_msgs [ x ] . msgnum = = msg )
return maintenance_msgs [ x ] . name ;
}
return " Unknown Message Type " ;
}
2001-05-13 00:41:32 +08:00
static inline int q931_cr ( q931_h * h )
{
int cr = 0 ;
int x ;
if ( h - > crlen > 3 ) {
2005-05-23 23:06:33 +08:00
pri_error ( NULL , " 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 :
2005-05-23 23:06:33 +08:00
pri_error ( NULL , " Call Reference Length not supported: %d \n " , h - > crlen ) ;
2001-05-13 00:41:32 +08:00
}
return cr ;
}
2005-05-23 23:06:33 +08:00
static inline void q931_dumpie ( struct pri * pri , 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 ;
2006-06-02 22:34:20 +08:00
char * buf = malloc ( ielen ( ie ) * 3 + 1 ) ;
int buflen = 0 ;
2004-06-14 11:29:19 +08:00
2006-06-02 22:34:20 +08:00
buf [ 0 ] = ' \0 ' ;
2004-06-15 06:21:05 +08:00
if ( ! ( ie - > ie & 0x80 ) ) {
2006-06-02 22:34:20 +08:00
buflen + = sprintf ( buf , " %02x " , ielen ( ie ) - 2 ) ;
2004-06-15 06:21:05 +08:00
for ( x = 0 ; x + 2 < ielen ( ie ) ; + + x )
2006-06-02 22:34:20 +08:00
buflen + = sprintf ( buf + buflen , " %02x " , ie - > data [ x ] ) ;
2004-06-14 11:29:19 +08:00
}
2006-06-02 22:34:20 +08:00
pri_message ( pri , " %c [%02x%s] \n " , prefix , ie - > ie , buf ) ;
free ( buf ) ;
2004-06-14 11:29:19 +08:00
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 ;
2009-04-22 06:08:45 +08:00
for ( x = 0 ; x < ARRAY_LEN ( ies ) ; + + 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 )
2005-05-23 23:06:33 +08:00
ies [ x ] . dump ( full_ie , pri , ie , ielen ( ie ) , prefix ) ;
2001-05-13 00:41:32 +08:00
else
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %c IE: %s (len = %d) \n " , prefix , ies [ x ] . name , ielen ( ie ) ) ;
2001-05-13 00:41:32 +08:00
return ;
}
2006-01-06 04:50:51 +08:00
pri_error ( pri , " !! %c Unknown IE %d (cs%d, len = %d) \n " , prefix , Q931_IE_IE ( base_ie ) , Q931_IE_CODESET ( base_ie ) , ielen ( ie ) ) ;
2001-05-13 00:41:32 +08:00
}
2009-05-08 00:21:24 +08:00
static q931_call * q931_getcall ( struct pri * ctrl , int cr )
2001-05-13 00:41:32 +08:00
{
2009-05-08 00:21:24 +08:00
q931_call * cur ;
q931_call * prev ;
2008-05-08 03:51:44 +08:00
struct pri * master ;
/* Find the master - He has the call pool */
2009-05-08 00:21:24 +08:00
if ( ctrl - > master ) {
master = ctrl - > master ;
} else {
master = ctrl ;
}
2008-05-08 03:51:44 +08:00
cur = * master - > callpool ;
2001-05-13 00:41:32 +08:00
prev = NULL ;
2009-05-08 00:21:24 +08:00
while ( cur ) {
if ( cur - > cr = = cr ) {
2001-05-13 00:41:32 +08:00
return cur ;
2009-05-08 00:21:24 +08:00
}
2001-05-13 00:41:32 +08:00
prev = cur ;
cur = cur - > next ;
}
2009-05-08 00:21:24 +08:00
2001-05-13 00:41:32 +08:00
/* No call exists, make a new one */
2009-05-08 00:21:24 +08:00
if ( ctrl - > debug & PRI_DEBUG_Q931_STATE ) {
pri_message ( ctrl , " -- Making new call for cr %d \n " , cr ) ;
}
cur = calloc ( 1 , sizeof ( * cur ) ) ;
if ( ! cur ) {
2008-05-08 03:51:44 +08:00
return NULL ;
2009-05-08 00:21:24 +08:00
}
2008-05-08 03:51:44 +08:00
2009-05-08 00:21:24 +08:00
/* Initialize call structure. */
2008-05-08 03:51:44 +08:00
cur - > cr = cr ;
2009-05-08 00:21:24 +08:00
cur - > slotmap = - 1 ;
cur - > channelno = - 1 ;
cur - > newcall = 1 ;
cur - > ourcallstate = Q931_CALL_STATE_NULL ;
cur - > peercallstate = Q931_CALL_STATE_NULL ;
2008-05-08 03:51:44 +08:00
/* PRI is set to whoever called us */
2009-05-08 00:21:24 +08:00
if ( ctrl - > bri & & ( ctrl - > localtype = = PRI_CPE ) ) {
2009-05-08 00:06:19 +08:00
/*
* Point to the master to avoid stale pointer problems if
* the TEI is removed later .
*/
cur - > pri = master ;
} else {
2009-05-08 00:21:24 +08:00
cur - > pri = ctrl ;
2009-05-08 00:06:19 +08:00
}
2008-05-08 03:51:44 +08:00
/* Append to end of list */
2009-05-08 00:21:24 +08:00
if ( prev ) {
2008-05-08 03:51:44 +08:00
prev - > next = cur ;
2009-05-08 00:21:24 +08:00
} else {
2008-05-08 03:51:44 +08:00
* master - > callpool = cur ;
2009-05-08 00:21:24 +08:00
}
2001-05-13 00:41:32 +08:00
return cur ;
}
q931_call * q931_new_call ( struct pri * pri )
{
q931_call * cur ;
2008-05-08 03:51:44 +08:00
2001-05-13 00:41:32 +08:00
do {
2004-06-07 11:33:51 +08:00
cur = * pri - > callpool ;
2001-05-13 00:41:32 +08:00
pri - > cref + + ;
2008-05-08 03:51:44 +08:00
if ( ! pri - > bri ) {
if ( pri - > cref > 32767 )
pri - > cref = 1 ;
} else {
if ( pri - > cref > 127 )
pri - > cref = 1 ;
}
2001-05-13 00:41:32 +08:00
while ( cur ) {
if ( cur - > cr = = ( 0x8000 | pri - > cref ) )
break ;
cur = cur - > next ;
}
} while ( cur ) ;
2008-05-08 03:51:44 +08:00
2009-05-08 00:21:24 +08:00
return q931_getcall ( pri , pri - > cref | 0x8000 ) ;
2001-05-13 00:41:32 +08:00
}
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 ;
2008-05-08 03:51:44 +08:00
/* For destroying, make sure we are using the master span, since it maintains the call pool */
for ( ; pri - > master ; pri = pri - > master ) ;
2001-05-13 00:41:32 +08:00
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 )
2005-05-23 23:06:33 +08:00
pri_message ( pri , " 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 ;
}
2005-05-23 23:06:33 +08:00
pri_error ( pri , " Can't destroy call %d! \n " , cr ) ;
2001-05-13 00:41:32 +08:00
}
2009-05-08 00:21:24 +08:00
static void q931_destroycall ( struct pri * ctrl , int cr )
2004-06-07 07:26:43 +08:00
{
2009-05-08 00:21:24 +08:00
q931_destroy ( ctrl , cr , NULL ) ;
2004-06-07 07:26:43 +08:00
}
2009-05-08 00:21:24 +08:00
void __q931_destroycall ( struct pri * ctrl , q931_call * call )
2004-06-07 07:26:43 +08:00
{
2009-05-08 00:21:24 +08:00
if ( ctrl & & call ) {
q931_destroy ( ctrl , 0 , call ) ;
}
2003-08-13 04:16:55 +08:00
}
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 ) ;
}
2009-04-22 06:08:45 +08:00
} while ( res > 0 & & order < ies_count ) ;
2005-01-17 20:58:05 +08:00
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 {
2005-05-23 23:06:33 +08:00
pri_error ( pri , " !! Don't know how to add an IE %s (%d) \n " , ie2str ( ie ) , ie ) ;
2001-05-13 00:41:32 +08:00
return - 1 ;
}
}
}
2005-05-23 23:06:33 +08:00
pri_error ( pri , " !! 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
}
2005-05-23 23:06:33 +08:00
void q931_dump ( struct pri * pri , 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 ;
2009-05-08 00:21:24 +08:00
int cref ;
2002-03-18 22:04:47 +08:00
c = txrx ? ' > ' : ' < ' ;
2005-05-23 23:06:33 +08:00
pri_message ( pri , " %c Protocol Discriminator: %s (%d) len=%d \n " , c , disc2str ( h - > pd ) , h - > pd , len ) ;
2009-05-08 00:21:24 +08:00
cref = q931_cr ( h ) ;
pri_message ( pri , " %c Call Ref: len=%2d (reference %d/0x%X) (%s) \n " ,
c , h - > crlen , cref & 0x7FFF , cref & 0x7FFF ,
( cref & 0x8000 ) ? " 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 ) ;
2009-04-14 23:05:21 +08:00
if ( ( h - > pd = = MAINTENANCE_PROTOCOL_DISCRIMINATOR_1 ) | | ( h - > pd = = MAINTENANCE_PROTOCOL_DISCRIMINATOR_2 ) ) {
pri_message ( pri , " %c Message Type: %s (%d) \n " , c , maintenance_msg2str ( mh - > msg ) , mh - > msg ) ;
} else {
pri_message ( pri , " %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 ) ) ;
2005-05-23 23:06:33 +08:00
q931_dumpie ( pri , cur_codeset , ( q931_ie * ) ( mh - > data + x ) , c ) ;
2004-06-15 06:21:05 +08:00
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 )
2005-05-23 23:06:33 +08:00
pri_error ( pri , " 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 )
2005-05-23 23:06:33 +08:00
pri_message ( pri , " -- 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 )
2005-05-23 23:06:33 +08:00
pri_error ( pri , " !! 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 ;
}
}
}
2005-05-23 23:06:33 +08:00
pri_message ( pri , " !! Unknown IE %d (cs%d, %s) \n " , ie - > ie , codeset , ie2str ( full_ie ) ) ;
2001-05-13 00:41:32 +08:00
return - 1 ;
}
2009-05-08 00:21:24 +08:00
/* Returns header and message header and modifies length in place */
static void init_header ( struct pri * ctrl , q931_call * call , unsigned char * buf , q931_h * * hb , q931_mh * * mhb , int * len , int protodisc )
2001-05-13 00:41:32 +08:00
{
2009-05-08 00:21:24 +08:00
q931_h * h = ( q931_h * ) buf ;
q931_mh * mh ;
unsigned crv ;
2009-04-14 23:05:21 +08:00
if ( protodisc ) {
h - > pd = protodisc ;
} else {
2009-05-08 00:21:24 +08:00
h - > pd = ctrl - > protodisc ;
2009-04-14 23:05:21 +08:00
}
2001-05-13 00:41:32 +08:00
h - > x0 = 0 ; /* Reserved 0 */
2009-05-08 00:21:24 +08:00
if ( ! ctrl - > bri ) {
/* Two bytes of Call Reference. */
h - > crlen = 2 ;
/* Invert the top bit to make it from our sense */
crv = ( unsigned ) call - > cr ;
h - > crv [ 0 ] = ( ( crv > > 8 ) ^ 0x80 ) & 0xff ;
h - > crv [ 1 ] = crv & 0xff ;
if ( ctrl - > subchannel & & ! ctrl - > bri ) {
2008-05-08 03:51:44 +08:00
/* On GR-303, top bit is always 0 */
h - > crv [ 0 ] & = 0x7f ;
}
2001-05-13 00:41:32 +08:00
} else {
2008-05-08 03:51:44 +08:00
h - > crlen = 1 ;
2009-05-08 00:21:24 +08:00
/* Invert the top bit to make it from our sense */
crv = ( unsigned ) call - > cr ;
h - > crv [ 0 ] = ( ( ( crv > > 8 ) ^ 0x80 ) & 0x80 ) | ( crv & 0x7f ) ;
2004-06-05 14:50:55 +08:00
}
2001-05-13 00:41:32 +08:00
* hb = h ;
2009-05-08 00:21:24 +08:00
* len - = 3 ; /* Protocol discriminator, call reference length, message type id */
* len - = h - > crlen ;
mh = ( q931_mh * ) ( h - > contents + h - > crlen ) ;
mh - > f = 0 ;
2001-05-13 00:41:32 +08:00
* mhb = mh ;
}
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 )
2005-05-23 23:06:33 +08:00
q931_dump ( pri , 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 ;
}
2009-05-08 00:21:24 +08:00
static int send_message ( struct pri * ctrl , q931_call * call , int msgtype , int ies [ ] )
2001-05-13 00:41:32 +08:00
{
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 ;
2009-05-08 00:21:24 +08:00
2001-05-13 00:41:32 +08:00
memset ( buf , 0 , sizeof ( buf ) ) ;
len = sizeof ( buf ) ;
2009-05-08 00:21:24 +08:00
init_header ( ctrl , call , buf , & h , & mh , & len , ( msgtype > > 8 ) ) ;
2009-04-14 23:05:21 +08:00
mh - > msg = msgtype & 0x00ff ;
2001-05-13 00:41:32 +08:00
x = 0 ;
2004-06-15 06:21:05 +08:00
codeset = 0 ;
2001-05-13 00:41:32 +08:00
while ( ies [ x ] > - 1 ) {
2009-05-08 00:21:24 +08:00
res = add_ie ( ctrl , call , mh - > msg , ies [ x ] , ( q931_ie * ) ( mh - > data + offset ) , len , & codeset ) ;
2001-05-13 00:41:32 +08:00
if ( res < 0 ) {
2009-05-08 00:21:24 +08:00
pri_error ( ctrl , " !! 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 ;
2009-05-08 00:06:19 +08:00
2009-05-08 00:21:24 +08:00
ctrl = call - > pri ;
if ( ctrl - > bri & & ( ctrl - > localtype = = PRI_CPE ) ) {
2009-05-08 00:06:19 +08:00
/*
* Must use the BRI subchannel structure to send with the correct TEI .
* Note : If the subchannel is NULL then there is no TEI assigned and
* we should not be sending anything out at this time .
*/
2009-05-08 00:21:24 +08:00
ctrl = ctrl - > subchannel ;
2009-05-08 00:06:19 +08:00
}
2009-05-08 00:21:24 +08:00
if ( ctrl ) {
q931_xmit ( ctrl , h , len , 1 ) ;
2009-05-08 00:06:19 +08:00
}
2009-05-08 00:21:24 +08:00
call - > acked = 1 ;
2001-05-13 00:41:32 +08:00
return 0 ;
}
2009-04-14 23:05:21 +08:00
static int maintenance_service_ies [ ] = { Q931_IE_CHANGE_STATUS , Q931_CHANNEL_IDENT , - 1 } ;
int maintenance_service_ack ( struct pri * pri , q931_call * c )
{
return send_message ( pri , c , ( MAINTENANCE_PROTOCOL_DISCRIMINATOR_1 < < 8 ) | NATIONAL_SERVICE_ACKNOWLEDGE , maintenance_service_ies ) ;
}
int maintenance_service ( struct pri * pri , int span , int channel , int changestatus )
{
struct q931_call * c ;
2009-05-08 00:21:24 +08:00
c = q931_getcall ( pri , 0 | 0x8000 ) ;
2009-04-14 23:05:21 +08:00
if ( ! c ) {
return - 1 ;
}
if ( channel > - 1 ) {
channel & = 0xff ;
}
c - > ds1no = span ;
c - > channelno = channel ;
c - > chanflags | = FLAG_EXCLUSIVE ;
c - > changestatus = changestatus ;
return send_message ( pri , c , ( MAINTENANCE_PROTOCOL_DISCRIMINATOR_1 < < 8 ) | NATIONAL_SERVICE , maintenance_service_ies ) ;
}
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 ) {
2005-05-23 23:06:33 +08:00
pri_message ( pri , " 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 ) ;
}
2005-12-02 01:59:56 +08:00
static int information_ies [ ] = { Q931_IE_KEYPAD_FACILITY , Q931_CALLED_PARTY_NUMBER , - 1 } ;
2003-03-25 05:52:51 +08:00
int q931_information ( struct pri * pri , q931_call * c , char digit )
{
2005-12-02 01:59:56 +08:00
c - > callednum [ 0 ] = digit ;
c - > callednum [ 1 ] = ' \0 ' ;
2003-03-25 05:52:51 +08:00
return send_message ( pri , c , Q931_INFORMATION , information_ies ) ;
}
2005-12-02 01:59:56 +08:00
static int keypad_facility_ies [ ] = { Q931_IE_KEYPAD_FACILITY , - 1 } ;
int q931_keypad_facility ( struct pri * pri , q931_call * call , char * digits )
{
libpri_copy_string ( call - > keypad_digits , digits , sizeof ( call - > keypad_digits ) ) ;
return send_message ( pri , call , Q931_INFORMATION , keypad_facility_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 )
{
2006-07-07 05:11:37 +08:00
UPDATE_OURCALLSTATE ( pri , c , 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
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 )
{
2005-07-12 01:48:30 +08:00
if ( ( pri - > switchtype = = PRI_SWITCH_EUROISDN_T1 ) | | ( pri - > switchtype ! = PRI_SWITCH_EUROISDN_E1 ) ) {
if ( ( info > 0x2 ) | | ( info < 0x00 ) )
return 0 ;
}
2004-06-14 10:48:24 +08:00
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
2008-10-18 00:13:42 +08:00
static int call_progress_with_cause_ies [ ] = { Q931_PROGRESS_INDICATOR , Q931_CAUSE , - 1 } ;
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 ;
2005-05-24 23:03:33 +08:00
c - > ds1explicit = ( channel & 0x10000 ) > > 16 ;
2004-06-17 02:04:22 +08:00
channel & = 0xff ;
c - > channelno = channel ;
}
2008-10-18 00:13:42 +08:00
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 */
2005-05-23 23:06:33 +08:00
pri_error ( pri , " XXX Progress message requested but no information is provided \n " ) ;
2005-01-17 20:58:05 +08:00
c - > progressmask = 0 ;
}
2008-10-18 00:13:42 +08:00
2004-05-19 23:34:43 +08:00
c - > alive = 1 ;
return send_message ( pri , c , Q931_PROGRESS , call_progress_ies ) ;
}
2008-10-18 00:13:42 +08:00
int q931_call_progress_with_cause ( struct pri * pri , q931_call * c , int channel , int info , int cause )
{
if ( channel ) {
c - > ds1no = ( channel & 0xff00 ) > > 8 ;
c - > ds1explicit = ( channel & 0x10000 ) > > 16 ;
channel & = 0xff ;
c - > channelno = channel ;
}
if ( info ) {
c - > progloc = LOC_PRIV_NET_LOCAL_USER ;
c - > progcode = CODE_CCITT ;
c - > progressmask = PRI_PROG_INBAND_AVAILABLE ;
} else {
/* PI is mandatory IE for PROGRESS message - Q.931 3.1.8 */
pri_error ( pri , " XXX Progress message requested but no information is provided \n " ) ;
c - > progressmask = 0 ;
}
c - > cause = cause ;
c - > causecode = CODE_CCITT ;
c - > causeloc = LOC_PRIV_NET_LOCAL_USER ;
c - > alive = 1 ;
return send_message ( pri , c , Q931_PROGRESS , call_progress_with_cause_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 ;
2005-05-24 23:03:33 +08:00
c - > ds1explicit = ( channel & 0x10000 ) > > 16 ;
2004-06-05 14:50:55 +08:00
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 ;
2006-07-07 05:11:37 +08:00
UPDATE_OURCALLSTATE ( pri , c , 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
2005-10-26 00:59:59 +08:00
static int alerting_ies [ ] = { Q931_PROGRESS_INDICATOR , Q931_IE_USER_USER , - 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 ;
2006-07-07 05:11:37 +08:00
UPDATE_OURCALLSTATE ( pri , c , 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 ;
2005-05-24 23:03:33 +08:00
c - > ds1explicit = ( channel & 0x10000 ) > > 16 ;
2004-06-05 14:50:55 +08:00
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 ;
2006-07-07 05:11:37 +08:00
UPDATE_OURCALLSTATE ( pri , c , 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
2008-05-08 03:51:44 +08:00
/* T313 expiry, first time */
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 )
2005-05-23 23:06:33 +08:00
pri_message ( pri , " Timed out looking for connect acknowledge \n " ) ;
2003-09-25 14:13:14 +08:00
q931_disconnect ( pri , c , PRI_CAUSE_NORMAL_CLEARING ) ;
}
2008-05-08 03:51:44 +08:00
/* T308 expiry, first time */
2003-09-25 14:13:14 +08:00
static void pri_release_timeout ( void * data )
{
struct q931_call * c = data ;
struct pri * pri = c - > pri ;
if ( pri - > debug & PRI_DEBUG_Q931_STATE )
2005-05-23 23:06:33 +08:00
pri_message ( pri , " Timed out looking for release complete \n " ) ;
2003-09-25 14:13:14 +08:00
c - > t308_timedout + + ;
c - > alive = 1 ;
2008-05-08 03:51:44 +08:00
/* The call to q931_release will re-schedule T308 */
q931_release ( pri , c , c - > cause ) ;
2003-09-25 14:13:14 +08:00
}
2008-05-08 03:51:44 +08:00
/* T308 expiry, second time */
2003-09-25 14:13:14 +08:00
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 )
2005-05-23 23:06:33 +08:00
pri_message ( pri , " Final time-out looking for release complete \n " ) ;
2003-09-25 14:13:14 +08:00
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 . cause = c - > cause ;
2006-06-02 02:00:31 +08:00
pri - > ev . hangup . cref = c - > cr ;
2004-04-06 22:50:19 +08:00
pri - > ev . hangup . call = c ;
2006-06-02 02:00:31 +08:00
pri - > ev . hangup . aoc_units = c - > aoc_units ;
libpri_copy_string ( pri - > ev . hangup . useruserinfo , c - > useruserinfo , sizeof ( pri - > ev . hangup . useruserinfo ) ) ;
2004-04-06 22:50:19 +08:00
q931_hangup ( pri , c , c - > cause ) ;
2003-09-25 14:13:14 +08:00
}
2008-05-08 03:51:44 +08:00
/* T305 expiry, first time */
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 )
2005-05-23 23:06:33 +08:00
pri_message ( pri , " Timed out looking for release \n " ) ;
2003-09-25 14:13:14 +08:00
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 ;
2005-05-24 23:03:33 +08:00
c - > ds1explicit = ( channel & 0x10000 ) > > 16 ;
2004-06-05 14:50:55 +08:00
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 ;
2006-07-21 23:43:31 +08:00
if ( pri - > localtype = = PRI_NETWORK | | pri - > switchtype = = PRI_SWITCH_QSIG )
2006-07-07 05:11:37 +08:00
UPDATE_OURCALLSTATE ( pri , c , Q931_CALL_STATE_ACTIVE ) ;
2006-07-21 23:43:31 +08:00
else
UPDATE_OURCALLSTATE ( pri , c , 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 ;
2006-07-21 23:43:31 +08:00
/* Connect request timer */
2003-09-25 14:13:14 +08:00
if ( c - > retranstimer )
pri_schedule_del ( pri , c - > retranstimer ) ;
2004-09-20 21:29:37 +08:00
c - > retranstimer = 0 ;
2008-05-08 03:51:44 +08:00
if ( ( c - > ourcallstate = = Q931_CALL_STATE_CONNECT_REQUEST ) & & ( pri - > bri | | ( ! 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 ) ;
}
2005-10-22 04:20:22 +08:00
static int release_ies [ ] = { Q931_CAUSE , Q931_IE_USER_USER , - 1 } ;
2001-05-13 00:41:32 +08:00
int q931_release ( struct pri * pri , q931_call * c , int cause )
{
2006-07-07 05:11:37 +08:00
UPDATE_OURCALLSTATE ( pri , c , 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 ;
2009-05-08 00:21:24 +08:00
c = q931_getcall ( pri , 0 | 0x8000 ) ;
2002-04-25 11:51:36 +08:00
if ( ! c )
return - 1 ;
if ( ! channel )
return - 1 ;
c - > ri = 0 ;
2004-06-05 14:50:55 +08:00
c - > ds1no = ( channel & 0xff00 ) > > 8 ;
2005-05-24 23:03:33 +08:00
c - > ds1explicit = ( channel & 0x10000 ) > > 16 ;
2004-06-05 14:50:55 +08:00
channel & = 0xff ;
c - > channelno = channel ;
2002-04-25 11:51:36 +08:00
c - > chanflags & = ~ FLAG_PREFERRED ;
c - > chanflags | = FLAG_EXCLUSIVE ;
2006-07-07 05:11:37 +08:00
UPDATE_OURCALLSTATE ( pri , c , 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 ) ;
}
2005-10-22 04:20:22 +08:00
static int disconnect_ies [ ] = { Q931_CAUSE , Q931_IE_USER_USER , - 1 } ;
2001-05-13 00:41:32 +08:00
int q931_disconnect ( struct pri * pri , q931_call * c , int cause )
{
2006-07-07 05:11:37 +08:00
UPDATE_OURCALLSTATE ( pri , c , 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 ;
}
2007-09-26 05:37:40 +08:00
static int setup_ies [ ] = { Q931_BEARER_CAPABILITY , Q931_CHANNEL_IDENT , Q931_IE_FACILITY , Q931_PROGRESS_INDICATOR , Q931_NETWORK_SPEC_FAC , Q931_DISPLAY ,
Q931_CALLING_PARTY_NUMBER , Q931_CALLED_PARTY_NUMBER , Q931_REDIRECTING_NUMBER , Q931_IE_USER_USER , 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 ;
2008-02-19 04:31:38 +08:00
c - > userl2 = - 1 ;
c - > userl3 = - 1 ;
2004-06-16 23:33:58 +08:00
c - > ds1no = ( req - > channel & 0xff00 ) > > 8 ;
2005-05-24 23:03:33 +08:00
c - > ds1explicit = ( req - > channel & 0x10000 ) > > 16 ;
2004-06-16 23:33:58 +08:00
req - > channel & = 0xff ;
2008-05-08 03:51:44 +08:00
if ( ( pri - > localtype = = PRI_CPE ) & & pri - > subchannel & & ! pri - > bri ) {
2004-06-29 12:28:34 +08:00
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 ) {
2005-06-22 06:47:39 +08:00
libpri_copy_string ( c - > callernum , req - > caller , sizeof ( c - > callernum ) ) ;
2004-06-16 23:33:58 +08:00
c - > callerplan = req - > callerplan ;
if ( req - > callername )
2005-06-22 06:47:39 +08:00
libpri_copy_string ( c - > callername , req - > callername , sizeof ( c - > callername ) ) ;
2003-02-12 21:59:23 +08:00
else
2005-06-22 06:47:39 +08:00
c - > callername [ 0 ] = ' \0 ' ;
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 {
2005-06-22 06:47:39 +08:00
c - > callernum [ 0 ] = ' \0 ' ;
c - > callername [ 0 ] = ' \0 ' ;
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 ) {
2005-06-22 06:47:39 +08:00
libpri_copy_string ( c - > redirectingnum , req - > redirectingnum , sizeof ( c - > redirectingnum ) ) ;
2004-10-31 04:13:20 +08:00
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 {
2005-06-22 06:47:39 +08:00
c - > redirectingnum [ 0 ] = ' \0 ' ;
2004-10-31 04:13:20 +08:00
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 ) {
2005-06-22 06:47:39 +08:00
libpri_copy_string ( c - > callednum , req - > called , sizeof ( c - > callednum ) ) ;
2004-06-16 23:33:58 +08:00
c - > calledplan = req - > calledplan ;
2001-05-13 00:41:32 +08:00
} else
return - 1 ;
2005-10-22 04:20:22 +08:00
if ( req - > useruserinfo )
libpri_copy_string ( c - > useruserinfo , req - > useruserinfo , sizeof ( c - > useruserinfo ) ) ;
2006-01-17 21:44:12 +08:00
else
c - > useruserinfo [ 0 ] = ' \0 ' ;
2005-10-22 04:20:22 +08:00
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 ) ;
2008-05-08 03:51:44 +08:00
if ( pri - > subchannel & & ! pri - > bri )
2004-06-06 09:21:41 +08:00
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 ;
2006-07-07 05:11:37 +08:00
UPDATE_OURCALLSTATE ( pri , c , Q931_CALL_STATE_CALL_INITIATED ) ;
2003-08-07 08:45:04 +08:00
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 ;
}
2005-10-22 04:20:22 +08:00
static int release_complete_ies [ ] = { Q931_IE_USER_USER , - 1 } ;
2001-05-13 00:41:32 +08:00
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 ;
2006-07-07 05:11:37 +08:00
UPDATE_OURCALLSTATE ( pri , c , 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 )
{
2008-05-08 03:51:44 +08:00
if ( pri - > subchannel & & ! pri - > bri ) {
2004-06-07 23:55:39 +08:00
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 )
2005-05-23 23:06:33 +08:00
pri_message ( pri , " NEW_HANGUP DEBUG: Calling q931_hangup, ourstate %s, peerstate %s \n " , callstate2str ( c - > ourcallstate ) , callstate2str ( c - > peercallstate ) ) ;
2003-08-05 09:00:45 +08:00
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_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
2005-05-23 23:06:33 +08:00
pri_error ( pri , " Wierd, doing nothing but this shouldn't happen, ourstate %s, peerstate %s \n " , callstate2str ( c - > ourcallstate ) , callstate2str ( c - > peercallstate ) ) ;
2003-08-05 09:00:45 +08:00
break ;
2007-01-23 06:29:24 +08:00
case Q931_CALL_STATE_ACTIVE :
/* received CONNECT */
q931_disconnect ( pri , c , cause ) ;
break ;
2003-08-05 09:00:45 +08:00
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 */
2005-06-23 03:27:43 +08:00
pri_error ( pri , " q931_hangup shouldn't be called in this state, ourstate %s, peerstate %s \n " , callstate2str ( c - > ourcallstate ) , callstate2str ( c - > peercallstate ) ) ;
2003-08-05 09:00:45 +08:00
break ;
default :
2005-06-23 03:27:43 +08:00
pri_error ( pri , " We're not yet handling hanging up when our state is %d, contact support@digium.com, ourstate %s, peerstate %s \n " ,
c - > ourcallstate ,
callstate2str ( c - > ourcallstate ) ,
callstate2str ( c - > peercallstate ) ) ;
2003-08-05 09:00:45 +08:00
return - 1 ;
}
/* we did handle hangup properly at this point */
return 0 ;
}
2001-05-13 00:41:32 +08:00
2009-04-14 23:05:21 +08:00
static int prepare_to_handle_maintenance_message ( struct pri * pri , q931_mh * mh , q931_call * c )
2001-05-13 00:41:32 +08:00
{
2009-04-14 23:05:21 +08:00
if ( ( ! pri ) | | ( ! mh ) | | ( ! c ) ) {
return - 1 ;
2001-05-13 00:41:32 +08:00
}
2009-04-14 23:05:21 +08:00
/* SERVICE messages are a superset of messages that can take b-channels
* or entire d - channels in and out of service */
switch ( mh - > msg ) {
case NATIONAL_SERVICE :
case NATIONAL_SERVICE_ACKNOWLEDGE :
c - > channelno = - 1 ;
c - > slotmap = - 1 ;
c - > chanflags = 0 ;
c - > ds1no = 0 ;
c - > ri = - 1 ;
c - > changestatus = - 1 ;
break ;
default :
pri_error ( pri , " !! Don't know how to pre-handle maintenance message type '%s' (%d) \n " , maintenance_msg2str ( mh - > msg ) , mh - > msg ) ;
return - 1 ;
}
return 0 ;
}
static int prepare_to_handle_q931_message ( struct pri * pri , q931_mh * mh , q931_call * c )
{
if ( ( ! pri ) | | ( ! mh ) | | ( ! c ) ) {
2001-05-13 00:41:32 +08:00
return - 1 ;
}
2009-04-14 23:05:21 +08:00
2001-05-13 00:41:32 +08:00
switch ( mh - > msg ) {
case Q931_RESTART :
if ( pri - > debug & PRI_DEBUG_Q931_STATE )
2005-05-23 23:06:33 +08:00
pri_message ( pri , " -- 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 :
2005-06-22 06:47:39 +08:00
c - > callername [ 0 ] = ' \0 ' ;
2003-02-12 21:59:23 +08:00
break ;
2001-05-13 00:41:32 +08:00
case Q931_SETUP :
if ( pri - > debug & PRI_DEBUG_Q931_STATE )
2005-05-23 23:06:33 +08:00
pri_message ( pri , " -- 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 ;
2005-06-22 06:47:39 +08:00
c - > callernum [ 0 ] = ' \0 ' ;
c - > callednum [ 0 ] = ' \0 ' ;
c - > callername [ 0 ] = ' \0 ' ;
2005-07-12 10:33:25 +08:00
c - > callerani [ 0 ] = ' \0 ' ;
c - > callerplanani = - 1 ;
c - > redirectingplan = - 1 ;
c - > redirectingpres = - 1 ;
c - > redirectingreason = - 1 ;
c - > origcalledplan = - 1 ;
c - > origcalledpres = - 1 ;
c - > origredirectingreason = - 1 ;
2005-06-22 06:47:39 +08:00
c - > redirectingnum [ 0 ] = ' \0 ' ;
c - > origcallednum [ 0 ] = ' \0 ' ;
c - > redirectingname [ 0 ] = ' \0 ' ;
c - > origcalledname [ 0 ] = ' \0 ' ;
2005-07-12 10:33:25 +08:00
c - > useruserprotocoldisc = - 1 ;
2005-06-22 06:47:39 +08:00
c - > useruserinfo [ 0 ] = ' \0 ' ;
2003-07-26 23:14:44 +08:00
c - > complete = 0 ;
2005-01-17 20:58:05 +08:00
c - > nonisdn = 0 ;
2005-07-12 10:33:25 +08:00
c - > aoc_units = - 1 ;
2005-01-17 20:58:05 +08:00
/* Fall through */
2001-05-13 00:41:32 +08:00
case Q931_CONNECT :
case Q931_ALERTING :
case Q931_PROGRESS :
2005-10-22 04:20:22 +08:00
c - > useruserinfo [ 0 ] = ' \0 ' ;
2005-06-30 01:27:03 +08:00
c - > cause = - 1 ;
2006-07-21 23:55:54 +08:00
/* Fall through */
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 ;
2005-10-22 04:20:22 +08:00
c - > useruserinfo [ 0 ] = ' \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 ;
2005-10-22 04:20:22 +08:00
c - > useruserinfo [ 0 ] = ' \0 ' ;
2006-07-21 23:55:54 +08:00
/* Fall through */
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 :
2005-12-27 21:59:37 +08:00
c - > callednum [ 0 ] = ' \0 ' ;
2003-02-12 21:59:23 +08:00
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 :
2005-05-23 23:06:33 +08:00
pri_error ( pri , " !! 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 :
2006-07-21 23:55:54 +08:00
pri_error ( pri , " !! Don't know how to pre-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 ;
}
2009-04-14 23:05:21 +08:00
return 0 ;
}
int q931_receive ( struct pri * pri , q931_h * h , int len )
{
q931_mh * mh ;
q931_call * c ;
q931_ie * ie ;
unsigned int x ;
int y ;
int res ;
int r ;
int mandies [ MAX_MAND_IES ] ;
int missingmand ;
int codeset , cur_codeset ;
int last_ie [ 8 ] ;
2009-05-08 00:21:24 +08:00
int cref ;
2009-04-14 23:05:21 +08:00
memset ( last_ie , 0 , sizeof ( last_ie ) ) ;
if ( pri - > debug & PRI_DEBUG_Q931_DUMP )
q931_dump ( pri , h , len , 0 ) ;
# ifdef LIBPRI_COUNTERS
pri - > q931_rxcount + + ;
# endif
mh = ( q931_mh * ) ( h - > contents + h - > crlen ) ;
if ( ( h - > pd ! = pri - > protodisc ) & & ( h - > pd ! = MAINTENANCE_PROTOCOL_DISCRIMINATOR_1 ) & & ( h - > pd ! = MAINTENANCE_PROTOCOL_DISCRIMINATOR_2 ) ) {
pri_error ( pri , " Warning: unknown/inappropriate protocol discriminator received (%02x/%d) \n " , h - > pd , h - > pd ) ;
return 0 ;
}
if ( ( ( h - > pd = = MAINTENANCE_PROTOCOL_DISCRIMINATOR_1 ) | | ( h - > pd = = MAINTENANCE_PROTOCOL_DISCRIMINATOR_2 ) ) & & ( ! pri - > service_message_support ) ) {
/* Real service message support has not been enabled (and is OFF in libpri by default),
* so we have to revert to the ' traditional ' KLUDGE of changing byte 4 from a 0xf ( SERVICE )
* to a 0x7 ( SERVICE ACKNOWLEDGE ) */
/* This is the weird maintenance stuff. We majorly
KLUDGE this by changing byte 4 from a 0xf ( SERVICE )
to a 0x7 ( SERVICE ACKNOWLEDGE ) */
h - > raw [ h - > crlen + 2 ] - = 0x8 ;
q931_xmit ( pri , h , len , 1 ) ;
return 0 ;
}
2009-05-08 00:21:24 +08:00
cref = q931_cr ( h ) ;
c = q931_getcall ( pri , cref ) ;
2009-04-14 23:05:21 +08:00
if ( ! c ) {
2009-05-08 00:21:24 +08:00
pri_error ( pri , " Unable to locate call %d \n " , cref ) ;
2009-04-14 23:05:21 +08:00
return - 1 ;
}
/* Preliminary handling */
if ( ( h - > pd = = MAINTENANCE_PROTOCOL_DISCRIMINATOR_1 ) | | ( h - > pd = = MAINTENANCE_PROTOCOL_DISCRIMINATOR_2 ) ) {
prepare_to_handle_maintenance_message ( pri , mh , c ) ;
} else {
prepare_to_handle_q931_message ( pri , mh , c ) ;
}
2006-07-21 23:55:54 +08:00
/* Handle IEs */
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 ) {
2005-05-23 23:06:33 +08:00
pri_error ( pri , " 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 ) )
2005-05-23 23:06:33 +08:00
pri_message ( pri , " XXX Locking shift immediately follows non-locking shift (from %d through %d to %d) XXX \n " , codeset , cur_codeset , y ) ;
2004-06-15 06:21:05 +08:00
if ( y > 0 ) {
if ( ( y < codeset ) & & ( pri - > debug & PRI_DEBUG_Q931_ANOMALY ) )
2005-05-23 23:06:33 +08:00
pri_error ( pri , " !! Trying to locked downshift codeset from %d to %d !! \n " , codeset , y ) ;
2004-06-15 06:21:05 +08:00
codeset = cur_codeset = y ;
}
else {
/* Locking shift to codeset 0 is forbidden by all specifications */
2005-05-23 23:06:33 +08:00
pri_error ( pri , " !! Invalid locking shift to codeset 0 !! \n " ) ;
2004-06-15 06:21:05 +08:00
}
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 ) )
2005-05-23 23:06:33 +08:00
pri_message ( pri , " XXX Out-of-order IE %d at codeset %d (last was %d) \n " , ie - > ie , cur_codeset , last_ie [ cur_codeset ] ) ;
2004-06-15 06:21:05 +08:00
}
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 ) )
2005-05-23 23:06:33 +08:00
pri_message ( pri , " XXX Ignoring IE %d for temporary codeset %d XXX \n " , ie - > ie , cur_codeset ) ;
2004-06-15 06:21:05 +08:00
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 ) ) ) {
2005-05-23 23:06:33 +08:00
pri_error ( pri , " 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 */
2009-04-14 23:05:21 +08:00
if ( ( h - > pd = = MAINTENANCE_PROTOCOL_DISCRIMINATOR_1 ) | | ( h - > pd = = MAINTENANCE_PROTOCOL_DISCRIMINATOR_2 ) ) {
res = post_handle_maintenance_message ( pri , mh , c ) ;
} else {
res = post_handle_q931_message ( pri , mh , c , missingmand ) ;
}
return res ;
}
static int post_handle_maintenance_message ( struct pri * pri , struct q931_mh * mh , struct q931_call * c )
{
/* Do some maintenance stuff */
switch ( mh - > msg ) {
case NATIONAL_SERVICE :
if ( c - > channelno > 0 ) {
pri - > ev . e = PRI_EVENT_SERVICE ;
pri - > ev . service . channel = c - > channelno | ( c - > ds1no < < 8 ) ;
pri - > ev . service . changestatus = 0x0f & c - > changestatus ;
} else {
switch ( 0x0f & c - > changestatus ) {
case SERVICE_CHANGE_STATUS_INSERVICE :
pri - > ev . e = PRI_EVENT_DCHAN_UP ;
q921_dchannel_up ( pri ) ;
break ;
case SERVICE_CHANGE_STATUS_OUTOFSERVICE :
pri - > ev . e = PRI_EVENT_DCHAN_DOWN ;
q921_dchannel_down ( pri ) ;
break ;
default :
pri_error ( pri , " !! Don't know how to handle span service change status '%d' \n " , ( 0x0f & c - > changestatus ) ) ;
return - 1 ;
}
}
maintenance_service_ack ( pri , c ) ;
return Q931_RES_HAVEEVENT ;
case NATIONAL_SERVICE_ACKNOWLEDGE :
if ( c - > channelno > 0 ) {
pri - > ev . e = PRI_EVENT_SERVICE_ACK ;
pri - > ev . service_ack . channel = c - > channelno | ( c - > ds1no < < 8 ) ;
pri - > ev . service_ack . changestatus = 0x0f & c - > changestatus ;
} else {
switch ( 0x0f & c - > changestatus ) {
case SERVICE_CHANGE_STATUS_INSERVICE :
pri - > ev . e = PRI_EVENT_DCHAN_UP ;
q921_dchannel_up ( pri ) ;
break ;
case SERVICE_CHANGE_STATUS_OUTOFSERVICE :
pri - > ev . e = PRI_EVENT_DCHAN_DOWN ;
q921_dchannel_down ( pri ) ;
break ;
default :
pri_error ( pri , " !! Don't know how to handle span service change status '%d' \n " , ( 0x0f & c - > changestatus ) ) ;
return - 1 ;
}
}
return Q931_RES_HAVEEVENT ;
default :
pri_error ( pri , " !! Don't know how to post-handle maintenance message type %s (%d) \n " , maintenance_msg2str ( mh - > msg ) , mh - > msg ) ;
}
return - 1 ;
}
static int post_handle_q931_message ( struct pri * pri , struct q931_mh * mh , struct q931_call * c , int missingmand )
{
int res ;
struct apdu_event * cur = NULL ;
2001-05-13 00:41:32 +08:00
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 ;
}
2006-07-07 05:11:37 +08:00
UPDATE_OURCALLSTATE ( pri , c , Q931_CALL_STATE_RESTART ) ;
2003-08-05 09:00:45 +08:00
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 ;
2005-05-19 22:06:43 +08:00
pri - > ev . restart . channel = c - > channelno | ( c - > ds1no < < 8 ) | ( c - > ds1explicit < < 16 ) ;
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 ;
2006-07-07 05:11:37 +08:00
UPDATE_OURCALLSTATE ( pri , c , 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 ;
2005-05-19 22:06:43 +08:00
pri - > ev . ring . channel = c - > channelno | ( c - > ds1no < < 8 ) | ( c - > ds1explicit < < 16 ) ;
2001-05-13 00:41:32 +08:00
pri - > ev . ring . callingpres = c - > callerpres ;
pri - > ev . ring . callingplan = c - > callerplan ;
2005-07-12 10:33:25 +08:00
pri - > ev . ring . callingplanani = c - > callerplanani ;
2005-09-03 02:37:03 +08:00
pri - > ev . ring . callingplanrdnis = c - > redirectingplan ;
pri - > ev . ring . callingplanorigcalled = c - > origcalledplan ;
2004-09-17 12:02:16 +08:00
pri - > ev . ring . ani2 = c - > ani2 ;
2005-06-22 06:47:39 +08:00
libpri_copy_string ( pri - > ev . ring . callingani , c - > callerani , sizeof ( pri - > ev . ring . callingani ) ) ;
libpri_copy_string ( pri - > ev . ring . callingnum , c - > callernum , sizeof ( pri - > ev . ring . callingnum ) ) ;
libpri_copy_string ( pri - > ev . ring . callingname , c - > callername , sizeof ( pri - > ev . ring . callingname ) ) ;
2001-05-13 00:41:32 +08:00
pri - > ev . ring . calledplan = c - > calledplan ;
2005-06-22 06:47:39 +08:00
libpri_copy_string ( pri - > ev . ring . callingsubaddr , c - > callingsubaddr , sizeof ( pri - > ev . ring . callingsubaddr ) ) ;
libpri_copy_string ( pri - > ev . ring . callednum , c - > callednum , sizeof ( pri - > ev . ring . callednum ) ) ;
libpri_copy_string ( pri - > ev . ring . origcalledname , c - > origcalledname , sizeof ( pri - > ev . ring . origcalledname ) ) ;
libpri_copy_string ( pri - > ev . ring . origcallednum , c - > origcallednum , sizeof ( pri - > ev . ring . origcallednum ) ) ;
2006-06-02 02:00:31 +08:00
libpri_copy_string ( pri - > ev . ring . redirectingnum , c - > redirectingnum , sizeof ( pri - > ev . ring . redirectingnum ) ) ;
libpri_copy_string ( pri - > ev . ring . redirectingname , c - > redirectingname , sizeof ( pri - > ev . ring . redirectingname ) ) ;
libpri_copy_string ( pri - > ev . ring . useruserinfo , c - > useruserinfo , sizeof ( pri - > ev . ring . useruserinfo ) ) ;
2005-10-22 04:20:22 +08:00
c - > useruserinfo [ 0 ] = ' \0 ' ;
2005-04-07 03:42:41 +08:00
pri - > ev . ring . redirectingreason = c - > redirectingreason ;
pri - > ev . ring . origredirectingreason = c - > origredirectingreason ;
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 ;
}
2006-07-07 05:11:37 +08:00
UPDATE_OURCALLSTATE ( pri , c , 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 ;
2005-05-19 22:06:43 +08:00
pri - > ev . ringing . channel = c - > channelno | ( c - > ds1no < < 8 ) | ( c - > ds1explicit < < 16 ) ;
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 ;
2006-06-02 02:00:31 +08:00
libpri_copy_string ( pri - > ev . ringing . useruserinfo , c - > useruserinfo , sizeof ( pri - > ev . ringing . useruserinfo ) ) ;
2005-10-22 04:20:22 +08:00
c - > useruserinfo [ 0 ] = ' \0 ' ;
2007-06-20 02:23:36 +08:00
cur = c - > apdus ;
while ( cur ) {
if ( ! cur - > sent & & cur - > message = = Q931_FACILITY ) {
q931_facility ( pri , c ) ;
break ;
}
cur = cur - > next ;
}
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 ;
}
2006-07-07 05:11:37 +08:00
UPDATE_OURCALLSTATE ( pri , c , 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 ;
2005-05-19 22:06:43 +08:00
pri - > ev . answer . channel = c - > channelno | ( c - > ds1no < < 8 ) | ( c - > ds1explicit < < 16 ) ;
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 ;
2006-06-02 02:00:31 +08:00
libpri_copy_string ( pri - > ev . answer . useruserinfo , c - > useruserinfo , sizeof ( pri - > ev . answer . useruserinfo ) ) ;
2005-10-22 04:20:22 +08:00
c - > useruserinfo [ 0 ] = ' \0 ' ;
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 ;
2005-06-22 06:47:39 +08:00
libpri_copy_string ( pri - > ev . facname . callingname , c - > callername , sizeof ( pri - > ev . facname . callingname ) ) ;
libpri_copy_string ( pri - > ev . facname . callingnum , c - > callernum , sizeof ( pri - > ev . facname . callingnum ) ) ;
2005-05-19 22:06:43 +08:00
pri - > ev . facname . channel = c - > channelno | ( c - > ds1no < < 8 ) | ( c - > ds1explicit < < 16 ) ;
2008-05-08 03:51:44 +08:00
pri - > ev . facname . callingpres = c - > callerpres ;
pri - > ev . facname . callingplan = c - > callerplan ;
2003-02-12 21:59:23 +08:00
pri - > ev . facname . cref = c - > cr ;
pri - > ev . facname . call = c ;
#if 0
2005-05-23 23:06:33 +08:00
pri_message ( pri , " Sending facility event (%s/%s) \n " , pri - > ev . facname . callingname , pri - > ev . facname . callingnum ) ;
2003-02-12 21:59:23 +08:00
# 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 ;
2005-06-30 01:27:03 +08:00
pri - > ev . proceeding . cause = c - > cause ;
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 ;
}
2005-05-19 22:06:43 +08:00
pri - > ev . proceeding . channel = c - > channelno | ( c - > ds1no < < 8 ) | ( c - > ds1explicit < < 16 ) ;
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 ;
2006-07-07 05:11:37 +08:00
UPDATE_OURCALLSTATE ( pri , c , Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING ) ;
2003-09-25 14:13:14 +08:00
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 ;
2006-07-28 22:41:57 +08:00
cur = c - > apdus ;
while ( cur ) {
if ( ! cur - > sent & & cur - > message = = Q931_FACILITY ) {
q931_facility ( pri , c ) ;
break ;
}
cur = cur - > next ;
}
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 ;
}
2006-07-21 23:43:31 +08:00
if ( ! ( c - > ourcallstate = = Q931_CALL_STATE_CONNECT_REQUEST ) & &
! ( c - > ourcallstate = = Q931_CALL_STATE_ACTIVE & &
( pri - > localtype = = PRI_NETWORK | | pri - > switchtype = = PRI_SWITCH_QSIG ) ) ) {
2003-09-25 14:13:14 +08:00
q931_status ( pri , c , PRI_CAUSE_WRONG_MESSAGE ) ;
break ;
}
2006-07-07 05:11:37 +08:00
UPDATE_OURCALLSTATE ( pri , c , 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 ) )
2005-05-23 23:06:33 +08:00
pri_error ( pri , " 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 */
2008-05-08 03:51:44 +08:00
#if 0
2005-01-25 04:57:04 +08:00
if ( ! c - > sugcallstate & & ( c - > ourcallstate ! = Q931_CALL_STATE_CALL_INITIATED ) ) {
2008-05-08 03:51:44 +08:00
# else
/* Remove "workaround" since it breaks certification testing. If we receive a STATUS message of call state
* NULL and we are not in the call state NULL we must clear resources and return to the call state to pass
* testing . See section 5.8 .11 of Q .931 */
if ( ! c - > sugcallstate ) {
# endif
2005-05-19 22:06:43 +08:00
pri - > ev . hangup . channel = c - > channelno | ( c - > ds1no < < 8 ) | ( c - > ds1explicit < < 16 ) ;
2006-06-02 02:00:31 +08:00
pri - > ev . hangup . cause = c - > cause ;
pri - > ev . hangup . cref = c - > cr ;
pri - > ev . hangup . call = c ;
pri - > ev . hangup . aoc_units = c - > aoc_units ;
libpri_copy_string ( pri - > ev . hangup . useruserinfo , c - > useruserinfo , sizeof ( pri - > ev . hangup . useruserinfo ) ) ;
2003-09-25 14:13:14 +08:00
/* Free resources */
2006-07-07 05:11:37 +08:00
UPDATE_OURCALLSTATE ( pri , c , Q931_CALL_STATE_NULL ) ;
2003-09-25 14:13:14 +08:00
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 :
2006-07-07 05:11:37 +08:00
UPDATE_OURCALLSTATE ( pri , c , Q931_CALL_STATE_NULL ) ;
2003-08-05 09:00:45 +08:00
c - > peercallstate = Q931_CALL_STATE_NULL ;
2005-05-19 22:06:43 +08:00
pri - > ev . hangup . channel = c - > channelno | ( c - > ds1no < < 8 ) | ( c - > ds1explicit < < 16 ) ;
2006-06-02 02:00:31 +08:00
pri - > ev . hangup . cause = c - > cause ;
pri - > ev . hangup . cref = c - > cr ;
pri - > ev . hangup . call = c ;
pri - > ev . hangup . aoc_units = c - > aoc_units ;
libpri_copy_string ( pri - > ev . hangup . useruserinfo , c - > useruserinfo , sizeof ( pri - > ev . hangup . useruserinfo ) ) ;
2005-10-22 04:20:22 +08:00
c - > useruserinfo [ 0 ] = ' \0 ' ;
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 ;
}
2006-07-07 05:11:37 +08:00
UPDATE_OURCALLSTATE ( pri , c , Q931_CALL_STATE_NULL ) ;
2001-05-13 00:41:32 +08:00
pri - > ev . e = PRI_EVENT_HANGUP ;
2005-05-19 22:06:43 +08:00
pri - > ev . hangup . channel = c - > channelno | ( c - > ds1no < < 8 ) | ( c - > ds1explicit < < 16 ) ;
2001-05-13 00:41:32 +08:00
pri - > ev . hangup . cause = c - > cause ;
2006-06-02 02:00:31 +08:00
pri - > ev . hangup . cref = c - > cr ;
2001-05-13 00:41:32 +08:00
pri - > ev . hangup . call = c ;
2005-04-05 11:55:58 +08:00
pri - > ev . hangup . aoc_units = c - > aoc_units ;
2006-06-02 02:00:31 +08:00
libpri_copy_string ( pri - > ev . hangup . useruserinfo , c - > useruserinfo , sizeof ( pri - > ev . hangup . useruserinfo ) ) ;
2005-10-22 04:20:22 +08:00
c - > useruserinfo [ 0 ] = ' \0 ' ;
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 ;
}
2006-07-07 05:11:37 +08:00
UPDATE_OURCALLSTATE ( pri , c , 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 ;
2008-02-22 00:38:11 +08:00
/* wait for a RELEASE so that sufficient time has passed
for the inband audio to be heard */
2008-07-23 03:43:26 +08:00
if ( pri - > acceptinbanddisconnect & & ( c - > progressmask & PRI_PROG_INBAND_AVAILABLE ) )
2008-02-22 00:38:11 +08:00
break ;
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 ;
2005-05-19 22:06:43 +08:00
pri - > ev . hangup . channel = c - > channelno | ( c - > ds1no < < 8 ) | ( c - > ds1explicit < < 16 ) ;
2001-05-13 00:41:32 +08:00
pri - > ev . hangup . cause = c - > cause ;
2006-06-02 02:00:31 +08:00
pri - > ev . hangup . cref = c - > cr ;
2001-05-13 00:41:32 +08:00
pri - > ev . hangup . call = c ;
2005-04-05 11:55:58 +08:00
pri - > ev . hangup . aoc_units = c - > aoc_units ;
2006-06-02 02:00:31 +08:00
libpri_copy_string ( pri - > ev . hangup . useruserinfo , c - > useruserinfo , sizeof ( pri - > ev . hangup . useruserinfo ) ) ;
2006-02-15 03:30:32 +08:00
c - > useruserinfo [ 0 ] = ' \0 ' ;
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 :
2006-07-07 05:11:37 +08:00
UPDATE_OURCALLSTATE ( pri , c , 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 ;
2005-05-19 22:06:43 +08:00
pri - > ev . restartack . channel = c - > channelno | ( c - > ds1no < < 8 ) | ( c - > ds1explicit < < 16 ) ;
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 ) ;
2005-12-02 01:59:56 +08:00
libpri_copy_string ( pri - > ev . digit . digits , c - > keypad_digits , sizeof ( pri - > ev . digit . digits ) ) ;
/* Make sure we clear it out before we return */
c - > keypad_digits [ 0 ] = ' \0 ' ;
2005-03-02 23:56:11 +08:00
return Q931_RES_HAVEEVENT ;
}
2003-02-12 21:59:23 +08:00
pri - > ev . e = PRI_EVENT_INFO_RECEIVED ;
pri - > ev . ring . call = c ;
2005-05-19 22:06:43 +08:00
pri - > ev . ring . channel = c - > channelno | ( c - > ds1no < < 8 ) | ( c - > ds1explicit < < 16 ) ;
2005-06-22 06:47:39 +08:00
libpri_copy_string ( pri - > ev . ring . callednum , c - > callednum , sizeof ( pri - > ev . ring . callednum ) ) ;
libpri_copy_string ( pri - > ev . ring . callingsubaddr , c - > callingsubaddr , sizeof ( pri - > ev . ring . callingsubaddr ) ) ;
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 ;
}
2006-07-07 05:11:37 +08:00
UPDATE_OURCALLSTATE ( pri , c , 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 ;
2005-05-19 22:06:43 +08:00
pri - > ev . setup_ack . channel = c - > channelno | ( c - > ds1no < < 8 ) | ( c - > ds1explicit < < 16 ) ;
2006-04-28 00:09:11 +08:00
pri - > ev . setup_ack . call = c ;
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 :
2005-05-23 23:06:33 +08:00
pri_error ( pri , " !! 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
2005-05-23 23:06:33 +08:00
pri_error ( pri , " !! 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
2006-07-07 05:11:37 +08:00
/* Clear a call, although we did not receive any hangup notification. */
static int pri_internal_clear ( void * data )
{
struct q931_call * c = data ;
struct pri * pri = c - > pri ;
int res ;
if ( c - > retranstimer )
pri_schedule_del ( pri , c - > retranstimer ) ;
c - > retranstimer = 0 ;
c - > useruserinfo [ 0 ] = ' \0 ' ;
c - > cause = - 1 ;
c - > causecode = - 1 ;
c - > causeloc = - 1 ;
c - > sugcallstate = - 1 ;
c - > aoc_units = - 1 ;
UPDATE_OURCALLSTATE ( pri , c , Q931_CALL_STATE_NULL ) ;
c - > peercallstate = Q931_CALL_STATE_NULL ;
pri - > ev . hangup . channel = c - > channelno | ( c - > ds1no < < 8 ) | ( c - > ds1explicit < < 16 ) ;
pri - > ev . hangup . cause = c - > cause ;
pri - > ev . hangup . cref = c - > cr ;
pri - > ev . hangup . call = c ;
pri - > ev . hangup . aoc_units = c - > aoc_units ;
libpri_copy_string ( pri - > ev . hangup . useruserinfo , c - > useruserinfo , sizeof ( pri - > ev . hangup . useruserinfo ) ) ;
/* Free resources */
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 {
res = 0 ;
q931_hangup ( pri , c , c - > cause ) ;
}
return res ;
}
/* Handle T309 timeout for an active call. */
static void pri_dl_down_timeout ( void * data )
{
struct q931_call * c = data ;
struct pri * pri = c - > pri ;
if ( pri - > debug & PRI_DEBUG_Q931_STATE )
pri_message ( pri , DBGHEAD " Timed out waiting for data link re-establishment \n " , DBGINFO ) ;
c - > cause = PRI_CAUSE_DESTINATION_OUT_OF_ORDER ;
if ( pri_internal_clear ( c ) = = Q931_RES_HAVEEVENT )
pri - > schedev = 1 ;
}
/* Handle Layer 2 down event for a non active call. */
static void pri_dl_down_cancelcall ( void * data )
{
struct q931_call * c = data ;
struct pri * pri = c - > pri ;
if ( pri - > debug & PRI_DEBUG_Q931_STATE )
pri_message ( pri , DBGHEAD " Cancel non active call after data link failure \n " , DBGINFO ) ;
c - > cause = PRI_CAUSE_DESTINATION_OUT_OF_ORDER ;
if ( pri_internal_clear ( c ) = = Q931_RES_HAVEEVENT )
pri - > schedev = 1 ;
}
/* Receive an indication from Layer 2 */
void q931_dl_indication ( struct pri * pri , int event )
{
q931_call * cur = NULL ;
/* Just return if T309 is not enabled. */
if ( ! pri | | pri - > timers [ PRI_TIMER_T309 ] < 0 )
return ;
switch ( event ) {
case PRI_EVENT_DCHAN_DOWN :
pri_message ( pri , DBGHEAD " link is DOWN \n " , DBGINFO ) ;
cur = * pri - > callpool ;
while ( cur ) {
if ( cur - > ourcallstate = = Q931_CALL_STATE_ACTIVE ) {
/* For a call in Active state, activate T309 only if there is no timer already running. */
if ( ! cur - > retranstimer ) {
pri_message ( pri , DBGHEAD " activate T309 for call %d on channel %d \n " , DBGINFO , cur - > cr , cur - > channelno ) ;
cur - > retranstimer = pri_schedule_event ( pri , pri - > timers [ PRI_TIMER_T309 ] , pri_dl_down_timeout , cur ) ;
}
} else if ( cur - > ourcallstate ! = Q931_CALL_STATE_NULL ) {
/* For a call that is not in Active state, schedule internal clearing of the call 'ASAP' (delay 0). */
pri_message ( pri , DBGHEAD " cancel call %d on channel %d in state %d (%s) \n " , DBGINFO ,
cur - > cr , cur - > channelno , cur - > ourcallstate , callstate2str ( cur - > ourcallstate ) ) ;
if ( cur - > retranstimer )
pri_schedule_del ( pri , cur - > retranstimer ) ;
cur - > retranstimer = pri_schedule_event ( pri , 0 , pri_dl_down_cancelcall , cur ) ;
}
cur = cur - > next ;
}
break ;
case PRI_EVENT_DCHAN_UP :
pri_message ( pri , DBGHEAD " link is UP \n " , DBGINFO ) ;
cur = * pri - > callpool ;
while ( cur ) {
if ( cur - > ourcallstate = = Q931_CALL_STATE_ACTIVE & & cur - > retranstimer ) {
pri_message ( pri , DBGHEAD " cancel T309 for call %d on channel %d \n " , DBGINFO , cur - > cr , cur - > channelno ) ;
pri_schedule_del ( pri , cur - > retranstimer ) ;
cur - > retranstimer = 0 ;
q931_status ( pri , cur , PRI_CAUSE_NORMAL_UNSPECIFIED ) ;
} else if ( cur - > ourcallstate ! = Q931_CALL_STATE_NULL & &
cur - > ourcallstate ! = Q931_CALL_STATE_DISCONNECT_REQUEST & &
cur - > ourcallstate ! = Q931_CALL_STATE_DISCONNECT_INDICATION & &
cur - > ourcallstate ! = Q931_CALL_STATE_RELEASE_REQUEST ) {
/* The STATUS message sent here is not required by Q.931, but it may help anyway. */
q931_status ( pri , cur , PRI_CAUSE_NORMAL_UNSPECIFIED ) ;
}
cur = cur - > next ;
}
break ;
default :
pri_message ( pri , DBGHEAD " unexpected event %d. \n " , DBGINFO , event ) ;
}
}
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 ;
}