/* * libpri: An implementation of Primary Rate ISDN * * Written by Mark Spencer * * Copyright (C) 2001-2005, Digium, Inc. * All Rights Reserved. */ /* * 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. * * 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. * * 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. */ #include "compat.h" #include "libpri.h" #include "pri_internal.h" #include "pri_facility.h" #include #include #include #include #include #include #include #define MAX_MAND_IES 10 struct msgtype { int msgnum; char *name; int mandies[MAX_MAND_IES]; }; static 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_IE_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_REGISTER, "REGISTER" }, { Q931_NOTIFY, "NOTIFY", { Q931_IE_NOTIFY_IND } }, /* Call Management */ { Q931_HOLD, "HOLD" }, { Q931_HOLD_ACKNOWLEDGE, "HOLD ACKNOWLEDGE" }, { Q931_HOLD_REJECT, "HOLD REJECT", { Q931_CAUSE } }, { Q931_RETRIEVE, "RETRIEVE" }, { Q931_RETRIEVE_ACKNOWLEDGE, "RETRIEVE ACKNOWLEDGE" }, { Q931_RETRIEVE_REJECT, "RETRIEVE REJECT", { Q931_CAUSE } }, { 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" }, { Q931_ANY_MESSAGE, "ANY MESSAGE" }, }; static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct q931_call *c, int missingmand); static void nt_ptmp_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct q931_call *c, int *allow_event, int *allow_posthandle); struct msgtype att_maintenance_msgs[] = { { ATT_SERVICE, "SERVICE", { Q931_CHANNEL_IDENT } }, { ATT_SERVICE_ACKNOWLEDGE, "SERVICE ACKNOWLEDGE", { Q931_CHANNEL_IDENT } }, }; struct msgtype national_maintenance_msgs[] = { { NATIONAL_SERVICE, "SERVICE", { Q931_CHANNEL_IDENT } }, { NATIONAL_SERVICE_ACKNOWLEDGE, "SERVICE ACKNOWLEDGE", { Q931_CHANNEL_IDENT } }, }; static int post_handle_maintenance_message(struct pri *ctrl, int protodisc, struct q931_mh *mh, struct q931_call *c); static 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_NONSELECTED_USER_CLEARING, "Non-selected user clearing" }, { 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_RESOURCE_UNAVAIL_UNSPECIFIED, "Resource unavailable, unspecified" }, { 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_SERVICEOROPTION_NOTAVAIL, "Service or option not available, unspecified" }, { 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_IDENTIFIED_CHANNEL_NOTEXIST, "Identified channel does not exist" }, { 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" }, }; static 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_WHOLE_INTERFACE 0x01 #define FLAG_PREFERRED 0x02 #define FLAG_EXCLUSIVE 0x04 #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 /* Don't forget to update PRI_PROG_xxx at libpri.h */ #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_CALLER_RETURNED_TO_ISDN 0x04 #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 static char *ie2str(int ie); #define FUNC_DUMP(name) void (name)(int full_ie, struct pri *pri, 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, int order) #if 1 /* Update call state with transition trace. */ #define UPDATE_OURCALLSTATE(ctrl, call, newstate) \ do { \ if (((ctrl)->debug & PRI_DEBUG_Q931_STATE) && (call)->ourcallstate != (newstate)) { \ pri_message((ctrl), \ DBGHEAD "%s %d enters state %d (%s). Hold state: %s\n", \ DBGINFO, ((call) == (call)->master_call) ? "Call" : "Subcall", \ (call)->cr, (newstate), q931_call_state_str(newstate), \ q931_hold_state_str((call)->master_call->hold_state)); \ } \ (call)->ourcallstate = (newstate); \ } while (0) #else /* Update call state with no trace. */ #define UPDATE_OURCALLSTATE(ctrl, call, newstate) (call)->ourcallstate = (newstate) #endif #if 1 /* Update hold state with transition trace. */ #define UPDATE_HOLD_STATE(ctrl, master_call, newstate) \ do { \ if (((ctrl)->debug & PRI_DEBUG_Q931_STATE) \ && (master_call)->hold_state != (newstate)) { \ pri_message((ctrl), \ DBGHEAD "Call %d in state %d (%s) enters Hold state: %s\n", \ DBGINFO, (master_call)->cr, (master_call)->ourcallstate, \ q931_call_state_str((master_call)->ourcallstate), \ q931_hold_state_str(newstate)); \ } \ (master_call)->hold_state = (newstate); \ } while (0) #else /* Update hold state with no trace. */ #define UPDATE_HOLD_STATE(ctrl, master_call, newstate) (master_call)->hold_state = (newstate) #endif struct ie { /* Maximal count of same IEs at the message (0 - any, 1..n - limited) */ int max_count; /* IE code */ int ie; /* IE friendly name */ 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); }; /*! * \internal * \brief Encode the channel id information to pass to upper level. * * \param call Q.931 call leg * * \return Encoded channel value. */ static int q931_encode_channel(const q931_call *call) { int held_call; int channelno; int ds1no; switch (call->master_call->hold_state) { case Q931_HOLD_STATE_CALL_HELD: case Q931_HOLD_STATE_RETRIEVE_REQ: case Q931_HOLD_STATE_RETRIEVE_IND: held_call = 1 << 18; break; default: held_call = 0; break; } if (held_call || call->cis_call) { /* So a -1 does not wipe out the held_call or cis_call flags. */ channelno = call->channelno & 0xFF; ds1no = call->ds1no & 0xFF; } else { channelno = call->channelno; ds1no = call->ds1no; } return channelno | (ds1no << 8) | (call->ds1explicit << 16) | (call->cis_call << 17) | held_call; } /*! * \brief Check if the given call ptr is valid. * * \param ctrl D channel controller. * \param call Q.931 call leg. * * \retval TRUE if call ptr is valid. * \retval FALSE if call ptr is invalid. */ int q931_is_call_valid(struct pri *ctrl, struct q931_call *call) { struct q931_call *cur; struct q921_link *link; int idx; if (!call) { return 0; } if (!ctrl) { /* Must use suspect ctrl from call ptr. */ if (!call->pri) { /* Definitely a bad call pointer. */ return 0; } ctrl = call->pri; } /* Check real call records. */ for (cur = *ctrl->callpool; cur; cur = cur->next) { if (call == cur) { /* Found it. */ return 1; } if (cur->outboundbroadcast) { /* Check subcalls for call ptr. */ for (idx = 0; idx < ARRAY_LEN(cur->subcalls); ++idx) { if (call == cur->subcalls[idx]) { /* Found it. */ return 1; } } } } /* Check dummy call records. */ for (link = &ctrl->link; link; link = link->next) { if (link->dummy_call == call) { /* Found it. */ return 1; } } /* Well it looks like this is a stale call ptr. */ return 0; } /*! * \brief Check if the given call ptr is valid and gripe if not. * * \param ctrl D channel controller. * \param call Q.931 call leg. * \param func_name Calling function name for debug tracing. (__PRETTY_FUNCTION__) * \param func_line Calling function line number for debug tracing. (__LINE__) * * \retval TRUE if call ptr is valid. * \retval FALSE if call ptr is invalid. */ int q931_is_call_valid_gripe(struct pri *ctrl, struct q931_call *call, const char *func_name, unsigned long func_line) { int res; if (!call) { /* Let's not gripe about this invalid call pointer. */ return 0; } res = q931_is_call_valid(ctrl, call); if (!res) { pri_message(ctrl, "!! %s() line:%lu Called with invalid call ptr (%p)\n", func_name, func_line, call); } return res; } /*! * \brief Initialize the given struct q931_party_name * * \param name Structure to initialize * * \return Nothing */ void q931_party_name_init(struct q931_party_name *name) { name->valid = 0; name->presentation = PRI_PRES_UNAVAILABLE; name->char_set = PRI_CHAR_SET_ISO8859_1; name->str[0] = '\0'; } /*! * \brief Initialize the given struct q931_party_number * * \param number Structure to initialize * * \return Nothing */ void q931_party_number_init(struct q931_party_number *number) { number->valid = 0; number->presentation = PRES_NUMBER_NOT_AVAILABLE; number->plan = (PRI_TON_UNKNOWN << 4) | PRI_NPI_E163_E164; number->str[0] = '\0'; } /*! * \brief Initialize the given struct q931_party_subaddress * * \param subaddress Structure to initialize * * \return Nothing */ void q931_party_subaddress_init(struct q931_party_subaddress *subaddress) { subaddress->valid = 0; subaddress->type = 0; subaddress->odd_even_indicator = 0; subaddress->length = 0; subaddress->data[0] = '\0'; } /*! * \brief Initialize the given struct q931_party_address * * \param address Structure to initialize * * \return Nothing */ void q931_party_address_init(struct q931_party_address *address) { q931_party_number_init(&address->number); q931_party_subaddress_init(&address->subaddress); } /*! * \brief Initialize the given struct q931_party_id * * \param id Structure to initialize * * \return Nothing */ void q931_party_id_init(struct q931_party_id *id) { q931_party_name_init(&id->name); q931_party_number_init(&id->number); q931_party_subaddress_init(&id->subaddress); } /*! * \brief Initialize the given struct q931_party_redirecting * * \param redirecting Structure to initialize * * \return Nothing */ void q931_party_redirecting_init(struct q931_party_redirecting *redirecting) { q931_party_id_init(&redirecting->from); q931_party_id_init(&redirecting->to); q931_party_id_init(&redirecting->orig_called); redirecting->state = Q931_REDIRECTING_STATE_IDLE; redirecting->count = 0; redirecting->orig_reason = PRI_REDIR_UNKNOWN; redirecting->reason = PRI_REDIR_UNKNOWN; } /*! * \brief Compare the left and right party name. * * \param left Left parameter party name. * \param right Right parameter party name. * * \retval < 0 when left < right. * \retval == 0 when left == right. * \retval > 0 when left > right. */ int q931_party_name_cmp(const struct q931_party_name *left, const struct q931_party_name *right) { int cmp; if (!left->valid) { if (!right->valid) { return 0; } return -1; } else if (!right->valid) { return 1; } cmp = left->char_set - right->char_set; if (cmp) { return cmp; } cmp = strcmp(left->str, right->str); if (cmp) { return cmp; } cmp = left->presentation - right->presentation; return cmp; } /*! * \brief Compare the left and right party number. * * \param left Left parameter party number. * \param right Right parameter party number. * * \retval < 0 when left < right. * \retval == 0 when left == right. * \retval > 0 when left > right. */ int q931_party_number_cmp(const struct q931_party_number *left, const struct q931_party_number *right) { int cmp; if (!left->valid) { if (!right->valid) { return 0; } return -1; } else if (!right->valid) { return 1; } cmp = left->plan - right->plan; if (cmp) { return cmp; } cmp = strcmp(left->str, right->str); if (cmp) { return cmp; } cmp = left->presentation - right->presentation; return cmp; } /*! * \brief Compare the left and right party subaddress. * * \param left Left parameter party subaddress. * \param right Right parameter party subaddress. * * \retval < 0 when left < right. * \retval == 0 when left == right. * \retval > 0 when left > right. */ int q931_party_subaddress_cmp(const struct q931_party_subaddress *left, const struct q931_party_subaddress *right) { int cmp; if (!left->valid) { if (!right->valid) { return 0; } return -1; } else if (!right->valid) { return 1; } cmp = left->type - right->type; if (cmp) { return cmp; } cmp = memcmp(left->data, right->data, (left->length < right->length) ? left->length : right->length); if (cmp) { return cmp; } cmp = left->length - right->length; if (cmp) { return cmp; } cmp = left->odd_even_indicator - right->odd_even_indicator; return cmp; } /*! * \brief Compare the left and right party address. * * \param left Left parameter party address. * \param right Right parameter party address. * * \retval < 0 when left < right. * \retval == 0 when left == right. * \retval > 0 when left > right. */ int q931_party_address_cmp(const struct q931_party_address *left, const struct q931_party_address *right) { int cmp; cmp = q931_party_number_cmp(&left->number, &right->number); if (cmp) { return cmp; } cmp = q931_party_subaddress_cmp(&left->subaddress, &right->subaddress); return cmp; } /*! * \brief Compare the left and right party id. * * \param left Left parameter party id. * \param right Right parameter party id. * * \retval < 0 when left < right. * \retval == 0 when left == right. * \retval > 0 when left > right. */ int q931_party_id_cmp(const struct q931_party_id *left, const struct q931_party_id *right) { int cmp; cmp = q931_party_number_cmp(&left->number, &right->number); if (cmp) { return cmp; } cmp = q931_party_subaddress_cmp(&left->subaddress, &right->subaddress); if (cmp) { return cmp; } cmp = q931_party_name_cmp(&left->name, &right->name); return cmp; } /*! * \brief Compare the left and right party id addresses. * * \param left Left parameter party id. * \param right Right parameter party id. * * \retval < 0 when left < right. * \retval == 0 when left == right. * \retval > 0 when left > right. */ int q931_party_id_cmp_address(const struct q931_party_id *left, const struct q931_party_id *right) { int cmp; cmp = q931_party_number_cmp(&left->number, &right->number); if (cmp) { return cmp; } cmp = q931_party_subaddress_cmp(&left->subaddress, &right->subaddress); return cmp; } /*! * \brief Compare the party id to the party address. * * \param id Party id. * \param address Party address. * * \retval < 0 when id < address. * \retval == 0 when id == address. * \retval > 0 when id > address. */ int q931_cmp_party_id_to_address(const struct q931_party_id *id, const struct q931_party_address *address) { int cmp; cmp = q931_party_number_cmp(&id->number, &address->number); if (cmp) { return cmp; } cmp = q931_party_subaddress_cmp(&id->subaddress, &address->subaddress); return cmp; } /*! * \brief Copy a party id into a party address. * * \param address Party address. * \param id Party id. * * \return Nothing */ void q931_party_id_copy_to_address(struct q931_party_address *address, const struct q931_party_id *id) { address->number = id->number; address->subaddress = id->subaddress; } /*! * \brief Copy the Q.931 party name to the PRI party name structure. * * \param pri_name PRI party name structure * \param q931_name Q.931 party name structure * * \return Nothing */ void q931_party_name_copy_to_pri(struct pri_party_name *pri_name, const struct q931_party_name *q931_name) { if (q931_name->valid) { pri_name->valid = 1; pri_name->presentation = q931_name->presentation; pri_name->char_set = q931_name->char_set; libpri_copy_string(pri_name->str, q931_name->str, sizeof(pri_name->str)); } else { pri_name->valid = 0; pri_name->presentation = PRI_PRES_UNAVAILABLE; pri_name->char_set = PRI_CHAR_SET_ISO8859_1; pri_name->str[0] = '\0'; } } /*! * \brief Copy the Q.931 party number to the PRI party number structure. * * \param pri_number PRI party number structure * \param q931_number Q.931 party number structure * * \return Nothing */ void q931_party_number_copy_to_pri(struct pri_party_number *pri_number, const struct q931_party_number *q931_number) { if (q931_number->valid) { pri_number->valid = 1; pri_number->presentation = q931_number->presentation; pri_number->plan = q931_number->plan; libpri_copy_string(pri_number->str, q931_number->str, sizeof(pri_number->str)); } else { pri_number->valid = 0; pri_number->presentation = PRES_NUMBER_NOT_AVAILABLE; pri_number->plan = (PRI_TON_UNKNOWN << 4) | PRI_NPI_E163_E164; pri_number->str[0] = '\0'; } } /*! * \brief Copy the Q.931 party subaddress to the PRI party subaddress structure. * * \param pri_subaddress PRI party subaddress structure * \param q931_subaddress Q.931 party subaddress structure * * \return Nothing */ void q931_party_subaddress_copy_to_pri(struct pri_party_subaddress *pri_subaddress, const struct q931_party_subaddress *q931_subaddress) { int length; if (!q931_subaddress->valid) { pri_subaddress->valid = 0; pri_subaddress->type = 0; pri_subaddress->odd_even_indicator = 0; pri_subaddress->length = 0; pri_subaddress->data[0] = '\0'; return; } pri_subaddress->valid = 1; pri_subaddress->type = q931_subaddress->type; pri_subaddress->odd_even_indicator = q931_subaddress->odd_even_indicator; /* * The size of pri_subaddress->data[] is not the same as the size of * q931_subaddress->data[]. */ length = q931_subaddress->length; pri_subaddress->length = length; memcpy(pri_subaddress->data, q931_subaddress->data, length); pri_subaddress->data[length] = '\0'; } /*! * \brief Copy the Q.931 party address to the PRI party address structure. * * \param pri_address PRI party address structure * \param q931_address Q.931 party address structure * * \return Nothing */ void q931_party_address_copy_to_pri(struct pri_party_address *pri_address, const struct q931_party_address *q931_address) { q931_party_number_copy_to_pri(&pri_address->number, &q931_address->number); q931_party_subaddress_copy_to_pri(&pri_address->subaddress, &q931_address->subaddress); } /*! * \brief Copy the Q.931 party id to the PRI party id structure. * * \param pri_id PRI party id structure * \param q931_id Q.931 party id structure * * \return Nothing */ void q931_party_id_copy_to_pri(struct pri_party_id *pri_id, const struct q931_party_id *q931_id) { q931_party_name_copy_to_pri(&pri_id->name, &q931_id->name); q931_party_number_copy_to_pri(&pri_id->number, &q931_id->number); q931_party_subaddress_copy_to_pri(&pri_id->subaddress, &q931_id->subaddress); } /*! * \brief Copy the Q.931 redirecting data to the PRI redirecting structure. * * \param pri_redirecting PRI redirecting structure * \param q931_redirecting Q.931 redirecting structure * * \return Nothing */ void q931_party_redirecting_copy_to_pri(struct pri_party_redirecting *pri_redirecting, const struct q931_party_redirecting *q931_redirecting) { q931_party_id_copy_to_pri(&pri_redirecting->from, &q931_redirecting->from); q931_party_id_copy_to_pri(&pri_redirecting->to, &q931_redirecting->to); q931_party_id_copy_to_pri(&pri_redirecting->orig_called, &q931_redirecting->orig_called); pri_redirecting->count = q931_redirecting->count; pri_redirecting->orig_reason = q931_redirecting->orig_reason; pri_redirecting->reason = q931_redirecting->reason; } /*! * \brief Fixup some values in the q931_party_id that may be objectionable by switches. * * \param ctrl D channel controller. * \param id Party ID to tweak. * * \return Nothing */ void q931_party_id_fixup(const struct pri *ctrl, struct q931_party_id *id) { switch (ctrl->switchtype) { case PRI_SWITCH_DMS100: case PRI_SWITCH_ATT4ESS: /* Doesn't like certain presentation types */ if (id->number.valid && (id->number.presentation & PRI_PRES_RESTRICTION) == PRI_PRES_ALLOWED) { /* i.e., If presentation is allowed it must be a network number */ id->number.presentation = PRES_ALLOWED_NETWORK_NUMBER; } break; default: break; } } /*! * \brief Determine the overall presentation value for the given party. * * \param id Party to determine the overall presentation value. * * \return Overall presentation value for the given party. */ int q931_party_id_presentation(const struct q931_party_id *id) { int number_priority; int number_value; int number_screening; int name_priority; int name_value; /* Determine name presentation priority. */ if (!id->name.valid) { name_value = PRI_PRES_UNAVAILABLE; name_priority = 3; } else { name_value = id->name.presentation & PRI_PRES_RESTRICTION; switch (name_value) { case PRI_PRES_RESTRICTED: name_priority = 0; break; case PRI_PRES_ALLOWED: name_priority = 1; break; case PRI_PRES_UNAVAILABLE: name_priority = 2; break; default: name_value = PRI_PRES_UNAVAILABLE; name_priority = 3; break; } } /* Determine number presentation priority. */ if (!id->number.valid) { number_screening = PRI_PRES_USER_NUMBER_UNSCREENED; number_value = PRI_PRES_UNAVAILABLE; number_priority = 3; } else { number_screening = id->number.presentation & PRI_PRES_NUMBER_TYPE; number_value = id->number.presentation & PRI_PRES_RESTRICTION; switch (number_value) { case PRI_PRES_RESTRICTED: number_priority = 0; break; case PRI_PRES_ALLOWED: number_priority = 1; break; case PRI_PRES_UNAVAILABLE: number_priority = 2; break; default: number_screening = PRI_PRES_USER_NUMBER_UNSCREENED; number_value = PRI_PRES_UNAVAILABLE; number_priority = 3; break; } } /* Select the wining presentation value. */ if (name_priority < number_priority) { number_value = name_value; } if (number_value == PRI_PRES_UNAVAILABLE) { return PRES_NUMBER_NOT_AVAILABLE; } return number_value | number_screening; } /*! * \internal * \brief Get binary buffer contents into the destination buffer. * * \param dst Destination buffer. * \param dst_size Destination buffer sizeof() * \param src Source buffer. * \param src_len Source buffer length to copy. * * \note The destination buffer is nul terminated just in case * the contents are used as a string anyway. * * \retval 0 on success. * \retval -1 on error. The copy did not happen. */ static int q931_memget(unsigned char *dst, size_t dst_size, const unsigned char *src, int src_len) { if (src_len < 0 || src_len > dst_size - 1) { dst[0] = 0; return -1; } memcpy(dst, src, src_len); dst[src_len] = 0; return 0; } /*! * \internal * \brief Get source buffer contents into the destination buffer for a string. * * \param dst Destination buffer. * \param dst_size Destination buffer sizeof() * \param src Source buffer. * \param src_len Source buffer length to copy. * * \note The destination buffer is nul terminated. * \note Nul bytes from the source buffer are not copied. * * \retval 0 on success. * \retval -1 if nul bytes were found in the source data. */ static int q931_strget(unsigned char *dst, size_t dst_size, const unsigned char *src, int src_len) { int saw_nul; if (src_len < 1) { dst[0] = '\0'; return 0; } saw_nul = 0; --dst_size; while (dst_size && src_len) { if (*src) { *dst++ = *src; --dst_size; } else { /* Skip nul bytes in the source buffer. */ saw_nul = -1; } ++src; --src_len; } *dst = '\0'; return saw_nul; } /*! * \internal * \brief Get source buffer contents into the destination buffer for a string. * * \param ctrl D channel controller. * \param ie_name IE name to report nul bytes found in. * \param dst Destination buffer. * \param dst_size Destination buffer sizeof() * \param src Source buffer. * \param src_len Source buffer length to copy. * * \note The destination buffer is nul terminated. * \note Nul bytes from the source buffer are not copied. * * \retval 0 on success. * \retval -1 if nul bytes were found in the source data. */ static int q931_strget_gripe(struct pri *ctrl, const char *ie_name, unsigned char *dst, size_t dst_size, const unsigned char *src, int src_len) { int saw_nul; /* To quietly remove nul octets just comment out the following line. */ #define UNCONDITIONALLY_REPORT_REMOVED_NUL_OCTETS 1 saw_nul = q931_strget(dst, dst_size, src, src_len); if (saw_nul #if !defined(UNCONDITIONALLY_REPORT_REMOVED_NUL_OCTETS) && (ctrl->debug & PRI_DEBUG_Q931_STATE) #endif ) { pri_message(ctrl, "!! Removed nul octets from IE '%s' and returning '%s'.\n", ie_name, dst); } return saw_nul; } /*! * \internal * \brief Clear the display text. * * \param call Q.931 call to clear display text. * * \return Nothing */ static void q931_display_clear(struct q931_call *call) { call->display.text = NULL; } /*! * \internal * \brief Set the display text for the party name. * * \param call Q.931 call to set display text to the party name. * * \return Nothing */ static void q931_display_name_send(struct q931_call *call, const struct q931_party_name *name) { if (name->valid) { switch (name->presentation & PRI_PRES_RESTRICTION) { case PRI_PRES_ALLOWED: call->display.text = (unsigned char *) name->str; call->display.full_ie = 0; call->display.length = strlen(name->str); call->display.char_set = name->char_set; break; default: call->display.text = NULL; break; } } else { call->display.text = NULL; } } /*! * \brief Get the display text into the party name. * * \param call Q.931 call to get the display text into the party name. * \param name Party name to fill if there is display text. * * \note * The party name is not touched if there is no display text. * * \note * The display text is consumed. * * \return TRUE if party name filled. */ int q931_display_name_get(struct q931_call *call, struct q931_party_name *name) { if (!call->display.text) { return 0; } name->valid = 1; name->char_set = call->display.char_set; q931_strget_gripe(call->pri, ie2str(call->display.full_ie), (unsigned char *) name->str, sizeof(name->str), call->display.text, call->display.length); if (name->str[0]) { name->presentation = PRI_PRES_ALLOWED; } else { name->presentation = PRI_PRES_RESTRICTED; } /* Mark the display text as consumed. */ call->display.text = NULL; return 1; } /*! * \internal * \brief Fill a subcmd with any display text. * * \param ctrl D channel controller. * \param call Q.931 call leg. * * \note * The display text is consumed. * * \return Nothing */ static void q931_display_subcmd(struct pri *ctrl, struct q931_call *call) { struct pri_subcommand *subcmd; if (call->display.text && call->display.length && (ctrl->display_flags.receive & PRI_DISPLAY_OPTION_TEXT)) { subcmd = q931_alloc_subcommand(ctrl); if (subcmd) { /* Setup display text subcommand */ subcmd->cmd = PRI_SUBCMD_DISPLAY_TEXT; subcmd->u.display.char_set = call->display.char_set; q931_strget_gripe(ctrl, ie2str(call->display.full_ie), (unsigned char *) subcmd->u.display.text, sizeof(subcmd->u.display.text), call->display.text, call->display.length); subcmd->u.display.length = strlen(subcmd->u.display.text); } } /* Mark the display text as consumed. */ call->display.text = NULL; } /*! * \brief Find the winning subcall if it exists or current call if not outboundbroadcast. * * \param call Starting Q.931 call record of search. * * \retval winning-call or given call if not outboundbroadcast. * \retval NULL if no winning call yet. */ struct q931_call *q931_find_winning_call(struct q931_call *call) { struct q931_call *master; master = call->master_call; if (master->outboundbroadcast) { /* We have potential subcalls. Now get the winning call if declared yet. */ if (master->pri_winner < 0) { /* Winner not declared yet.*/ call = NULL; } else { call = master->subcalls[master->pri_winner]; } } return call; } /*! * \internal * \brief Append the given ie contents to the save ie location. * * \param save_ie Saved ie contents to append new ie. * \param ie Contents to append. * * \return Nothing */ static void q931_append_ie_contents(struct q931_saved_ie_contents *save_ie, struct q931_ie *ie) { int size; size = ie->len + 2; if (size < sizeof(save_ie->data) - save_ie->length) { /* Contents will fit so append it. */ memcpy(&save_ie->data[save_ie->length], ie, size); save_ie->length += size; } } static void q931_clr_subcommands(struct pri *ctrl) { ctrl->subcmds.counter_subcmd = 0; } struct pri_subcommand *q931_alloc_subcommand(struct pri *ctrl) { if (ctrl->subcmds.counter_subcmd < PRI_MAX_SUBCOMMANDS) { return &ctrl->subcmds.subcmd[ctrl->subcmds.counter_subcmd++]; } pri_error(ctrl, "ERROR: Too many facility subcommands\n"); return NULL; } static char *code2str(int code, struct msgtype *codes, int max) { int x; for (x=0;x 32) len = 32; for (x=1;x<=len;x++) res[x-1] = b & (1 << (len - x)) ? '1' : '0'; return res; } static int receive_channel_id(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) { int x; int pos = 0; int need_extended_channel_octets;/*!< TRUE if octets 3.2 and 3.3 need to be present. */ call->restart.count = 0; if (ie->data[0] & 0x08) { call->chanflags = FLAG_EXCLUSIVE; } else { call->chanflags = FLAG_PREFERRED; } need_extended_channel_octets = 0; if (ie->data[0] & 0x20) { /* PRI encoded interface type */ switch (ie->data[0] & 0x03) { case 0x00: /* No channel */ call->channelno = 0; call->chanflags = FLAG_PREFERRED; break; case 0x01: /* As indicated in following octets */ need_extended_channel_octets = 1; break; case 0x03: /* Any channel */ call->chanflags = FLAG_PREFERRED; break; default: pri_error(ctrl, "!! Unexpected Channel selection %d\n", ie->data[0] & 0x03); return -1; } } else { /* BRI encoded interface type */ switch (ie->data[0] & 0x03) { case 0x00: /* No channel */ call->channelno = 0; call->chanflags = FLAG_PREFERRED; break; case 0x03: /* Any channel */ call->chanflags = FLAG_PREFERRED; break; default: /* Specified B channel (B1 or B2) */ call->channelno = ie->data[0] & 0x03; break; } } pos++; if (ie->data[0] & 0x40) { /* DS1 specified -- stop here */ call->ds1no = ie->data[1] & 0x7f; call->ds1explicit = 1; pos++; } else { call->ds1explicit = 0; } if (ie->data[0] & 0x04) { /* D channel call. Signaling only. */ call->cis_call = 1; call->chanflags = FLAG_EXCLUSIVE;/* For safety mark this channel as exclusive. */ call->channelno = 0; return 0; } if (need_extended_channel_octets && pos + 2 < len) { /* More coming */ if ((ie->data[pos] & 0x0f) != 3) { /* Channel type/mapping is not for B channel units. */ pri_error(ctrl, "!! Unexpected Channel Type %d\n", ie->data[pos] & 0x0f); return -1; } if ((ie->data[pos] & 0x60) != 0) { pri_error(ctrl, "!! Invalid CCITT coding %d\n", (ie->data[pos] & 0x60) >> 5); return -1; } if (ie->data[pos] & 0x10) { /* Expect Slot Map */ call->slotmap = 0; pos++; call->slotmap_size = (ie->len - pos > 3) ? 1 : 0; for (x = 0; x < (call->slotmap_size ? 4 : 3); ++x) { call->slotmap <<= 8; call->slotmap |= ie->data[x + pos]; } if (msgtype == Q931_RESTART) { int bit; /* Convert the slotmap to a channel list for RESTART support. */ for (bit = 0; bit < ARRAY_LEN(call->restart.chan_no); ++bit) { if (call->slotmap & (1UL << bit)) { call->restart.chan_no[call->restart.count++] = bit + (call->slotmap_size ? 0 : 1); } } } } else { pos++; /* Only expect a particular channel */ call->channelno = ie->data[pos] & 0x7f; if (ctrl->chan_mapping_logical && call->channelno > 15) { call->channelno++; } if (msgtype == Q931_RESTART) { /* Read in channel list for RESTART support. */ while (call->restart.count < ARRAY_LEN(call->restart.chan_no)) { int chan_no; chan_no = ie->data[pos] & 0x7f; if (ctrl->chan_mapping_logical && chan_no > 15) { ++chan_no; } call->restart.chan_no[call->restart.count++] = chan_no; if (ie->data[pos++] & 0x80) { /* Channel list finished. */ break; } if (ie->len <= pos) { /* No more ie contents. */ break; } } } } } return 0; } static int transmit_channel_id(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) { int pos = 0; /* We are ready to transmit single IE only */ if (order > 1) return 0; if (call->cis_call) { /* * Read the standards docs to figure this out. * Q.SIG ECMA-165 section 7.3 * ITU Q.931 section 4.5.13 */ ie->data[pos++] = ctrl->bri ? 0x8c : 0xac; return pos + 2; } /* Start with standard stuff */ if (ctrl->switchtype == PRI_SWITCH_GR303_TMC) ie->data[pos] = 0x69; else if (ctrl->bri) { ie->data[pos] = 0x80; ie->data[pos] |= (call->channelno & 0x3); } else { /* PRI */ if (call->slotmap != -1 || (call->chanflags & FLAG_WHOLE_INTERFACE)) { /* Specified channel */ ie->data[pos] = 0xa1; } else if (call->channelno < 0 || call->channelno == 0xff) { /* Any channel */ ie->data[pos] = 0xa3; } else if (!call->channelno) { /* No channel */ ie->data[pos] = 0xa0; } else { /* Specified channel */ ie->data[pos] = 0xa1; } } if (call->chanflags & FLAG_EXCLUSIVE) { /* Channel is exclusive */ if (!(ie->data[pos] & 0x03)) { /* An exclusive no channel id ie is to be discarded. */ return 0; } ie->data[pos] |= 0x08; } else if (!call->chanflags) { /* Don't need this IE */ return 0; } if (!ctrl->bri && (((ctrl->switchtype != PRI_SWITCH_QSIG) && (call->ds1no > 0)) || call->ds1explicit)) { /* We are specifying the interface. Octet 3.1 */ ie->data[pos++] |= 0x40; ie->data[pos++] = 0x80 | call->ds1no; } else { ++pos; } if (!ctrl->bri && (ie->data[0] & 0x03) == 0x01 /* Specified channel */ && !(call->chanflags & FLAG_WHOLE_INTERFACE)) { /* The 3.2 and 3.3 octets need to be present */ ie->data[pos] = 0x83; if (0 < call->channelno && call->channelno != 0xff) { /* Channel number specified and preferred over slot map if we have one. */ ++pos; if (msgtype == Q931_RESTART_ACKNOWLEDGE && call->restart.count) { int chan_no; int idx; /* Build RESTART_ACKNOWLEDGE channel list */ for (idx = 0; idx < call->restart.count; ++idx) { chan_no = call->restart.chan_no[idx]; if (ctrl->chan_mapping_logical && chan_no > 16) { --chan_no; } if (call->restart.count <= idx + 1) { /* Last channel list channel. */ chan_no |= 0x80; } ie->data[pos++] = chan_no; } } else { if (ctrl->chan_mapping_logical && call->channelno > 16) { ie->data[pos++] = 0x80 | (call->channelno - 1); } else { ie->data[pos++] = 0x80 | call->channelno; } } } else if (call->slotmap != -1) { int octet; /* We have to send a slot map */ ie->data[pos++] |= 0x10; for (octet = call->slotmap_size ? 4 : 3; octet--;) { ie->data[pos++] = (call->slotmap >> (8 * octet)) & 0xff; } } else { pri_error(ctrl, "XXX We need either a channelno or slotmap but have neither!\n"); /* Discard this malformed ie. */ return 0; } } return pos + 2; } static void dump_channel_id(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) { int pos; int x; int res; static const char *msg_chan_sel[] = { "No channel selected", "B1 channel", "B2 channel", "Any channel selected", "No channel selected", "As indicated in following octets", "Reserved", "Any channel selected" }; pri_message(ctrl, "%c %s (len=%2d) [ Ext: %d IntID: %s %s Spare: %d %s Dchan: %d\n", prefix, ie2str(full_ie), len, (ie->data[0] & 0x80) ? 1 : 0, (ie->data[0] & 0x40) ? "Explicit" : "Implicit", (ie->data[0] & 0x20) ? "Other(PRI)" : "BRI", (ie->data[0] & 0x10) ? 1 : 0, (ie->data[0] & 0x08) ? "Exclusive" : "Preferred", (ie->data[0] & 0x04) ? 1 : 0); pri_message(ctrl, "%c ChanSel: %s\n", prefix, msg_chan_sel[(ie->data[0] & 0x03) | ((ie->data[0] >> 3) & 0x04)]); pos = 1; len -= 2; if (ie->data[0] & 0x40) { /* Explicitly defined DS1 */ do { pri_message(ctrl, "%c Ext: %d DS1 Identifier: %d \n", prefix, (ie->data[pos] & 0x80) >> 7, ie->data[pos] & 0x7f); ++pos; } while (!(ie->data[pos - 1] & 0x80) && pos < len); } else { /* Implicitly defined DS1 */ } if (pos < len) { /* Still more information here */ pri_message(ctrl, "%c Ext: %d Coding: %d %s Specified Channel Type: %d\n", prefix, (ie->data[pos] & 0x80) >> 7, (ie->data[pos] & 60) >> 5, (ie->data[pos] & 0x10) ? "Slot Map" : "Number", ie->data[pos] & 0x0f); ++pos; } if (pos < len) { if (!(ie->data[pos - 1] & 0x10)) { /* Number specified */ do { pri_message(ctrl, "%c Ext: %d Channel: %d Type: %s%c\n", prefix, (ie->data[pos] & 0x80) >> 7, (ie->data[pos]) & 0x7f, pritype(ctrl->localtype), (pos + 1 < len) ? ' ' : ']'); ++pos; } while (pos < len); } else { /* Map specified */ res = 0; x = 0; do { res <<= 8; res |= ie->data[pos++]; ++x; } while (pos < len); pri_message(ctrl, "%c Map len: %d Map: %s ]\n", prefix, x, binary(res, x << 3)); } } else { pri_message(ctrl, "%c ]\n", prefix); } } static char *ri2str(int ri) { static struct msgtype ris[] = { { 0, "Indicated Channel" }, { 6, "Single DS1 Facility" }, { 7, "All DS1 Facilities" }, }; return code2str(ri, ris, sizeof(ris) / sizeof(ris[0])); } static void dump_restart_indicator(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) { pri_message(ctrl, "%c %s (len=%2d) [ Ext: %d Spare: %d Resetting %s (%d) ]\n", prefix, ie2str(full_ie), len, (ie->data[0] & 0x80) >> 7, (ie->data[0] & 0x78) >> 3, ri2str(ie->data[0] & 0x7), ie->data[0] & 0x7); } static int receive_restart_indicator(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) { /* Pretty simple */ call->ri = ie->data[0] & 0x7; return 0; } static int transmit_restart_indicator(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) { /* 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: pri_error(ctrl, "!! Invalid restart indicator value %d\n", call->ri); return-1; } return 3; } 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])); } static char *cap2str(int mode) { static struct msgtype modes[] = { { PRI_TRANS_CAP_SPEECH, "Speech" }, { PRI_TRANS_CAP_DIGITAL, "Unrestricted digital information" }, { PRI_TRANS_CAP_RESTRICTED_DIGITAL, "Restricted digital information" }, { PRI_TRANS_CAP_3_1K_AUDIO, "3.1kHz audio" }, { PRI_TRANS_CAP_DIGITAL_W_TONES, "Unrestricted digital information with tones/announcements" }, { PRI_TRANS_CAP_VIDEO, "Video" }, { PRI_TRANS_CAP_AUDIO_4ESS, "3.1khz audio (4ESS)" }, }; return code2str(mode, modes, sizeof(modes) / sizeof(modes[0])); } static char *mode2str(int mode) { 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])); } static char *l12str(int proto) { static struct msgtype protos[] = { { PRI_LAYER_1_ITU_RATE_ADAPT, "V.110 Rate Adaption" }, { PRI_LAYER_1_ULAW, "u-Law" }, { PRI_LAYER_1_ALAW, "A-Law" }, { PRI_LAYER_1_G721, "G.721 ADPCM" }, { PRI_LAYER_1_G722_G725, "G.722/G.725 7kHz Audio" }, { PRI_LAYER_1_H223_H245, "H.223/H.245 Multimedia" }, { 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" }, }; return code2str(proto, protos, sizeof(protos) / sizeof(protos[0])); } static char *ra2str(int proto) { static struct msgtype protos[] = { { PRI_RATE_ADAPT_9K6, "9.6 kbit/s" }, }; return code2str(proto, protos, sizeof(protos) / sizeof(protos[0])); } static char *l22str(int proto) { static struct msgtype protos[] = { { LAYER_2_LAPB, "LAPB" }, }; return code2str(proto, protos, sizeof(protos) / sizeof(protos[0])); } static char *l32str(int proto) { static struct msgtype protos[] = { { LAYER_3_X25, "X.25" }, }; return code2str(proto, protos, sizeof(protos) / sizeof(protos[0])); } 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])); } static void dump_bearer_capability(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) { int pos=2; pri_message(ctrl, "%c %s (len=%2d) [ Ext: %d Coding-Std: %d Info transfer capability: %s (%d)\n", prefix, ie2str(full_ie), len, (ie->data[0] & 0x80 ) >> 7, (ie->data[0] & 0x60) >> 5, cap2str(ie->data[0] & 0x1f), (ie->data[0] & 0x1f)); pri_message(ctrl, "%c Ext: %d Trans mode/rate: %s (%d)\n", prefix, (ie->data[1] & 0x80) >> 7, mode2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f); /* octet 4.1 exists if mode/rate is multirate */ if ((ie->data[1] & 0x7f) == 0x18) { pri_message(ctrl, "%c Ext: %d Transfer rate multiplier: %d x 64\n", prefix, (ie->data[2] & 0x80) >> 7, ie->data[2] & 0x7f); pos++; } /* 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(ctrl, "%c User information layer 1: %s (%d)\n", prefix, l12str(layer1), layer1); pos++; /* octet 5a? */ if (pos < len && !(ie->data[pos-1] & 0x80)) { int ra = ie->data[pos] & 0x7f; pri_message(ctrl, "%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(ctrl, "%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(ctrl, "%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(ctrl, "%c Unknown octet 5b: 0x%x\n", prefix, 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(ctrl, "%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(ctrl, "%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(ctrl, "%c User information layer 2: %s (%d)\n", prefix, l22str(ie->data[pos] & 0x1f), ie->data[pos] & 0x1f); pos++; } /* Look for octet 7; this is identified by bits 5,6 == 11 */ if (pos < len && (ie->data[pos] & 0x60) == 0x60) { pri_message(ctrl, "%c User information layer 3: %s (%d)\n", prefix, l32str(ie->data[pos] & 0x1f), ie->data[pos] & 0x1f); pos++; /* 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(ctrl, "%c Network layer: 0x%x\n", prefix, proto ); pos += 2; } } } static int receive_bearer_capability(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) { int pos = 2; switch (ie->data[0] & 0x60) { case 0x00:/* ITU-T standardized coding */ call->bc.transcapability = ie->data[0] & 0x1f; call->bc.transmoderate = ie->data[1] & 0x7f; /* octet 4.1 exists if mode/rate is multirate */ if (call->bc.transmoderate == TRANS_MODE_MULTIRATE) { call->bc.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 */ call->bc.userl1 = ie->data[pos] & 0x7f; pos++; /* octet 5a? */ if (pos < len && !(ie->data[pos-1] & 0x80)) { call->bc.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->bc.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->bc.userl3 = ie->data[pos++] & 0x1f; } break; case 0x20:/* ISO/IEC standard */ if (ie->data[0] == 0xa8 && ie->data[1] == 0x80) { /* * Q.SIG uses for CIS calls. ECMA-165 Section 11.3.1 * This mandatory ie is more or less a place holder in this case. */ call->bc.transcapability = PRI_TRANS_CAP_DIGITAL; call->bc.transmoderate = TRANS_MODE_64_CIRCUIT; break; } /* Fall through */ default: pri_error(ctrl, "!! Coding-standard field is not Q.931.\n"); return -1; } return 0; } static int transmit_bearer_capability(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) { int tc; int pos; /* We are ready to transmit single IE only */ if(order > 1) return 0; if (ctrl->link.next && !ctrl->bri) { /* Bearer capability is *hard coded* in GR-303 */ ie->data[0] = 0x88; ie->data[1] = 0x90; return 4; } if (call->cis_call) { ie->data[0] = 0xa8; ie->data[1] = 0x80; return 4; } tc = call->bc.transcapability; ie->data[0] = 0x80 | tc; ie->data[1] = call->bc.transmoderate | 0x80; pos = 2; /* octet 4.1 exists if mode/rate is multirate */ if (call->bc.transmoderate == TRANS_MODE_MULTIRATE) { ie->data[pos++] = call->bc.transmultiple | 0x80; } if ((tc & PRI_TRANS_CAP_DIGITAL) && (ctrl->switchtype == PRI_SWITCH_EUROISDN_E1) && (call->bc.transmoderate == TRANS_MODE_PACKET)) { /* Apparently EuroISDN switches don't seem to like user layer 2/3 */ return 4; } if ((tc & PRI_TRANS_CAP_DIGITAL) && (call->bc.transmoderate == TRANS_MODE_64_CIRCUIT)) { /* Unrestricted digital 64k data calls don't use user layer 2/3 */ return 4; } if (call->bc.transmoderate != TRANS_MODE_PACKET) { /* If you have an AT&T 4ESS, you don't send any more info */ if ((ctrl->switchtype != PRI_SWITCH_ATT4ESS) && (call->bc.userl1 > -1)) { ie->data[pos++] = call->bc.userl1 | 0x80; /* XXX Ext bit? XXX */ if (call->bc.userl1 == PRI_LAYER_1_ITU_RATE_ADAPT) { ie->data[pos++] = call->bc.rateadaption | 0x80; } return pos + 2; } ie->data[pos++] = 0xa0 | (call->bc.userl1 & 0x1f); if (call->bc.userl1 == PRI_LAYER_1_ITU_RATE_ADAPT) { ie->data[pos-1] &= ~0x80; /* clear EXT bit in octet 5 */ ie->data[pos++] = call->bc.rateadaption | 0x80; } } if (call->bc.userl2 != -1) ie->data[pos++] = 0xc0 | (call->bc.userl2 & 0x1f); if (call->bc.userl3 != -1) ie->data[pos++] = 0xe0 | (call->bc.userl3 & 0x1f); return pos + 2; } char *pri_plan2str(int plan) { 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])); } 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])); } /* Calling Party Category (Definitions from Q.763) */ static char *cpc2str(int plan) { static struct msgtype plans[] = { { 0, "Unknown Source" }, { 1, "Operator French" }, { 2, "Operator English" }, { 3, "Operator German" }, { 4, "Operator Russian" }, { 5, "Operator Spanish" }, { 6, "Mut Agree Chinese" }, { 7, "Mut Agreement" }, { 8, "Mut Agree Japanese" }, { 9, "National Operator" }, { 10, "Ordinary Toll Caller" }, { 11, "Priority Toll Caller" }, { 12, "Data Call" }, { 13, "Test Call" }, { 14, "Spare" }, { 15, "Pay Phone" }, }; return code2str(plan, plans, ARRAY_LEN(plans)); } char *pri_pres2str(int pres) { static struct msgtype press[] = { { PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED, "Presentation allowed, User-provided, not screened" }, { PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_PASSED_SCREEN, "Presentation allowed, User-provided, verified and passed" }, { PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_FAILED_SCREEN, "Presentation allowed, User-provided, verified and failed" }, { PRI_PRES_ALLOWED | PRI_PRES_NETWORK_NUMBER, "Presentation allowed, Network provided" }, { PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED, "Presentation restricted, User-provided, not screened" }, { PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_PASSED_SCREEN, "Presentation restricted, User-provided, verified and passed" }, { PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_FAILED_SCREEN, "Presentation restricted, User-provided, verified and failed" }, { PRI_PRES_RESTRICTED | PRI_PRES_NETWORK_NUMBER, "Presentation restricted, Network provided" }, { PRI_PRES_UNAVAILABLE | PRI_PRES_USER_NUMBER_UNSCREENED, "Number not available, User-provided, not screened" }, { PRI_PRES_UNAVAILABLE | PRI_PRES_USER_NUMBER_PASSED_SCREEN, "Number not available, User-provided, verified and passed" }, { PRI_PRES_UNAVAILABLE | PRI_PRES_USER_NUMBER_FAILED_SCREEN, "Number not available, User-provided, verified and failed" }, { PRI_PRES_UNAVAILABLE | PRI_PRES_NETWORK_NUMBER, "Number not available, Network provided" }, { PRI_PRES_RESERVED | PRI_PRES_USER_NUMBER_UNSCREENED, "Reserved, User-provided, not screened" }, { PRI_PRES_RESERVED | PRI_PRES_USER_NUMBER_PASSED_SCREEN, "Reserved, User-provided, verified and passed" }, { PRI_PRES_RESERVED | PRI_PRES_USER_NUMBER_FAILED_SCREEN, "Reserved, User-provided, verified and failed" }, { PRI_PRES_RESERVED | PRI_PRES_NETWORK_NUMBER, "Reserved, Network provided" }, }; pres &= (PRI_PRES_RESTRICTION | PRI_PRES_NUMBER_TYPE); return code2str(pres, press, sizeof(press) / sizeof(press[0])); } static void q931_get_subaddr_specific(unsigned char *num, int maxlen, unsigned char *src, int len, char oddflag) { /* User Specified */ int x; char *ptr = (char *) num; if (len <= 0) { num[0] = '\0'; return; } if (((len * 2) + 1) > maxlen) { len = (maxlen / 2) - 1; } for (x = 0; x < (len - 1); ++x) { ptr += sprintf(ptr, "%02x", src[x]); } if (oddflag) { /* ODD */ sprintf(ptr, "%01x", (src[len - 1]) >> 4); } else { /* EVEN */ sprintf(ptr, "%02x", src[len - 1]); } } static int transmit_subaddr_helper(int full_ie, struct pri *ctrl, struct q931_party_subaddress *q931_subaddress, int msgtype, q931_ie *ie, int offset, int len, int order) { size_t datalen; if (!q931_subaddress->valid) { return 0; } datalen = q931_subaddress->length; if (!q931_subaddress->type) { /* 0 = NSAP */ /* 0 = Odd/Even indicator */ ie->data[0] = 0x80; } else { /* 2 = User Specified */ ie->data[0] = q931_subaddress->odd_even_indicator ? 0xA8 : 0xA0; } memcpy(ie->data + offset, q931_subaddress->data, datalen); return datalen + (offset + 2); } static int receive_subaddr_helper(int full_ie, struct pri *ctrl, struct q931_party_subaddress *q931_subaddress, int msgtype, q931_ie *ie, int offset, int len) { if (len <= 0) { return -1; } q931_subaddress->valid = 1; q931_subaddress->length = len; /* type: 0 = NSAP, 2 = User Specified */ q931_subaddress->type = ((ie->data[0] & 0x70) >> 4); q931_subaddress->odd_even_indicator = (ie->data[0] & 0x08) ? 1 : 0; q931_memget(q931_subaddress->data, sizeof(q931_subaddress->data), ie->data + offset, len); return 0; } static void dump_subaddr_helper(int full_ie, struct pri *ctrl, q931_ie *ie, int offset, int len, int datalen, char prefix) { unsigned char cnum[256]; if (!(ie->data[0] & 0x70)) { /* NSAP Get it as a string for dump display purposes only. */ q931_strget(cnum, sizeof(cnum), ie->data + offset, datalen); } else { /* User Specified */ q931_get_subaddr_specific(cnum, sizeof(cnum), ie->data + offset, datalen, ie->data[0] & 0x08); } pri_message(ctrl, "%c %s (len=%2d) [ Ext: %d Type: %s (%d) O: %d '%s' ]\n", prefix, ie2str(full_ie), len, ie->data[0] >> 7, subaddrtype2str((ie->data[0] & 0x70) >> 4), (ie->data[0] & 0x70) >> 4, (ie->data[0] & 0x08) >> 3, cnum); } static void dump_called_party_number(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) { unsigned char cnum[256]; q931_strget(cnum, sizeof(cnum), ie->data + 1, len - 3); pri_message(ctrl, "%c %s (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d) '%s' ]\n", prefix, ie2str(full_ie), len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f, cnum); } static void dump_called_party_subaddr(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) { dump_subaddr_helper(full_ie, ctrl, ie, 1, len, len - 3, prefix); } static void dump_calling_party_number(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) { unsigned char cnum[256]; if (ie->data[0] & 0x80) { q931_strget(cnum, sizeof(cnum), ie->data + 1, len - 3); } else { q931_strget(cnum, sizeof(cnum), ie->data + 2, len - 4); } pri_message(ctrl, "%c %s (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d)\n", prefix, ie2str(full_ie), 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); if (ie->data[0] & 0x80) { pri_message(ctrl, "%c Presentation: %s (%d) '%s' ]\n", prefix, pri_pres2str(0), 0, cnum); } else { pri_message(ctrl, "%c Presentation: %s (%d) '%s' ]\n", prefix, pri_pres2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f, cnum); } } static void dump_calling_party_subaddr(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) { dump_subaddr_helper(full_ie, ctrl, ie, 1, len, len - 3, prefix); } static void dump_calling_party_category(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) { pri_message(ctrl, "%c %s (len=%2d) [ Ext: %d Cat: %s (%d) ]\n", prefix, ie2str(full_ie), len, ie->data[0] >> 7, cpc2str(ie->data[0] & 0x0F), ie->data[0] & 0x0F); } static void dump_redirecting_number(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) { unsigned char cnum[256]; int i = 0; /* To follow Q.931 (4.5.1), we must search for start of octet 4 by walking through all bytes until one with ext bit (8) set to 1 */ do { switch(i) { case 0: /* Octet 3 */ pri_message(ctrl, "%c %s (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d)", prefix, ie2str(full_ie), len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f); break; case 1: /* Octet 3a */ pri_message(ctrl, "\n"); pri_message(ctrl, "%c Ext: %d Presentation: %s (%d)", prefix, ie->data[1] >> 7, pri_pres2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f); break; case 2: /* Octet 3b */ pri_message(ctrl, "\n"); pri_message(ctrl, "%c Ext: %d Reason: %s (%d)", prefix, ie->data[2] >> 7, redirection_reason2str(ie->data[2] & 0x7f), ie->data[2] & 0x7f); break; } } while (!(ie->data[i++] & 0x80)); q931_strget(cnum, sizeof(cnum), ie->data + i, ie->len - i); pri_message(ctrl, " '%s' ]\n", cnum); } static void dump_redirection_number(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) { unsigned char cnum[256]; int i = 0; /* To follow Q.931 (4.5.1), we must search for start of octet 4 by walking through all bytes until one with ext bit (8) set to 1 */ do { switch (i) { case 0: /* Octet 3 */ pri_message(ctrl, "%c %s (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d)", prefix, ie2str(full_ie), len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f); break; case 1: /* Octet 3a */ pri_message(ctrl, "\n"); pri_message(ctrl, "%c Ext: %d Presentation: %s (%d)", prefix, ie->data[1] >> 7, pri_pres2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f); break; } } while (!(ie->data[i++] & 0x80)); q931_strget(cnum, sizeof(cnum), ie->data + i, ie->len - i); pri_message(ctrl, " '%s' ]\n", cnum); } static int receive_connected_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) { int i = 0; call->connected_number_in_message = 1; call->remote_id.number.valid = 1; call->remote_id.number.presentation = PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED; /* 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->remote_id.number.plan = ie->data[i] & 0x7f; break; case 1: /* Keep only the presentation and screening fields */ call->remote_id.number.presentation = ie->data[i] & (PRI_PRES_RESTRICTION | PRI_PRES_NUMBER_TYPE); break; } } while (!(ie->data[i++] & 0x80)); q931_strget_gripe(ctrl, ie2str(full_ie), (unsigned char *) call->remote_id.number.str, sizeof(call->remote_id.number.str), ie->data + i, ie->len - i); return 0; } static int transmit_connected_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) { size_t datalen; if (!call->local_id.number.valid) { return 0; } datalen = strlen(call->local_id.number.str); ie->data[0] = call->local_id.number.plan; ie->data[1] = 0x80 | call->local_id.number.presentation; memcpy(ie->data + 2, call->local_id.number.str, datalen); return datalen + (2 + 2); } static void dump_connected_number(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) { unsigned char cnum[256]; int i = 0; /* To follow Q.931 (4.5.1), we must search for start of octet 4 by walking through all bytes until one with ext bit (8) set to 1 */ do { switch(i) { case 0: /* Octet 3 */ pri_message(ctrl, "%c %s (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d)", prefix, ie2str(full_ie), len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f); break; case 1: /* Octet 3a */ pri_message(ctrl, "\n"); pri_message(ctrl, "%c Ext: %d Presentation: %s (%d)", prefix, ie->data[1] >> 7, pri_pres2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f); break; } } while(!(ie->data[i++]& 0x80)); q931_strget(cnum, sizeof(cnum), ie->data + i, ie->len - i); pri_message(ctrl, " '%s' ]\n", cnum); } static int receive_connected_subaddr(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) { if (len < 3) { return -1; } return receive_subaddr_helper(full_ie, ctrl, &call->remote_id.subaddress, msgtype, ie, 1, len - 3); } static int transmit_connected_subaddr(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) { return transmit_subaddr_helper(full_ie, ctrl, &call->local_id.subaddress, msgtype, ie, 1, len, order); } static void dump_connected_subaddr(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) { dump_subaddr_helper(full_ie, ctrl, ie, 1, len, len - 3, prefix); } static int receive_redirecting_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) { int i = 0; call->redirecting_number_in_message = 1; call->redirecting.from.number.valid = 1; call->redirecting.from.number.presentation = PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED; call->redirecting.reason = PRI_REDIR_UNKNOWN; /* 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->redirecting.from.number.plan = ie->data[i] & 0x7f; break; case 1: /* Keep only the presentation and screening fields */ call->redirecting.from.number.presentation = ie->data[i] & (PRI_PRES_RESTRICTION | PRI_PRES_NUMBER_TYPE); break; case 2: call->redirecting.reason = ie->data[i] & 0x0f; break; } } while (!(ie->data[i++] & 0x80)); q931_strget_gripe(ctrl, ie2str(full_ie), (unsigned char *) call->redirecting.from.number.str, sizeof(call->redirecting.from.number.str), ie->data + i, ie->len - i); return 0; } static int transmit_redirecting_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) { size_t datalen; if (order > 1) return 0; if (!call->redirecting.from.number.valid) { return 0; } if (BRI_TE_PTMP(ctrl)) { /* * We should not send this ie to the network if we are the TE * PTMP side since phones do not redirect calls within * themselves. Well... If you consider someone else dialing the * handset a redirection then how is the network to know? */ return 0; } if (call->redirecting.state != Q931_REDIRECTING_STATE_IDLE) { /* * There was a DivertingLegInformation2 in the message so the * Q931_REDIRECTING_NUMBER ie is redundant. Some networks * (Deutsche Telekom) complain about it. */ return 0; } datalen = strlen(call->redirecting.from.number.str); ie->data[0] = call->redirecting.from.number.plan; #if 1 /* ETSI and Q.952 do not define the screening field */ ie->data[1] = call->redirecting.from.number.presentation & PRI_PRES_RESTRICTION; #else /* Q.931 defines the screening field */ ie->data[1] = call->redirecting.from.number.presentation; #endif ie->data[2] = (call->redirecting.reason & 0x0f) | 0x80; memcpy(ie->data + 3, call->redirecting.from.number.str, datalen); return datalen + (3 + 2); } static void dump_redirecting_subaddr(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) { dump_subaddr_helper(full_ie, ctrl, ie, 2, len, len - 4, prefix); } static int receive_redirection_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) { int i = 0; call->redirection_number.valid = 1; call->redirection_number.presentation = PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED; /* 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->redirection_number.plan = ie->data[i] & 0x7f; break; case 1: /* Keep only the presentation and screening fields */ call->redirection_number.presentation = ie->data[i] & (PRI_PRES_RESTRICTION | PRI_PRES_NUMBER_TYPE); break; } } while (!(ie->data[i++] & 0x80)); q931_strget_gripe(ctrl, ie2str(full_ie), (unsigned char *) call->redirection_number.str, sizeof(call->redirection_number.str), ie->data + i, ie->len - i); return 0; } static int transmit_redirection_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) { size_t datalen; if (order > 1) { return 0; } if (!call->redirection_number.valid) { return 0; } datalen = strlen(call->redirection_number.str); ie->data[0] = call->redirection_number.plan; ie->data[1] = (call->redirection_number.presentation & PRI_PRES_RESTRICTION) | 0x80; memcpy(ie->data + 2, call->redirection_number.str, datalen); return datalen + (2 + 2); } static int receive_calling_party_subaddr(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) { if (len < 3) { return -1; } return receive_subaddr_helper(full_ie, ctrl, &call->remote_id.subaddress, msgtype, ie, 1, len - 3); } static int transmit_calling_party_subaddr(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) { return transmit_subaddr_helper(full_ie, ctrl, &call->local_id.subaddress, msgtype, ie, 1, len, order); } static int receive_called_party_subaddr(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) { if (len < 3) { return -1; } return receive_subaddr_helper(full_ie, ctrl, &call->called.subaddress, msgtype, ie, 1, len - 3); } static int transmit_called_party_subaddr(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) { return transmit_subaddr_helper(full_ie, ctrl, &call->called.subaddress, msgtype, ie, 1, len, order); } static int receive_called_party_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) { size_t called_len; size_t max_len; char *called_end; if (len < 3) { return -1; } switch (msgtype) { case Q931_FACILITY: if (!q931_is_dummy_call(call)) { /* Discard the number. */ return 0; } /* Fall through */ case Q931_REGISTER: /* Accept the number for REGISTER only because it is so similar to SETUP. */ case Q931_SETUP: q931_strget((unsigned char *) call->called.number.str, sizeof(call->called.number.str), ie->data + 1, len - 3); break; case Q931_INFORMATION: if (call->ourcallstate == Q931_CALL_STATE_OVERLAP_RECEIVING) { /* * Since we are receiving overlap digits now, we need to append * them to any previously received digits in call->called.number.str. */ called_len = strlen(call->called.number.str); called_end = call->called.number.str + called_len; max_len = (sizeof(call->called.number.str) - 1) - called_len; if (max_len < len - 3) { called_len = max_len; } else { called_len = len - 3; } strncat(called_end, (char *) ie->data + 1, called_len); } break; default: /* Discard the number. */ return 0; } call->called.number.valid = 1; call->called.number.plan = ie->data[0] & 0x7f; q931_strget_gripe(ctrl, ie2str(full_ie), (unsigned char *) call->overlap_digits, sizeof(call->overlap_digits), ie->data + 1, len - 3); return 0; } static int transmit_called_party_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) { size_t datalen; if (!call->called.number.valid) { return 0; } datalen = strlen(call->overlap_digits); ie->data[0] = 0x80 | call->called.number.plan; memcpy(ie->data + 1, call->overlap_digits, datalen); return datalen + (1 + 2); } static int receive_calling_party_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) { int i = 0; struct q931_party_number number; q931_party_number_init(&number); number.valid = 1; number.presentation = PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED; /* 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: number.plan = ie->data[i] & 0x7f; break; case 1: /* Keep only the presentation and screening fields */ number.presentation = ie->data[i] & (PRI_PRES_RESTRICTION | PRI_PRES_NUMBER_TYPE); break; } } while (!(ie->data[i++] & 0x80)); q931_strget_gripe(ctrl, ie2str(full_ie), (unsigned char *) number.str, sizeof(number.str), ie->data + i, ie->len - i); /* There can be more than one calling party number ie in the SETUP message. */ if (number.presentation == (PRI_PRES_ALLOWED | PRI_PRES_NETWORK_NUMBER) || number.presentation == (PRI_PRES_RESTRICTED | PRI_PRES_NETWORK_NUMBER)) { /* The number is network provided so it is an ANI number. */ call->ani = number; if (!call->remote_id.number.valid) { /* Copy ANI to CallerID if CallerID is not already set. */ call->remote_id.number = number; } } else { call->remote_id.number = number; } return 0; } static int transmit_calling_party_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) { size_t datalen; if (!call->local_id.number.valid) { return 0; } datalen = strlen(call->local_id.number.str); ie->data[0] = call->local_id.number.plan; ie->data[1] = 0x80 | call->local_id.number.presentation; memcpy(ie->data + 2, call->local_id.number.str, datalen); return datalen + (2 + 2); } static void dump_user_user(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) { int x; pri_message(ctrl, "%c %s (len=%2d) [", prefix, ie2str(full_ie), len); for (x = 0; x < ie->len; ++x) { pri_message(ctrl, " %02x", ie->data[x] & 0x7f); } pri_message(ctrl, " ]\n"); } static int receive_user_user(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) { call->useruserprotocoldisc = ie->data[0] & 0xff; if (call->useruserprotocoldisc == 4) { /* IA5 */ q931_memget((unsigned char *) call->useruserinfo, sizeof(call->useruserinfo), ie->data + 1, len - 3); } return 0; } static int transmit_user_user(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) { 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; } static void dump_change_status(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) { int x; pri_message(ctrl, "%c %s (len=%2d) [", prefix, ie2str(full_ie), len); for (x = 0; x < ie->len; ++x) { pri_message(ctrl, " %02x", ie->data[x] & 0x7f); } pri_message(ctrl, " ]\n"); } static int receive_change_status(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) { call->changestatus = ie->data[0] & 0x0f; return 0; } static int transmit_change_status(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) { ie->data[0] = 0xc0 | call->changestatus; return 3; } static char *prog2str(int prog) { static struct msgtype progs[] = { { 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." }, }; return code2str(prog, progs, sizeof(progs) / sizeof(progs[0])); } static char *coding2str(int cod) { 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])); } static char *loc2str(int loc) { 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])); } static void dump_progress_indicator(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) { pri_message(ctrl, "%c %s (len=%2d) [ Ext: %d Coding: %s (%d) 0: %d Location: %s (%d)\n", prefix, ie2str(full_ie), len, ie->data[0] >> 7, coding2str((ie->data[0] & 0x60) >> 5), (ie->data[0] & 0x60) >> 5, (ie->data[0] & 0x10) >> 4, loc2str(ie->data[0] & 0xf), ie->data[0] & 0xf); pri_message(ctrl, "%c Ext: %d Progress Description: %s (%d) ]\n", prefix, ie->data[1] >> 7, prog2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f); } static int receive_display(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) { u_int8_t *data; if (ctrl->display_flags.receive & PRI_DISPLAY_OPTION_BLOCK) { return 0; } data = ie->data; if (data[0] & 0x80) { /* Skip over character set */ data++; len--; } call->display.text = data; call->display.full_ie = full_ie; call->display.length = len - 2; call->display.char_set = PRI_CHAR_SET_ISO8859_1; return 0; } static int transmit_display(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) { size_t datalen; int i; if (!call->display.text || !call->display.length) { return 0; } if (ctrl->display_flags.send & PRI_DISPLAY_OPTION_BLOCK) { return 0; } i = 0; switch (ctrl->switchtype) { case PRI_SWITCH_QSIG: case PRI_SWITCH_EUROISDN_E1: case PRI_SWITCH_EUROISDN_T1: break; default: /* Prefix text with character set indicator. */ ie->data[0] = 0xb1; ++i; break; } datalen = call->display.length; if (MAX_DISPLAY_TEXT < datalen + i) { datalen = MAX_DISPLAY_TEXT - i; } memcpy(ie->data + i, call->display.text, datalen); return 2 + i + datalen; } static int receive_progress_indicator(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) { call->progloc = ie->data[0] & 0xf; call->progcode = (ie->data[0] & 0x60) >> 5; 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; case Q931_PROG_CALLER_RETURNED_TO_ISDN: call->progressmask |= PRI_PROG_CALLER_RETURNED_TO_ISDN; break; case Q931_PROG_INBAND_AVAILABLE: call->progressmask |= PRI_PROG_INBAND_AVAILABLE; break; case Q931_PROG_DELAY_AT_INTERF: call->progressmask |= PRI_PROG_DELAY_AT_INTERF; break; case Q931_PROG_INTERWORKING_WITH_PUBLIC: call->progressmask |= PRI_PROG_INTERWORKING_WITH_PUBLIC; break; case Q931_PROG_INTERWORKING_NO_RELEASE: call->progressmask |= PRI_PROG_INTERWORKING_NO_RELEASE; break; case Q931_PROG_INTERWORKING_NO_RELEASE_PRE_ANSWER: call->progressmask |= PRI_PROG_INTERWORKING_NO_RELEASE_PRE_ANSWER; break; case Q931_PROG_INTERWORKING_NO_RELEASE_POST_ANSWER: call->progressmask |= PRI_PROG_INTERWORKING_NO_RELEASE_POST_ANSWER; break; default: pri_error(ctrl, "XXX Invalid Progress indicator value received: %02x\n",(ie->data[1] & 0x7f)); break; } return 0; } static void q931_apdu_timeout(void *data); static int transmit_facility(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) { struct apdu_event **prev; struct apdu_event *cur; int apdu_len; for (prev = &call->apdus, cur = call->apdus; cur; prev = &cur->next, cur = cur->next) { if (!cur->sent && (cur->message == msgtype || cur->message == Q931_ANY_MESSAGE)) { break; } } if (!cur) { /* No APDU found */ return 0; } if (ctrl->debug & PRI_DEBUG_APDU) { pri_message(ctrl, "Adding facility ie contents to send in %s message:\n", msg2str(msgtype)); facility_decode_dump(ctrl, cur->apdu, cur->apdu_len); } if (len < cur->apdu_len) { pri_error(ctrl, "Could not fit facility ie in message. Size needed:%d Available space:%d\n", cur->apdu_len + 2, len); /* Remove APDU from list. */ *prev = cur->next; if (cur->response.callback) { /* Indicate to callback that the APDU had a problem getting sent. */ cur->response.callback(APDU_CALLBACK_REASON_ERROR, ctrl, call, cur, NULL); } free(cur); return 0; } memcpy(ie->data, cur->apdu, cur->apdu_len); apdu_len = cur->apdu_len; cur->sent = 1; if (cur->response.callback && cur->response.timeout_time) { int failed; if (0 < cur->response.timeout_time) { /* Sender specified a timeout duration. */ cur->timer = pri_schedule_event(ctrl, cur->response.timeout_time, q931_apdu_timeout, cur); failed = !cur->timer; } else { /* Sender wants to "timeout" only when specified messages are received. */ failed = !cur->response.num_messages; } if (failed) { /* Remove APDU from list. */ *prev = cur->next; /* Indicate to callback that the APDU had a problem getting sent. */ cur->response.callback(APDU_CALLBACK_REASON_ERROR, ctrl, call, cur, NULL); free(cur); } } else { /* Remove APDU from list. */ *prev = cur->next; free(cur); } return apdu_len + 2; } static int receive_facility(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) { /* Delay processing facility ie's till after all other ie's are processed. */ if (MAX_FACILITY_IES <= ctrl->facility.count) { pri_message(ctrl, "!! Too many facility ie's to delay.\n"); return -1; } /* Make sure we have enough room for the protocol profile ie octet(s) */ if (ie->data + ie->len < ie->data + 2) { return -1; } /* Save the facility ie location for delayed decode. */ ctrl->facility.ie[ctrl->facility.count] = ie; ctrl->facility.codeset[ctrl->facility.count] = Q931_IE_CODESET((unsigned) full_ie); ++ctrl->facility.count; return 0; } static int process_facility(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie) { struct fac_extension_header header; struct rose_message rose; const unsigned char *pos; const unsigned char *end; 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) { return -1; } switch (*pos & Q932_PROTOCOL_MASK) { case Q932_PROTOCOL_ROSE: case Q932_PROTOCOL_EXTENSIONS: break; default: 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); } return -1; } if (!(*pos & 0x80)) { /* DMS-100 Service indicator octet - Just ignore for now */ ++pos; } ++pos; if (ctrl->debug & PRI_DEBUG_APDU) { asn1_dump(ctrl, pos, end); } pos = fac_dec_extension_header(ctrl, pos, end, &header); if (!pos) { return -1; } 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); } return -1; } /* Process all components in the facility. */ while (pos < end) { pos = rose_decode(ctrl, pos, end, &rose); if (!pos) { return -1; } switch (rose.type) { case ROSE_COMP_TYPE_INVOKE: rose_handle_invoke(ctrl, call, msgtype, ie, &header, &rose.component.invoke); break; case ROSE_COMP_TYPE_RESULT: rose_handle_result(ctrl, call, msgtype, ie, &header, &rose.component.result); break; case ROSE_COMP_TYPE_ERROR: rose_handle_error(ctrl, call, msgtype, ie, &header, &rose.component.error); break; case ROSE_COMP_TYPE_REJECT: rose_handle_reject(ctrl, call, msgtype, ie, &header, &rose.component.reject); break; default: return -1; } } return 0; } static void q931_handle_facilities(struct pri *ctrl, q931_call *call, int msgtype) { unsigned idx; unsigned codeset; unsigned full_ie; q931_ie *ie; for (idx = 0; idx < ctrl->facility.count; ++idx) { ie = ctrl->facility.ie[idx]; if (ctrl->debug & PRI_DEBUG_Q931_STATE) { codeset = ctrl->facility.codeset[idx]; full_ie = Q931_FULL_IE(codeset, ie->ie); pri_message(ctrl, "-- Delayed processing IE %d (cs%d, %s)\n", ie->ie, codeset, ie2str(full_ie)); } process_facility(ctrl, call, msgtype, ie); } } /*! * \internal * \brief Check if any APDU responses "timeout" with the current Q.931 message. * * \param ctrl D channel controller. * \param call Q.931 call leg. * \param msgtype Q.931 message type received. * * \return Nothing */ static void q931_apdu_msg_expire(struct pri *ctrl, struct q931_call *call, int msgtype) { struct apdu_event **prev; struct apdu_event **prev_next; struct apdu_event *cur; unsigned idx; for (prev = &call->apdus; *prev; prev = prev_next) { cur = *prev; prev_next = &cur->next; if (cur->sent) { for (idx = 0; idx < cur->response.num_messages; ++idx) { if (cur->response.message_type[idx] == msgtype) { /* * APDU response message "timeout". * * Extract the APDU from the list so it cannot be * deleted from under us by the callback. */ prev_next = prev; *prev = cur->next; /* Stop any response timeout. */ pri_schedule_del(ctrl, cur->timer); cur->timer = 0; cur->response.callback(APDU_CALLBACK_REASON_TIMEOUT, ctrl, call, cur, NULL); free(cur); break; } } } } } static int transmit_progress_indicator(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) { int code, mask; /* Can't send progress indicator on GR-303 -- EVER! */ if (ctrl->link.next && !ctrl->bri) return 0; if (call->progressmask > 0) { if (call->progressmask & (mask = PRI_PROG_CALL_NOT_E2E_ISDN)) code = Q931_PROG_CALL_NOT_E2E_ISDN; else if (call->progressmask & (mask = PRI_PROG_CALLED_NOT_ISDN)) code = Q931_PROG_CALLED_NOT_ISDN; else if (call->progressmask & (mask = PRI_PROG_CALLER_NOT_ISDN)) code = Q931_PROG_CALLER_NOT_ISDN; else if (call->progressmask & (mask = PRI_PROG_INBAND_AVAILABLE)) code = Q931_PROG_INBAND_AVAILABLE; else if (call->progressmask & (mask = PRI_PROG_DELAY_AT_INTERF)) code = Q931_PROG_DELAY_AT_INTERF; else if (call->progressmask & (mask = PRI_PROG_INTERWORKING_WITH_PUBLIC)) code = Q931_PROG_INTERWORKING_WITH_PUBLIC; else if (call->progressmask & (mask = PRI_PROG_INTERWORKING_NO_RELEASE)) code = Q931_PROG_INTERWORKING_NO_RELEASE; else if (call->progressmask & (mask = PRI_PROG_INTERWORKING_NO_RELEASE_PRE_ANSWER)) code = Q931_PROG_INTERWORKING_NO_RELEASE_PRE_ANSWER; else if (call->progressmask & (mask = PRI_PROG_INTERWORKING_NO_RELEASE_POST_ANSWER)) code = Q931_PROG_INTERWORKING_NO_RELEASE_POST_ANSWER; else { code = 0; pri_error(ctrl, "XXX Undefined progress bit: %x\n", call->progressmask); } if (code) { ie->data[0] = 0x80 | (call->progcode << 5) | (call->progloc); ie->data[1] = 0x80 | code; call->progressmask &= ~mask; return 4; } } /* Leave off */ return 0; } static int transmit_call_state(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) { ie->data[0] = Q931_CALL_STATE_NULL; switch (call->ourcallstate) { case Q931_CALL_STATE_NULL: case Q931_CALL_STATE_CALL_INITIATED: case Q931_CALL_STATE_OVERLAP_SENDING: case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING: case Q931_CALL_STATE_CALL_DELIVERED: case Q931_CALL_STATE_CALL_PRESENT: case Q931_CALL_STATE_CALL_RECEIVED: case Q931_CALL_STATE_CONNECT_REQUEST: case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING: case Q931_CALL_STATE_ACTIVE: case Q931_CALL_STATE_DISCONNECT_REQUEST: case Q931_CALL_STATE_DISCONNECT_INDICATION: case Q931_CALL_STATE_SUSPEND_REQUEST: case Q931_CALL_STATE_RESUME_REQUEST: case Q931_CALL_STATE_RELEASE_REQUEST: case Q931_CALL_STATE_CALL_ABORT: case Q931_CALL_STATE_OVERLAP_RECEIVING: case Q931_CALL_STATE_CALL_INDEPENDENT_SERVICE: case Q931_CALL_STATE_RESTART_REQUEST: case Q931_CALL_STATE_RESTART: ie->data[0] = call->ourcallstate; break; case Q931_CALL_STATE_NOT_SET: break; } return 3; } static int receive_call_state(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) { call->sugcallstate = ie->data[0] & 0x3f; return 0; } /*! * \brief Convert the internal Q.931 call state to a string. * * \param callstate Internal Q.931 call state. * * \return String equivalent of the given Q.931 call state. */ const char *q931_call_state_str(enum Q931_CALL_STATE callstate) { static struct msgtype callstates[] = { /* *INDENT-OFF* */ { Q931_CALL_STATE_NULL, "Null" }, { Q931_CALL_STATE_CALL_INITIATED, "Call Initiated" }, { Q931_CALL_STATE_OVERLAP_SENDING, "Overlap Sending" }, { Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING, "Outgoing Call Proceeding" }, { Q931_CALL_STATE_CALL_DELIVERED, "Call Delivered" }, { Q931_CALL_STATE_CALL_PRESENT, "Call Present" }, { Q931_CALL_STATE_CALL_RECEIVED, "Call Received" }, { Q931_CALL_STATE_CONNECT_REQUEST, "Connect Request" }, { Q931_CALL_STATE_INCOMING_CALL_PROCEEDING, "Incoming Call Proceeding" }, { Q931_CALL_STATE_ACTIVE, "Active" }, { Q931_CALL_STATE_DISCONNECT_REQUEST, "Disconnect Request" }, { Q931_CALL_STATE_DISCONNECT_INDICATION, "Disconnect Indication" }, { Q931_CALL_STATE_SUSPEND_REQUEST, "Suspend Request" }, { Q931_CALL_STATE_RESUME_REQUEST, "Resume Request" }, { Q931_CALL_STATE_RELEASE_REQUEST, "Release Request" }, { Q931_CALL_STATE_CALL_ABORT, "Call Abort" }, { Q931_CALL_STATE_OVERLAP_RECEIVING, "Overlap Receiving" }, { Q931_CALL_STATE_CALL_INDEPENDENT_SERVICE, "Call Independent Service" }, { Q931_CALL_STATE_RESTART_REQUEST, "Restart Request" }, { Q931_CALL_STATE_RESTART, "Restart" }, { Q931_CALL_STATE_NOT_SET, "Not set. Internal use only." }, /* *INDENT-ON* */ }; return code2str(callstate, callstates, ARRAY_LEN(callstates)); } /*! * \internal * \brief Convert the Q.932 supplementary hold state to a string. * * \param state Q.932 supplementary hold state. * * \return String equivalent of the given hold state. */ static const char *q931_hold_state_str(enum Q931_HOLD_STATE state) { static struct msgtype hold_states[] = { /* *INDENT-OFF* */ { Q931_HOLD_STATE_IDLE, "Idle" }, { Q931_HOLD_STATE_HOLD_REQ, "Hold Request" }, { Q931_HOLD_STATE_HOLD_IND, "Hold Indication" }, { Q931_HOLD_STATE_CALL_HELD, "Call Held" }, { Q931_HOLD_STATE_RETRIEVE_REQ, "Retrieve Request" }, { Q931_HOLD_STATE_RETRIEVE_IND, "Retrieve Indication" }, /* *INDENT-ON* */ }; return code2str(state, hold_states, ARRAY_LEN(hold_states)); } static void dump_call_state(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) { pri_message(ctrl, "%c %s (len=%2d) [ Ext: %d Coding: %s (%d) Call state: %s (%d)\n", prefix, ie2str(full_ie), len, ie->data[0] >> 7, coding2str((ie->data[0] & 0xC0) >> 6), (ie->data[0] & 0xC0) >> 6, q931_call_state_str(ie->data[0] & 0x3f), ie->data[0] & 0x3f); } static void dump_call_identity(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) { int x; pri_message(ctrl, "%c %s (len=%2d) [ ", prefix, ie2str(full_ie), len); for (x = 0; x < ie->len; ++x) { pri_message(ctrl, "0x%02X ", ie->data[x]); } pri_message(ctrl, " ]\n"); } static void dump_time_date(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) { pri_message(ctrl, "%c %s (len=%2d) [ ", prefix, ie2str(full_ie), len); if (ie->len > 0) pri_message(ctrl, "%02d", ie->data[0]); if (ie->len > 1) pri_message(ctrl, "-%02d", ie->data[1]); if (ie->len > 2) pri_message(ctrl, "-%02d", ie->data[2]); if (ie->len > 3) pri_message(ctrl, " %02d", ie->data[3]); if (ie->len > 4) pri_message(ctrl, ":%02d", ie->data[4]); if (ie->len > 5) pri_message(ctrl, ":%02d", ie->data[5]); pri_message(ctrl, " ]\n"); } static int receive_time_date(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) { /* Ignore incoming Date/Time since we have no use for it at this time. */ return 0; } static int transmit_time_date(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) { time_t now; struct tm timedate; int ie_len; do { if (ctrl->date_time_send < PRI_DATE_TIME_SEND_DATE) { ie_len = 0; break; } /* Send the current date/time. */ time(&now); localtime_r(&now, &timedate); ie->data[0] = timedate.tm_year - 100; /* 1900+ */ ie->data[1] = timedate.tm_mon + 1; ie->data[2] = timedate.tm_mday; ie_len = 2 + 3; if (ctrl->date_time_send < PRI_DATE_TIME_SEND_DATE_HH) { break; } /* Add optional hour. */ ie->data[3] = timedate.tm_hour; ++ie_len; if (ctrl->date_time_send < PRI_DATE_TIME_SEND_DATE_HHMM) { break; } /* Add optional minutes. */ ie->data[4] = timedate.tm_min; ++ie_len; if (ctrl->date_time_send < PRI_DATE_TIME_SEND_DATE_HHMMSS) { break; } /* Add optional seconds. */ ie->data[5] = timedate.tm_sec; ++ie_len; } while (0); return ie_len; } static void dump_keypad_facility(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) { unsigned char tmp[64]; q931_strget(tmp, sizeof(tmp), ie->data, ie->len); pri_message(ctrl, "%c %s (len=%2d) [ %s ]\n", prefix, ie2str(full_ie), ie->len, tmp); } static int receive_keypad_facility(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) { if (ie->len == 0) return -1; q931_strget_gripe(ctrl, ie2str(full_ie), (unsigned char *) call->keypad_digits, sizeof(call->keypad_digits), ie->data, ie->len); return 0; } static int transmit_keypad_facility(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) { int sublen; sublen = strlen(call->keypad_digits); if (sublen) { libpri_copy_string((char *) ie->data, call->keypad_digits, sizeof(call->keypad_digits)); return sublen + 2; } else return 0; } static void dump_display(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) { int x; unsigned char buf[2*80 + 1]; char tmp[20 + 1]; x = 0; if (ie->len && (ie->data[x] & 0x80)) { snprintf(tmp, sizeof(tmp), "Charset: %02x ", ie->data[x] & 0x7f); ++x; } else { tmp[0] = '\0'; } q931_strget(buf, sizeof(buf), &ie->data[x], ie->len - x); pri_message(ctrl, "%c %s (len=%2d) %s[ %s ]\n", prefix, ie2str(full_ie), ie->len, tmp, buf); } #define CHECK_OVERFLOW(limit) \ if (tmpptr - tmp + limit >= sizeof(tmp)) { \ *tmpptr = '\0'; \ pri_message(ctrl, "%s", tmpptr = tmp); \ } static void dump_ie_data(struct pri *ctrl, unsigned char *c, int len) { static char hexs[16] = "0123456789ABCDEF"; char tmp[1024], *tmpptr; int lastascii = 0; tmpptr = tmp; for (; len; --len, ++c) { CHECK_OVERFLOW(7); if (isprint(*c)) { if (!lastascii) { if (tmpptr != tmp) { *tmpptr++ = ','; *tmpptr++ = ' '; } *tmpptr++ = '\''; lastascii = 1; } *tmpptr++ = *c; } else { if (lastascii) { *tmpptr++ = '\''; lastascii = 0; } if (tmpptr != tmp) { *tmpptr++ = ','; *tmpptr++ = ' '; } *tmpptr++ = '0'; *tmpptr++ = 'x'; *tmpptr++ = hexs[(*c >> 4) & 0x0f]; *tmpptr++ = hexs[(*c) & 0x0f]; } } if (lastascii) *tmpptr++ = '\''; *tmpptr = '\0'; pri_message(ctrl, "%s", tmp); } static void dump_facility(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) { pri_message(ctrl, "%c %s (len=%2d, codeset=%d) [ ", prefix, ie2str(full_ie), len, Q931_IE_CODESET(full_ie)); dump_ie_data(ctrl, ie->data, ie->len); pri_message(ctrl, " ]\n"); #if 0 /* Lets not dump parse of facility contents here anymore. */ /* * The ASN.1 decode dump has already been done when the facility ie was added to the outgoing * message or the ASN.1 decode dump will be done when the facility ie is processed on incoming * messages. This dump is redundant and very noisy. */ if (ie->len > 1) { int dataat = (ie->data[0] & 0x80) ? 1 : 2; pri_message(ctrl, "PROTOCOL %02X\n", ie->data[0] & Q932_PROTOCOL_MASK); asn1_dump(ctrl, ie->data + dataat, ie->data + ie->len); } #endif /* Lets not dump parse of facility contents here anymore. */ } static void dump_network_spec_fac(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) { pri_message(ctrl, "%c %s (len=%2d) [ ", prefix, ie2str(full_ie), ie->len); if (ie->data[0] == 0x00) { pri_message(ctrl, "%s", code2str(ie->data[1], facilities, ARRAY_LEN(facilities))); } else { dump_ie_data(ctrl, ie->data, ie->len); } pri_message(ctrl, " ]\n"); } static int receive_network_spec_fac(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) { return 0; } static int transmit_network_spec_fac(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) { /* We are ready to transmit single IE only */ if (order > 1) return 0; if (ctrl->nsf != PRI_NSF_NONE) { ie->data[0] = 0x00; ie->data[1] = ctrl->nsf; return 4; } /* Leave off */ return 0; } char *pri_cause2str(int cause) { return code2str(cause, causes, sizeof(causes) / sizeof(causes[0])); } static char *pri_causeclass2str(int cause) { static struct msgtype causeclasses[] = { { 0, "Normal Event" }, { 1, "Normal Event" }, { 2, "Network Congestion (resource unavailable)" }, { 3, "Service or Option not Available" }, { 4, "Service or Option not Implemented" }, { 5, "Invalid message (e.g. parameter out of range)" }, { 6, "Protocol Error (e.g. unknown message)" }, { 7, "Interworking" }, }; return code2str(cause, causeclasses, sizeof(causeclasses) / sizeof(causeclasses[0])); } static void dump_cause(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) { int x; pri_message(ctrl, "%c %s (len=%2d) [ Ext: %d Coding: %s (%d) Spare: %d Location: %s (%d)\n", prefix, ie2str(full_ie), len, ie->data[0] >> 7, coding2str((ie->data[0] & 0x60) >> 5), (ie->data[0] & 0x60) >> 5, (ie->data[0] & 0x10) >> 4, loc2str(ie->data[0] & 0xf), ie->data[0] & 0xf); pri_message(ctrl, "%c Ext: %d Cause: %s (%d), class = %s (%d) ]\n", 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); if (ie->len < 3) return; /* Dump cause data in readable form */ switch(ie->data[1] & 0x7f) { case PRI_CAUSE_IE_NONEXIST: for (x=2;xlen;x++) pri_message(ctrl, "%c Cause data %d: %02x (%d, %s IE)\n", prefix, x-1, ie->data[x], ie->data[x], ie2str(ie->data[x])); break; case PRI_CAUSE_WRONG_CALL_STATE: for (x=2;xlen;x++) pri_message(ctrl, "%c Cause data %d: %02x (%d, %s message)\n", prefix, x-1, ie->data[x], ie->data[x], msg2str(ie->data[x])); break; case PRI_CAUSE_RECOVERY_ON_TIMER_EXPIRE: pri_message(ctrl, "%c Cause data:", prefix); for (x=2;xlen;x++) pri_message(ctrl, " %02x", ie->data[x]); pri_message(ctrl, " (Timer T"); for (x=2;xlen;x++) pri_message(ctrl, "%c", ((ie->data[x] >= ' ') && (ie->data[x] < 0x7f)) ? ie->data[x] : '.'); pri_message(ctrl, ")\n"); break; default: for (x=2;xlen;x++) pri_message(ctrl, "%c Cause data %d: %02x (%d)\n", prefix, x-1, ie->data[x], ie->data[x]); break; } } static int receive_cause(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) { call->causeloc = ie->data[0] & 0xf; call->causecode = (ie->data[0] & 0x60) >> 5; call->cause = (ie->data[1] & 0x7f); return 0; } static int transmit_cause(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) { /* We are ready to transmit single IE only */ if (order > 1) return 0; 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; } } static void dump_sending_complete(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) { pri_message(ctrl, "%c %s (len=%2d)\n", prefix, ie2str(full_ie), len); } static int receive_sending_complete(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) { /* We've got a "Complete" message: Exect no further digits. */ call->complete = 1; return 0; } static int transmit_sending_complete(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) { if ((ctrl->overlapdial && call->complete) || /* Explicit */ (!ctrl->overlapdial && ((ctrl->switchtype == PRI_SWITCH_EUROISDN_E1) || /* Implicit */ (ctrl->switchtype == PRI_SWITCH_EUROISDN_T1)))) { /* Include this single-byte IE */ return 1; } return 0; } 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])); } static void dump_notify(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) { pri_message(ctrl, "%c %s (len=%2d): Ext: %d %s (%d)\n", prefix, ie2str(full_ie), len, ie->data[0] >> 7, notify2str(ie->data[0] & 0x7f), ie->data[0] & 0x7f); } static int receive_notify(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) { call->notify = ie->data[0] & 0x7F; return 0; } static int transmit_notify(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) { if (call->notify >= 0) { ie->data[0] = 0x80 | call->notify; return 3; } return 0; } static void dump_shift(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) { pri_message(ctrl, "%c %sLocking Shift (len=%02d): Requested codeset %d\n", prefix, (full_ie & 8) ? "Non-" : "", len, full_ie & 7); } static char *lineinfo2str(int info) { /* NAPNA ANI II digits */ static struct msgtype lineinfo[] = { { 0, "Plain Old Telephone Service (POTS)" }, { 1, "Multiparty line (more than 2)" }, { 2, "ANI failure" }, { 6, "Station Level Rating" }, { 7, "Special Operator Handling Required" }, { 20, "Automatic Identified Outward Dialing (AIOD)" }, { 23, "Coing or Non-Coin" }, { 24, "Toll free translated to POTS originated for non-pay station" }, { 25, "Toll free translated to POTS originated from pay station" }, { 27, "Pay station with coin control signalling" }, { 29, "Prison/Inmate Service" }, { 30, "Intercept (blank)" }, { 31, "Intercept (trouble)" }, { 32, "Intercept (regular)" }, { 34, "Telco Operator Handled Call" }, { 52, "Outward Wide Area Telecommunications Service (OUTWATS)" }, { 60, "TRS call from unrestricted line" }, { 61, "Cellular/Wireless PCS (Type 1)" }, { 62, "Cellular/Wireless PCS (Type 2)" }, { 63, "Cellular/Wireless PCS (Roaming)" }, { 66, "TRS call from hotel/motel" }, { 67, "TRS call from restricted line" }, { 70, "Line connected to pay station" }, { 93, "Private virtual network call" }, }; return code2str(info, lineinfo, sizeof(lineinfo) / sizeof(lineinfo[0])); } static void dump_line_information(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) { pri_message(ctrl, "%c %s (len=%02d): %s (%d)\n", prefix, ie2str(full_ie), len, lineinfo2str(ie->data[0]), ie->data[0]); } static int receive_line_information(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) { call->ani2 = ie->data[0]; return 0; } static int transmit_line_information(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) { #if 0 /* XXX Is this IE possible for 4ESS only? XXX */ if(ctrl->switchtype == PRI_SWITCH_ATT4ESS) { ie->data[0] = 0; return 3; } #endif return 0; } 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 void dump_generic_digits(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) { int encoding; int type; int idx; int value; if (len < 3) { pri_message(ctrl, "%c %s (len=%02d): Invalid length\n", prefix, ie2str(full_ie), len); return; } encoding = (ie->data[0] >> 5) & 7; type = ie->data[0] & 0x1F; pri_message(ctrl, "%c %s (len=%02d): Encoding %s Type %s\n", prefix, ie2str(full_ie), len, gdencoding2str(encoding), gdtype2str(type)); if (encoding == 3) { /* Binary */ pri_message(ctrl, "%c Don't know how to handle binary encoding\n", prefix); return; } if (len == 3) /* No number information */ return; pri_message(ctrl, "%c Digits: ", prefix); value = 0; for(idx = 3; idx < len; ++idx) { switch(encoding) { case 0: /* BCD even */ case 1: /* BCD odd */ pri_message(ctrl, "%d", ie->data[idx-2] & 0x0f); value = value * 10 + (ie->data[idx-2] & 0x0f); if(!encoding || (idx+1 < len)) { /* Special handling for BCD odd */ pri_message(ctrl, "%d", (ie->data[idx-2] >> 4) & 0x0f); value = value * 10 + ((ie->data[idx-2] >> 4) & 0x0f); } break; case 2: /* IA5 */ pri_message(ctrl, "%c", ie->data[idx-2]); value = value * 10 + ie->data[idx-2] - '0'; break; } } switch(type) { case 4: /* Info Digits */ pri_message(ctrl, " - %s", lineinfo2str(value)); break; } pri_message(ctrl, "\n"); } static int receive_generic_digits(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) { int encoding; int type; int idx; int value; int num_idx; char number[260]; if (len < 3) { pri_error(ctrl, "Invalid length of Generic Digits IE\n"); return -1; } encoding = (ie->data[0] >> 5) & 7; type = ie->data[0] & 0x1F; if (encoding == 3) { /* Binary */ pri_message(ctrl, "!! Unable to handle binary encoded Generic Digits IE\n"); return 0; } if (len == 3) /* No number information */ return 0; value = 0; 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 */ value = value * 10 + (ie->data[idx-2] & 0x0f); if(!encoding || (idx+1 < len)) /* Special handling for BCD odd */ value = value * 10 + ((ie->data[idx-2] >> 4) & 0x0f); 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->remote_id.number.valid) { call->remote_id.number.valid = 1; call->remote_id.number.presentation = PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED; call->remote_id.number.plan = PRI_UNKNOWN; libpri_copy_string(call->remote_id.number.str, number, sizeof(call->remote_id.number.str)); } break; #endif } return 0; } static int transmit_generic_digits(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) { #if 0 /* XXX Is this IE possible for other switches? XXX */ if (order > 1) return 0; if(ctrl->switchtype == PRI_SWITCH_NI1) { ie->data[0] = 0x04; /* BCD even, Info Digits */ ie->data[1] = 0x00; /* POTS */ return 4; } #endif return 0; } 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 void dump_signal(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) { pri_message(ctrl, "%c %s (len=%02d): ", prefix, ie2str(full_ie), len); if (len < 3) { pri_message(ctrl, "Invalid length\n"); return; } pri_message(ctrl, "Signal %s (%d)\n", signal2str(ie->data[0]), ie->data[0]); } static void dump_transit_count(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) { /* Defined in ECMA-225 */ pri_message(ctrl, "%c %s (len=%02d): ", prefix, ie2str(full_ie), len); if (len < 3) { pri_message(ctrl, "Invalid length\n"); return; } pri_message(ctrl, "Count=%d (0x%02x)\n", ie->data[0] & 0x1f, ie->data[0] & 0x1f); } static void dump_reverse_charging_indication(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) { pri_message(ctrl, "%c %s (len=%02d): %d\n", prefix, ie2str(full_ie), len, ie->data[0] & 0x7); } static int receive_reverse_charging_indication(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) { call->reversecharge = ie->data[0] & 0x7; return 0; } static int transmit_reverse_charging_indication(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) { if (call->reversecharge != PRI_REVERSECHARGE_NONE) { ie->data[0] = 0x80 | (call->reversecharge & 0x7); return 3; } return 0; } static struct ie ies[] = { /* Codeset 0 - Common */ { 1, NATIONAL_CHANGE_STATUS, "Change Status Information", dump_change_status, receive_change_status, transmit_change_status }, { 0, Q931_LOCKING_SHIFT, "Locking Shift", dump_shift }, { 0, Q931_BEARER_CAPABILITY, "Bearer Capability", dump_bearer_capability, receive_bearer_capability, transmit_bearer_capability }, { 0, Q931_CAUSE, "Cause", dump_cause, receive_cause, transmit_cause }, { 1, Q931_IE_CALL_STATE, "Call State", dump_call_state, receive_call_state, transmit_call_state }, { 0, Q931_CHANNEL_IDENT, "Channel ID", 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", dump_reverse_charging_indication, receive_reverse_charging_indication, transmit_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, transmit_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, receive_called_party_subaddr, transmit_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" }, { 0, Q931_IE_FACILITY, "Facility" , dump_facility, receive_facility, transmit_facility }, { 1, Q931_IE_REDIRECTION_NUMBER, "Redirection Number", dump_redirection_number, receive_redirection_number, transmit_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, receive_time_date, transmit_time_date }, { 1, Q931_IE_KEYPAD_FACILITY, "Keypad Facility", dump_keypad_facility, receive_keypad_facility, transmit_keypad_facility }, { 0, Q931_IE_SIGNAL, "Signal", dump_signal }, { 1, Q931_IE_SWITCHHOOK, "Switch-hook" }, { 1, Q931_IE_USER_USER, "User-User Information", dump_user_user, receive_user_user, transmit_user_user }, { 1, Q931_IE_ESCAPE_FOR_EXT, "Escape for Extension" }, { 1, Q931_IE_CALL_STATUS, "Call Status" }, { 1, Q931_IE_CHANGE_STATUS, "Change Status Information", dump_change_status, receive_change_status, transmit_change_status }, { 1, Q931_IE_CONNECTED_ADDR, "Connected Address", dump_connected_number, receive_connected_number, transmit_connected_number }, { 1, Q931_IE_CONNECTED_NUM, "Connected Number", dump_connected_number, receive_connected_number, transmit_connected_number }, { 1, Q931_IE_CONNECTED_SUBADDR, "Connected Subaddress", dump_connected_subaddr, receive_connected_subaddr, transmit_connected_subaddr }, { 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 }, /* Codeset 4 - Q.SIG specific */ { 1, QSIG_IE_TRANSIT_COUNT | Q931_CODESET(4), "Transit Count", dump_transit_count }, /* Codeset 5 - National specific (ETSI PISN specific) */ { 1, Q931_CALLING_PARTY_CATEGORY, "Calling Party Category", dump_calling_party_category }, /* Codeset 6 - Network specific */ { 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 }, /* Codeset 7 */ }; static char *ie2str(int ie) { unsigned int x; /* 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"; default: break; } break; 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: break; } break; default: break; } for (x = 0; x < ARRAY_LEN(ies); ++x) { if (ie == ies[x].ie) { return ies[x].name; } } return "Unknown Information Element"; } static inline unsigned int ielen(q931_ie *ie) { if ((ie->ie & 0x80) != 0) return 1; else return 2 + ie->len; } static inline int ielen_checked(q931_ie *ie, int len_remaining) { int len; if (ie->ie & 0x80) { len = 1; } else if (len_remaining < 2) { /* There is no length octet when there should be. */ len = -1; } else { len = 2 + ie->len; if (len_remaining < len) { /* There is not enough room left in the packet for this ie. */ len = -1; } } return len; } const char *msg2str(int msg) { unsigned int x; for (x=0;xcrlen > 3) { pri_error(NULL, "Call Reference Length Too long: %d\n", h->crlen); return Q931_DUMMY_CALL_REFERENCE; } switch (h->crlen) { case 2: cr = 0; 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 |= Q931_CALL_REFERENCE_FLAG; } break; case 0: cr = Q931_DUMMY_CALL_REFERENCE; break; default: pri_error(NULL, "Call Reference Length not supported: %d\n", h->crlen); cr = Q931_DUMMY_CALL_REFERENCE; break; } return cr; } static inline void q931_dumpie(struct pri *ctrl, int codeset, q931_ie *ie, char prefix) { unsigned int x; int full_ie = Q931_FULL_IE(codeset, ie->ie); int base_ie; char *buf = malloc(ielen(ie) * 3 + 1); int buflen = 0; buf[0] = '\0'; if (!(ie->ie & 0x80)) { buflen += sprintf(buf, " %02x", ielen(ie)-2); for (x = 0; x + 2 < ielen(ie); ++x) buflen += sprintf(buf + buflen, " %02x", ie->data[x]); } pri_message(ctrl, "%c [%02x%s]\n", prefix, ie->ie, buf); free(buf); /* 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; for (x = 0; x < ARRAY_LEN(ies); ++x) if (ies[x].ie == base_ie) { if (ies[x].dump) ies[x].dump(full_ie, ctrl, ie, ielen(ie), prefix); else pri_message(ctrl, "%c IE: %s (len = %d)\n", prefix, ies[x].name, ielen(ie)); return; } pri_error(ctrl, "!! %c Unknown IE %d (cs%d, len = %d)\n", prefix, Q931_IE_IE(base_ie), Q931_IE_CODESET(base_ie), ielen(ie)); } /*! * \brief Initialize the call record. * * \param link Q.921 link associated with the call. * \param call Q.931 call leg. * \param cr Call Reference identifier. * * \note The call record is assumed to already be memset() to zero. * * \return Nothing */ void q931_init_call_record(struct q921_link *link, struct q931_call *call, int cr) { struct pri *ctrl; call->cr = cr; call->slotmap = -1; call->channelno = -1; if (cr != Q931_DUMMY_CALL_REFERENCE) { call->newcall = 1; } call->ourcallstate = Q931_CALL_STATE_NULL; call->peercallstate = Q931_CALL_STATE_NULL; call->sugcallstate = Q931_CALL_STATE_NOT_SET; call->ri = -1; call->bc.transcapability = -1; call->bc.transmoderate = -1; call->bc.transmultiple = -1; call->bc.userl1 = -1; call->bc.userl2 = -1; call->bc.userl3 = -1; call->bc.rateadaption = -1; call->progress = -1; call->causecode = -1; call->causeloc = -1; call->cause = -1; call->useruserprotocoldisc = -1; call->aoc_units = -1; call->changestatus = -1; call->reversecharge = -1; call->pri_winner = -1; call->master_call = call; q931_party_number_init(&call->redirection_number); q931_party_address_init(&call->called); q931_party_id_init(&call->local_id); q931_party_id_init(&call->remote_id); q931_party_number_init(&call->ani); q931_party_redirecting_init(&call->redirecting); /* The call is now attached to whoever called us */ ctrl = link->ctrl; call->pri = ctrl; if (cr == Q931_DUMMY_CALL_REFERENCE) { /* Dummy calls are always for the given link. */ call->link = link; } else if (BRI_TE_PTMP(ctrl)) { /* Always uses the specific TEI link. */ call->link = ctrl->link.next; } else { call->link = link; } } /*! * \internal * \brief Create a new call record. * * \param link Q.921 link associated with the call. * \param cr Call Reference identifier. * * \retval record on success. * \retval NULL on error. */ static struct q931_call *q931_create_call_record(struct q921_link *link, int cr) { struct q931_call *call; struct q931_call *prev; struct pri *ctrl; ctrl = link->ctrl; if (ctrl->debug & PRI_DEBUG_Q931_STATE) { pri_message(ctrl, "-- Making new call for cref %d\n", cr); } call = calloc(1, sizeof(*call)); if (!call) { return NULL; } /* Initialize call structure. */ q931_init_call_record(link, call, cr); /* Append to the list end */ if (*ctrl->callpool) { /* Find the list end. */ for (prev = *ctrl->callpool; prev->next; prev = prev->next) { } prev->next = call; } else { /* List was empty. */ *ctrl->callpool = call; } return call; } /*! * \internal * \brief Find a call in the active call pool. * * \param link Q.921 link associated with the call. * \param cr Call Reference identifier. * * \retval call if found. * \retval NULL if not found. */ static struct q931_call *q931_find_call(struct q921_link *link, int cr) { struct q931_call *cur; struct pri *ctrl; if (cr == Q931_DUMMY_CALL_REFERENCE) { return link->dummy_call; } ctrl = link->ctrl; if (BRI_NT_PTMP(ctrl) && !(cr & Q931_CALL_REFERENCE_FLAG)) { if (link->tei == Q921_TEI_GROUP) { /* Broadcast TEI. This is bad. We are using the wrong link structure. */ pri_error(ctrl, "Looking for cref %d when using broadcast TEI.\n", cr); return NULL; } /* We are looking for a call reference value that the other side allocated. */ for (cur = *ctrl->callpool; cur; cur = cur->next) { if (cur->cr == cr && cur->link == link) { /* Found existing call. The call reference and link matched. */ break; } } } else { for (cur = *ctrl->callpool; cur; cur = cur->next) { if (cur->cr == cr) { /* Found existing call. */ switch (ctrl->switchtype) { case PRI_SWITCH_GR303_EOC: case PRI_SWITCH_GR303_TMC: break; default: if (!ctrl->bri) { /* The call is now attached to whoever called us */ cur->pri = ctrl; cur->link = link; } break; } break; } } } return cur; } static struct q931_call *q931_getcall(struct q921_link *link, int cr) { struct q931_call *cur; struct pri *ctrl; cur = q931_find_call(link, cr); if (cur) { return cur; } if (cr == Q931_DUMMY_CALL_REFERENCE) { /* Do not create new dummy call records. */ return NULL; } ctrl = link->ctrl; if (link->tei == Q921_TEI_GROUP && BRI_NT_PTMP(ctrl)) { /* Do not create NT PTMP broadcast call records here. */ pri_error(ctrl, "NT PTMP cannot create call record for cref %d on the broadcast TEI.\n", cr); return NULL; } /* No call record exists, make a new one */ return q931_create_call_record(link, cr); } /*! * \brief Create a new call record for an outgoing call. * * \param ctrl D channel controller. * * \retval call on success. * \retval NULL on error. */ struct q931_call *q931_new_call(struct pri *ctrl) { struct q931_call *cur; struct q921_link *link; int first_cref; int cref; /* Find a new call reference value. */ first_cref = ctrl->cref; do { cref = Q931_CALL_REFERENCE_FLAG | ctrl->cref; /* Next call reference. */ ++ctrl->cref; if (!ctrl->bri) { if (ctrl->cref > 32767) { ctrl->cref = 1; } } else { if (ctrl->cref > 127) { ctrl->cref = 1; } } /* Is the call reference value in use? */ for (cur = *ctrl->callpool; cur; cur = cur->next) { if (cur->cr == cref) { /* Yes it is in use. */ if (first_cref == ctrl->cref) { /* All call reference values are in use! */ return NULL; } break; } } } while (cur); link = &ctrl->link; return q931_create_call_record(link, cref); } static void stop_t303(struct q931_call *call); static void stop_t312(struct q931_call *call) { /* T312 should only be running on the master call */ pri_schedule_del(call->pri, call->t312_timer); call->t312_timer = 0; } static void cleanup_and_free_call(struct q931_call *cur) { struct pri *ctrl; ctrl = cur->pri; pri_schedule_del(ctrl, cur->restart.timer); pri_schedule_del(ctrl, cur->restart_tx.t316_timer); pri_schedule_del(ctrl, cur->retranstimer); pri_schedule_del(ctrl, cur->hold_timer); pri_schedule_del(ctrl, cur->fake_clearing_timer); stop_t303(cur); stop_t312(cur); pri_call_apdu_queue_cleanup(cur); if (cur->cc.record) { /* Unlink CC associations. */ if (cur->cc.record->original_call == cur) { cur->cc.record->original_call = NULL; } if (cur->cc.record->signaling == cur) { cur->cc.record->signaling = NULL; } } free(cur); } int q931_get_subcall_count(struct q931_call *master) { int count = 0; int idx; for (idx = 0; idx < ARRAY_LEN(master->subcalls); ++idx) { if (master->subcalls[idx]) { ++count; } } return count; } static int pri_internal_clear(struct q931_call *call); /*! * \brief Fake RELEASE for NT-PTMP initiated SETUPs w/o response * * \param param call Call is not a subcall call record. */ static void pri_fake_clearing(struct q931_call *call) { struct pri *ctrl; ctrl = call->pri; if (ctrl->debug & PRI_DEBUG_Q931_STATE) { pri_message(ctrl, "Fake clearing. cref:%d\n", call->cr); } /* * This does not need to be running since this is what we are * doing right now anyway. */ pri_schedule_del(ctrl, call->fake_clearing_timer); call->fake_clearing_timer = 0; if (call->cause == -1) { /* Ensure that there is a resonable cause code. */ call->cause = PRI_CAUSE_NO_USER_RESPONSE; } if (pri_internal_clear(call) == Q931_RES_HAVEEVENT) { ctrl->schedev = 1; } } static void pri_fake_clearing_expiry(void *data) { struct q931_call *master = data; master->fake_clearing_timer = 0; pri_fake_clearing(master); } static void pri_create_fake_clearing(struct pri *ctrl, struct q931_call *master) { if (ctrl->debug & PRI_DEBUG_Q931_STATE) { pri_message(ctrl, "Fake clearing requested. cref:%d\n", master->cr); } pri_schedule_del(ctrl, master->fake_clearing_timer); master->fake_clearing_timer = pri_schedule_event(ctrl, 0, pri_fake_clearing_expiry, master); } static void t312_expiry(void *data) { struct q931_call *master = data; struct pri *ctrl; ctrl = master->pri; if (ctrl->debug & PRI_DEBUG_Q931_STATE) { pri_message(ctrl, "T312 timed out. cref:%d\n", master->cr); } master->t312_timer = 0; if (!q931_get_subcall_count(master)) { /* No subcalls remain. */ switch (master->ourcallstate) { case Q931_CALL_STATE_CALL_ABORT: /* We can destroy the master. */ q931_destroycall(ctrl, master); break; default: /* Let the upper layer know about the lack of call prospects. */ UPDATE_OURCALLSTATE(ctrl, master, Q931_CALL_STATE_CALL_ABORT); pri_fake_clearing(master); break; } } } /*! \param master Master call record for PTMP NT call. */ static void start_t312(struct q931_call *master) { struct pri *ctrl; ctrl = master->pri; pri_schedule_del(ctrl, master->t312_timer); master->t312_timer = pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T312], t312_expiry, master); } /*! * \internal * \brief Helper function to destroy a subcall. * * \param master Q.931 master call of subcall to destroy. * \param idx Master subcall index to destroy. * * \return Nothing */ static void q931_destroy_subcall(struct q931_call *master, int idx) { struct pri *ctrl = master->pri; if (ctrl->debug & PRI_DEBUG_Q931_STATE) { pri_message(ctrl, "Destroying subcall %p of call %p at %d\n", master->subcalls[idx], master, idx); } cleanup_and_free_call(master->subcalls[idx]); if (master->pri_winner == idx) { /* This was the winning subcall. */ master->pri_winner = -1; } master->subcalls[idx] = NULL; } void q931_destroycall(struct pri *ctrl, q931_call *c) { struct q931_call *cur; struct q931_call *prev; struct q931_call *slave; int i; int slavesleft; if (q931_is_dummy_call(c)) { /* Cannot destroy the dummy call. */ return; } if (c->master_call != c) { slave = c; c = slave->master_call; } else { slave = NULL; } prev = NULL; cur = *ctrl->callpool; while (cur) { if (cur == c) { if (slave) { /* Destroying a slave. */ for (i = 0; i < ARRAY_LEN(cur->subcalls); ++i) { if (cur->subcalls[i] == slave) { q931_destroy_subcall(cur, i); break; } } /* How many slaves are left? */ slavesleft = 0; for (i = 0; i < ARRAY_LEN(cur->subcalls); ++i) { if (cur->subcalls[i]) { if (ctrl->debug & PRI_DEBUG_Q931_STATE) { pri_message(ctrl, "Subcall still present at %d\n", i); } ++slavesleft; } } if (slavesleft || cur->t312_timer || cur->master_hanging_up) { return; } /* No slaves left. */ switch (cur->ourcallstate) { case Q931_CALL_STATE_CALL_ABORT: break; default: /* Let the upper layer know about the call clearing. */ UPDATE_OURCALLSTATE(ctrl, cur, Q931_CALL_STATE_CALL_ABORT); pri_create_fake_clearing(ctrl, cur); return; } /* We can try to destroy the master now. */ } else { /* Destroy any slaves that may be present as well. */ slavesleft = 0; for (i = 0; i < ARRAY_LEN(cur->subcalls); ++i) { if (cur->subcalls[i]) { ++slavesleft; q931_destroy_subcall(cur, i); } } } if (cur->fake_clearing_timer) { /* * Must wait for the fake clearing to complete before destroying * the master call record. */ return; } if (slavesleft) { /* This is likely not good. */ pri_error(ctrl, "Destroyed %d subcalls unconditionally with the master. cref:%d\n", slavesleft, cur->cr); } /* Master call or normal call destruction. */ if (prev) prev->next = cur->next; else *ctrl->callpool = cur->next; if (ctrl->debug & PRI_DEBUG_Q931_STATE) pri_message(ctrl, "Destroying call %p, ourstate %s, peerstate %s, hold-state %s\n", cur, q931_call_state_str(cur->ourcallstate), q931_call_state_str(cur->peercallstate), q931_hold_state_str(cur->hold_state)); cleanup_and_free_call(cur); return; } prev = cur; cur = cur->next; } pri_error(ctrl, "Can't destroy call %p cref:%d!\n", c, c->cr); } static int add_ie(struct pri *ctrl, q931_call *call, int msgtype, int ie, q931_ie *iet, int maxlen, int *codeset) { unsigned int x; int res, total_res; int have_shift; int ies_count, order; for (x = 0; x < ARRAY_LEN(ies); ++x) { if (ies[x].ie == ie) { /* This is our baby */ if (ies[x].transmit) { /* 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; 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, ctrl, 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; if (msgtype == Q931_SETUP && *codeset == 0) { switch (iet->ie) { case Q931_BEARER_CAPABILITY: if (!(call->cc.saved_ie_flags & CC_SAVED_IE_BC)) { /* Save first BC ie contents for possible CC. */ call->cc.saved_ie_flags |= CC_SAVED_IE_BC; q931_append_ie_contents(&call->cc.saved_ie_contents, iet); } break; case Q931_LOW_LAYER_COMPAT: if (!(call->cc.saved_ie_flags & CC_SAVED_IE_LLC)) { /* Save first LLC ie contents for possible CC. */ call->cc.saved_ie_flags |= CC_SAVED_IE_LLC; q931_append_ie_contents(&call->cc.saved_ie_contents, iet); } break; case Q931_HIGH_LAYER_COMPAT: if (!(call->cc.saved_ie_flags & CC_SAVED_IE_HLC)) { /* Save first HLC ie contents for possible CC. */ call->cc.saved_ie_flags |= CC_SAVED_IE_HLC; q931_append_ie_contents(&call->cc.saved_ie_contents, iet); } break; default: break; } } total_res += res; maxlen -= res; iet = (q931_ie *)((char *)iet + res); } } while (res > 0 && order < ies_count); if (have_shift && total_res) { if (Q931_IE_CODESET(ies[x].ie)) *codeset = Q931_IE_CODESET(ies[x].ie); return total_res + 1; /* Shift is single-byte IE */ } return total_res; } else { pri_error(ctrl, "!! Don't know how to add an IE %s (%d)\n", ie2str(ie), ie); return -1; } } } pri_error(ctrl, "!! Unknown IE %d (%s)\n", ie, ie2str(ie)); return -1; } static char *disc2str(int disc) { static struct msgtype discs[] = { { Q931_PROTOCOL_DISCRIMINATOR, "Q.931" }, { GR303_PROTOCOL_DISCRIMINATOR, "GR-303" }, { MAINTENANCE_PROTOCOL_DISCRIMINATOR_1, "AT&T Maintenance" }, { MAINTENANCE_PROTOCOL_DISCRIMINATOR_2, "New AT&T Maintenance" }, }; return code2str(disc, discs, sizeof(discs) / sizeof(discs[0])); } /*! * \internal * \brief Dump the Q.931 message header. * * \param ctrl D channel controller. * \param tei TEI the packet is associated with. * \param h Q.931 packet contents/header. * \param len Received length of the Q.931 packet. * \param c Message direction prefix character. * * \retval 0 on success. * \retval -1 on error. */ static int q931_dump_header(struct pri *ctrl, int tei, q931_h *h, int len, char c) { q931_mh *mh; int cref; pri_message(ctrl, "%c Protocol Discriminator: %s (%d) len=%d\n", c, disc2str(h->pd), h->pd, len); if (len < 2 || len < 2 + h->crlen) { pri_message(ctrl, "%c Message too short for call reference. len=%d\n", c, len); return -1; } cref = q931_cr(h); pri_message(ctrl, "%c TEI=%d Call Ref: len=%2d (reference %d/0x%X) (%s)\n", c, tei, h->crlen, cref & ~Q931_CALL_REFERENCE_FLAG, cref & ~Q931_CALL_REFERENCE_FLAG, (cref == Q931_DUMMY_CALL_REFERENCE) ? "Dummy" : (cref & Q931_CALL_REFERENCE_FLAG) ? "Sent to originator" : "Sent from originator"); if (len < 3 + h->crlen) { pri_message(ctrl, "%c Message too short for supported protocols. len=%d\n", c, len); return -1; } /* Message header begins at the end of the call reference number */ mh = (q931_mh *)(h->contents + h->crlen); switch (h->pd) { case MAINTENANCE_PROTOCOL_DISCRIMINATOR_1: case MAINTENANCE_PROTOCOL_DISCRIMINATOR_2: pri_message(ctrl, "%c Message Type: %s (%d)\n", c, maintenance_msg2str(mh->msg, h->pd), mh->msg); break; default: /* Unknown protocol discriminator but we will treat it as Q.931 anyway. */ case GR303_PROTOCOL_DISCRIMINATOR: case Q931_PROTOCOL_DISCRIMINATOR: pri_message(ctrl, "%c Message Type: %s (%d)\n", c, msg2str(mh->msg), mh->msg); break; } return 0; } /*! * \internal * \brief Q.931 is passing this message to Q.921 debug indication. * * \param ctrl D channel controller. * \param tei TEI the packet is associated with. * \param h Q.931 packet contents/header. * \param len Received length of the Q.931 packet * * \return Nothing */ static void q931_to_q921_passing_dump(struct pri *ctrl, int tei, q931_h *h, int len) { char c; c = '>'; pri_message(ctrl, "\n"); pri_message(ctrl, "%c DL-DATA request\n", c); q931_dump_header(ctrl, tei, h, len, c); } /*! * \brief Debug dump the given Q.931 packet. * * \param ctrl D channel controller. * \param tei TEI the packet is associated with. * \param h Q.931 packet contents/header. * \param len Received length of the Q.931 packet * \param txrx TRUE if packet is transmitted/outgoing * * \return Nothing */ void q931_dump(struct pri *ctrl, int tei, q931_h *h, int len, int txrx) { q931_mh *mh; char c; int x; int r; int cur_codeset; int codeset; c = txrx ? '>' : '<'; if (!(ctrl->debug & (PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_RAW))) { /* Put out a blank line if Q.921 is not dumping. */ pri_message(ctrl, "\n"); } if (q931_dump_header(ctrl, tei, h, len, c)) { return; } /* Drop length of header, including call reference */ mh = (q931_mh *)(h->contents + h->crlen); len -= (h->crlen + 3); codeset = cur_codeset = 0; for (x = 0; x < len; x += r) { r = ielen_checked((q931_ie *) (mh->data + x), len - x); if (r < 0) { /* We have garbage on the end of the packet. */ pri_message(ctrl, "Not enough room for codeset:%d ie:%d(%02x)\n", cur_codeset, mh->data[x], mh->data[x]); break; } q931_dumpie(ctrl, cur_codeset, (q931_ie *)(mh->data + x), c); switch (mh->data[x] & 0xf8) { case Q931_LOCKING_SHIFT: if ((mh->data[x] & 7) > 0) codeset = cur_codeset = mh->data[x] & 7; break; case Q931_NON_LOCKING_SHIFT: cur_codeset = mh->data[x] & 7; break; default: /* Reset temporary codeset change */ cur_codeset = codeset; break; } } } static int q931_handle_ie(int codeset, struct pri *ctrl, q931_call *c, int msg, q931_ie *ie) { unsigned int x; int full_ie = Q931_FULL_IE(codeset, ie->ie); if (ctrl->debug & PRI_DEBUG_Q931_STATE) pri_message(ctrl, "-- Processing IE %d (cs%d, %s)\n", ie->ie, codeset, ie2str(full_ie)); if (msg == Q931_SETUP && codeset == 0) { switch (ie->ie) { case Q931_BEARER_CAPABILITY: if (!(c->cc.saved_ie_flags & CC_SAVED_IE_BC)) { /* Save first BC ie contents for possible CC. */ c->cc.saved_ie_flags |= CC_SAVED_IE_BC; q931_append_ie_contents(&c->cc.saved_ie_contents, ie); } break; case Q931_LOW_LAYER_COMPAT: if (!(c->cc.saved_ie_flags & CC_SAVED_IE_LLC)) { /* Save first LLC ie contents for possible CC. */ c->cc.saved_ie_flags |= CC_SAVED_IE_LLC; q931_append_ie_contents(&c->cc.saved_ie_contents, ie); } break; case Q931_HIGH_LAYER_COMPAT: if (!(c->cc.saved_ie_flags & CC_SAVED_IE_HLC)) { /* Save first HLC ie contents for possible CC. */ c->cc.saved_ie_flags |= CC_SAVED_IE_HLC; q931_append_ie_contents(&c->cc.saved_ie_contents, ie); } break; default: break; } } for (x = 0; x < ARRAY_LEN(ies); ++x) { if (full_ie == ies[x].ie) { if (ies[x].receive) return ies[x].receive(full_ie, ctrl, c, msg, ie, ielen(ie)); else { if (ctrl->debug & PRI_DEBUG_Q931_ANOMALY) pri_message(ctrl, "!! No handler for IE %d (cs%d, %s)\n", ie->ie, codeset, ie2str(full_ie)); return -1; } } } pri_message(ctrl, "!! Unknown IE %d (cs%d)\n", ie->ie, codeset); return -1; } /* 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) { q931_h *h = (q931_h *) buf; q931_mh *mh; unsigned crv; if (protodisc) { h->pd = protodisc; } else { h->pd = ctrl->protodisc; } h->x0 = 0; /* Reserved 0 */ if (q931_is_dummy_call(call)) { h->crlen = 0; } else if (!ctrl->bri) { /* Two bytes of Call Reference. */ h->crlen = 2; if (ctrl->link.next) { /* On GR-303, Q931_CALL_REFERENCE_FLAG is always 0 */ crv = ((unsigned) call->cr) & ~Q931_CALL_REFERENCE_FLAG; } else { /* Invert the Q931_CALL_REFERENCE_FLAG to make it from our sense */ crv = ((unsigned) call->cr) ^ Q931_CALL_REFERENCE_FLAG; } h->crv[0] = (crv >> 8) & 0xff; h->crv[1] = crv & 0xff; } else { h->crlen = 1; /* Invert the Q931_CALL_REFERENCE_FLAG to make it from our sense */ crv = ((unsigned) call->cr) ^ Q931_CALL_REFERENCE_FLAG; h->crv[0] = ((crv >> 8) & 0x80) | (crv & 0x7f); } *hb = h; *len -= 3;/* Protocol discriminator, call reference length, message type id */ *len -= h->crlen; mh = (q931_mh *) (h->contents + h->crlen); mh->f = 0; *mhb = mh; } static void q931_xmit(struct q921_link *link, q931_h *h, int len, int cr, int uiframe) { struct pri *ctrl; ctrl = link->ctrl; ctrl->q931_txcount++; if (uiframe) { if (link->tei != Q921_TEI_GROUP) { pri_error(ctrl, "Huh?! Attempting to send UI-frame on TEI %d\n", link->tei); return; } q921_transmit_uiframe(link, h, len); if (ctrl->debug & PRI_DEBUG_Q931_DUMP) { /* * The transmit operation might dump the Q.921 header, so logging * the Q.931 message body after the transmit puts the sections of * the message in the right order in the log, */ q931_dump(ctrl, link->tei, h, len, 1); } } else { /* * Indicate passing the Q.931 message to Q.921 first. Q.921 may * have to request a TEI or bring the connection up before it can * actually send the message. Therefore, the Q.931 message may * actually get sent a few seconds later. Q.921 will dump the * Q.931 message as appropriate at that time. */ if (ctrl->debug & PRI_DEBUG_Q931_DUMP) { q931_to_q921_passing_dump(ctrl, link->tei, h, len); } q921_transmit_iframe(link, h, len, cr); } } /*! * \internal * \brief Build and send the requested message. * * \param ctrl D channel controller. * \param call Q.931 call leg * \param msgtype Q.931 message type to build. * \param ies List of ie's to put in the message. * * \note The ie's in the ie list must be in numerical order. * See Q.931 section 4.5.1 coding rules. * * \retval 0 on success. * \retval -1 on error. */ static int send_message(struct pri *ctrl, q931_call *call, int msgtype, int ies[]) { unsigned char buf[1024]; q931_h *h; q931_mh *mh; int len; int res; int offset=0; int x; int codeset; int uiframe; if (call->outboundbroadcast && call->master_call == call && msgtype != Q931_SETUP) { pri_error(ctrl, "Attempting to use master call record to send %s on BRI PTMP NT %p\n", msg2str(msgtype), ctrl); return -1; } if (!call->link) { pri_error(ctrl, "Call w/ cref:%d is not associated with a link. TEI removed due to error conditions?\n", call->cr); return -1; } memset(buf, 0, sizeof(buf)); len = sizeof(buf); init_header(ctrl, call, buf, &h, &mh, &len, (msgtype >> 8)); mh->msg = msgtype & 0x00ff; x=0; codeset = 0; while(ies[x] > -1) { res = add_ie(ctrl, call, mh->msg, ies[x], (q931_ie *)(mh->data + offset), len, &codeset); if (res < 0) { pri_error(ctrl, "!! Unable to add IE '%s'\n", ie2str(ies[x])); return -1; } offset += res; len -= res; x++; } /* Invert the logic */ len = sizeof(buf) - len; uiframe = 0; if (BRI_NT_PTMP(ctrl)) { /* NT PTMP is the only mode that can broadcast Q.931 messages. */ switch (msgtype) { case Q931_SETUP: /* * For NT-PTMP mode, we need to check the following: * MODE = NT-PTMP * MESSAGE = SETUP * * If those are true, we need to send the SETUP in a UI frame * instead of an I-frame. */ uiframe = 1; break; case Q931_FACILITY: if (call->link->tei == Q921_TEI_GROUP) { /* Broadcast TEI. */ if (q931_is_dummy_call(call)) { /* * This is a FACILITY message on the dummy call reference * for the broadcast TEI. */ uiframe = 1; } else { pri_error(ctrl, "Attempting to broadcast %s on cref %d\n", msg2str(msgtype), call->cr); return -1; } } break; default: break; } if (ctrl->debug & PRI_DEBUG_Q931_STATE) { /* This message is only interesting for NT PTMP mode. */ pri_message(ctrl, "Sending message for call %p on call->link: %p with TEI/SAPI %d/%d\n", call, call->link, call->link->tei, call->link->sapi); } } q931_xmit(call->link, h, len, 1, uiframe); call->acked = 1; return 0; } static int maintenance_service_ies[] = { Q931_IE_CHANGE_STATUS, Q931_CHANNEL_IDENT, -1 }; static int maintenance_service_ack(struct pri *ctrl, q931_call *c) { int pd = MAINTENANCE_PROTOCOL_DISCRIMINATOR_1; int mt = ATT_SERVICE_ACKNOWLEDGE; if (ctrl->switchtype == PRI_SWITCH_NI2) { pd = MAINTENANCE_PROTOCOL_DISCRIMINATOR_2; mt = NATIONAL_SERVICE_ACKNOWLEDGE; } return send_message(ctrl, c, (pd << 8) | mt, maintenance_service_ies); } /*! * \note Maintenance service messages only supported in PRI mode. */ int maintenance_service(struct pri *ctrl, int span, int channel, int changestatus) { struct q931_call *c; int pd = MAINTENANCE_PROTOCOL_DISCRIMINATOR_1; int mt = ATT_SERVICE; c = q931_getcall(&ctrl->link, 0 | Q931_CALL_REFERENCE_FLAG); if (!c) { return -1; } if (channel > -1) { c->channelno = channel & 0xff; c->chanflags = FLAG_EXCLUSIVE; } else { c->channelno = channel; c->chanflags = FLAG_EXCLUSIVE | FLAG_WHOLE_INTERFACE; } c->ds1no = span; c->ds1explicit = 0; c->changestatus = changestatus; if (ctrl->switchtype == PRI_SWITCH_NI2) { pd = MAINTENANCE_PROTOCOL_DISCRIMINATOR_2; mt = NATIONAL_SERVICE; } return send_message(ctrl, c, (pd << 8) | mt, maintenance_service_ies); } static int q931_status(struct pri *ctrl, q931_call *call, int cause) { static int status_ies[] = { Q931_CAUSE, Q931_IE_CALL_STATE, -1 }; call->cause = cause; call->causecode = CODE_CCITT; call->causeloc = LOC_USER; return send_message(ctrl, call, Q931_STATUS, status_ies); } int q931_information(struct pri *ctrl, q931_call *c, char digit) { static int information_ies[] = { Q931_CALLED_PARTY_NUMBER, -1 }; c->overlap_digits[0] = digit; c->overlap_digits[1] = '\0'; /* * Since we are doing overlap dialing now, we need to accumulate * the digits into call->called.number.str. */ c->called.number.valid = 1; if (strlen(c->called.number.str) < sizeof(c->called.number.str) - 1) { /* There is enough room for the new digit. */ strcat(c->called.number.str, c->overlap_digits); } return send_message(ctrl, c, Q931_INFORMATION, information_ies); } /*! * \internal * \brief Actually send display text if in the right call state. * * \param ctrl D channel controller. * \param call Q.931 call leg * \param display Display text to send. * * \retval 0 on success. * \retval -1 on error. */ static int q931_display_text_helper(struct pri *ctrl, struct q931_call *call, const struct pri_subcmd_display_txt *display) { int status; static int information_display_ies[] = { Q931_DISPLAY, -1 }; switch (call->ourcallstate) { case Q931_CALL_STATE_OVERLAP_SENDING: case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING: case Q931_CALL_STATE_CALL_DELIVERED: case Q931_CALL_STATE_CALL_RECEIVED: case Q931_CALL_STATE_CONNECT_REQUEST: case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING: case Q931_CALL_STATE_ACTIVE: case Q931_CALL_STATE_OVERLAP_RECEIVING: call->display.text = (unsigned char *) display->text; call->display.full_ie = 0; call->display.length = display->length; call->display.char_set = display->char_set; status = send_message(ctrl, call, Q931_INFORMATION, information_display_ies); q931_display_clear(call); break; default: status = 0; break; } return status; } /*! * \brief Send display text during a call. * * \param ctrl D channel controller. * \param call Q.931 call leg * \param display Display text to send. * * \retval 0 on success. * \retval -1 on error. */ int q931_display_text(struct pri *ctrl, struct q931_call *call, const struct pri_subcmd_display_txt *display) { int status; unsigned idx; struct q931_call *subcall; if ((ctrl->display_flags.send & (PRI_DISPLAY_OPTION_BLOCK | PRI_DISPLAY_OPTION_TEXT)) != PRI_DISPLAY_OPTION_TEXT) { /* Not enabled */ return 0; } if (call->outboundbroadcast && call->master_call == call) { status = 0; for (idx = 0; idx < ARRAY_LEN(call->subcalls); ++idx) { subcall = call->subcalls[idx]; if (subcall && q931_display_text_helper(ctrl, subcall, display)) { status = -1; } } } else { status = q931_display_text_helper(ctrl, call, display); } return status; } static int keypad_facility_ies[] = { Q931_IE_KEYPAD_FACILITY, -1 }; int q931_keypad_facility(struct pri *ctrl, q931_call *call, const char *digits) { libpri_copy_string(call->keypad_digits, digits, sizeof(call->keypad_digits)); return send_message(ctrl, call, Q931_INFORMATION, keypad_facility_ies); } static int restart_ack_ies[] = { Q931_CHANNEL_IDENT, Q931_RESTART_INDICATOR, -1 }; static int restart_ack(struct pri *ctrl, q931_call *c) { UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_NULL); c->peercallstate = Q931_CALL_STATE_NULL; return send_message(ctrl, c, Q931_RESTART_ACKNOWLEDGE, restart_ack_ies); } int q931_facility(struct pri *ctrl, struct q931_call *call) { static int facility_ies[] = { Q931_IE_FACILITY, -1 }; return send_message(ctrl, call, Q931_FACILITY, facility_ies); } /*! * \brief Send a FACILITY message with the called party number and subaddress ies. * * \param ctrl D channel controller. * \param call Call leg to send message over. * \param called Called party information to send. * * \note * This function can only be used by the dummy call because the call's called * structure is used by normal calls to contain persistent information. * * \retval 0 on success. * \retval -1 on error. */ int q931_facility_called(struct pri *ctrl, struct q931_call *call, const struct q931_party_id *called) { static int facility_called_ies[] = { Q931_IE_FACILITY, Q931_CALLED_PARTY_NUMBER, Q931_CALLED_PARTY_SUBADDR, -1 }; q931_party_id_copy_to_address(&call->called, called); libpri_copy_string(call->overlap_digits, call->called.number.str, sizeof(call->overlap_digits)); return send_message(ctrl, call, Q931_FACILITY, facility_called_ies); } int q931_facility_display_name(struct pri *ctrl, struct q931_call *call, const struct q931_party_name *name) { int status; static int facility_display_ies[] = { Q931_IE_FACILITY, Q931_DISPLAY, -1 }; q931_display_name_send(call, name); status = send_message(ctrl, call, Q931_FACILITY, facility_display_ies); q931_display_clear(call); return status; } /*! * \brief Send a FACILITY RequestSubaddress with optional redirection name and number. * * \param ctrl D channel controller. * \param call Q.931 call leg * \param notify Notification indicator * \param name Redirection name to send if not NULL. * \param number Redirection number to send if not NULL. * * \retval 0 on success. * \retval -1 on error. */ int q931_request_subaddress(struct pri *ctrl, struct q931_call *call, int notify, const struct q931_party_name *name, const struct q931_party_number *number) { int status; struct q931_call *winner; static int facility_notify_ies[] = { Q931_IE_FACILITY, Q931_IE_NOTIFY_IND, Q931_DISPLAY, Q931_IE_REDIRECTION_NUMBER, -1 }; winner = q931_find_winning_call(call); if (!winner) { return -1; } q931_display_clear(winner); if (number) { winner->redirection_number = *number; if (number->valid && name && (ctrl->display_flags.send & PRI_DISPLAY_OPTION_NAME_UPDATE)) { q931_display_name_send(winner, name); } } else { q931_party_number_init(&winner->redirection_number); } winner->notify = notify; if (rose_request_subaddress_encode(ctrl, winner) || send_message(ctrl, winner, Q931_FACILITY, facility_notify_ies)) { pri_message(ctrl, "Could not schedule facility message for request subaddress.\n"); status = -1; } else { status = 0; } q931_display_clear(winner); return status; } /*! * \brief Send a FACILITY SubaddressTransfer to all parties. * * \param ctrl D channel controller. * \param call Q.931 call leg * * \retval 0 on success. * \retval -1 on error. */ int q931_subaddress_transfer(struct pri *ctrl, struct q931_call *call) { int status; unsigned idx; struct q931_call *subcall; if (call->outboundbroadcast && call->master_call == call) { status = 0; for (idx = 0; idx < ARRAY_LEN(call->subcalls); ++idx) { subcall = call->subcalls[idx]; if (subcall) { /* Send to all subcalls that have given a positive response. */ switch (subcall->ourcallstate) { case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING: case Q931_CALL_STATE_CALL_DELIVERED: case Q931_CALL_STATE_ACTIVE: if (send_subaddress_transfer(ctrl, subcall)) { status = -1; } break; default: break; } } } } else { status = send_subaddress_transfer(ctrl, call); } return status; } /*! * \internal * \brief Actually send a NOTIFY message with optional redirection name and number. * * \param ctrl D channel controller. * \param call Q.931 call leg * \param notify Notification indicator * \param name Redirection display name to send if not NULL. * \param number Redirection number to send if not NULL. * * \retval 0 on success. * \retval -1 on error. */ static int q931_notify_redirection_helper(struct pri *ctrl, struct q931_call *call, int notify, const struct q931_party_name *name, const struct q931_party_number *number) { int status; static int notify_ies[] = { Q931_IE_NOTIFY_IND, Q931_DISPLAY, Q931_IE_REDIRECTION_NUMBER, -1 }; q931_display_clear(call); if (number) { call->redirection_number = *number; if (number->valid && name && (ctrl->display_flags.send & PRI_DISPLAY_OPTION_NAME_UPDATE)) { q931_display_name_send(call, name); } } else { q931_party_number_init(&call->redirection_number); } call->notify = notify; status = send_message(ctrl, call, Q931_NOTIFY, notify_ies); q931_display_clear(call); return status; } /*! * \brief Send a NOTIFY message with optional redirection name and number. * * \param ctrl D channel controller. * \param call Q.931 call leg * \param notify Notification indicator * \param name Redirection display name to send if not NULL. * \param number Redirection number to send if not NULL. * * \retval 0 on success. * \retval -1 on error. */ int q931_notify_redirection(struct pri *ctrl, struct q931_call *call, int notify, const struct q931_party_name *name, const struct q931_party_number *number) { int status; unsigned idx; struct q931_call *subcall; if (call->outboundbroadcast && call->master_call == call) { status = 0; for (idx = 0; idx < ARRAY_LEN(call->subcalls); ++idx) { subcall = call->subcalls[idx]; if (subcall) { /* Send to all subcalls that have given a positive response. */ switch (subcall->ourcallstate) { case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING: case Q931_CALL_STATE_CALL_DELIVERED: case Q931_CALL_STATE_ACTIVE: if (q931_notify_redirection_helper(ctrl, subcall, notify, name, number)) { status = -1; } break; default: break; } } } } else { status = q931_notify_redirection_helper(ctrl, call, notify, name, number); } return status; } int q931_notify(struct pri *ctrl, q931_call *c, int channel, int info) { switch (ctrl->switchtype) { case PRI_SWITCH_EUROISDN_T1: case PRI_SWITCH_EUROISDN_E1: break; default: if ((info > 0x2) || (info < 0x00)) { return -1; } break; } if (info >= 0) { info &= 0x7F; } else { /* Cannot send NOTIFY message if the mandatory ie is not going to be present. */ return -1; } return q931_notify_redirection(ctrl, c, info, NULL, NULL); } #ifdef ALERTING_NO_PROGRESS static int call_progress_ies[] = { -1 }; #else static int call_progress_with_cause_ies[] = { Q931_CAUSE, Q931_PROGRESS_INDICATOR, -1 }; static int call_progress_ies[] = { Q931_PROGRESS_INDICATOR, -1 }; #endif int q931_call_progress(struct pri *ctrl, q931_call *c, int channel, int info) { if (c->ourcallstate == Q931_CALL_STATE_CALL_INDEPENDENT_SERVICE) { /* Cannot send this message when in this state */ return 0; } if (channel) { c->ds1no = (channel & 0xff00) >> 8; c->ds1explicit = (channel & 0x10000) >> 16; c->channelno = channel & 0xff; } 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(ctrl, "XXX Progress message requested but no information is provided\n"); c->progressmask = 0; } c->alive = 1; return send_message(ctrl, c, Q931_PROGRESS, call_progress_ies); } int q931_call_progress_with_cause(struct pri *ctrl, q931_call *c, int channel, int info, int cause) { if (c->ourcallstate == Q931_CALL_STATE_CALL_INDEPENDENT_SERVICE) { /* Cannot send this message when in this state */ return 0; } if (channel) { c->ds1no = (channel & 0xff00) >> 8; c->ds1explicit = (channel & 0x10000) >> 16; c->channelno = channel & 0xff; } 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(ctrl, "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(ctrl, c, Q931_PROGRESS, call_progress_with_cause_ies); } #ifdef ALERTING_NO_PROGRESS static int call_proceeding_ies[] = { Q931_CHANNEL_IDENT, -1 }; #else static int call_proceeding_ies[] = { Q931_CHANNEL_IDENT, Q931_PROGRESS_INDICATOR, -1 }; #endif int q931_call_proceeding(struct pri *ctrl, q931_call *c, int channel, int info) { if (c->proc) { /* We have already sent a PROCEEDING message. Don't send another one. */ return 0; } if (c->ourcallstate == Q931_CALL_STATE_CALL_INDEPENDENT_SERVICE) { /* Cannot send this message when in this state */ return 0; } if (channel) { c->ds1no = (channel & 0xff00) >> 8; c->ds1explicit = (channel & 0x10000) >> 16; c->channelno = channel & 0xff; } c->chanflags &= ~FLAG_PREFERRED; c->chanflags |= FLAG_EXCLUSIVE; UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_INCOMING_CALL_PROCEEDING); c->peercallstate = Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING; if (info) { c->progloc = LOC_PRIV_NET_LOCAL_USER; c->progcode = CODE_CCITT; c->progressmask = PRI_PROG_INBAND_AVAILABLE; } else c->progressmask = 0; c->proc = 1; c->alive = 1; return send_message(ctrl, c, Q931_CALL_PROCEEDING, call_proceeding_ies); } #ifndef ALERTING_NO_PROGRESS static int alerting_ies[] = { Q931_IE_FACILITY, Q931_PROGRESS_INDICATOR, Q931_IE_USER_USER, -1 }; #else static int alerting_ies[] = { Q931_IE_FACILITY, -1 }; #endif int q931_alerting(struct pri *ctrl, q931_call *c, int channel, int info) { if (c->ourcallstate == Q931_CALL_STATE_CALL_INDEPENDENT_SERVICE) { /* Cannot send this message when in this state */ return 0; } if (!c->proc) q931_call_proceeding(ctrl, c, channel, 0); if (info) { c->progloc = LOC_PRIV_NET_LOCAL_USER; c->progcode = CODE_CCITT; c->progressmask = PRI_PROG_INBAND_AVAILABLE; } else c->progressmask = 0; UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_CALL_RECEIVED); c->peercallstate = Q931_CALL_STATE_CALL_DELIVERED; c->alive = 1; switch (ctrl->switchtype) { case PRI_SWITCH_QSIG: if (c->local_id.name.valid) { /* Send calledName with ALERTING */ rose_called_name_encode(ctrl, c, Q931_ALERTING); } break; default: break; } if (c->cc.record) { pri_cc_event(ctrl, c, c->cc.record, CC_EVENT_MSG_ALERTING); } return send_message(ctrl, c, Q931_ALERTING, alerting_ies); } static int setup_ack_ies[] = { Q931_CHANNEL_IDENT, Q931_IE_FACILITY, Q931_PROGRESS_INDICATOR, -1 }; int q931_setup_ack(struct pri *ctrl, q931_call *c, int channel, int nonisdn) { if (c->ourcallstate == Q931_CALL_STATE_CALL_INDEPENDENT_SERVICE) { /* Cannot send this message when in this state */ return 0; } if (channel) { c->ds1no = (channel & 0xff00) >> 8; c->ds1explicit = (channel & 0x10000) >> 16; c->channelno = channel & 0xff; } c->chanflags &= ~FLAG_PREFERRED; c->chanflags |= FLAG_EXCLUSIVE; if (nonisdn && (ctrl->switchtype != PRI_SWITCH_DMS100)) { c->progloc = LOC_PRIV_NET_LOCAL_USER; c->progcode = CODE_CCITT; c->progressmask = PRI_PROG_CALLED_NOT_ISDN; } else c->progressmask = 0; UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_OVERLAP_RECEIVING); c->peercallstate = Q931_CALL_STATE_OVERLAP_SENDING; c->alive = 1; return send_message(ctrl, c, Q931_SETUP_ACKNOWLEDGE, setup_ack_ies); } /* T313 expiry, first time */ static void pri_connect_timeout(void *data) { struct q931_call *c = data; struct pri *ctrl = c->pri; if (ctrl->debug & PRI_DEBUG_Q931_STATE) pri_message(ctrl, "Timed out looking for connect acknowledge\n"); c->retranstimer = 0; q931_disconnect(ctrl, c, PRI_CAUSE_NORMAL_CLEARING); } /* T308 expiry, first time */ static void pri_release_timeout(void *data) { struct q931_call *c = data; struct pri *ctrl = c->pri; if (ctrl->debug & PRI_DEBUG_Q931_STATE) pri_message(ctrl, "Timed out looking for release complete\n"); c->t308_timedout++; c->retranstimer = 0; c->alive = 1; /* The call to q931_release will re-schedule T308 */ q931_release(ctrl, c, c->cause); } /* T308 expiry, second time */ static void pri_release_finaltimeout(void *data) { struct q931_call *c = data; struct pri *ctrl = c->pri; c->retranstimer = 0; c->alive = 1; if (ctrl->debug & PRI_DEBUG_Q931_STATE) pri_message(ctrl, "Final time-out looking for release complete\n"); c->t308_timedout++; c->ourcallstate = Q931_CALL_STATE_NULL; c->peercallstate = Q931_CALL_STATE_NULL; q931_clr_subcommands(ctrl); ctrl->schedev = 1; ctrl->ev.e = PRI_EVENT_HANGUP_ACK; ctrl->ev.hangup.subcmds = &ctrl->subcmds; ctrl->ev.hangup.channel = q931_encode_channel(c); ctrl->ev.hangup.cause = c->cause; ctrl->ev.hangup.cref = c->cr; ctrl->ev.hangup.call = c->master_call; ctrl->ev.hangup.aoc_units = c->aoc_units; ctrl->ev.hangup.call_held = NULL; ctrl->ev.hangup.call_active = NULL; libpri_copy_string(ctrl->ev.hangup.useruserinfo, c->useruserinfo, sizeof(ctrl->ev.hangup.useruserinfo)); pri_hangup(ctrl, c, c->cause); } /* T305 expiry, first time */ static void pri_disconnect_timeout(void *data) { struct q931_call *c = data; struct pri *ctrl = c->pri; if (ctrl->debug & PRI_DEBUG_Q931_STATE) pri_message(ctrl, "Timed out looking for release\n"); c->retranstimer = 0; c->alive = 1; q931_release(ctrl, c, PRI_CAUSE_NORMAL_CLEARING); } static int connect_ies[] = { Q931_CHANNEL_IDENT, Q931_IE_FACILITY, Q931_PROGRESS_INDICATOR, Q931_DISPLAY, Q931_IE_TIME_DATE, Q931_IE_CONNECTED_NUM, Q931_IE_CONNECTED_SUBADDR, -1 }; int q931_connect(struct pri *ctrl, q931_call *c, int channel, int nonisdn) { if (c->ourcallstate == Q931_CALL_STATE_CALL_INDEPENDENT_SERVICE) { /* Cannot send this message when in this state */ return 0; } if (channel) { c->ds1no = (channel & 0xff00) >> 8; c->ds1explicit = (channel & 0x10000) >> 16; c->channelno = channel & 0xff; } c->chanflags &= ~FLAG_PREFERRED; c->chanflags |= FLAG_EXCLUSIVE; if (nonisdn && (ctrl->switchtype != PRI_SWITCH_DMS100)) { c->progloc = LOC_PRIV_NET_LOCAL_USER; c->progcode = CODE_CCITT; c->progressmask = PRI_PROG_CALLED_NOT_ISDN; } else c->progressmask = 0; if(ctrl->localtype == PRI_NETWORK || ctrl->switchtype == PRI_SWITCH_QSIG) UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_ACTIVE); else UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_CONNECT_REQUEST); c->peercallstate = Q931_CALL_STATE_ACTIVE; c->alive = 1; /* Connect request timer */ pri_schedule_del(ctrl, c->retranstimer); c->retranstimer = 0; if ((c->ourcallstate == Q931_CALL_STATE_CONNECT_REQUEST) && (ctrl->bri || (!ctrl->link.next))) c->retranstimer = pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T313], pri_connect_timeout, c); if (c->redirecting.state == Q931_REDIRECTING_STATE_PENDING_TX_DIV_LEG_3) { c->redirecting.state = Q931_REDIRECTING_STATE_IDLE; /* Send DivertingLegInformation3 with CONNECT. */ c->redirecting.to = c->local_id; if (!c->redirecting.to.number.valid) { q931_party_number_init(&c->redirecting.to.number); c->redirecting.to.number.valid = 1; c->redirecting.to.number.presentation = PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED; } rose_diverting_leg_information3_encode(ctrl, c, Q931_CONNECT); } switch (ctrl->switchtype) { case PRI_SWITCH_QSIG: if (c->local_id.name.valid) { /* Send connectedName with CONNECT */ rose_connected_name_encode(ctrl, c, Q931_CONNECT); } break; default: break; } if (ctrl->display_flags.send & PRI_DISPLAY_OPTION_NAME_INITIAL) { q931_display_name_send(c, &c->local_id.name); } else { q931_display_clear(c); } return send_message(ctrl, c, Q931_CONNECT, connect_ies); } static int release_ies[] = { Q931_CAUSE, Q931_IE_FACILITY, Q931_IE_USER_USER, -1 }; int q931_release(struct pri *ctrl, q931_call *c, int cause) { UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_RELEASE_REQUEST); /* c->peercallstate stays the same */ if (c->alive) { c->alive = 0; c->cause = cause; c->causecode = CODE_CCITT; c->causeloc = LOC_PRIV_NET_LOCAL_USER; if (c->acked) { pri_schedule_del(ctrl, c->retranstimer); if (!c->t308_timedout) { c->retranstimer = pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T308], pri_release_timeout, c); } else { c->retranstimer = pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T308], pri_release_finaltimeout, c); } if (c->cc.record) { pri_cc_event(ctrl, c, c->cc.record, CC_EVENT_MSG_RELEASE); } return send_message(ctrl, c, Q931_RELEASE, release_ies); } else { if (c->cc.record) { pri_cc_event(ctrl, c, c->cc.record, CC_EVENT_MSG_RELEASE_COMPLETE); } return send_message(ctrl, c, Q931_RELEASE_COMPLETE, release_ies); /* Yes, release_ies, not release_complete_ies */ } } else return 0; } static int restart_ies[] = { Q931_CHANNEL_IDENT, Q931_RESTART_INDICATOR, -1 }; static void t316_expire(void *vcall); /*! * \internal * \brief Send the RESTART message to the peer. * * \param call Q.931 call leg * \param channel Encoded channel id to use. * * \retval 0 on success. * \retval -1 on error. */ static int q931_send_restart(struct q931_call *call) { struct pri *ctrl = call->pri; int channel = call->restart_tx.channel; /* Start timer T316 if enabled. */ if (0 < ctrl->timers[PRI_TIMER_T316]) { call->restart_tx.t316_timer = pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T316], t316_expire, call); --call->restart_tx.remain; } call->ri = 0; call->ds1no = (channel >> 8) & 0xFF; call->ds1explicit = (channel >> 16) & 0x1; call->channelno = channel & 0xFF; call->chanflags &= ~FLAG_PREFERRED; call->chanflags |= FLAG_EXCLUSIVE; UPDATE_OURCALLSTATE(ctrl, call, Q931_CALL_STATE_RESTART); call->peercallstate = Q931_CALL_STATE_RESTART_REQUEST; return send_message(ctrl, call, Q931_RESTART, restart_ies); } /*! * \internal * \brief T316 expired. * * \param vcall Q.931 call leg * * \return Nothing */ static void t316_expire(void *vcall) { struct q931_call *call = vcall; call->restart_tx.t316_timer = 0; if (call->restart_tx.remain) { /* Retransmit the RESTART */ q931_send_restart(call); } else { int channel = call->restart_tx.channel; pri_message(call->pri, "!! Peer failed to ack our RESTART request for ds1/channel:%d/%d.\n", (channel >> 8) & 0xFF, channel & 0xFF); } } /*! * \internal * \brief Stop timer T316. * * \param call Q.931 call leg * * \return Nothing */ static void stop_t316(struct q931_call *call) { pri_schedule_del(call->pri, call->restart_tx.t316_timer); call->restart_tx.t316_timer = 0; } /*! * \brief Send the RESTART message to the peer. * * \param ctrl D channel controller. * \param channel Encoded channel id to use. * * \note * Sending RESTART in NT PTMP mode is not supported at the * present time. * * \note * NT PTMP should broadcast the RESTART if there is a TEI * allocated. Otherwise it should immediately ACK the RESTART * itself to avoid the T316 timeout delay (2 minutes) since * there might not be anything connected. The broadcast could * be handled in a similar manner to the broadcast SETUP. * * \todo NT PTMP mode should implement some protection from * receiving a RESTART on channels in use by another TEI. * * \retval 0 on success. * \retval -1 on error. */ int q931_restart(struct pri *ctrl, int channel) { struct q931_call *call; if (!channel) { return -1; } call = q931_getcall(&ctrl->link, 0 | Q931_CALL_REFERENCE_FLAG); if (!call) { return -1; } stop_t316(call); call->restart_tx.remain = (0 < ctrl->timers[PRI_TIMER_N316]) ? ctrl->timers[PRI_TIMER_N316] : 1; call->restart_tx.channel = channel; return q931_send_restart(call); } static int disconnect_ies[] = { Q931_CAUSE, Q931_IE_FACILITY, Q931_IE_USER_USER, -1 }; int q931_disconnect(struct pri *ctrl, q931_call *c, int cause) { UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_DISCONNECT_REQUEST); c->peercallstate = Q931_CALL_STATE_DISCONNECT_INDICATION; if (c->alive) { c->alive = 0; c->cause = cause; c->causecode = CODE_CCITT; c->causeloc = LOC_PRIV_NET_LOCAL_USER; c->sendhangupack = 1; if (c->cc.record) { pri_cc_event(ctrl, c, c->cc.record, CC_EVENT_MSG_DISCONNECT); } pri_schedule_del(ctrl, c->retranstimer); c->retranstimer = pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T305], pri_disconnect_timeout, c); return send_message(ctrl, c, Q931_DISCONNECT, disconnect_ies); } else return 0; } static int setup_ies[] = { Q931_BEARER_CAPABILITY, Q931_CHANNEL_IDENT, Q931_IE_FACILITY, Q931_PROGRESS_INDICATOR, Q931_NETWORK_SPEC_FAC, Q931_DISPLAY, Q931_IE_KEYPAD_FACILITY, Q931_REVERSE_CHARGE_INDIC, Q931_CALLING_PARTY_NUMBER, Q931_CALLING_PARTY_SUBADDR, Q931_CALLED_PARTY_NUMBER, Q931_CALLED_PARTY_SUBADDR, Q931_REDIRECTING_NUMBER, Q931_IE_USER_USER, Q931_SENDING_COMPLETE, Q931_IE_ORIGINATING_LINE_INFO, Q931_IE_GENERIC_DIGITS, -1 }; static int gr303_setup_ies[] = { Q931_BEARER_CAPABILITY, Q931_CHANNEL_IDENT, -1 }; /*! Call Independent Signalling SETUP ie's */ static int cis_setup_ies[] = { Q931_BEARER_CAPABILITY, Q931_CHANNEL_IDENT, Q931_IE_FACILITY, Q931_IE_KEYPAD_FACILITY, Q931_CALLING_PARTY_NUMBER, Q931_CALLING_PARTY_SUBADDR, Q931_CALLED_PARTY_NUMBER, Q931_CALLED_PARTY_SUBADDR, Q931_SENDING_COMPLETE, -1 }; static void stop_t303(struct q931_call *call) { /* T303 should only be running on the master call */ pri_schedule_del(call->pri, call->t303_timer); call->t303_timer = 0; } static void t303_expiry(void *data); /*! \param call Call is not a subcall call record. */ static void start_t303(struct q931_call *call) { struct pri *ctrl; ctrl = call->pri; pri_schedule_del(ctrl, call->t303_timer); call->t303_timer = pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T303], t303_expiry, call); } static void t303_expiry(void *data) { struct q931_call *c = data;/* Call is not a subcall call record. */ struct pri *ctrl = c->pri; int res; if (ctrl->debug & PRI_DEBUG_Q931_STATE) { pri_message(ctrl, "T303 timed out. cref:%d\n", c->cr); } c->t303_expirycnt++; c->t303_timer = 0; if (c->cause != -1) { /* We got a DISCONNECT, RELEASE, or RELEASE_COMPLETE and no other responses. */ if (c->outboundbroadcast) { UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_CALL_ABORT); } else { /* This should never happen. T303 should not be running in this case. */ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_NULL); c->peercallstate = Q931_CALL_STATE_NULL; } pri_fake_clearing(c); } else if (c->t303_expirycnt < 2) { /*! * \todo XXX Resending the SETUP message loses any facility ies * that the original may have had that were not added by * pri_call_add_standard_apdus(). Actually any message Q.931 * retransmits will lose the facility ies. */ pri_call_add_standard_apdus(ctrl, c); if (ctrl->display_flags.send & PRI_DISPLAY_OPTION_NAME_INITIAL) { q931_display_name_send(c, &c->local_id.name); } else { q931_display_clear(c); } c->cc.saved_ie_contents.length = 0; c->cc.saved_ie_flags = 0; if (ctrl->link.next && !ctrl->bri) res = send_message(ctrl, c, Q931_SETUP, gr303_setup_ies); else if (c->cis_call) res = send_message(ctrl, c, Q931_SETUP, cis_setup_ies); else res = send_message(ctrl, c, Q931_SETUP, setup_ies); if (res) { pri_error(ctrl, "Error resending setup message!\n"); } start_t303(c); if (c->outboundbroadcast) { start_t312(c); } } else { /* * We never got any response for a normal call or an * establishment response from any TEI for a master/subcall * call. */ c->cause = PRI_CAUSE_NO_USER_RESPONSE; if (c->outboundbroadcast) { UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_CALL_ABORT); } else { UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_NULL); c->peercallstate = Q931_CALL_STATE_NULL; } pri_fake_clearing(c); } } int q931_setup(struct pri *ctrl, q931_call *c, struct pri_sr *req) { int res; if (!req->called.number.valid && (!req->keypad_digits || !req->keypad_digits[0])) { /* No called number or keypad digits to send. */ return -1; } c->called = req->called; libpri_copy_string(c->overlap_digits, req->called.number.str, sizeof(c->overlap_digits)); if (req->keypad_digits) { libpri_copy_string(c->keypad_digits, req->keypad_digits, sizeof(c->keypad_digits)); } else { c->keypad_digits[0] = '\0'; } c->bc.transcapability = req->transmode; c->bc.transmoderate = TRANS_MODE_64_CIRCUIT; if (!req->userl1) req->userl1 = PRI_LAYER_1_ULAW; c->bc.userl1 = req->userl1; c->bc.userl2 = -1; c->bc.userl3 = -1; c->ds1no = (req->channel & 0xff00) >> 8; c->ds1explicit = (req->channel & 0x10000) >> 16; if ((ctrl->localtype == PRI_CPE) && ctrl->link.next && !ctrl->bri) { c->channelno = 0; c->chanflags = 0; } else { c->channelno = req->channel & 0xff; if (req->exclusive) { c->chanflags = FLAG_EXCLUSIVE; } else { c->chanflags = FLAG_PREFERRED; } } c->slotmap = -1; c->nonisdn = req->nonisdn; c->newcall = 0; c->cis_call = req->cis_call; c->cis_recognized = req->cis_call; c->cis_auto_disconnect = req->cis_auto_disconnect; c->complete = req->numcomplete; if (req->caller.number.valid) { c->local_id = req->caller; q931_party_id_fixup(ctrl, &c->local_id); } if (req->redirecting.from.number.valid) { c->redirecting = req->redirecting; q931_party_id_fixup(ctrl, &c->redirecting.from); q931_party_id_fixup(ctrl, &c->redirecting.to); q931_party_id_fixup(ctrl, &c->redirecting.orig_called); } if (req->useruserinfo) libpri_copy_string(c->useruserinfo, req->useruserinfo, sizeof(c->useruserinfo)); else c->useruserinfo[0] = '\0'; if (req->nonisdn && (ctrl->switchtype == PRI_SWITCH_NI2)) c->progressmask = PRI_PROG_CALLER_NOT_ISDN; else c->progressmask = 0; c->reversecharge = req->reversecharge; c->aoc_charging_request = req->aoc_charging_request; pri_call_add_standard_apdus(ctrl, c); if (ctrl->display_flags.send & PRI_DISPLAY_OPTION_NAME_INITIAL) { q931_display_name_send(c, &c->local_id.name); } else { q931_display_clear(c); } /* Save the initial cc-parties. */ c->cc.party_a = c->local_id; c->cc.originated = 1; if (c->redirecting.from.number.valid) { c->cc.initially_redirected = 1; } c->cc.saved_ie_contents.length = 0; c->cc.saved_ie_flags = 0; if (BRI_NT_PTMP(ctrl)) { c->outboundbroadcast = 1; } if (ctrl->link.next && !ctrl->bri) res = send_message(ctrl, c, Q931_SETUP, gr303_setup_ies); else if (c->cis_call) res = send_message(ctrl, c, Q931_SETUP, cis_setup_ies); else res = send_message(ctrl, c, Q931_SETUP, setup_ies); if (!res) { c->alive = 1; /* make sure we call PRI_EVENT_HANGUP_ACK once we send/receive RELEASE_COMPLETE */ c->sendhangupack = 1; UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_CALL_INITIATED); c->peercallstate = Q931_CALL_STATE_CALL_PRESENT; c->t303_expirycnt = 0; start_t303(c); if (c->outboundbroadcast) { start_t312(c); } } return res; } static int register_ies[] = { Q931_IE_FACILITY, -1 }; /*! * \brief Build and send the REGISTER message. * * \param ctrl D channel controller. * \param call Q.931 call leg * * \retval 0 on success. * \retval -1 on error. */ int q931_register(struct pri *ctrl, q931_call *call) { int res; call->newcall = 0; call->cis_call = 1; call->cis_recognized = 1; call->cis_auto_disconnect = 0; call->chanflags = FLAG_EXCLUSIVE;/* For safety mark this channel as exclusive. */ call->channelno = 0; res = send_message(ctrl, call, Q931_REGISTER, register_ies); if (!res) { call->alive = 1; UPDATE_OURCALLSTATE(ctrl, call, Q931_CALL_STATE_CALL_INDEPENDENT_SERVICE); call->peercallstate = Q931_CALL_STATE_CALL_INDEPENDENT_SERVICE; } return res; } static int release_complete_ies[] = { Q931_IE_FACILITY, Q931_IE_USER_USER, -1 }; static int q931_release_complete(struct pri *ctrl, q931_call *c, int cause) { int res = 0; UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_NULL); c->peercallstate = Q931_CALL_STATE_NULL; if (c->cc.record) { pri_cc_event(ctrl, c, c->cc.record, CC_EVENT_MSG_RELEASE_COMPLETE); } if (cause > -1) { c->cause = cause; c->causecode = CODE_CCITT; c->causeloc = LOC_PRIV_NET_LOCAL_USER; /* release_ies has CAUSE in it */ res = send_message(ctrl, c, Q931_RELEASE_COMPLETE, release_ies); } else res = send_message(ctrl, c, Q931_RELEASE_COMPLETE, release_complete_ies); c->alive = 0; /* release the structure */ res += pri_hangup(ctrl, c, cause); return res; } static int connect_ack_ies[] = { -1 }; static int connect_ack_w_chan_id_ies[] = { Q931_CHANNEL_IDENT, -1 }; static int gr303_connect_ack_ies[] = { Q931_CHANNEL_IDENT, -1 }; int q931_connect_acknowledge(struct pri *ctrl, q931_call *call, int channel) { int *use_ies; struct q931_call *winner; winner = q931_find_winning_call(call); if (!winner) { return -1; } if (winner != call) { UPDATE_OURCALLSTATE(ctrl, call, Q931_CALL_STATE_ACTIVE); call->peercallstate = Q931_CALL_STATE_ACTIVE; } UPDATE_OURCALLSTATE(ctrl, winner, Q931_CALL_STATE_ACTIVE); winner->peercallstate = Q931_CALL_STATE_ACTIVE; if (channel) { winner->ds1no = (channel & 0xff00) >> 8; winner->ds1explicit = (channel & 0x10000) >> 16; winner->channelno = channel & 0xff; winner->chanflags &= ~FLAG_PREFERRED; winner->chanflags |= FLAG_EXCLUSIVE; } use_ies = NULL; if (ctrl->link.next && !ctrl->bri) { if (ctrl->localtype == PRI_CPE) { use_ies = gr303_connect_ack_ies; } } else if (channel) { use_ies = connect_ack_w_chan_id_ies; } else { use_ies = connect_ack_ies; } if (use_ies) { return send_message(ctrl, winner, Q931_CONNECT_ACKNOWLEDGE, use_ies); } return 0; } /*! * \internal * \brief Send HOLD message response wait timeout. * * \param data Q.931 call leg. (Master Q.931 subcall structure) * * \return Nothing */ static void q931_hold_timeout(void *data) { struct q931_call *call = data; struct q931_call *master = call->master_call; struct pri *ctrl = call->pri; if (ctrl->debug & PRI_DEBUG_Q931_STATE) { pri_message(ctrl, "Time-out waiting for HOLD response\n"); } /* Ensure that the timer is deleted. */ pri_schedule_del(ctrl, master->hold_timer); master->hold_timer = 0; /* Don't change the hold state if there was HOLD a collision. */ switch (master->hold_state) { case Q931_HOLD_STATE_HOLD_REQ: UPDATE_HOLD_STATE(ctrl, master, Q931_HOLD_STATE_IDLE); break; default: break; } q931_clr_subcommands(ctrl); ctrl->schedev = 1; ctrl->ev.e = PRI_EVENT_HOLD_REJ; ctrl->ev.hold_rej.channel = q931_encode_channel(call); ctrl->ev.hold_rej.call = master; ctrl->ev.hold_rej.cause = PRI_CAUSE_MESSAGE_TYPE_NONEXIST; ctrl->ev.hold_rej.subcmds = &ctrl->subcmds; } /*! * \internal * \brief Determine if a hold request is allowed now. * * \param ctrl D channel controller. * \param call Q.931 call leg. (Master Q.931 subcall structure) * * \retval TRUE if we can send a HOLD request. * \retval FALSE if not allowed. */ static int q931_is_hold_allowed(const struct pri *ctrl, const struct q931_call *call) { int allowed; allowed = 0; switch (call->ourcallstate) { case Q931_CALL_STATE_CALL_RECEIVED: case Q931_CALL_STATE_CONNECT_REQUEST: case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING: if (PTMP_MODE(ctrl)) { /* HOLD request only allowed in these states if point-to-point mode. */ break; } /* Fall through */ case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING: case Q931_CALL_STATE_CALL_DELIVERED: case Q931_CALL_STATE_ACTIVE: switch (call->hold_state) { case Q931_HOLD_STATE_IDLE: allowed = 1; break; default: break; } break; case Q931_CALL_STATE_DISCONNECT_INDICATION: case Q931_CALL_STATE_RELEASE_REQUEST: /* Ignore HOLD request in these states. */ break; default: break; } return allowed; } static int hold_ies[] = { -1 }; /*! * \brief Send the HOLD message. * * \param ctrl D channel controller. * \param call Q.931 call leg. (Master Q.931 subcall structure) * * \retval 0 on success. * \retval -1 on error. */ int q931_send_hold(struct pri *ctrl, struct q931_call *call) { struct q931_call *winner; winner = q931_find_winning_call(call); if (!winner || !q931_is_hold_allowed(ctrl, call)) { return -1; } pri_schedule_del(ctrl, call->hold_timer); call->hold_timer = pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T_HOLD], q931_hold_timeout, winner); if (!call->hold_timer || send_message(ctrl, winner, Q931_HOLD, hold_ies)) { pri_schedule_del(ctrl, call->hold_timer); call->hold_timer = 0; return -1; } UPDATE_HOLD_STATE(ctrl, call, Q931_HOLD_STATE_HOLD_REQ); return 0; } static int hold_ack_ies[] = { -1 }; /*! * \brief Send the HOLD ACKNOWLEDGE message. * * \param ctrl D channel controller. * \param call Q.931 call leg. (Master Q.931 subcall structure) * * \retval 0 on success. * \retval -1 on error. */ int q931_send_hold_ack(struct pri *ctrl, struct q931_call *call) { struct q931_call *winner; UPDATE_HOLD_STATE(ctrl, call, Q931_HOLD_STATE_CALL_HELD); winner = q931_find_winning_call(call); if (!winner) { return -1; } /* Call is now on hold so forget the channel. */ winner->channelno = 0;/* No channel */ winner->ds1no = 0; winner->ds1explicit = 0; winner->chanflags = 0; return send_message(ctrl, winner, Q931_HOLD_ACKNOWLEDGE, hold_ack_ies); } static int hold_reject_ies[] = { Q931_CAUSE, -1 }; /*! * \internal * \brief Send the HOLD REJECT message only. * * \param ctrl D channel controller. * \param call Q.931 call leg. (subcall) * \param cause Q.931 cause code for rejecting the hold request. * * \retval 0 on success. * \retval -1 on error. */ static int q931_send_hold_rej_msg(struct pri *ctrl, struct q931_call *call, int cause) { call->cause = cause; call->causecode = CODE_CCITT; call->causeloc = LOC_PRIV_NET_LOCAL_USER; return send_message(ctrl, call, Q931_HOLD_REJECT, hold_reject_ies); } /*! * \brief Send the HOLD REJECT message. * * \param ctrl D channel controller. * \param call Q.931 call leg. (Master Q.931 subcall structure) * \param cause Q.931 cause code for rejecting the hold request. * * \retval 0 on success. * \retval -1 on error. */ int q931_send_hold_rej(struct pri *ctrl, struct q931_call *call, int cause) { struct q931_call *winner; UPDATE_HOLD_STATE(ctrl, call, Q931_HOLD_STATE_IDLE); winner = q931_find_winning_call(call); if (!winner) { return -1; } return q931_send_hold_rej_msg(ctrl, winner, cause); } /*! * \internal * \brief Send RETRIEVE message response wait timeout. * * \param data Q.931 call leg. (Master Q.931 subcall structure) * * \return Nothing */ static void q931_retrieve_timeout(void *data) { struct q931_call *call = data; struct q931_call *master = call->master_call; struct pri *ctrl = call->pri; if (ctrl->debug & PRI_DEBUG_Q931_STATE) { pri_message(ctrl, "Time-out waiting for RETRIEVE response\n"); } /* Ensure that the timer is deleted. */ pri_schedule_del(ctrl, master->hold_timer); master->hold_timer = 0; /* Don't change the hold state if there was RETRIEVE a collision. */ switch (master->hold_state) { case Q931_HOLD_STATE_CALL_HELD: case Q931_HOLD_STATE_RETRIEVE_REQ: UPDATE_HOLD_STATE(ctrl, master, Q931_HOLD_STATE_CALL_HELD); /* Call is still on hold so forget the channel. */ call->channelno = 0;/* No channel */ call->ds1no = 0; call->ds1explicit = 0; call->chanflags = 0; break; default: break; } q931_clr_subcommands(ctrl); ctrl->schedev = 1; ctrl->ev.e = PRI_EVENT_RETRIEVE_REJ; ctrl->ev.retrieve_rej.channel = q931_encode_channel(call); ctrl->ev.retrieve_rej.call = master; ctrl->ev.retrieve_rej.cause = PRI_CAUSE_MESSAGE_TYPE_NONEXIST; ctrl->ev.retrieve_rej.subcmds = &ctrl->subcmds; } /*! * \internal * \brief Determine if a retrieve request is allowed now. * * \param ctrl D channel controller. * \param call Q.931 call leg. (Master Q.931 subcall structure) * * \retval TRUE if we can send a RETRIEVE request. * \retval FALSE if not allowed. */ static int q931_is_retrieve_allowed(const struct pri *ctrl, const struct q931_call *call) { int allowed; allowed = 0; switch (call->ourcallstate) { case Q931_CALL_STATE_CALL_RECEIVED: case Q931_CALL_STATE_CONNECT_REQUEST: case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING: if (PTMP_MODE(ctrl)) { /* RETRIEVE request only allowed in these states if point-to-point mode. */ break; } /* Fall through */ case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING: case Q931_CALL_STATE_CALL_DELIVERED: case Q931_CALL_STATE_ACTIVE: switch (call->hold_state) { case Q931_HOLD_STATE_CALL_HELD: allowed = 1; break; default: break; } break; case Q931_CALL_STATE_DISCONNECT_INDICATION: case Q931_CALL_STATE_RELEASE_REQUEST: /* Ignore RETRIEVE request in these states. */ break; default: break; } return allowed; } static int retrieve_ies[] = { Q931_CHANNEL_IDENT, -1 }; /*! * \brief Send the RETRIEVE message. * * \param ctrl D channel controller. * \param call Q.931 call leg. (Master Q.931 subcall structure) * \param channel Encoded channel id to use. If zero do not send channel id. * * \retval 0 on success. * \retval -1 on error. */ int q931_send_retrieve(struct pri *ctrl, struct q931_call *call, int channel) { struct q931_call *winner; winner = q931_find_winning_call(call); if (!winner || !q931_is_retrieve_allowed(ctrl, call)) { return -1; } if (channel) { winner->ds1no = (channel & 0xff00) >> 8; winner->ds1explicit = (channel & 0x10000) >> 16; winner->channelno = channel & 0xff; if (ctrl->localtype == PRI_NETWORK && winner->channelno != 0xFF) { winner->chanflags = FLAG_EXCLUSIVE; } else { winner->chanflags = FLAG_PREFERRED; } } else { /* Do not send Q931_CHANNEL_IDENT */ winner->chanflags = 0; } pri_schedule_del(ctrl, call->hold_timer); call->hold_timer = pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T_RETRIEVE], q931_retrieve_timeout, winner); if (!call->hold_timer || send_message(ctrl, winner, Q931_RETRIEVE, retrieve_ies)) { pri_schedule_del(ctrl, call->hold_timer); call->hold_timer = 0; /* Call is still on hold so forget the channel. */ winner->channelno = 0;/* No channel */ winner->ds1no = 0; winner->ds1explicit = 0; winner->chanflags = 0; return -1; } UPDATE_HOLD_STATE(ctrl, call, Q931_HOLD_STATE_RETRIEVE_REQ); return 0; } static int retrieve_ack_ies[] = { Q931_CHANNEL_IDENT, -1 }; /*! * \brief Send the RETRIEVE ACKNOWLEDGE message. * * \param ctrl D channel controller. * \param call Q.931 call leg. (Master Q.931 subcall structure) * \param channel Encoded channel id to use. * * \retval 0 on success. * \retval -1 on error. */ int q931_send_retrieve_ack(struct pri *ctrl, struct q931_call *call, int channel) { struct q931_call *winner; winner = q931_find_winning_call(call); if (!winner) { return -1; } winner->ds1no = (channel & 0xff00) >> 8; winner->ds1explicit = (channel & 0x10000) >> 16; winner->channelno = channel & 0xff; winner->chanflags = FLAG_EXCLUSIVE; UPDATE_HOLD_STATE(ctrl, call, Q931_HOLD_STATE_IDLE); return send_message(ctrl, winner, Q931_RETRIEVE_ACKNOWLEDGE, retrieve_ack_ies); } static int retrieve_reject_ies[] = { Q931_CAUSE, -1 }; /*! * \internal * \brief Send the RETRIEVE REJECT message only. * * \param ctrl D channel controller. * \param call Q.931 call leg. (subcall) * \param cause Q.931 cause code for rejecting the retrieve request. * * \retval 0 on success. * \retval -1 on error. */ static int q931_send_retrieve_rej_msg(struct pri *ctrl, struct q931_call *call, int cause) { call->cause = cause; call->causecode = CODE_CCITT; call->causeloc = LOC_PRIV_NET_LOCAL_USER; return send_message(ctrl, call, Q931_RETRIEVE_REJECT, retrieve_reject_ies); } /*! * \brief Send the RETRIEVE REJECT message. * * \param ctrl D channel controller. * \param call Q.931 call leg. (Master Q.931 subcall structure) * \param cause Q.931 cause code for rejecting the retrieve request. * * \retval 0 on success. * \retval -1 on error. */ int q931_send_retrieve_rej(struct pri *ctrl, struct q931_call *call, int cause) { struct q931_call *winner; UPDATE_HOLD_STATE(ctrl, call, Q931_HOLD_STATE_CALL_HELD); winner = q931_find_winning_call(call); if (!winner) { return -1; } /* Call is still on hold so forget the channel. */ winner->channelno = 0;/* No channel */ winner->ds1no = 0; winner->ds1explicit = 0; winner->chanflags = 0; return q931_send_retrieve_rej_msg(ctrl, winner, cause); } static int __q931_hangup(struct pri *ctrl, q931_call *c, int cause) { int disconnect = 1; int release_compl = 0; if (!ctrl || !c) { return -1; } if (ctrl->debug & PRI_DEBUG_Q931_STATE) { pri_message(ctrl, DBGHEAD "ourstate %s, peerstate %s, hold-state %s\n", DBGINFO, q931_call_state_str(c->ourcallstate), q931_call_state_str(c->peercallstate), q931_hold_state_str(c->master_call->hold_state)); } /* If mandatory IE was missing, insist upon that cause code */ if (c->cause == PRI_CAUSE_MANDATORY_IE_MISSING) cause = c->cause; switch (cause) { case PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION: case PRI_CAUSE_REQUESTED_CHAN_UNAVAIL: case PRI_CAUSE_IDENTIFIED_CHANNEL_NOTEXIST: case PRI_CAUSE_UNALLOCATED: if (!ctrl->hangup_fix_enabled) { /* Legacy: We'll send RELEASE_COMPLETE with these causes */ disconnect = 0; release_compl = 1; break; } /* Fall through */ case PRI_CAUSE_INCOMPATIBLE_DESTINATION: /* See Q.931 Section 5.3.2 a) */ switch (c->ourcallstate) { case Q931_CALL_STATE_NULL: case Q931_CALL_STATE_CALL_INITIATED: case Q931_CALL_STATE_CALL_PRESENT: /* * Send RELEASE_COMPLETE because some other message * has not been sent previously. */ disconnect = 0; release_compl = 1; break; case Q931_CALL_STATE_CONNECT_REQUEST: /* * Send RELEASE because the B channel negotiation failed * for call waiting. */ disconnect = 0; break; default: /* * Send DISCONNECT because some other message * has been sent previously. */ break; } break; case PRI_CAUSE_INVALID_CALL_REFERENCE: /* We'll send RELEASE_COMPLETE with these causes */ disconnect = 0; release_compl = 1; break; case PRI_CAUSE_CHANNEL_UNACCEPTABLE: case PRI_CAUSE_CALL_AWARDED_DELIVERED: case PRI_CAUSE_NONSELECTED_USER_CLEARING: /* We'll send RELEASE with these causes */ disconnect = 0; break; default: break; } if (c->cis_call) { disconnect = 0; } c->hangupinitiated = 1; stop_t303(c); /* All other causes we send with DISCONNECT */ 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 */ pri_destroycall(ctrl, c); else if (c->peercallstate == Q931_CALL_STATE_RELEASE_REQUEST) q931_release_complete(ctrl,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 */ switch (c->peercallstate) { default: if (disconnect) q931_disconnect(ctrl,c,cause); else if (release_compl) q931_release_complete(ctrl,c,cause); else q931_release(ctrl,c,cause); break; case Q931_CALL_STATE_NULL: case Q931_CALL_STATE_DISCONNECT_REQUEST: case Q931_CALL_STATE_DISCONNECT_INDICATION: case Q931_CALL_STATE_RELEASE_REQUEST: case Q931_CALL_STATE_RESTART_REQUEST: case Q931_CALL_STATE_RESTART: pri_error(ctrl, "Weird, doing nothing but this shouldn't happen, ourstate %s, peerstate %s\n", q931_call_state_str(c->ourcallstate), q931_call_state_str(c->peercallstate)); break; } break; case Q931_CALL_STATE_ACTIVE: /* received CONNECT */ if (c->cis_call) { q931_release(ctrl, c, cause); break; } q931_disconnect(ctrl,c,cause); break; case Q931_CALL_STATE_DISCONNECT_REQUEST: /* sent DISCONNECT */ q931_release(ctrl,c,cause); break; case Q931_CALL_STATE_CALL_ABORT: /* Don't do anything, waiting for T312 to expire. */ break; case Q931_CALL_STATE_DISCONNECT_INDICATION: /* received DISCONNECT */ if (c->peercallstate == Q931_CALL_STATE_DISCONNECT_REQUEST) { c->alive = 1; q931_release(ctrl,c,cause); } break; case Q931_CALL_STATE_RELEASE_REQUEST: /* sent RELEASE */ /* don't do anything, waiting for RELEASE_COMPLETE */ break; case Q931_CALL_STATE_CALL_INDEPENDENT_SERVICE: /* we sent or received REGISTER */ q931_release_complete(ctrl, c, cause); break; case Q931_CALL_STATE_RESTART: case Q931_CALL_STATE_RESTART_REQUEST: /* sent RESTART */ pri_error(ctrl, "q931_hangup shouldn't be called in this state, ourstate %s, peerstate %s\n", q931_call_state_str(c->ourcallstate), q931_call_state_str(c->peercallstate)); break; default: pri_error(ctrl, "We're not yet handling hanging up when our state is %d, contact support@digium.com, ourstate %s, peerstate %s\n", c->ourcallstate, q931_call_state_str(c->ourcallstate), q931_call_state_str(c->peercallstate)); return -1; } /* we did handle hangup properly at this point */ return 0; } static void initiate_hangup_if_needed(struct q931_call *master, int idx, int cause); int q931_hangup(struct pri *ctrl, q931_call *call, int cause) { int i; if (call->master_call->outboundbroadcast) { if (call->master_call == call) { int slaves; if (ctrl->debug & PRI_DEBUG_Q931_STATE) { pri_message(ctrl, DBGHEAD "Hangup master cref:%d\n", DBGINFO, call->cr); } UPDATE_OURCALLSTATE(ctrl, call, Q931_CALL_STATE_CALL_ABORT); if (call->pri_winner < 0 && call->alive) { /* * Fake clearing if we have no winner to get rid of the upper * layer. */ pri_create_fake_clearing(ctrl, call); } else if (call->fake_clearing_timer) { /* * No need for fake clearing to be running anymore. * Will this actually happen? */ if (ctrl->debug & PRI_DEBUG_Q931_STATE) { pri_message(ctrl, "Fake clearing request cancelled. cref:%d\n", call->cr); } pri_schedule_del(ctrl, call->fake_clearing_timer); call->fake_clearing_timer = 0; } /* Initiate hangup of slaves */ call->master_hanging_up = 1; for (i = 0; i < ARRAY_LEN(call->subcalls); ++i) { if (call->subcalls[i]) { if (ctrl->debug & PRI_DEBUG_Q931_STATE) { pri_message(ctrl, DBGHEAD "Hanging up %d, winner:%d subcall:%p\n", DBGINFO, i, call->pri_winner, call->subcalls[i]); } if (i == call->pri_winner) { q931_hangup(ctrl, call->subcalls[i], cause); } else { initiate_hangup_if_needed(call, i, cause); } } } call->master_hanging_up = 0; slaves = q931_get_subcall_count(call); if (ctrl->debug & PRI_DEBUG_Q931_STATE) { pri_message(ctrl, DBGHEAD "Remaining slaves %d\n", DBGINFO, slaves); } stop_t303(call); if (!call->t312_timer && !slaves) { /* * T312 has expired and no slaves are left so we can safely * destroy the master. */ q931_destroycall(ctrl, call); } return 0; } else { if (ctrl->debug & PRI_DEBUG_Q931_STATE) { pri_message(ctrl, DBGHEAD "Hangup slave cref:%d\n", DBGINFO, call->cr); } return __q931_hangup(ctrl, call, cause); } } else { if (ctrl->debug & PRI_DEBUG_Q931_STATE) { pri_message(ctrl, DBGHEAD "Hangup other cref:%d\n", DBGINFO, call->cr); } return __q931_hangup(ctrl, call, cause); } return 0; } static int prepare_to_handle_maintenance_message(struct pri *ctrl, q931_mh *mh, q931_call *c) { if ((!ctrl) || (!mh) || (!c)) { return -1; } /* SERVICE messages are a superset of messages that can take b-channels * or entire d-channels in and out of service */ switch(mh->msg) { /* the ATT_SERVICE/ATT_SERVICE_ACKNOWLEDGE and NATIONAL_SERVICE/NATIONAL_SERVICE_ACKNOWLEDGE * are mirrors of each other. We only have to check for one type because they are pre-handled * the same way as each other */ case ATT_SERVICE: case ATT_SERVICE_ACKNOWLEDGE: c->channelno = -1; c->slotmap = -1; c->chanflags = 0; c->ds1explicit = 0; c->ds1no = 0; c->cis_call = 0; c->ri = -1; c->changestatus = -1; break; default: pri_error(ctrl, "!! Don't know how to pre-handle maintenance message type '0x%X'\n", mh->msg); return -1; } return 0; } static int prepare_to_handle_q931_message(struct pri *ctrl, q931_mh *mh, q931_call *c) { if ((!ctrl) || (!mh) || (!c)) { return -1; } switch(mh->msg) { case Q931_RESTART: if (ctrl->debug & PRI_DEBUG_Q931_STATE) pri_message(ctrl, "-- Processing Q.931 Restart\n"); /* Reset information */ c->channelno = -1; c->slotmap = -1; c->chanflags = 0; c->ds1no = 0; c->ds1explicit = 0; c->cis_call = 0; c->ri = -1; break; case Q931_FACILITY: c->notify = -1; q931_party_number_init(&c->redirection_number); if (q931_is_dummy_call(c)) { q931_party_address_init(&c->called); } break; case Q931_SETUP: if (ctrl->debug & PRI_DEBUG_Q931_STATE) pri_message(ctrl, "-- Processing Q.931 Call Setup\n"); c->cc.saved_ie_contents.length = 0; c->cc.saved_ie_flags = 0; /* Fall through */ case Q931_REGISTER: c->channelno = -1; c->slotmap = -1; c->chanflags = 0; c->ds1no = 0; c->ri = -1; c->bc.transcapability = -1; c->bc.transmoderate = -1; c->bc.transmultiple = -1; c->bc.userl1 = -1; c->bc.userl2 = -1; c->bc.userl3 = -1; c->bc.rateadaption = -1; q931_party_address_init(&c->called); q931_party_id_init(&c->local_id); q931_party_id_init(&c->remote_id); q931_party_number_init(&c->ani); q931_party_redirecting_init(&c->redirecting); /* * Make sure that keypad and overlap digit buffers are empty in * case they are not in the message. */ c->keypad_digits[0] = '\0'; c->overlap_digits[0] = '\0'; c->useruserprotocoldisc = -1; c->useruserinfo[0] = '\0'; c->complete = 0; c->nonisdn = 0; c->aoc_units = -1; c->reversecharge = -1; /* Fall through */ case Q931_CONNECT: case Q931_ALERTING: case Q931_PROGRESS: c->useruserinfo[0] = '\0'; c->cause = -1; /* Fall through */ case Q931_CALL_PROCEEDING: c->progress = -1; c->progressmask = 0; break; case Q931_CONNECT_ACKNOWLEDGE: pri_schedule_del(ctrl, c->retranstimer); c->retranstimer = 0; break; case Q931_RELEASE: case Q931_DISCONNECT: c->cause = -1; c->causecode = -1; c->causeloc = -1; c->aoc_units = -1; pri_schedule_del(ctrl, c->retranstimer); c->retranstimer = 0; c->useruserinfo[0] = '\0'; break; case Q931_RELEASE_COMPLETE: pri_schedule_del(ctrl, c->retranstimer); c->retranstimer = 0; c->useruserinfo[0] = '\0'; /* Fall through */ case Q931_STATUS: c->cause = -1; c->causecode = -1; c->causeloc = -1; c->sugcallstate = Q931_CALL_STATE_NOT_SET; c->aoc_units = -1; break; case Q931_RESTART_ACKNOWLEDGE: c->channelno = -1; c->ds1no = 0; c->ds1explicit = 0; c->cis_call = 0; break; case Q931_INFORMATION: /* * Make sure that keypad and overlap digit buffers are empty in * case they are not in the message. */ c->keypad_digits[0] = '\0'; c->overlap_digits[0] = '\0'; break; case Q931_STATUS_ENQUIRY: break; case Q931_SETUP_ACKNOWLEDGE: break; case Q931_NOTIFY: c->notify = -1; q931_party_number_init(&c->redirection_number); break; case Q931_HOLD: break; case Q931_HOLD_ACKNOWLEDGE: break; case Q931_HOLD_REJECT: c->cause = -1; break; case Q931_RETRIEVE: c->channelno = 0xFF; c->ds1no = 0; c->ds1explicit = 0; break; case Q931_RETRIEVE_ACKNOWLEDGE: break; case Q931_RETRIEVE_REJECT: c->cause = -1; break; case Q931_USER_INFORMATION: case Q931_SEGMENT: case Q931_CONGESTION_CONTROL: case Q931_RESUME: case Q931_RESUME_ACKNOWLEDGE: case Q931_RESUME_REJECT: case Q931_SUSPEND: case Q931_SUSPEND_ACKNOWLEDGE: case Q931_SUSPEND_REJECT: pri_error(ctrl, "!! Not yet handling pre-handle message type %s (0x%X)\n", msg2str(mh->msg), mh->msg); /* Fall through */ default: pri_error(ctrl, "!! Don't know how to pre-handle message type %s (0x%X)\n", msg2str(mh->msg), mh->msg); q931_status(ctrl,c, PRI_CAUSE_MESSAGE_TYPE_NONEXIST); return -1; } return 0; } static struct q931_call *q931_get_subcall_winner(struct q931_call *master) { if (master->pri_winner < 0) { return NULL; } else { return master->subcalls[master->pri_winner]; } } static void initiate_hangup_if_needed(struct q931_call *master, int idx, int cause) { struct pri *ctrl; struct q931_call *subcall; ctrl = master->pri; subcall = master->subcalls[idx]; if (!subcall->hangupinitiated) { q931_hangup(ctrl, subcall, cause); if (master->subcalls[idx] == subcall) { /* The subcall was not destroyed. */ subcall->alive = 0; } } } static void q931_set_subcall_winner(struct q931_call *subcall) { struct q931_call *master = subcall->master_call; int i; /* Set the winner first */ for (i = 0; ; ++i) { if (ARRAY_LEN(master->subcalls) <= i) { pri_error(subcall->pri, "We should always find the winner in the list!\n"); return; } if (master->subcalls[i] == subcall) { master->pri_winner = i; break; } } /* Start tear down of calls that were not chosen */ for (i = 0; i < ARRAY_LEN(master->subcalls); ++i) { if (master->subcalls[i] && master->subcalls[i] != subcall) { initiate_hangup_if_needed(master, i, PRI_CAUSE_NONSELECTED_USER_CLEARING); } } } static struct q931_call *q931_get_subcall(struct q921_link *link, struct q931_call *master_call) { int i; struct q931_call *cur; struct pri *ctrl; int firstfree = -1; ctrl = link->ctrl; /* First try to locate our subcall */ for (i = 0; i < ARRAY_LEN(master_call->subcalls); ++i) { if (master_call->subcalls[i]) { if (master_call->subcalls[i]->link == link) { return master_call->subcalls[i]; } } else if (firstfree == -1) { firstfree = i; } } if (firstfree < 0) { pri_error(ctrl, "Tried to add more than %d TEIs to call and failed\n", (int) ARRAY_LEN(master_call->subcalls)); return NULL; } /* Create new subcall. */ cur = malloc(sizeof(*cur)); if (!cur) { pri_error(ctrl, "Unable to allocate call\n"); return NULL; } *cur = *master_call; //cur->pri = ctrl;/* We get this assignment for free. */ cur->link = link; cur->next = NULL; cur->apdus = NULL; cur->bridged_call = NULL; //cur->master_call = master_call; /* We get this assignment for free. */ for (i = 0; i < ARRAY_LEN(cur->subcalls); ++i) { cur->subcalls[i] = NULL; } cur->t303_timer = 0;/* T303 should only be on on the master call */ cur->t312_timer = 0;/* T312 should only be on on the master call */ cur->fake_clearing_timer = 0;/* Fake clearing should only be on on the master call */ cur->hold_timer = 0; cur->retranstimer = 0; /* * Mark this subcall as a newcall until it is determined if the * subcall can compete for the call. */ cur->newcall = 1; /* Assume we sent a SETUP and this is the first response to it from this peer. */ cur->ourcallstate = Q931_CALL_STATE_CALL_INITIATED; cur->peercallstate = Q931_CALL_STATE_CALL_PRESENT; master_call->subcalls[firstfree] = cur; if (ctrl->debug & PRI_DEBUG_Q931_STATE) { pri_message(ctrl, "Adding subcall %p for TEI %d to call %p at position %d\n", cur, link->tei, master_call, firstfree); } /* Should only get here if the TEI is not found */ return cur; } int q931_receive(struct q921_link *link, q931_h *h, int len) { q931_mh *mh; struct q931_call *c; struct pri *ctrl; 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]; int cref; int allow_event; int allow_posthandle; ctrl = link->ctrl; memset(last_ie, 0, sizeof(last_ie)); ctrl->q931_rxcount++; if (len < 3 || len < 3 + h->crlen) { /* Message too short for supported protocols. */ return -1; } switch (h->pd) { case MAINTENANCE_PROTOCOL_DISCRIMINATOR_1: case MAINTENANCE_PROTOCOL_DISCRIMINATOR_2: if (!ctrl->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(link, h, len, 1, 0); return 0; } break; default: if (h->pd != ctrl->protodisc) { pri_error(ctrl, "Warning: unknown/inappropriate protocol discriminator received (%02x/%d)\n", h->pd, h->pd); return 0; } break; } cref = q931_cr(h); c = q931_getcall(link, cref); if (!c) { pri_error(ctrl, "Unable to locate call %d\n", cref); return -1; } if (c->master_call->outboundbroadcast && link != &ctrl->link) { c = q931_get_subcall(link, c->master_call); if (!c) { pri_error(ctrl, "Unable to locate subcall for %d\n", cref); return -1; } } if (ctrl->debug & PRI_DEBUG_Q931_STATE) { pri_message(ctrl, "Received message for call %p on link %p TEI/SAPI %d/%d\n", c, link, link->tei, link->sapi); } /* Preliminary handling */ ctrl->facility.count = 0; c->connected_number_in_message = 0; c->redirecting_number_in_message = 0; mh = (q931_mh *)(h->contents + h->crlen); switch (h->pd) { case MAINTENANCE_PROTOCOL_DISCRIMINATOR_1: case MAINTENANCE_PROTOCOL_DISCRIMINATOR_2: prepare_to_handle_maintenance_message(ctrl, mh, c); break; default: /* Unknown protocol discriminator but we will treat it as Q.931 anyway. */ case GR303_PROTOCOL_DISCRIMINATOR: case Q931_PROTOCOL_DISCRIMINATOR: if (prepare_to_handle_q931_message(ctrl, mh, c)) { /* Discard message. We don't know how to handle it. */ if (c->newcall) { pri_destroycall(ctrl, c); } return 0; } break; } q931_clr_subcommands(ctrl); q931_display_clear(c); /* Handle IEs */ memset(mandies, 0, sizeof(mandies)); for (x = 0; x < ARRAY_LEN(msgs); ++x) { if (msgs[x].msgnum == mh->msg) { memcpy(mandies, msgs[x].mandies, sizeof(mandies)); break; } } /* Do real IE processing */ len -= (h->crlen + 3); codeset = cur_codeset = 0; for (x = 0; x < len; x += r) { ie = (q931_ie *)(mh->data + x); r = ielen_checked(ie, len - x); if (r < 0) { /* We have garbage on the end of the packet. */ pri_error(ctrl, "XXX Message longer than it should be?? XXX\n"); if (x) { /* Allow the message anyway. We have already processed an ie. */ break; } q931_display_clear(c); return -1; } for (y = 0; y < ARRAY_LEN(mandies); ++y) { if (mandies[y] == Q931_FULL_IE(cur_codeset, ie->ie)) mandies[y] = 0; } /* 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) && (ctrl->debug & PRI_DEBUG_Q931_ANOMALY)) pri_message(ctrl, "XXX Locking shift immediately follows non-locking shift (from %d through %d to %d) XXX\n", codeset, cur_codeset, y); if (y > 0) { if ((y < codeset) && (ctrl->debug & PRI_DEBUG_Q931_ANOMALY)) pri_error(ctrl, "!! Trying to locked downshift codeset from %d to %d !!\n", codeset, y); codeset = cur_codeset = y; } else { /* Locking shift to codeset 0 is forbidden by all specifications */ pri_error(ctrl, "!! Invalid locking shift to codeset 0 !!\n"); } break; case Q931_NON_LOCKING_SHIFT: cur_codeset = ie->ie & 7; break; default: /* Sanity check for IE code order */ if (!(ie->ie & 0x80)) { if (last_ie[cur_codeset] > ie->ie) { if ((ctrl->debug & PRI_DEBUG_Q931_ANOMALY)) pri_message(ctrl, "XXX Out-of-order IE %d at codeset %d (last was %d)\n", ie->ie, cur_codeset, last_ie[cur_codeset]); } else last_ie[cur_codeset] = ie->ie; } /* Ignore non-locking shifts for TR41459-based signalling */ switch (ctrl->switchtype) { case PRI_SWITCH_LUCENT5E: case PRI_SWITCH_ATT4ESS: if (cur_codeset != codeset) { if ((ctrl->debug & PRI_DEBUG_Q931_DUMP)) pri_message(ctrl, "XXX Ignoring IE %d for temporary codeset %d XXX\n", ie->ie, cur_codeset); break; } /* Fall through */ default: y = q931_handle_ie(cur_codeset, ctrl, c, mh->msg, ie); /* XXX Applicable to codeset 0 only? XXX */ if (!cur_codeset && !(ie->ie & 0xf0) && (y < 0)) { /* * Q.931 Section 5.8.7.1 * Unhandled ies in codeset 0 with the * upper nybble zero are mandatory. */ mandies[MAX_MAND_IES - 1] = Q931_FULL_IE(cur_codeset, ie->ie); } break; } /* Reset current codeset */ cur_codeset = codeset; break; } } missingmand = 0; for (x = 0; x < ARRAY_LEN(mandies); ++x) { if (mandies[x]) { /* check if there is no channel identification when we're configured as network -> that's not an error */ if (((ctrl->localtype != PRI_NETWORK) || (mh->msg != Q931_SETUP) || (mandies[x] != Q931_CHANNEL_IDENT)) && ((mh->msg != Q931_PROGRESS) || (mandies[x] != Q931_PROGRESS_INDICATOR))) { pri_error(ctrl, "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])); missingmand++; } } } if (!missingmand) { switch (mh->msg) { case Q931_SETUP: case Q931_CONNECT: if (ctrl->display_flags.receive & PRI_DISPLAY_OPTION_NAME_INITIAL) { q931_display_name_get(c, &c->remote_id.name); } break; default: break; } /* Now handle the facility ie's after all the other ie's were processed. */ q931_handle_facilities(ctrl, c, mh->msg); } q931_apdu_msg_expire(ctrl, c, mh->msg); /* Post handling */ switch (h->pd) { case MAINTENANCE_PROTOCOL_DISCRIMINATOR_1: case MAINTENANCE_PROTOCOL_DISCRIMINATOR_2: res = post_handle_maintenance_message(ctrl, h->pd, mh, c); q931_display_clear(c); break; default: allow_event = 1; allow_posthandle = 1; if (c->master_call->outboundbroadcast) { nt_ptmp_handle_q931_message(ctrl, mh, c, &allow_event, &allow_posthandle); if (allow_event) { q931_apdu_msg_expire(ctrl, c->master_call, mh->msg); } } if (allow_posthandle) { res = post_handle_q931_message(ctrl, mh, c, missingmand); if (res == Q931_RES_HAVEEVENT && !allow_event) { res = 0; } } else { q931_display_clear(c); res = 0; } break; } return res; } static int post_handle_maintenance_message(struct pri *ctrl, int protodisc, struct q931_mh *mh, struct q931_call *c) { /* Do some maintenance stuff */ if (((protodisc == MAINTENANCE_PROTOCOL_DISCRIMINATOR_1) && (mh->msg == ATT_SERVICE)) || ((protodisc == MAINTENANCE_PROTOCOL_DISCRIMINATOR_2) && (mh->msg == NATIONAL_SERVICE))) { if (c->channelno > 0) { ctrl->ev.e = PRI_EVENT_SERVICE; ctrl->ev.service.channel = q931_encode_channel(c); ctrl->ev.service.changestatus = 0x0f & c->changestatus; } else { switch (0x0f & c->changestatus) { case SERVICE_CHANGE_STATUS_INSERVICE: ctrl->ev.e = PRI_EVENT_DCHAN_UP; //q921_dchannel_up(ctrl); break; case SERVICE_CHANGE_STATUS_OUTOFSERVICE: ctrl->ev.e = PRI_EVENT_DCHAN_DOWN; //q921_dchannel_down(ctrl); break; default: pri_error(ctrl, "!! Don't know how to handle span service change status '%d'\n", (0x0f & c->changestatus)); return -1; } } maintenance_service_ack(ctrl, c); return Q931_RES_HAVEEVENT; } if (((protodisc == MAINTENANCE_PROTOCOL_DISCRIMINATOR_1) && (mh->msg == ATT_SERVICE_ACKNOWLEDGE)) || ((protodisc == MAINTENANCE_PROTOCOL_DISCRIMINATOR_2) && (mh->msg == NATIONAL_SERVICE_ACKNOWLEDGE))) { if (c->channelno > 0) { ctrl->ev.e = PRI_EVENT_SERVICE_ACK; ctrl->ev.service_ack.channel = q931_encode_channel(c); ctrl->ev.service_ack.changestatus = 0x0f & c->changestatus; } else { switch (0x0f & c->changestatus) { case SERVICE_CHANGE_STATUS_INSERVICE: ctrl->ev.e = PRI_EVENT_DCHAN_UP; //q921_dchannel_up(ctrl); break; case SERVICE_CHANGE_STATUS_OUTOFSERVICE: ctrl->ev.e = PRI_EVENT_DCHAN_DOWN; //q921_dchannel_down(ctrl); break; default: pri_error(ctrl, "!! Don't know how to handle span service change status '%d'\n", (0x0f & c->changestatus)); return -1; } } return Q931_RES_HAVEEVENT; } pri_error(ctrl, "!! Don't know how to post-handle maintenance message type 0x%X\n", mh->msg); return -1; } /*! * \internal * \brief Rank the given Q.931 call state for call etablishment. * * \param state Q.931 call state to rank for competing PTMP NT calls. * * \return Call establishment state ranking. */ static enum Q931_RANKED_CALL_STATE q931_rank_state(enum Q931_CALL_STATE state) { enum Q931_RANKED_CALL_STATE rank; switch (state) { case Q931_CALL_STATE_CALL_INITIATED: case Q931_CALL_STATE_CALL_PRESENT: rank = Q931_RANKED_CALL_STATE_PRESENT; break; case Q931_CALL_STATE_OVERLAP_SENDING: case Q931_CALL_STATE_OVERLAP_RECEIVING: rank = Q931_RANKED_CALL_STATE_OVERLAP; break; case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING: case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING: rank = Q931_RANKED_CALL_STATE_PROCEEDING; break; case Q931_CALL_STATE_CALL_DELIVERED: case Q931_CALL_STATE_CALL_RECEIVED: case Q931_CALL_STATE_CONNECT_REQUEST: rank = Q931_RANKED_CALL_STATE_ALERTING; break; case Q931_CALL_STATE_ACTIVE: case Q931_CALL_STATE_CALL_INDEPENDENT_SERVICE: rank = Q931_RANKED_CALL_STATE_CONNECT; break; case Q931_CALL_STATE_CALL_ABORT: rank = Q931_RANKED_CALL_STATE_ABORT; break; default: rank = Q931_RANKED_CALL_STATE_OTHER; break; } return rank; } /*! * \brief Determine if the master will pass an event to the upper layer. * * \param ctrl D channel controller. * \param subcall Q.931 call leg. * \param msg_type Current message type being processed. * * \note This function must parallel nt_ptmp_handle_q931_message(). * * \retval TRUE if the master will pass an event to the upper layer. * \retval FALSE if the event will be blocked. */ int q931_master_pass_event(struct pri *ctrl, struct q931_call *subcall, int msg_type) { struct q931_call *winner; struct q931_call *master; enum Q931_RANKED_CALL_STATE master_rank; enum Q931_RANKED_CALL_STATE subcall_rank; int will_pass; /*!< TRUE if the master will pass an event to the upper layer. */ master = subcall->master_call; if (subcall == master) { /* We are the master call so of course the master will pass an event. */ return 1; } winner = q931_get_subcall_winner(master); if (winner && subcall == winner) { /* We are the winner so of course the master will pass an event. */ return 1; } master_rank = q931_rank_state(master->ourcallstate); will_pass = 0; switch (msg_type) { case Q931_SETUP_ACKNOWLEDGE: #if 0 /* Overlap dialing in PTMP NT mode not supported at the present time. */ if (master_rank < Q931_RANKED_CALL_STATE_OVERLAP) { will_pass = 1; } #endif /* Overlap dialing in PTMP NT mode not supported at the present time. */ break; case Q931_CALL_PROCEEDING: if (master_rank < Q931_RANKED_CALL_STATE_PROCEEDING) { will_pass = 1; } break; case Q931_PROGRESS: /* * We will just ignore this message since there could be multiple devices * competing for this call. Who has access to the B channel at this time * to give in-band signals anyway? */ break; case Q931_ALERTING: if (master_rank < Q931_RANKED_CALL_STATE_ALERTING) { will_pass = 1; } break; case Q931_CONNECT: if (master_rank < Q931_RANKED_CALL_STATE_CONNECT) { /* We are expected to be the winner for the next message. */ will_pass = 1; } break; case Q931_DISCONNECT: case Q931_RELEASE: case Q931_RELEASE_COMPLETE: /* Only deal with the winner. */ break; case Q931_FACILITY: case Q931_NOTIFY: if (!winner) { /* The overlap rank does not count here. */ if (master_rank == Q931_RANKED_CALL_STATE_OVERLAP) { master_rank = Q931_RANKED_CALL_STATE_PRESENT; } subcall_rank = q931_rank_state(subcall->ourcallstate); if (subcall_rank == Q931_RANKED_CALL_STATE_OVERLAP) { subcall_rank = Q931_RANKED_CALL_STATE_PRESENT; } if (master_rank == subcall_rank) { /* * No winner yet but the subcall is as advanced as the master. * Allow the supplementary service event to pass. */ will_pass = 1; } } break; default: /* Only deal with the winner. */ break; } return will_pass; } /*! * \internal * \brief Handle outboundbroadcast incoming messages for the master_call's state. * * \param ctrl D channel controller. * \param mh Q.931 message type header. * \param subcall Q.931 call leg. * \param allow_event Where to set the allow event to upper layer flag. * \param allow_posthandle Where to set the allow post handle event flag. * * \details * This is where we interact the subcalls state with the master_call's state. * * \note This function must parallel q931_master_pass_event(). * * \return Nothing */ static void nt_ptmp_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct q931_call *subcall, int *allow_event, int *allow_posthandle) { struct q931_call *master = subcall->master_call; struct q931_call *winner = q931_get_subcall_winner(master); enum Q931_RANKED_CALL_STATE master_rank; enum Q931_RANKED_CALL_STATE subcall_rank; /* For broadcast calls, we default to not allowing events to keep events received to a minimum * and to allow post processing, since that is where hangup and subcall state handling and other processing is done */ *allow_event = 0; *allow_posthandle = 1; master_rank = q931_rank_state(master->ourcallstate); if (master_rank < Q931_RANKED_CALL_STATE_CONNECT) { /* This subcall can compete for the call. */ subcall->newcall = 0; } switch (mh->msg) { case Q931_SETUP_ACKNOWLEDGE: #if 0 /* Overlap dialing in PTMP NT mode not supported at the present time. */ if (master_rank < Q931_RANKED_CALL_STATE_OVERLAP) { *allow_event = 1; UPDATE_OURCALLSTATE(ctrl, master, Q931_CALL_STATE_OVERLAP_SENDING); } #endif /* Overlap dialing in PTMP NT mode not supported at the present time. */ break; case Q931_CALL_PROCEEDING: if (master_rank < Q931_RANKED_CALL_STATE_PROCEEDING) { *allow_event = 1; UPDATE_OURCALLSTATE(ctrl, master, Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING); } break; case Q931_PROGRESS: /* * We will just ignore this message since there could be multiple devices * competing for this call. Who has access to the B channel at this time * to give in-band signals anyway? */ break; case Q931_ALERTING: if (master_rank < Q931_RANKED_CALL_STATE_ALERTING) { *allow_event = 1; UPDATE_OURCALLSTATE(ctrl, master, Q931_CALL_STATE_CALL_DELIVERED); } break; case Q931_CONNECT: if (master_rank < Q931_RANKED_CALL_STATE_CONNECT) { UPDATE_OURCALLSTATE(ctrl, master, Q931_CALL_STATE_ACTIVE); q931_set_subcall_winner(subcall); *allow_event = 1; } else { /* Call clearing of non selected calls occurs in * q931_set_subcall_winner() - All we need to do is make sure * that this connect is not acknowledged */ *allow_posthandle = 0; } break; case Q931_DISCONNECT: case Q931_RELEASE: case Q931_RELEASE_COMPLETE: if (!winner) { int master_priority; int slave_priority; /* Pass up the cause on a priority basis. */ switch (master->cause) { case PRI_CAUSE_USER_BUSY: master_priority = 2; break; case PRI_CAUSE_CALL_REJECTED: master_priority = 1; break; default: master_priority = 0; break; case -1: /* First time priority. */ master_priority = -2; break; } switch (subcall->cause) { case PRI_CAUSE_USER_BUSY: slave_priority = 2; break; case PRI_CAUSE_CALL_REJECTED: slave_priority = 1; break; default: slave_priority = 0; break; case PRI_CAUSE_INCOMPATIBLE_DESTINATION: /* Cause explicitly ignored */ slave_priority = -1; break; } if (master_priority < slave_priority) { /* Pass up the cause to the master. */ master->cause = subcall->cause; } } else { /* There *is* a winner */ if (subcall == winner) { /* .. and we're it: */ *allow_event = 1; UPDATE_OURCALLSTATE(ctrl, master, Q931_CALL_STATE_CALL_ABORT); } } break; case Q931_FACILITY: case Q931_NOTIFY: if (winner) { if (subcall == winner) { /* Only deal with the winner. */ *allow_event = 1; } } else { /* The overlap rank does not count here. */ if (master_rank == Q931_RANKED_CALL_STATE_OVERLAP) { master_rank = Q931_RANKED_CALL_STATE_PRESENT; } subcall_rank = q931_rank_state(subcall->ourcallstate); if (subcall_rank == Q931_RANKED_CALL_STATE_OVERLAP) { subcall_rank = Q931_RANKED_CALL_STATE_PRESENT; } if (master_rank == subcall_rank) { /* * No winner yet but the subcall is as advanced as the master. * Allow the supplementary service event to pass. */ *allow_event = 1; } } break; default: if (winner && subcall == winner) { /* Only deal with the winner. */ *allow_event = 1; } break; } } /*! * \internal * \brief Fill in the RING event fields. * * \param ctrl D channel controller. * \param call Q.931 call leg * * \return Nothing */ static void q931_fill_ring_event(struct pri *ctrl, struct q931_call *call) { struct pri_subcommand *subcmd; if (call->redirecting.from.number.valid && !call->redirecting.count) { /* * This is most likely because the redirecting number came in * with the redirecting ie only and not a DivertingLegInformation2. */ call->redirecting.count = 1; } if (call->redirecting.state == Q931_REDIRECTING_STATE_PENDING_TX_DIV_LEG_3) { /* * Valid for Q.SIG and ETSI PRI/BRI-PTP modes: * Setup the redirecting.to informtion so we can identify * if the user wants to manually supply the COLR for this * redirected to number if further redirects could happen. * * All the user needs to do is set the REDIRECTING(to-pres) * to the COLR and REDIRECTING(to-num) = complete-dialed-number * (i.e. CALLERID(dnid)) to be safe after determining that the * incoming call was redirected by checking if the * REDIRECTING(count) is nonzero. */ call->redirecting.to.number = call->called.number; call->redirecting.to.number.presentation = PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED; } ctrl->ev.e = PRI_EVENT_RING; ctrl->ev.ring.subcmds = &ctrl->subcmds; ctrl->ev.ring.channel = q931_encode_channel(call); /* Calling party information */ ctrl->ev.ring.callingpres = q931_party_id_presentation(&call->remote_id); ctrl->ev.ring.callingplan = call->remote_id.number.plan; if (call->ani.valid) { ctrl->ev.ring.callingplanani = call->ani.plan; libpri_copy_string(ctrl->ev.ring.callingani, call->ani.str, sizeof(ctrl->ev.ring.callingani)); } else { ctrl->ev.ring.callingplanani = -1; ctrl->ev.ring.callingani[0] = '\0'; } libpri_copy_string(ctrl->ev.ring.callingnum, call->remote_id.number.str, sizeof(ctrl->ev.ring.callingnum)); libpri_copy_string(ctrl->ev.ring.callingname, call->remote_id.name.str, sizeof(ctrl->ev.ring.callingname)); q931_party_id_copy_to_pri(&ctrl->ev.ring.calling, &call->remote_id); /* for backwards compatibility, still need ctrl->ev.ring.callingsubaddr */ if (!call->remote_id.subaddress.type) { /* NSAP: Type = 0 */ libpri_copy_string(ctrl->ev.ring.callingsubaddr, (char *) call->remote_id.subaddress.data, sizeof(ctrl->ev.ring.callingsubaddr)); } else { ctrl->ev.ring.callingsubaddr[0] = '\0'; } ctrl->ev.ring.ani2 = call->ani2; /* Called party information */ ctrl->ev.ring.calledplan = call->called.number.plan; libpri_copy_string(ctrl->ev.ring.callednum, call->called.number.str, sizeof(ctrl->ev.ring.callednum)); q931_party_subaddress_copy_to_pri(&ctrl->ev.ring.called_subaddress, &call->called.subaddress); /* Original called party information (For backward compatibility) */ libpri_copy_string(ctrl->ev.ring.origcalledname, call->redirecting.orig_called.name.str, sizeof(ctrl->ev.ring.origcalledname)); libpri_copy_string(ctrl->ev.ring.origcallednum, call->redirecting.orig_called.number.str, sizeof(ctrl->ev.ring.origcallednum)); ctrl->ev.ring.callingplanorigcalled = call->redirecting.orig_called.number.plan; if (call->redirecting.orig_called.number.valid || call->redirecting.orig_called.name.valid) { ctrl->ev.ring.origredirectingreason = call->redirecting.orig_reason; } else { ctrl->ev.ring.origredirectingreason = -1; } /* Redirecting from party information (For backward compatibility) */ ctrl->ev.ring.callingplanrdnis = call->redirecting.from.number.plan; libpri_copy_string(ctrl->ev.ring.redirectingnum, call->redirecting.from.number.str, sizeof(ctrl->ev.ring.redirectingnum)); libpri_copy_string(ctrl->ev.ring.redirectingname, call->redirecting.from.name.str, sizeof(ctrl->ev.ring.redirectingname)); ctrl->ev.ring.redirectingreason = call->redirecting.reason; libpri_copy_string(ctrl->ev.ring.useruserinfo, call->useruserinfo, sizeof(ctrl->ev.ring.useruserinfo)); call->useruserinfo[0] = '\0'; libpri_copy_string(ctrl->ev.ring.keypad_digits, call->keypad_digits, sizeof(ctrl->ev.ring.keypad_digits)); ctrl->ev.ring.flexible = !(call->chanflags & FLAG_EXCLUSIVE); ctrl->ev.ring.cref = call->cr; ctrl->ev.ring.call = call->master_call; ctrl->ev.ring.layer1 = call->bc.userl1; ctrl->ev.ring.complete = call->complete; ctrl->ev.ring.ctype = call->bc.transcapability; ctrl->ev.ring.progress = call->progress; ctrl->ev.ring.progressmask = call->progressmask; ctrl->ev.ring.reversecharge = call->reversecharge; if (call->redirecting.count) { subcmd = q931_alloc_subcommand(ctrl); if (subcmd) { /* Setup redirecting subcommand */ subcmd->cmd = PRI_SUBCMD_REDIRECTING; q931_party_redirecting_copy_to_pri(&subcmd->u.redirecting, &call->redirecting); } } } /*! * \internal * \brief Fill in the FACILITY event fields. * * \param ctrl D channel controller. * \param call Q.931 call leg. * * \return Nothing */ static void q931_fill_facility_event(struct pri *ctrl, struct q931_call *call) { ctrl->ev.e = PRI_EVENT_FACILITY; ctrl->ev.facility.subcmds = &ctrl->subcmds; ctrl->ev.facility.channel = q931_encode_channel(call); ctrl->ev.facility.cref = call->cr; if (q931_is_dummy_call(call)) { ctrl->ev.facility.call = NULL; } else { ctrl->ev.facility.call = call->master_call; } ctrl->ev.facility.subcall = call; /* Need to do this for backward compatibility with struct pri_event_facname */ libpri_copy_string(ctrl->ev.facility.callingname, call->remote_id.name.str, sizeof(ctrl->ev.facility.callingname)); libpri_copy_string(ctrl->ev.facility.callingnum, call->remote_id.number.str, sizeof(ctrl->ev.facility.callingnum)); ctrl->ev.facility.callingpres = q931_party_id_presentation(&call->remote_id); ctrl->ev.facility.callingplan = call->remote_id.number.plan; } /*! * \internal * \brief APDU wait for response message timeout. * * \param data Callback data pointer. * * \return Nothing */ static void q931_apdu_timeout(void *data) { struct apdu_event *apdu; struct pri *ctrl; struct q931_call *call; int free_it; apdu = data; call = apdu->call; ctrl = call->pri; /* * Extract the APDU from the list so it cannot be * deleted from under us by the callback. */ free_it = pri_call_apdu_extract(call, apdu); q931_clr_subcommands(ctrl); apdu->response.callback(APDU_CALLBACK_REASON_TIMEOUT, ctrl, call, apdu, NULL); if (ctrl->subcmds.counter_subcmd) { q931_fill_facility_event(ctrl, call); ctrl->schedev = 1; } if (free_it) { free(apdu); } } /*! * \brief Generic call-completion timeout event handler. * * \param ctrl D channel controller. * \param cc_record Call completion record to process event. * \param event Event to process. * * \retval nonzero if cc record destroyed because FSM completed. */ int q931_cc_timeout(struct pri *ctrl, struct pri_cc_record *cc_record, enum CC_EVENTS event) { q931_call *call; q931_call *dummy; int fsm_complete; q931_clr_subcommands(ctrl); dummy = ctrl->link.dummy_call; call = cc_record->signaling; if (!call) { /* Substitute the broadcast dummy call reference call. */ call = dummy; } fsm_complete = pri_cc_event(ctrl, call, cc_record, event); if (ctrl->subcmds.counter_subcmd) { q931_fill_facility_event(ctrl, dummy); ctrl->schedev = 1; } return fsm_complete; } /*! * \brief Generic call-completion indirect event creation. * * \param ctrl D channel controller. * \param cc_record Call completion record to process event. * \param func Function to call that will generate a libpri event. * * \return Nothing */ void q931_cc_indirect(struct pri *ctrl, struct pri_cc_record *cc_record, void (*func)(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record)) { q931_call *call; q931_call *dummy; q931_clr_subcommands(ctrl); dummy = ctrl->link.dummy_call; call = cc_record->signaling; if (!call) { /* Substitute the broadcast dummy call reference call. */ call = dummy; } func(ctrl, call, cc_record); if (ctrl->subcmds.counter_subcmd) { q931_fill_facility_event(ctrl, dummy); ctrl->schedev = 1; } } /*! * \brief Find the transfer call indicated by the given link_id. * * \param ctrl D channel controller. * \param link_id Link id of the other call involved in the transfer. * * \retval found-master-call on success. * \retval NULL on error. */ struct q931_call *q931_find_link_id_call(struct pri *ctrl, int link_id) { struct q931_call *cur; struct q931_call *winner; struct q931_call *match; match = NULL; for (cur = *ctrl->callpool; cur; cur = cur->next) { if (cur->is_link_id_valid && cur->link_id == link_id) { /* Found the link_id call. */ winner = q931_find_winning_call(cur); if (!winner) { /* There is no winner. */ break; } switch (winner->ourcallstate) { case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING: case Q931_CALL_STATE_CALL_DELIVERED: case Q931_CALL_STATE_CALL_RECEIVED: case Q931_CALL_STATE_CONNECT_REQUEST: case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING: case Q931_CALL_STATE_ACTIVE: /* The link_id call is in a state suitable for transfer. */ match = cur; break; default: /* The link_id call is not in a good state to transfer. */ break; } break; } } return match; } /*! * \brief Find the active call given the held call. * * \param ctrl D channel controller. * \param held_call Held call to help locate a compatible active call. * * \retval master-active-call on success. * \retval NULL on error. */ struct q931_call *q931_find_held_active_call(struct pri *ctrl, struct q931_call *held_call) { struct q931_call *cur; struct q931_call *winner; struct q931_call *match; if (!held_call->link) { /* Held call does not have an active link. */ return NULL; } match = NULL; for (cur = *ctrl->callpool; cur; cur = cur->next) { if (cur->hold_state == Q931_HOLD_STATE_IDLE) { /* Found an active call. */ winner = q931_find_winning_call(cur); if (!winner || (BRI_NT_PTMP(ctrl) && winner->link != held_call->link)) { /* There is no winner or the active call does not go to the same TEI. */ continue; } switch (winner->ourcallstate) { case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING: case Q931_CALL_STATE_CALL_DELIVERED: case Q931_CALL_STATE_CALL_RECEIVED: case Q931_CALL_STATE_CONNECT_REQUEST: case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING: case Q931_CALL_STATE_ACTIVE: break; default: /* Active call not in a good state to transfer. */ continue; } if (q931_party_number_cmp(&winner->remote_id.number, &held_call->remote_id.number)) { /* The remote party number does not match. This is a weak match. */ match = cur; continue; } /* Found an exact match. */ match = cur; break; } } return match; } /*! * \internal * \brief Find the held call given the active call. * * \param ctrl D channel controller. * \param active_call Active call to help locate a compatible held call. * * \retval master-held-call on success. * \retval NULL on error. */ static struct q931_call *q931_find_held_call(struct pri *ctrl, struct q931_call *active_call) { struct q931_call *cur; struct q931_call *winner; struct q931_call *match; if (!active_call->link) { /* Active call does not have an active link. */ return NULL; } match = NULL; for (cur = *ctrl->callpool; cur; cur = cur->next) { if (cur->hold_state == Q931_HOLD_STATE_CALL_HELD) { /* Found a held call. */ winner = q931_find_winning_call(cur); if (!winner || (BRI_NT_PTMP(ctrl) && winner->link != active_call->link)) { /* There is no winner or the held call does not go to the same TEI. */ continue; } switch (winner->ourcallstate) { case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING: case Q931_CALL_STATE_CALL_DELIVERED: case Q931_CALL_STATE_CALL_RECEIVED: case Q931_CALL_STATE_CONNECT_REQUEST: case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING: case Q931_CALL_STATE_ACTIVE: break; default: /* Held call not in a good state to transfer. */ continue; } if (q931_party_number_cmp(&winner->remote_id.number, &active_call->remote_id.number)) { /* The remote party number does not match. This is a weak match. */ match = cur; continue; } /* Found an exact match. */ match = cur; break; } } return match; } /*! * \internal * \brief Determine RELEASE_COMPLETE cause code for newcall rejection. * * \param call Q.931 call leg. * * \return Cause code for RELEASE_COMPLETE. */ static int newcall_rel_comp_cause(struct q931_call *call) { struct q931_call *master; int cause; cause = PRI_CAUSE_INVALID_CALL_REFERENCE; master = call->master_call; if (master != call && master->t312_timer) { switch (master->ourcallstate) { case Q931_CALL_STATE_CALL_ABORT: cause = PRI_CAUSE_RECOVERY_ON_TIMER_EXPIRE; break; default: break; } } return cause; } /*! * \internal * \brief Restart channel notify event for upper layer notify chain timeout. * * \param data Callback data pointer. * * \return Nothing */ static void q931_restart_notify_timeout(void *data) { struct q931_call *call = data; struct pri *ctrl = call->pri; /* Create channel restart event to upper layer. */ call->channelno = call->restart.chan_no[call->restart.idx++]; ctrl->ev.e = PRI_EVENT_RESTART; ctrl->ev.restart.channel = q931_encode_channel(call); ctrl->schedev = 1; /* Reschedule for next channel restart event needed. */ if (call->restart.idx < call->restart.count) { call->restart.timer = pri_schedule_event(ctrl, 0, q931_restart_notify_timeout, call); } else { /* No more restart events needed. */ call->restart.timer = 0; /* Send back the Restart Acknowledge. All channels are now restarted. */ if (call->slotmap != -1) { /* Send slotmap format. */ call->channelno = -1; } restart_ack(ctrl, call); } } /*! * \internal * \brief Setup restart channel notify events for upper layer. * * \param call Q.931 call leg. * * \return Nothing */ static void q931_restart_notify(struct q931_call *call) { struct pri *ctrl = call->pri; /* Start notify chain. */ pri_schedule_del(ctrl, call->restart.timer); call->restart.idx = 0; q931_restart_notify_timeout(call); } /*! * \internal * \brief Process the decoded information in the Q.931 message. * * \param ctrl D channel controller. * \param mh Q.931 message header. * \param c Q.931 call leg. * \param missingmand Number of missing mandatory ie's. * * \note * When this function returns c may be destroyed so you can no * longer dereference it. * * \retval 0 if no error or event. * \retval Q931_RES_HAVEEVENT if have an event. * \retval -1 on error. */ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct q931_call *c, int missingmand) { int res; int changed; struct apdu_event *cur = NULL; struct pri_subcommand *subcmd; struct q931_call *master_call; switch(mh->msg) { case Q931_RESTART: q931_display_subcmd(ctrl, c); if (missingmand) { q931_status(ctrl, c, PRI_CAUSE_MANDATORY_IE_MISSING); pri_destroycall(ctrl, c); break; } UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_RESTART); c->peercallstate = Q931_CALL_STATE_RESTART_REQUEST; /* Notify upper layer of restart event */ if ((c->channelno == -1 && c->slotmap == -1) || !c->restart.count) { /* * Whole link restart or channel not identified by Channel ID ie * 3.3 octets. * * Send back the Restart Acknowledge */ restart_ack(ctrl, c); /* Create channel restart event to upper layer. */ ctrl->ev.e = PRI_EVENT_RESTART; ctrl->ev.restart.channel = q931_encode_channel(c); } else { /* Start notify chain. */ q931_restart_notify(c); } return Q931_RES_HAVEEVENT; case Q931_REGISTER: q931_display_subcmd(ctrl, c); /* Must be new call */ if (!c->newcall) { q931_status(ctrl, c, PRI_CAUSE_WRONG_CALL_STATE); break; } c->newcall = 0; c->alive = 1; c->cis_call = 1; c->chanflags = FLAG_EXCLUSIVE;/* For safety mark this channel as exclusive. */ c->channelno = 0; UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_CALL_INDEPENDENT_SERVICE); c->peercallstate = Q931_CALL_STATE_CALL_INDEPENDENT_SERVICE; if (c->cc.hangup_call) { q931_release_complete(ctrl, c, PRI_CAUSE_NORMAL_CLEARING); break; } if (/* c->cis_call && */ !c->cis_recognized) { pri_message(ctrl, "-- CIS connection not marked as handled. Disconnecting it.\n"); q931_release_complete(ctrl, c, PRI_CAUSE_FACILITY_NOT_IMPLEMENTED); break; } q931_fill_ring_event(ctrl, c); return Q931_RES_HAVEEVENT; case Q931_SETUP: q931_display_subcmd(ctrl, c); if (missingmand) { q931_release_complete(ctrl, c, PRI_CAUSE_MANDATORY_IE_MISSING); break; } /* Must be new call */ if (!c->newcall) { break; } if (c->progressmask & PRI_PROG_CALLER_NOT_ISDN) c->nonisdn = 1; c->newcall = 0; UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_CALL_PRESENT); c->peercallstate = Q931_CALL_STATE_CALL_INITIATED; if (c->cis_call) { /* * Make call alive so any message events clearing this * signaling call can pass up any subcmds. */ c->alive = 1; } else { /* it's not yet a call since higher level can respond with RELEASE or RELEASE_COMPLETE */ c->alive = 0; } if (c->bc.transmoderate != TRANS_MODE_64_CIRCUIT) { q931_release_complete(ctrl, c, PRI_CAUSE_BEARERCAPABILITY_NOTIMPL); break; } if (c->cc.hangup_call) { q931_release_complete(ctrl, c, PRI_CAUSE_NORMAL_CLEARING); break; } if (c->cis_call && !c->cis_recognized) { pri_message(ctrl, "-- CIS call not marked as handled. Disconnecting it.\n"); q931_release_complete(ctrl, c, PRI_CAUSE_FACILITY_NOT_IMPLEMENTED); break; } /* Save the initial cc-parties. (Incoming SETUP can only be a master call.) */ c->cc.party_a = c->remote_id; q931_fill_ring_event(ctrl, c); return Q931_RES_HAVEEVENT; case Q931_ALERTING: q931_display_subcmd(ctrl, c); stop_t303(c->master_call); if (c->newcall) { q931_release_complete(ctrl, c, newcall_rel_comp_cause(c)); break; } UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_CALL_DELIVERED); c->peercallstate = Q931_CALL_STATE_CALL_RECEIVED; ctrl->ev.e = PRI_EVENT_RINGING; ctrl->ev.ringing.subcmds = &ctrl->subcmds; ctrl->ev.ringing.channel = q931_encode_channel(c); ctrl->ev.ringing.cref = c->cr; ctrl->ev.ringing.call = c->master_call; ctrl->ev.ringing.progress = c->progress; ctrl->ev.ringing.progressmask = c->progressmask; libpri_copy_string(ctrl->ev.ringing.useruserinfo, c->useruserinfo, sizeof(ctrl->ev.ringing.useruserinfo)); c->useruserinfo[0] = '\0'; switch (ctrl->switchtype) { case PRI_SWITCH_QSIG: pri_cc_qsig_determine_available(ctrl, c); break; default: break; } for (cur = c->apdus; cur; cur = cur->next) { if (!cur->sent && cur->message == Q931_FACILITY) { q931_facility(ctrl, c); break; } } return Q931_RES_HAVEEVENT; case Q931_CONNECT: q931_display_subcmd(ctrl, c); stop_t303(c->master_call); if (c->newcall) { q931_release_complete(ctrl, c, newcall_rel_comp_cause(c)); break; } switch (c->ourcallstate) { case Q931_CALL_STATE_CALL_INITIATED: case Q931_CALL_STATE_OVERLAP_SENDING: case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING: case Q931_CALL_STATE_CALL_DELIVERED: case Q931_CALL_STATE_CALL_PRESENT: case Q931_CALL_STATE_CALL_RECEIVED: case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING: case Q931_CALL_STATE_OVERLAP_RECEIVING: /* Accept CONNECT in these states. */ break; default: q931_status(ctrl, c, PRI_CAUSE_WRONG_CALL_STATE); return 0; } ctrl->ev.e = PRI_EVENT_ANSWER; ctrl->ev.answer.subcmds = &ctrl->subcmds; ctrl->ev.answer.channel = q931_encode_channel(c); ctrl->ev.answer.cref = c->cr; ctrl->ev.answer.call = c->master_call; ctrl->ev.answer.progress = c->progress; ctrl->ev.answer.progressmask = c->progressmask; libpri_copy_string(ctrl->ev.answer.useruserinfo, c->useruserinfo, sizeof(ctrl->ev.answer.useruserinfo)); c->useruserinfo[0] = '\0'; if (!ctrl->manual_connect_ack) { q931_connect_acknowledge(ctrl, c, 0); } else { UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_CONNECT_REQUEST); c->peercallstate = Q931_CALL_STATE_CONNECT_REQUEST; } if (c->cis_auto_disconnect && c->cis_call) { /* Make sure WE release when we initiate a signalling only connection */ q931_hangup(ctrl, c, PRI_CAUSE_NORMAL_CLEARING); } else { c->incoming_ct_state = INCOMING_CT_STATE_IDLE; /* Setup connected line subcommand */ subcmd = q931_alloc_subcommand(ctrl); if (subcmd) { subcmd->cmd = PRI_SUBCMD_CONNECTED_LINE; q931_party_id_copy_to_pri(&subcmd->u.connected_line.id, &c->remote_id); } return Q931_RES_HAVEEVENT; } break; case Q931_FACILITY: q931_display_subcmd(ctrl, c); if (c->newcall) { q931_release_complete(ctrl, c, newcall_rel_comp_cause(c)); break; } switch (c->incoming_ct_state) { case INCOMING_CT_STATE_POST_CONNECTED_LINE: c->incoming_ct_state = INCOMING_CT_STATE_IDLE; subcmd = q931_alloc_subcommand(ctrl); if (subcmd) { subcmd->cmd = PRI_SUBCMD_CONNECTED_LINE; q931_party_id_copy_to_pri(&subcmd->u.connected_line.id, &c->remote_id); } break; default: break; } if (ctrl->subcmds.counter_subcmd) { q931_fill_facility_event(ctrl, c); return Q931_RES_HAVEEVENT; } break; case Q931_PROGRESS: if (missingmand) { q931_status(ctrl, c, PRI_CAUSE_MANDATORY_IE_MISSING); pri_destroycall(ctrl, c); break; } ctrl->ev.e = PRI_EVENT_PROGRESS; ctrl->ev.proceeding.cause = c->cause; /* Fall through */ case Q931_CALL_PROCEEDING: q931_display_subcmd(ctrl, c); stop_t303(c->master_call); ctrl->ev.proceeding.subcmds = &ctrl->subcmds; if (c->newcall) { q931_release_complete(ctrl, c, newcall_rel_comp_cause(c)); break; } if ((c->ourcallstate != Q931_CALL_STATE_CALL_INITIATED) && (c->ourcallstate != Q931_CALL_STATE_OVERLAP_SENDING) && (c->ourcallstate != Q931_CALL_STATE_CALL_DELIVERED) && (c->ourcallstate != Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING)) { q931_status(ctrl,c,PRI_CAUSE_WRONG_MESSAGE); break; } ctrl->ev.proceeding.channel = q931_encode_channel(c); if (mh->msg == Q931_CALL_PROCEEDING) { ctrl->ev.e = PRI_EVENT_PROCEEDING; UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING); c->peercallstate = Q931_CALL_STATE_INCOMING_CALL_PROCEEDING; } ctrl->ev.proceeding.progress = c->progress; ctrl->ev.proceeding.progressmask = c->progressmask; ctrl->ev.proceeding.cref = c->cr; ctrl->ev.proceeding.call = c->master_call; for (cur = c->apdus; cur; cur = cur->next) { if (!cur->sent && cur->message == Q931_FACILITY) { q931_facility(ctrl, c); break; } } return Q931_RES_HAVEEVENT; case Q931_CONNECT_ACKNOWLEDGE: q931_display_subcmd(ctrl, c); if (c->newcall) { q931_release_complete(ctrl, c, newcall_rel_comp_cause(c)); break; } switch (c->ourcallstate) { default: if (ctrl->localtype == PRI_NETWORK || ctrl->switchtype == PRI_SWITCH_QSIG) { q931_status(ctrl, c, PRI_CAUSE_WRONG_MESSAGE); break; } /* Fall through */ case Q931_CALL_STATE_CONNECT_REQUEST: case Q931_CALL_STATE_ACTIVE: UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_ACTIVE); c->peercallstate = Q931_CALL_STATE_ACTIVE; if (ctrl->manual_connect_ack) { ctrl->ev.e = PRI_EVENT_CONNECT_ACK; ctrl->ev.connect_ack.subcmds = &ctrl->subcmds; ctrl->ev.connect_ack.channel = q931_encode_channel(c); ctrl->ev.connect_ack.call = c->master_call; return Q931_RES_HAVEEVENT; } break; } break; case Q931_STATUS: q931_display_subcmd(ctrl, c); if (missingmand) { q931_status(ctrl, c, PRI_CAUSE_MANDATORY_IE_MISSING); pri_destroycall(ctrl, c); break; } if (c->newcall) { if (c->cr & 0x7fff) q931_release_complete(ctrl,c,PRI_CAUSE_WRONG_CALL_STATE); break; } /* Do nothing */ /* Also when the STATUS asks for the call of an unexisting reference send RELEASE_COMPLETE */ if ((ctrl->debug & PRI_DEBUG_Q931_ANOMALY) && (c->cause != PRI_CAUSE_INTERWORKING)) pri_error(ctrl, "Received unsolicited status: %s\n", pri_cause2str(c->cause)); if ( #if 0 /* * Workaround for S-12 ver 7.3 - it responds to * invalid/non-implemented IEs in SETUP with NULL call state. */ !c->sugcallstate && (c->ourcallstate != Q931_CALL_STATE_CALL_INITIATED) #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. */ !c->sugcallstate #endif ) { ctrl->ev.hangup.subcmds = &ctrl->subcmds; ctrl->ev.hangup.channel = q931_encode_channel(c); ctrl->ev.hangup.cause = c->cause; ctrl->ev.hangup.cref = c->cr; ctrl->ev.hangup.call = c->master_call; ctrl->ev.hangup.aoc_units = c->aoc_units; ctrl->ev.hangup.call_held = NULL; ctrl->ev.hangup.call_active = NULL; libpri_copy_string(ctrl->ev.hangup.useruserinfo, c->useruserinfo, sizeof(ctrl->ev.hangup.useruserinfo)); /* Free resources */ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_NULL); c->peercallstate = Q931_CALL_STATE_NULL; if (c->outboundbroadcast && (c != q931_get_subcall_winner(c->master_call))) { /* Complete clearing the disconnecting non-winning subcall. */ pri_hangup(ctrl, c, -1); return 0; } /* Free resources */ if (c->alive) { ctrl->ev.e = PRI_EVENT_HANGUP; c->alive = 0; } else if (c->sendhangupack) { ctrl->ev.e = PRI_EVENT_HANGUP_ACK; pri_hangup(ctrl, c, c->cause); } else { pri_hangup(ctrl, c, c->cause); return 0; } return Q931_RES_HAVEEVENT; } break; case Q931_RELEASE_COMPLETE: q931_display_subcmd(ctrl, c); c->hangupinitiated = 1; UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_NULL); c->peercallstate = Q931_CALL_STATE_NULL; ctrl->ev.hangup.subcmds = &ctrl->subcmds; ctrl->ev.hangup.channel = q931_encode_channel(c); ctrl->ev.hangup.cause = c->cause; ctrl->ev.hangup.cref = c->cr; ctrl->ev.hangup.call = c->master_call; ctrl->ev.hangup.aoc_units = c->aoc_units; ctrl->ev.hangup.call_held = NULL; ctrl->ev.hangup.call_active = NULL; libpri_copy_string(ctrl->ev.hangup.useruserinfo, c->useruserinfo, sizeof(ctrl->ev.hangup.useruserinfo)); c->useruserinfo[0] = '\0'; if (c->cc.record && c->cc.record->signaling == c) { pri_cc_event(ctrl, c, c->cc.record, CC_EVENT_SIGNALING_GONE); } if (c->outboundbroadcast && (c != q931_get_subcall_winner(c->master_call))) { /* Complete clearing the disconnecting non-winning subcall. */ pri_hangup(ctrl, c, -1); return 0; } /* Free resources */ if (c->alive) { ctrl->ev.e = PRI_EVENT_HANGUP; c->alive = 0; } else if (c->sendhangupack) { ctrl->ev.e = PRI_EVENT_HANGUP_ACK; pri_hangup(ctrl, c, c->cause); } else { pri_hangup(ctrl, c, c->cause); return 0; } return Q931_RES_HAVEEVENT; case Q931_RELEASE: q931_display_subcmd(ctrl, c); c->hangupinitiated = 1; if (missingmand) { /* Force cause to be mandatory IE missing */ c->cause = PRI_CAUSE_MANDATORY_IE_MISSING; } /* * Don't send RELEASE_COMPLETE if they sent us RELEASE while we * were waiting for RELEASE_COMPLETE from them, assume a NULL state. */ if (c->ourcallstate == Q931_CALL_STATE_RELEASE_REQUEST) c->peercallstate = Q931_CALL_STATE_NULL; else { c->peercallstate = Q931_CALL_STATE_RELEASE_REQUEST; } UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_NULL); if (c->newcall) { q931_release_complete(ctrl, c, newcall_rel_comp_cause(c)); break; } ctrl->ev.e = PRI_EVENT_HANGUP; ctrl->ev.hangup.subcmds = &ctrl->subcmds; ctrl->ev.hangup.channel = q931_encode_channel(c); ctrl->ev.hangup.cause = c->cause; ctrl->ev.hangup.cref = c->cr; ctrl->ev.hangup.call = c->master_call; ctrl->ev.hangup.aoc_units = c->aoc_units; ctrl->ev.hangup.call_held = NULL; ctrl->ev.hangup.call_active = NULL; libpri_copy_string(ctrl->ev.hangup.useruserinfo, c->useruserinfo, sizeof(ctrl->ev.hangup.useruserinfo)); c->useruserinfo[0] = '\0'; if (c->cc.record && c->cc.record->signaling == c) { pri_cc_event(ctrl, c, c->cc.record, CC_EVENT_SIGNALING_GONE); } if (c->outboundbroadcast && (c != q931_get_subcall_winner(c->master_call))) { /* Complete clearing the disconnecting non-winning subcall. */ pri_hangup(ctrl, c, -1); return 0; } return Q931_RES_HAVEEVENT; case Q931_DISCONNECT: q931_display_subcmd(ctrl, c); c->hangupinitiated = 1; if (missingmand) { /* Still let user call release */ c->cause = PRI_CAUSE_MANDATORY_IE_MISSING; } if (c->newcall) { q931_release_complete(ctrl, c, newcall_rel_comp_cause(c)); break; } /* * Determine if there are any calls that can be proposed for * a transfer of held call on disconnect. */ ctrl->ev.hangup.call_held = NULL; ctrl->ev.hangup.call_active = NULL; switch (c->ourcallstate) { case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING: case Q931_CALL_STATE_CALL_DELIVERED: case Q931_CALL_STATE_CALL_RECEIVED: case Q931_CALL_STATE_CONNECT_REQUEST: case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING: case Q931_CALL_STATE_ACTIVE: if (c->master_call->hold_state == Q931_HOLD_STATE_CALL_HELD) { /* Held call is being disconnected first. */ ctrl->ev.hangup.call_held = c->master_call; ctrl->ev.hangup.call_active = q931_find_held_active_call(ctrl, c); } else { /* Active call is being disconnected first. */ if (q931_find_winning_call(c) == c) { /* * Only a normal call or the winning call of a broadcast SETUP * can participate in a transfer of held call on disconnet. */ ctrl->ev.hangup.call_active = c->master_call; ctrl->ev.hangup.call_held = q931_find_held_call(ctrl, c); } } break; default: break; } if (ctrl->debug & PRI_DEBUG_Q931_STATE) { if (ctrl->ev.hangup.call_held) { pri_message(ctrl, "-- Found held call: %p cref:%d\n", ctrl->ev.hangup.call_held, ctrl->ev.hangup.call_held->cr); } if (ctrl->ev.hangup.call_active) { pri_message(ctrl, "-- Found active call: %p cref:%d\n", ctrl->ev.hangup.call_active, ctrl->ev.hangup.call_active->cr); } if (ctrl->ev.hangup.call_held && ctrl->ev.hangup.call_active) { pri_message(ctrl, "-- Transfer held call on disconnect possible.\n"); } } UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_DISCONNECT_INDICATION); c->peercallstate = Q931_CALL_STATE_DISCONNECT_REQUEST; c->sendhangupack = 1; /* wait for a RELEASE so that sufficient time has passed for the inband audio to be heard */ if (ctrl->acceptinbanddisconnect && (c->progressmask & PRI_PROG_INBAND_AVAILABLE)) break; /* Return such an event */ ctrl->ev.e = PRI_EVENT_HANGUP_REQ; ctrl->ev.hangup.subcmds = &ctrl->subcmds; ctrl->ev.hangup.channel = q931_encode_channel(c); ctrl->ev.hangup.cause = c->cause; ctrl->ev.hangup.cref = c->cr; ctrl->ev.hangup.call = c->master_call; ctrl->ev.hangup.aoc_units = c->aoc_units; libpri_copy_string(ctrl->ev.hangup.useruserinfo, c->useruserinfo, sizeof(ctrl->ev.hangup.useruserinfo)); c->useruserinfo[0] = '\0'; if (c->outboundbroadcast && (c != q931_get_subcall_winner(c->master_call))) { /* Complete clearing the disconnecting non-winning subcall. */ pri_hangup(ctrl, c, -1); return 0; } if (c->alive) { switch (c->cause) { case PRI_CAUSE_USER_BUSY: case PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION: switch (ctrl->switchtype) { case PRI_SWITCH_QSIG: pri_cc_qsig_determine_available(ctrl, c); break; default: break; } break; default: break; } return Q931_RES_HAVEEVENT; } else { pri_hangup(ctrl,c,c->cause); } break; case Q931_RESTART_ACKNOWLEDGE: q931_display_subcmd(ctrl, c); UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_NULL); c->peercallstate = Q931_CALL_STATE_NULL; ctrl->ev.e = PRI_EVENT_RESTART_ACK; ctrl->ev.restartack.channel = q931_encode_channel(c); if (c->restart_tx.t316_timer /* * Since the DS1 value can vary, only check the channel number. * We're only supposed to have one RESTART request outstanding * at a time anyway. */ && (c->restart_tx.channel & 0xFF) == (ctrl->ev.restartack.channel & 0xFF)) { /* This is the RESTART ACKNOWLEDGE we are expecting. */ stop_t316(c); } return Q931_RES_HAVEEVENT; case Q931_INFORMATION: /* XXX We're handling only INFORMATION messages that contain overlap dialing received digit + the "Complete" msg which is basically an EOF on further digits XXX */ q931_display_subcmd(ctrl, c); if (c->newcall) { q931_release_complete(ctrl, c, newcall_rel_comp_cause(c)); break; } if (c->ourcallstate != Q931_CALL_STATE_OVERLAP_RECEIVING) { ctrl->ev.e = PRI_EVENT_KEYPAD_DIGIT; ctrl->ev.digit.subcmds = &ctrl->subcmds; ctrl->ev.digit.call = c->master_call; ctrl->ev.digit.channel = q931_encode_channel(c); libpri_copy_string(ctrl->ev.digit.digits, c->keypad_digits, sizeof(ctrl->ev.digit.digits)); return Q931_RES_HAVEEVENT; } ctrl->ev.e = PRI_EVENT_INFO_RECEIVED; ctrl->ev.ring.subcmds = &ctrl->subcmds; ctrl->ev.ring.call = c->master_call; ctrl->ev.ring.channel = q931_encode_channel(c); libpri_copy_string(ctrl->ev.ring.callednum, c->overlap_digits, sizeof(ctrl->ev.ring.callednum)); q931_party_id_copy_to_pri(&ctrl->ev.ring.calling, &c->remote_id); /* for backwards compatibility, still need ctrl->ev.ring.callingsubaddr */ if (!c->remote_id.subaddress.type) { /* NSAP: Type = 0 */ libpri_copy_string(ctrl->ev.ring.callingsubaddr, (char *) c->remote_id.subaddress.data, sizeof(ctrl->ev.ring.callingsubaddr)); } else { ctrl->ev.ring.callingsubaddr[0] = '\0'; } ctrl->ev.ring.complete = c->complete; /* this covers IE 33 (Sending Complete) */ return Q931_RES_HAVEEVENT; case Q931_STATUS_ENQUIRY: q931_display_clear(c); if (c->newcall) { q931_release_complete(ctrl, c, newcall_rel_comp_cause(c)); } else q931_status(ctrl,c, PRI_CAUSE_RESPONSE_TO_STATUS_ENQUIRY); break; case Q931_SETUP_ACKNOWLEDGE: q931_display_subcmd(ctrl, c); stop_t303(c->master_call); if (c->newcall) { q931_release_complete(ctrl, c, newcall_rel_comp_cause(c)); break; } UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_OVERLAP_SENDING); c->peercallstate = Q931_CALL_STATE_OVERLAP_RECEIVING; ctrl->ev.e = PRI_EVENT_SETUP_ACK; ctrl->ev.setup_ack.subcmds = &ctrl->subcmds; ctrl->ev.setup_ack.channel = q931_encode_channel(c); ctrl->ev.setup_ack.call = c->master_call; for (cur = c->apdus; cur; cur = cur->next) { if (!cur->sent && cur->message == Q931_FACILITY) { q931_facility(ctrl, c); break; } } return Q931_RES_HAVEEVENT; case Q931_NOTIFY: res = 0; changed = 0; switch (c->notify) { case PRI_NOTIFY_CALL_DIVERTING: if (c->redirection_number.valid) { c->redirecting.to.number = c->redirection_number; if (c->redirecting.count < PRI_MAX_REDIRECTS) { ++c->redirecting.count; } switch (c->ourcallstate) { case Q931_CALL_STATE_CALL_DELIVERED: /* Call is deflecting after we have seen an ALERTING message */ c->redirecting.reason = PRI_REDIR_FORWARD_ON_NO_REPLY; break; default: /* Call is deflecting for call forwarding unconditional or busy reason. */ c->redirecting.reason = PRI_REDIR_UNKNOWN; break; } /* Setup redirecting subcommand */ subcmd = q931_alloc_subcommand(ctrl); if (subcmd) { subcmd->cmd = PRI_SUBCMD_REDIRECTING; q931_party_redirecting_copy_to_pri(&subcmd->u.redirecting, &c->redirecting); } } q931_display_subcmd(ctrl, c); if (ctrl->subcmds.counter_subcmd) { q931_fill_facility_event(ctrl, c); res = Q931_RES_HAVEEVENT; } break; case PRI_NOTIFY_TRANSFER_ACTIVE: if (q931_party_number_cmp(&c->remote_id.number, &c->redirection_number)) { /* The remote party number information changed. */ c->remote_id.number = c->redirection_number; changed = 1; } /* Fall through */ case PRI_NOTIFY_TRANSFER_ALERTING: if (ctrl->display_flags.receive & PRI_DISPLAY_OPTION_NAME_UPDATE) { struct q931_party_name name; if (q931_display_name_get(c, &name)) { if (q931_party_name_cmp(&c->remote_id.name, &name)) { /* The remote party name information changed. */ c->remote_id.name = name; changed = 1; } } } if (c->redirection_number.valid && q931_party_number_cmp(&c->remote_id.number, &c->redirection_number)) { /* The remote party number information changed. */ c->remote_id.number = c->redirection_number; changed = 1; } if (c->remote_id.subaddress.valid) { /* * Clear the subaddress as the remote party has been changed. * Any new subaddress will arrive later. */ q931_party_subaddress_init(&c->remote_id.subaddress); changed = 1; } if (changed) { /* Setup connected line subcommand */ subcmd = q931_alloc_subcommand(ctrl); if (subcmd) { subcmd->cmd = PRI_SUBCMD_CONNECTED_LINE; q931_party_id_copy_to_pri(&subcmd->u.connected_line.id, &c->remote_id); } } q931_display_subcmd(ctrl, c); if (ctrl->subcmds.counter_subcmd) { q931_fill_facility_event(ctrl, c); res = Q931_RES_HAVEEVENT; } break; default: ctrl->ev.e = PRI_EVENT_NOTIFY; ctrl->ev.notify.subcmds = &ctrl->subcmds; ctrl->ev.notify.channel = q931_encode_channel(c); ctrl->ev.notify.info = c->notify; ctrl->ev.notify.call = c->master_call; res = Q931_RES_HAVEEVENT; break; } q931_display_subcmd(ctrl, c); return res; case Q931_HOLD: q931_display_subcmd(ctrl, c); res = 0; if (!ctrl->hold_support) { /* * Blocking any calls from getting on HOLD effectively * disables HOLD/RETRIEVE. */ q931_send_hold_rej_msg(ctrl, c, PRI_CAUSE_FACILITY_NOT_IMPLEMENTED); break; } switch (c->ourcallstate) { case Q931_CALL_STATE_CALL_RECEIVED: case Q931_CALL_STATE_CONNECT_REQUEST: case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING: if (PTMP_MODE(ctrl)) { /* HOLD request only allowed in these states if point-to-point mode. */ q931_send_hold_rej_msg(ctrl, c, PRI_CAUSE_WRONG_CALL_STATE); break; } /* Fall through */ case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING: case Q931_CALL_STATE_CALL_DELIVERED: case Q931_CALL_STATE_ACTIVE: if (!q931_find_winning_call(c)) { /* * Only the winning call of a broadcast SETUP can do hold since the * call must be answered first. */ q931_send_hold_rej_msg(ctrl, c, PRI_CAUSE_WRONG_CALL_STATE); break; } master_call = c->master_call; switch (master_call->hold_state) { case Q931_HOLD_STATE_HOLD_REQ: if (ctrl->debug & PRI_DEBUG_Q931_STATE) { pri_message(ctrl, "HOLD collision\n"); } if (ctrl->localtype == PRI_NETWORK) { /* The network ignores HOLD request on a hold collision. */ break; } /* Fall through */ case Q931_HOLD_STATE_IDLE: ctrl->ev.e = PRI_EVENT_HOLD; ctrl->ev.hold.channel = q931_encode_channel(c); ctrl->ev.hold.call = master_call; ctrl->ev.hold.subcmds = &ctrl->subcmds; res = Q931_RES_HAVEEVENT; UPDATE_HOLD_STATE(ctrl, master_call, Q931_HOLD_STATE_HOLD_IND); break; default: q931_send_hold_rej_msg(ctrl, c, PRI_CAUSE_WRONG_CALL_STATE); break; } break; case Q931_CALL_STATE_DISCONNECT_INDICATION: case Q931_CALL_STATE_RELEASE_REQUEST: /* Ignore HOLD request in these states. */ break; default: q931_send_hold_rej_msg(ctrl, c, PRI_CAUSE_WRONG_CALL_STATE); break; } return res; case Q931_HOLD_ACKNOWLEDGE: q931_display_subcmd(ctrl, c); res = 0; master_call = c->master_call; switch (master_call->hold_state) { case Q931_HOLD_STATE_HOLD_REQ: ctrl->ev.e = PRI_EVENT_HOLD_ACK; ctrl->ev.hold_ack.channel = q931_encode_channel(c); ctrl->ev.hold_ack.call = master_call; ctrl->ev.hold_ack.subcmds = &ctrl->subcmds; res = Q931_RES_HAVEEVENT; UPDATE_HOLD_STATE(ctrl, master_call, Q931_HOLD_STATE_CALL_HELD); /* Call is now on hold so forget the channel. */ c->channelno = 0;/* No channel */ c->ds1no = 0; c->ds1explicit = 0; c->chanflags = 0; /* Stop T-HOLD timer */ pri_schedule_del(ctrl, master_call->hold_timer); master_call->hold_timer = 0; break; default: /* Ignore response. Response is late or spurrious. */ break; } return res; case Q931_HOLD_REJECT: q931_display_subcmd(ctrl, c); res = 0; master_call = c->master_call; switch (master_call->hold_state) { case Q931_HOLD_STATE_HOLD_REQ: if (missingmand) { /* Still, let hold rejection continue. */ c->cause = PRI_CAUSE_MANDATORY_IE_MISSING; } ctrl->ev.e = PRI_EVENT_HOLD_REJ; ctrl->ev.hold_rej.channel = q931_encode_channel(c); ctrl->ev.hold_rej.call = master_call; ctrl->ev.hold_rej.cause = c->cause; ctrl->ev.hold_rej.subcmds = &ctrl->subcmds; res = Q931_RES_HAVEEVENT; UPDATE_HOLD_STATE(ctrl, master_call, Q931_HOLD_STATE_IDLE); /* Stop T-HOLD timer */ pri_schedule_del(ctrl, master_call->hold_timer); master_call->hold_timer = 0; break; default: /* Ignore response. Response is late or spurrious. */ break; } return res; case Q931_RETRIEVE: q931_display_subcmd(ctrl, c); res = 0; switch (c->ourcallstate) { case Q931_CALL_STATE_CALL_RECEIVED: case Q931_CALL_STATE_CONNECT_REQUEST: case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING: if (PTMP_MODE(ctrl)) { /* RETRIEVE request only allowed in these states if point-to-point mode. */ q931_send_retrieve_rej_msg(ctrl, c, PRI_CAUSE_WRONG_CALL_STATE); break; } /* Fall through */ case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING: case Q931_CALL_STATE_CALL_DELIVERED: case Q931_CALL_STATE_ACTIVE: if (!q931_find_winning_call(c)) { /* * Only the winning call of a broadcast SETUP can do hold since the * call must be answered first. */ q931_send_retrieve_rej_msg(ctrl, c, PRI_CAUSE_WRONG_CALL_STATE); break; } master_call = c->master_call; switch (master_call->hold_state) { case Q931_HOLD_STATE_RETRIEVE_REQ: if (ctrl->debug & PRI_DEBUG_Q931_STATE) { pri_message(ctrl, "RETRIEVE collision\n"); } if (ctrl->localtype == PRI_NETWORK) { /* The network ignores RETRIEVE request on a retrieve collision. */ break; } /* Fall through */ case Q931_HOLD_STATE_CALL_HELD: ctrl->ev.e = PRI_EVENT_RETRIEVE; ctrl->ev.retrieve.channel = q931_encode_channel(c); ctrl->ev.retrieve.call = master_call; ctrl->ev.retrieve.flexible = !(c->chanflags & FLAG_EXCLUSIVE); ctrl->ev.retrieve.subcmds = &ctrl->subcmds; res = Q931_RES_HAVEEVENT; UPDATE_HOLD_STATE(ctrl, master_call, Q931_HOLD_STATE_RETRIEVE_IND); break; default: q931_send_retrieve_rej_msg(ctrl, c, PRI_CAUSE_WRONG_CALL_STATE); break; } break; case Q931_CALL_STATE_DISCONNECT_INDICATION: case Q931_CALL_STATE_RELEASE_REQUEST: /* Ignore RETRIEVE request in these states. */ break; default: q931_send_retrieve_rej_msg(ctrl, c, PRI_CAUSE_WRONG_CALL_STATE); break; } return res; case Q931_RETRIEVE_ACKNOWLEDGE: q931_display_subcmd(ctrl, c); res = 0; master_call = c->master_call; switch (master_call->hold_state) { case Q931_HOLD_STATE_RETRIEVE_REQ: UPDATE_HOLD_STATE(ctrl, master_call, Q931_HOLD_STATE_IDLE); /* Stop T-RETRIEVE timer */ pri_schedule_del(ctrl, master_call->hold_timer); master_call->hold_timer = 0; ctrl->ev.e = PRI_EVENT_RETRIEVE_ACK; ctrl->ev.retrieve_ack.channel = q931_encode_channel(c); ctrl->ev.retrieve_ack.call = master_call; ctrl->ev.retrieve_ack.subcmds = &ctrl->subcmds; res = Q931_RES_HAVEEVENT; break; default: /* Ignore response. Response is late or spurrious. */ break; } return res; case Q931_RETRIEVE_REJECT: q931_display_subcmd(ctrl, c); res = 0; master_call = c->master_call; switch (master_call->hold_state) { case Q931_HOLD_STATE_CALL_HELD: /* In this state likely because of a RETRIEVE collision. */ case Q931_HOLD_STATE_RETRIEVE_REQ: UPDATE_HOLD_STATE(ctrl, master_call, Q931_HOLD_STATE_CALL_HELD); /* Call is still on hold so forget the channel. */ c->channelno = 0;/* No channel */ c->ds1no = 0; c->ds1explicit = 0; c->chanflags = 0; /* Stop T-RETRIEVE timer */ pri_schedule_del(ctrl, master_call->hold_timer); master_call->hold_timer = 0; if (missingmand) { /* Still, let retrive rejection continue. */ c->cause = PRI_CAUSE_MANDATORY_IE_MISSING; } ctrl->ev.e = PRI_EVENT_RETRIEVE_REJ; ctrl->ev.retrieve_rej.channel = q931_encode_channel(c); ctrl->ev.retrieve_rej.call = master_call; ctrl->ev.retrieve_rej.cause = c->cause; ctrl->ev.retrieve_rej.subcmds = &ctrl->subcmds; res = Q931_RES_HAVEEVENT; break; default: /* Ignore response. Response is late or spurrious. */ break; } return res; case Q931_USER_INFORMATION: case Q931_SEGMENT: case Q931_CONGESTION_CONTROL: case Q931_RESUME: case Q931_RESUME_ACKNOWLEDGE: case Q931_RESUME_REJECT: case Q931_SUSPEND: case Q931_SUSPEND_ACKNOWLEDGE: case Q931_SUSPEND_REJECT: pri_error(ctrl, "!! Not yet handling post-handle message type %s (0x%X)\n", msg2str(mh->msg), mh->msg); /* Fall through */ default: pri_error(ctrl, "!! Don't know how to post-handle message type %s (0x%X)\n", msg2str(mh->msg), mh->msg); q931_display_clear(c); q931_status(ctrl,c, PRI_CAUSE_MESSAGE_TYPE_NONEXIST); if (c->newcall) { pri_destroycall(ctrl, c); } return -1; } return 0; } /* Clear a call, although we did not receive any hangup notification. */ static int pri_internal_clear(struct q931_call *c) { struct pri *ctrl = c->pri; int res; pri_schedule_del(ctrl, c->retranstimer); c->retranstimer = 0; c->useruserinfo[0] = '\0'; //c->cause = -1; c->causecode = -1; c->causeloc = -1; c->sugcallstate = Q931_CALL_STATE_NOT_SET; c->aoc_units = -1; if (c->master_call->outboundbroadcast && c == q931_find_winning_call(c)) { /* Pass the hangup cause to the master_call. */ c->master_call->cause = c->cause; } q931_clr_subcommands(ctrl); ctrl->ev.hangup.subcmds = &ctrl->subcmds; ctrl->ev.hangup.channel = q931_encode_channel(c); ctrl->ev.hangup.cause = c->cause; ctrl->ev.hangup.cref = c->cr; ctrl->ev.hangup.call = c->master_call; ctrl->ev.hangup.aoc_units = c->aoc_units; ctrl->ev.hangup.call_held = NULL; ctrl->ev.hangup.call_active = NULL; libpri_copy_string(ctrl->ev.hangup.useruserinfo, c->useruserinfo, sizeof(ctrl->ev.hangup.useruserinfo)); if (ctrl->debug & PRI_DEBUG_Q931_STATE) { pri_message(ctrl, DBGHEAD "alive %d, hangupack %d\n", DBGINFO, c->alive, c->sendhangupack); } if (c->cc.record) { if (c->cc.record->signaling == c) { pri_cc_event(ctrl, c, c->cc.record, CC_EVENT_SIGNALING_GONE); } else if (c->cc.record->original_call == c) { pri_cc_event(ctrl, c, c->cc.record, CC_EVENT_INTERNAL_CLEARING); } } /* Free resources */ if (c->alive) { c->alive = 0; ctrl->ev.e = PRI_EVENT_HANGUP; res = Q931_RES_HAVEEVENT; } else if (c->sendhangupack) { pri_hangup(ctrl, c, c->cause); ctrl->ev.e = PRI_EVENT_HANGUP_ACK; res = Q931_RES_HAVEEVENT; } else { pri_hangup(ctrl, c, c->cause); if (ctrl->subcmds.counter_subcmd) { q931_fill_facility_event(ctrl, ctrl->link.dummy_call); res = Q931_RES_HAVEEVENT; } else { res = 0; } } return res; } /* Handle T309 timeout for an active call. */ static void pri_dl_down_timeout(void *data) { struct q931_call *c = data; struct pri *ctrl = c->pri; if (ctrl->debug & PRI_DEBUG_Q931_STATE) { pri_message(ctrl, "T309 timed out waiting for data link re-establishment\n"); } c->retranstimer = 0; c->cause = PRI_CAUSE_DESTINATION_OUT_OF_ORDER; UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_NULL); c->peercallstate = Q931_CALL_STATE_NULL; if (pri_internal_clear(c) == Q931_RES_HAVEEVENT) { ctrl->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 *ctrl = c->pri; if (ctrl->debug & PRI_DEBUG_Q931_STATE) { pri_message(ctrl, "Cancel call after data link failure\n"); } c->retranstimer = 0; c->cause = PRI_CAUSE_DESTINATION_OUT_OF_ORDER; UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_NULL); c->peercallstate = Q931_CALL_STATE_NULL; if (pri_internal_clear(c) == Q931_RES_HAVEEVENT) { ctrl->schedev = 1; } } /*! * \internal * \brief Convert the DL event to a string. * * \param event Data-link event to convert to a string. * * \return DL event string */ static const char *q931_dl_event2str(enum Q931_DL_EVENT event) { const char *str; str = "Unknown"; switch (event) { case Q931_DL_EVENT_NONE: str = "Q931_DL_EVENT_NONE"; break; case Q931_DL_EVENT_DL_ESTABLISH_IND: str = "Q931_DL_EVENT_DL_ESTABLISH_IND"; break; case Q931_DL_EVENT_DL_ESTABLISH_CONFIRM: str = "Q931_DL_EVENT_DL_ESTABLISH_CONFIRM"; break; case Q931_DL_EVENT_DL_RELEASE_IND: str = "Q931_DL_EVENT_DL_RELEASE_IND"; break; case Q931_DL_EVENT_DL_RELEASE_CONFIRM: str = "Q931_DL_EVENT_DL_RELEASE_CONFIRM"; break; case Q931_DL_EVENT_TEI_REMOVAL: str = "Q931_DL_EVENT_TEI_REMOVAL"; break; } return str; } /*! * \brief Receive a DL event from layer 2. * * \param link Q.921 link event occurred on. * \param event Data-link event reporting. * * \return Nothing */ void q931_dl_event(struct q921_link *link, enum Q931_DL_EVENT event) { struct q931_call *cur; struct q931_call *cur_next; struct q931_call *call; struct pri *ctrl; int idx; if (!link) { return; } ctrl = link->ctrl; if (ctrl->debug & PRI_DEBUG_Q931_STATE) { pri_message(ctrl, "TEI=%d DL event: %s(%d)\n", link->tei, q931_dl_event2str(event), event); } switch (event) { case Q931_DL_EVENT_TEI_REMOVAL: if (!BRI_NT_PTMP(ctrl)) { /* Only NT PTMP has anything to worry about when the TEI is removed. */ break; } /* * For NT PTMP, this deviation from the specifications is needed * because we have no way to re-associate any T309 calls on the * removed TEI. */ for (cur = *ctrl->callpool; cur; cur = cur->next) { if (cur->outboundbroadcast) { /* Does this master call have a subcall on the link that went down? */ call = NULL; for (idx = 0; idx < ARRAY_LEN(cur->subcalls); ++idx) { if (cur->subcalls[idx] && cur->subcalls[idx]->link == link) { /* This subcall is on the link that went down. */ call = cur->subcalls[idx]; break; } } if (!call) { /* No subcall is on the link that went down. */ continue; } } else if (cur->link != link) { /* This call is not on the link that went down. */ continue; } else { call = cur; } if (!(cur->cr & ~Q931_CALL_REFERENCE_FLAG)) { /* Simply destroy the global call reference call record. */ if (ctrl->debug & PRI_DEBUG_Q931_STATE) { pri_message(ctrl, "TEI=%d Destroying global call record\n", link->tei); } q931_destroycall(ctrl, call); continue; } /* * NOTE: We are gambling that no T309 timer's have had a chance * to expire. They should not expire since we are either called * immediately after the Q931_DL_EVENT_DL_RELEASE_xxx or after a * timeout of 0. */ if (ctrl->debug & PRI_DEBUG_Q931_STATE) { pri_message(ctrl, "Cancel call cref=%d on channel %d in state %d (%s)\n", call->cr, call->channelno, call->ourcallstate, q931_call_state_str(call->ourcallstate)); } call->link = NULL; pri_schedule_del(ctrl, call->retranstimer); call->retranstimer = pri_schedule_event(ctrl, 0, pri_dl_down_cancelcall, call); } break; case Q931_DL_EVENT_DL_RELEASE_IND: case Q931_DL_EVENT_DL_RELEASE_CONFIRM: for (cur = *ctrl->callpool; cur; cur = cur_next) { /* The master call could get destroyed if the last subcall dies. */ cur_next = cur->next; if (!(cur->cr & ~Q931_CALL_REFERENCE_FLAG)) { /* Don't do anything on the global call reference call record. */ continue; } if (cur->outboundbroadcast) { /* Does this master call have a subcall on the link that went down? */ call = NULL; for (idx = 0; idx < ARRAY_LEN(cur->subcalls); ++idx) { if (cur->subcalls[idx] && cur->subcalls[idx]->link == link) { /* This subcall is on the link that went down. */ call = cur->subcalls[idx]; break; } } if (!call) { /* No subcall is on the link that went down. */ continue; } } else if (cur->link != link) { /* This call is not on the link that went down. */ continue; } else { call = cur; } switch (call->ourcallstate) { case Q931_CALL_STATE_ACTIVE: /* NOTE: Only a winning subcall can get to the active state. */ if (ctrl->nfas) { /* * The upper layer should handle T309 for NFAS since the calls * could be maintained by a backup D channel if the B channel * for the call did not go into alarm. */ break; } /* * For a call in Active state, activate T309 only if there is * no timer already running. * * NOTE: cur != call when we have a winning subcall. */ if (!cur->retranstimer || !call->retranstimer) { if (ctrl->debug & PRI_DEBUG_Q931_STATE) { pri_message(ctrl, "Start T309 for call cref=%d on channel %d\n", call->cr, call->channelno); } call->retranstimer = pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T309], pri_dl_down_timeout, call); } break; case Q931_CALL_STATE_NULL: break; default: /* * For a call that is not in Active state, schedule internal * clearing of the call 'ASAP' (delay 0). * * NOTE: We are killing NFAS calls that are not connected yet * because there are likely messages in flight when this link * went down that could leave the call in an unknown/stuck state. */ if (ctrl->debug & PRI_DEBUG_Q931_STATE) { pri_message(ctrl, "Cancel call cref=%d on channel %d in state %d (%s)\n", call->cr, call->channelno, call->ourcallstate, q931_call_state_str(call->ourcallstate)); } if (cur->outboundbroadcast) { /* Simply destroy non-winning subcalls. */ q931_destroycall(ctrl, call); continue; } pri_schedule_del(ctrl, call->retranstimer); call->retranstimer = pri_schedule_event(ctrl, 0, pri_dl_down_cancelcall, call); break; } } break; case Q931_DL_EVENT_DL_ESTABLISH_IND: case Q931_DL_EVENT_DL_ESTABLISH_CONFIRM: for (cur = *ctrl->callpool; cur; cur = cur->next) { if (!(cur->cr & ~Q931_CALL_REFERENCE_FLAG)) { /* Don't do anything on the global call reference call record. */ continue; } if (cur->outboundbroadcast) { /* Does this master call have a subcall on the link that came up? */ call = NULL; for (idx = 0; idx < ARRAY_LEN(cur->subcalls); ++idx) { if (cur->subcalls[idx] && cur->subcalls[idx]->link == link) { /* This subcall is on the link that came up. */ call = cur->subcalls[idx]; break; } } if (!call) { /* No subcall is on the link that came up. */ continue; } } else if (cur->link != link) { /* This call is not on the link that came up. */ continue; } else { call = cur; } switch (call->ourcallstate) { case Q931_CALL_STATE_ACTIVE: /* NOTE: Only a winning subcall can get to the active state. */ if (pri_schedule_check(ctrl, call->retranstimer, pri_dl_down_timeout, call)) { if (ctrl->debug & PRI_DEBUG_Q931_STATE) { pri_message(ctrl, "Stop T309 for call cref=%d on channel %d\n", call->cr, call->channelno); } pri_schedule_del(ctrl, call->retranstimer); call->retranstimer = 0; } q931_status(ctrl, call, PRI_CAUSE_NORMAL_UNSPECIFIED); break; case Q931_CALL_STATE_NULL: case Q931_CALL_STATE_DISCONNECT_REQUEST: case Q931_CALL_STATE_DISCONNECT_INDICATION: case Q931_CALL_STATE_RELEASE_REQUEST: break; default: if (event == Q931_DL_EVENT_DL_ESTABLISH_CONFIRM) { /* * Lets not send a STATUS message for this call as we * requested the link to be established as a likely * result of this call. */ break; } /* * The STATUS message sent here is not required by Q.931, * but it may help anyway. * This looks like a new call started while the link was down. */ q931_status(ctrl, call, PRI_CAUSE_NORMAL_UNSPECIFIED); break; } } break; default: pri_message(ctrl, DBGHEAD "unexpected event %d.\n", DBGINFO, event); break; } } int q931_call_getcrv(struct pri *ctrl, q931_call *call, int *callmode) { if (callmode) *callmode = call->cr & 0x7; return ((call->cr & 0x7fff) >> 3); } int q931_call_setcrv(struct pri *ctrl, q931_call *call, int crv, int callmode) { /* Do not allow changing the dummy call reference */ if (!q931_is_dummy_call(call)) { call->cr = (crv << 3) & 0x7fff; call->cr |= (callmode & 0x7); } return 0; }