?? q931.c
字號:
/* * libpri: An implementation of Primary Rate ISDN * * Written by Mark Spencer <markster@linux-support.net> * * Copyright (C) 2001, Linux Support Services, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include "libpri.h"#include "pri_internal.h"#include "pri_q921.h"#include "pri_q931.h"#include <unistd.h>#include <stdlib.h>#include <string.h>#include <stdio.h>#define MAX_MAND_IES 10struct msgtype { int msgnum; unsigned char *name; int mandies[MAX_MAND_IES];};struct msgtype msgs[] = { /* Call establishment messages */ { Q931_ALERTING, "ALERTING" }, { Q931_CALL_PROCEEDING, "CALL PROCEEDING" }, { Q931_CONNECT, "CONNECT" }, { Q931_CONNECT_ACKNOWLEDGE, "CONNECT ACKNOWLEDGE" }, { Q931_PROGRESS, "PROGRESS", { Q931_PROGRESS_INDICATOR } }, { Q931_SETUP, "SETUP", { Q931_BEARER_CAPABILITY, Q931_CHANNEL_IDENT } }, { Q931_SETUP_ACKNOWLEDGE, "SETUP ACKNOWLEDGE" }, /* Call disestablishment messages */ { Q931_DISCONNECT, "DISCONNECT", { Q931_CAUSE } }, { Q931_RELEASE, "RELEASE" }, { Q931_RELEASE_COMPLETE, "RELEASE COMPLETE" }, { Q931_RESTART, "RESTART", { Q931_RESTART_INDICATOR } }, { Q931_RESTART_ACKNOWLEDGE, "RESTART ACKNOWLEDGE", { Q931_RESTART_INDICATOR } }, /* Miscellaneous */ { Q931_STATUS, "STATUS", { Q931_CAUSE, Q931_CALL_STATE } }, { Q931_STATUS_ENQUIRY, "STATUS ENQUIRY" }, { Q931_USER_INFORMATION, "USER_INFORMATION" }, { Q931_SEGMENT, "SEGMENT" }, { Q931_CONGESTION_CONTROL, "CONGESTION CONTROL" }, { Q931_INFORMATION, "INFORMATION" }, { Q931_FACILITY, "FACILITY" }, { Q931_NOTIFY, "NOTIFY", { Q931_IE_NOTIFY_IND } }, /* 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" }, { Q931_RESUME_ACKNOWLEDGE, "RESUME ACKNOWLEDGE", { Q931_CHANNEL_IDENT } }, { Q931_RESUME_REJECT, "RESUME REJECT", { Q931_CAUSE } }, { Q931_SUSPEND, "SUSPEND" }, { Q931_SUSPEND_ACKNOWLEDGE, "SUSPEND ACKNOWLEDGE" }, { Q931_SUSPEND_REJECT, "SUSPEND REJECT" }, /* Maintenance */ { NATIONAL_SERVICE, "SERVICE" }, { NATIONAL_SERVICE_ACKNOWLEDGE, "SERVICE ACKNOWLEDGE" },};struct msgtype causes[] = { { PRI_CAUSE_UNALLOCATED, "Unallocated (unassigned) number" }, { PRI_CAUSE_NO_ROUTE_TRANSIT_NET, "No route to specified transmit network" }, { PRI_CAUSE_NO_ROUTE_DESTINATION, "No route to destination" }, { PRI_CAUSE_CHANNEL_UNACCEPTABLE, "Channel unacceptable" }, { PRI_CAUSE_CALL_AWARDED_DELIVERED, "Call awarded and being delivered in an established channel" }, { PRI_CAUSE_NORMAL_CLEARING, "Normal Clearing" }, { PRI_CAUSE_USER_BUSY, "User busy" }, { PRI_CAUSE_NO_USER_RESPONSE, "No user responding" }, { PRI_CAUSE_NO_ANSWER, "User alerting, no answer" }, { PRI_CAUSE_CALL_REJECTED, "Call Rejected" }, { PRI_CAUSE_NUMBER_CHANGED, "Number changed" }, { PRI_CAUSE_DESTINATION_OUT_OF_ORDER, "Destination out of order" }, { PRI_CAUSE_INVALID_NUMBER_FORMAT, "Invalid number format" }, { PRI_CAUSE_FACILITY_REJECTED, "Facility rejected" }, { PRI_CAUSE_RESPONSE_TO_STATUS_ENQUIRY, "Response to STATus ENQuiry" }, { PRI_CAUSE_NORMAL_UNSPECIFIED, "Normal, unspecified" }, { PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION, "Circuit/channel congestion" }, { PRI_CAUSE_NETWORK_OUT_OF_ORDER, "Network out of order" }, { 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" }, { 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" }, { PRI_CAUSE_BEARERCAPABILITY_NOTAUTH, "Bearer capability not authorized" }, { PRI_CAUSE_BEARERCAPABILITY_NOTAVAIL, "Bearer capability not available" }, { PRI_CAUSE_BEARERCAPABILITY_NOTIMPL, "Bearer capability not implemented" }, { PRI_CAUSE_CHAN_NOT_IMPLEMENTED, "Channel not implemented" }, { PRI_CAUSE_FACILITY_NOT_IMPLEMENTED, "Facility not implemented" }, { PRI_CAUSE_INVALID_CALL_REFERENCE, "Invalid call reference value" }, { PRI_CAUSE_INCOMPATIBLE_DESTINATION, "Incompatible destination" }, { PRI_CAUSE_INVALID_MSG_UNSPECIFIED, "Invalid message unspecified" }, { PRI_CAUSE_MANDATORY_IE_MISSING, "Mandatory information element is missing" }, { PRI_CAUSE_MESSAGE_TYPE_NONEXIST, "Message type nonexist." }, { PRI_CAUSE_WRONG_MESSAGE, "Wrong message" }, { 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" }, { PRI_CAUSE_MANDATORY_IE_LENGTH_ERROR, "Mandatory IE length error" }, { PRI_CAUSE_PROTOCOL_ERROR, "Protocol error, unspecified" }, { PRI_CAUSE_INTERWORKING, "Interworking, unspecified" },};struct msgtype facilities[] = { { PRI_NSF_SID_PREFERRED, "CPN (SID) preferred" }, { PRI_NSF_ANI_PREFERRED, "BN (ANI) preferred" }, { PRI_NSF_SID_ONLY, "CPN (SID) only" }, { PRI_NSF_ANI_ONLY, "BN (ANI) only" }, { PRI_NSF_CALL_ASSOC_TSC, "Call Associated TSC" }, { PRI_NSF_NOTIF_CATSC_CLEARING, "Notification of CATSC Clearing or Resource Unavailable" }, { PRI_NSF_OPERATOR, "Operator" }, { PRI_NSF_PCCO, "Pre-subscribed Common Carrier Operator (PCCO)" }, { PRI_NSF_SDN, "SDN (including GSDN)" }, { PRI_NSF_TOLL_FREE_MEGACOM, "Toll Free MEGACOM" }, { PRI_NSF_MEGACOM, "MEGACOM" }, { PRI_NSF_ACCUNET, "ACCUNET Switched Digital Service" }, { PRI_NSF_LONG_DISTANCE_SERVICE, "Long Distance Service" }, { PRI_NSF_INTERNATIONAL_TOLL_FREE, "International Toll Free Service" }, { PRI_NSF_ATT_MULTIQUEST, "AT&T MultiQuest" }, { PRI_NSF_CALL_REDIRECTION_SERVICE, "Call Redirection Service" }};#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#define TRANS_MODE_2x64_CIRCUIT 0x11#define TRANS_MODE_384_CIRCUIT 0x13#define TRANS_MODE_1536_CIRCUIT 0x15#define TRANS_MODE_1920_CIRCUIT 0x17#define TRANS_MODE_MULTIRATE 0x18#define TRANS_MODE_PACKET 0x40#define RATE_ADAPT_56K 0x0f#define LAYER_2_LAPB 0x46#define LAYER_3_X25 0x66/* The 4ESS uses a different audio field */#define PRI_TRANS_CAP_AUDIO_4ESS 0x08#define Q931_PROG_CALL_NOT_E2E_ISDN 0x01#define Q931_PROG_CALLED_NOT_ISDN 0x02#define Q931_PROG_CALLER_NOT_ISDN 0x03#define Q931_PROG_INBAND_AVAILABLE 0x08#define Q931_PROG_DELAY_AT_INTERF 0x0a#define Q931_PROG_INTERWORKING_WITH_PUBLIC 0x10#define Q931_PROG_INTERWORKING_NO_RELEASE 0x11#define Q931_PROG_INTERWORKING_NO_RELEASE_PRE_ANSWER 0x12#define Q931_PROG_INTERWORKING_NO_RELEASE_POST_ANSWER 0x13#define CODE_CCITT 0x0#define CODE_INTERNATIONAL 0x1#define CODE_NATIONAL 0x2#define CODE_NETWORK_SPECIFIC 0x3#define LOC_USER 0x0#define LOC_PRIV_NET_LOCAL_USER 0x1#define LOC_PUB_NET_LOCAL_USER 0x2#define LOC_TRANSIT_NET 0x3#define LOC_PUB_NET_REMOTE_USER 0x4#define LOC_PRIV_NET_REMOTE_USER 0x5#define LOC_INTERNATIONAL_NETWORK 0x7#define LOC_NETWORK_BEYOND_INTERWORKING 0xa#define T_308 4000#define T_305 30000#define T_313 4000struct q931_call { struct pri *pri; /* PRI */ int cr; /* Call Reference */ int forceinvert; /* Force inversion of call number even if 0 */ q931_call *next; /* Slotmap specified (bitmap of channels 31/24-1) (Channel Identifier IE) (-1 means not specified) */ int slotmap; /* An explicit channel (Channel Identifier IE) (-1 means not specified) */ int channelno; /* An explicit DS1 (-1 means not specified) */ int ds1no; /* Channel flags (0 means none retrieved) */ int chanflags; int alive; /* Whether or not the call is alive */ int acked; /* Whether setup has been acked or not */ int sendhangupack; /* Whether or not to send a hangup ack */ int proc; /* Whether we've sent a call proceeding / alerting */ int ri; /* Restart Indicator (Restart Indicator IE) */ /* Bearer Capability */ int transcapability; int transmoderate; int transmultiple; int userl1; int userl2; int userl3; int rateadaption; int sentchannel; int progcode; /* Progress coding */ int progloc; /* Progress Location */ int progress; /* Progress indicator */ int notify; /* Notification */ int causecode; /* Cause Coding */ int causeloc; /* Cause Location */ int cause; /* Cause of clearing */ int peercallstate; /* Call state of peer as reported */ int ourcallstate; /* Our call state */ int sugcallstate; /* Status call state */ int callerplan; int callerpres; /* Caller presentation */ char callernum[256]; /* Caller */ char callername[256]; int ani2; /* ANI II */ int calledplan; int nonisdn; char callednum[256]; /* Called Number */ int complete; /* no more digits coming */ int newcall; /* if the received message has a new call reference value */ int retranstimer; /* Timer for retransmitting DISC */ int t308_timedout; /* Whether t308 timed out once */ int redirectingplan; int redirectingpres; int redirectingreason; char redirectingnum[256]; int useruserprotocoldisc; char useruserinfo[256]; char callingsubaddr[256]; /* Calling parties sub address */};#define FUNC_DUMP(name) void ((name))(int full_ie, q931_ie *ie, int len, char prefix)#define FUNC_RECV(name) int ((name))(int full_ie, struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len)#define FUNC_SEND(name) int ((name))(int full_ie, struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len)struct ie { int ie; char *name; /* Dump an IE for debugging (preceed all lines by prefix) */ FUNC_DUMP(*dump); /* Handle IE returns 0 on success, -1 on failure */ FUNC_RECV(*receive); /* Add IE to a message, return the # of bytes added or -1 on failure */ FUNC_SEND(*transmit);};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";}static void call_init(struct q931_call *c){ memset(c, 0, sizeof(*c)); c->alive = 0; c->sendhangupack = 0; c->forceinvert = -1; c->cr = -1; c->slotmap = -1; c->channelno = -1; c->ds1no = 0; c->chanflags = 0; c->next = NULL; c->sentchannel = 0; c->newcall = 1; c->ourcallstate = Q931_CALL_STATE_NULL; c->peercallstate = Q931_CALL_STATE_NULL;}static char *binary(int b, int len) { static char res[33]; int x; memset(res, 0, sizeof(res)); if (len > 32) len = 32; for (x=1;x<=len;x++) res[x-1] = b & (1 << (len - x)) ? '1' : '0'; return res;}static FUNC_RECV(receive_channel_id){ int x; int pos=0;#ifdef NO_BRI_SUPPORT if (!ie->data[0] & 0x20) { pri_error("!! Not PRI type!?\n"); return -1; }#endif#ifndef NOAUTO_CHANNEL_SELECTION_SUPPORT if ((ie->data[0] & 3) != 1) { pri_error("!! Unexpected Channel selection %d\n", ie->data[0] & 3); return -1; }#endif if (ie->data[0] & 0x08) call->chanflags = FLAG_EXCLUSIVE; else call->chanflags = FLAG_PREFERRED; pos++; if (ie->data[0] & 0x40) { /* DS1 specified -- stop here */ call->ds1no = ie->data[1] & 0x7f; pos++; } if (pos+2 < len) { /* More coming */ if ((ie->data[pos] & 0x0f) != 3) { pri_error("!! Unexpected Channel Type %d\n", ie->data[1] & 0x0f); return -1; } if ((ie->data[pos] & 0x60) != 0) { pri_error("!! Invalid CCITT coding %d\n", (ie->data[1] & 0x60) >> 5); return -1; } if (ie->data[pos] & 0x10) { /* Expect Slot Map */ call->slotmap = 0; pos++; for (x=0;x<3;x++) { call->slotmap <<= 8; call->slotmap |= ie->data[x + pos]; } return 0; } else { pos++; /* Only expect a particular channel */ call->channelno = ie->data[pos] & 0x7f; return 0; } } else return 0; return -1;}static FUNC_SEND(transmit_channel_id){ int pos=0; /* Start with standard stuff */ if (pri->switchtype == PRI_SWITCH_GR303_TMC) ie->data[pos] = 0x69; else ie->data[pos] = 0xa1; /* Add exclusive flag if necessary */ if (call->chanflags & FLAG_EXCLUSIVE) ie->data[pos] |= 0x08; else if (!(call->chanflags & FLAG_PREFERRED)) { /* Don't need this IE */ return 0; } if (call->ds1no > 0) { /* Note that we are specifying the identifier */ ie->data[pos++] |= 0x40; /* We need to use the Channel Identifier Present thingy. Just specify it and we're done */ ie->data[pos++] = 0x80 | call->ds1no; } else pos++; if ((call->channelno > -1) || (call->slotmap != -1)) { /* We'll have the octet 8.2 and 8.3's present */ ie->data[pos++] = 0x83; if (call->channelno > -1) { /* Channel number specified */ ie->data[pos++] = 0x80 | call->channelno; return pos + 2;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -