libisdn
Q931mes.c
Go to the documentation of this file.
00001 /*****************************************************************************
00002 
00003   FileName:     Q931mes.c
00004 
00005   Contents:     Pack/Unpack functions. These functions will unpack a Q931
00006                 message from the bit packed original format into structs
00007                 that contains variables sized by the user. It will also pack
00008                 the struct back into a Q.931 message as required.
00009 
00010                 See q931.h for description.
00011 
00012   License/Copyright:
00013 
00014   Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
00015   email:janvb@caselaboratories.com
00016 
00017   Redistribution and use in source and binary forms, with or without
00018   modification, are permitted provided that the following conditions are
00019   met:
00020 
00021         * Redistributions of source code must retain the above copyright notice,
00022           this list of conditions and the following disclaimer.
00023         * Redistributions in binary form must reproduce the above copyright notice,
00024           this list of conditions and the following disclaimer in the documentation
00025           and/or other materials provided with the distribution.
00026         * Neither the name of the Case Labs, Ltd nor the names of its contributors
00027           may be used to endorse or promote products derived from this software
00028           without specific prior written permission.
00029 
00030   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00031   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00032   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00033   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00034   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00035   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00036   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00037   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00038   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00039   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00040   POSSIBILITY OF SUCH DAMAGE.
00041 
00042 *****************************************************************************/
00043 
00044 #include <stdio.h>
00045 #include <stdlib.h>
00046 #include <assert.h>
00047 #include <string.h>
00048 #include <limits.h>
00049 
00050 #include "Q931.h"
00051 #include "Q931priv.h"
00052 #include "Q932.h"
00053 
00054 /*
00055  * TODO: Convert this into something like:
00056  *
00057  * { Q931mes_ALERTING,
00058  *                       { Q931ie_BEARER_CAPABILITY, 4, 12, Q931_IEF_TO_BOTH },
00059  *                       { Q931ie_CHANNEL_ID,        2,  0, Q931_IEF_TO_BOTH },
00060  *                       ...
00061  * },
00062  */
00063 
00064 struct Q931MessageIE Q931MessageIEs[] = {
00065         /*
00066          * ITU-T Q.931 IE table
00067          */
00068 
00069         /* ALERTING */
00070         { Q931mes_ALERTING, 8, "ALERTING", {
00071                         { Q931ie_BEARER_CAPABILITY,        4, 12, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00072                         { Q931ie_CHANNEL_IDENTIFICATION,   2,  0, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00073                         { Q931ie_PROGRESS_INDICATOR,       2,  4, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00074                         { Q931ie_DISPLAY,                  2, 34, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00075                         { Q931ie_SIGNAL,                   2,  3, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00076                         { Q931ie_HIGH_LAYER_COMPATIBILITY, 2,  5, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00077 
00078                         { Q932ie_FACILITY,                 2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00079                         { Q932ie_EXTENDED_FACILITY,        2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00080 
00081 /* Q.952 */
00082                         { Q931ie_REDIRECTION_NUMBER,       2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00083 
00084                         { 0, 0, 0, 0 },
00085         }},
00086 
00087         /* CALL PROCEEDING */
00088         { Q931mes_CALL_PROCEEDING, 8, "CALL PROCEEDING", {
00089                         { Q931ie_BEARER_CAPABILITY,        4, 12, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00090                         { Q931ie_CHANNEL_IDENTIFICATION,   2,  0, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00091                         { Q931ie_PROGRESS_INDICATOR,       2,  4, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00092                         { Q931ie_DISPLAY,                  2, 34, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00093                         { Q931ie_HIGH_LAYER_COMPATIBILITY, 2,  5, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00094 
00095                         { Q932ie_FACILITY,                 2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00096                         { Q932ie_EXTENDED_FACILITY,        2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00097 
00098                         { 0, 0, 0, 0 },
00099         }},
00100 
00101         /* CONNECT */
00102         { Q931mes_CONNECT, 8, "CONNECT", {
00103                         { Q931ie_BEARER_CAPABILITY,        4, 12, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00104                         { Q931ie_CHANNEL_IDENTIFICATION,   2,  0, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00105                         { Q931ie_PROGRESS_INDICATOR,       2,  4, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00106                         { Q931ie_DISPLAY,                  2, 34, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00107                         { Q931ie_DATETIME,                 5,  8, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00108                         { Q931ie_SIGNAL,                   2,  3, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00109                         { Q931ie_LOW_LAYER_COMPATIBILITY,  2, 18, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00110                         { Q931ie_HIGH_LAYER_COMPATIBILITY, 2,  5, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00111 
00112                         { Q931ie_CONNECTED_NUMBER,         4, 24, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00113 /* Q.951.5 */           { Q931ie_CONNECTED_SUBADDRESS,     2, 23, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00114 
00115                         { Q932ie_FACILITY,                 2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00116                         { Q932ie_EXTENDED_FACILITY,        2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00117 
00118 /* Q.952 */
00119                         { Q931ie_REDIRECTION_NUMBER,       2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00120 
00121                         { 0, 0, 0, 0 },
00122         }},
00123 
00124         /* CONNECT ACKNOWLEDGE */
00125         { Q931mes_CONNECT_ACKNOWLEDGE, 8, "CONNECT ACKNOWLEDGE", {
00126                         { Q931ie_DISPLAY,           2, 34, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00127                         { Q931ie_SIGNAL,            2,  3, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00128 
00129                         { Q932ie_FACILITY,          2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00130                         { Q932ie_EXTENDED_FACILITY, 2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00131 
00132                         { 0, 0, 0, 0 },
00133         }},
00134 
00135         /* DISCONNECT */
00136         { Q931mes_DISCONNECT, 8, "DISCONNECT", {
00137                         { Q931ie_CAUSE,              4, 32, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH | Q931_IEF_MANDATORY },
00138                         { Q931ie_PROGRESS_INDICATOR, 2,  4, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00139                         { Q931ie_DISPLAY,            2, 34, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00140                         { Q931ie_SIGNAL,             2,  3, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00141 
00142                         { Q932ie_FACILITY,           2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00143                         { Q932ie_EXTENDED_FACILITY,  2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00144 
00145                         { 0, 0, 0, 0 },
00146         }},
00147 
00148         /* INFORMATION */
00149         { Q931mes_INFORMATION, 8, "INFORMATION", {
00150                         { Q931ie_SENDING_COMPLETE,    1,  1, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00151                         { Q931ie_DISPLAY,             2, 34, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00152                         { Q931ie_KEYPAD_FACILITY,     2, 34, Q931_IE_CODESET_0, Q931_IEF_TO_NET },
00153                         { Q931ie_SIGNAL,              2,  3, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00154                         { Q931ie_CALLED_PARTY_NUMBER, 2, 34, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00155                         { 0, 0, 0, 0 },
00156         }},
00157 
00158         /* NOTIFY */
00159         { Q931mes_NOTIFY, 8, "NOTIFY", {
00160                         { Q931ie_BEARER_CAPABILITY,      2, 12, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00161                         { Q931ie_NOTIFICATION_INDICATOR, 3,  3, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH | Q931_IEF_MANDATORY },
00162                         { Q931ie_DISPLAY,                2, 34, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00163 
00164 /* Q.952 */
00165                         { Q931ie_REDIRECTION_NUMBER,       2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00166 
00167                         { 0, 0, 0, 0 },
00168         }},
00169 
00170         /* PROGRESS */
00171         { Q931mes_PROGRESS, 8, "PROGRESS", {
00172                         { Q931ie_BEARER_CAPABILITY,        4, 12, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00173                         { Q931ie_CAUSE,                    4, 32, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00174                         { Q931ie_PROGRESS_INDICATOR,       2,  4, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH | Q931_IEF_MANDATORY },
00175                         { Q931ie_DISPLAY,                  2, 34, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00176                         { Q931ie_HIGH_LAYER_COMPATIBILITY, 2,  5, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00177 
00178                         { Q932ie_FACILITY,                 2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00179                         { Q932ie_EXTENDED_FACILITY,        2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00180 
00181 /* Q.952 */
00182                         { Q931ie_REDIRECTION_NUMBER,       2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00183 
00184                         { 0, 0, 0, 0 },
00185         }},
00186 
00187         /* RELEASE */
00188         { Q931mes_RELEASE, 8, "RELEASE", {
00189                         { Q931ie_CAUSE,             4, 32, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00190                         { Q931ie_DISPLAY,           2, 34, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00191                         { Q931ie_SIGNAL,            2,  3, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00192 
00193                         { Q932ie_FACILITY,          2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00194                         { Q932ie_EXTENDED_FACILITY, 2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00195 
00196                         { 0, 0, 0, 0 },
00197         }},
00198 
00199         /* RELEASE COMPLETE */
00200         { Q931mes_RELEASE_COMPLETE, 8, "RELEASE COMPLETE", {
00201                         { Q931ie_CAUSE,             4, 32, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00202                         { Q931ie_DISPLAY,           2, 34, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00203                         { Q931ie_SIGNAL,            2,  3, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00204 
00205                         { Q932ie_FACILITY,          2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00206                         { Q932ie_EXTENDED_FACILITY, 2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00207 
00208                         { 0, 0, 0, 0 },
00209         }},
00210 
00211         /* RESUME */
00212         { Q931mes_RESUME, 8, "RESUME", {
00213                         { Q931ie_CALL_IDENTITY, 2, 10, Q931_IE_CODESET_0, Q931_IEF_TO_NET },
00214                         { 0, 0, 0, 0 },
00215         }},
00216 
00217         /* RESUME ACKNOWLEDGE */
00218         { Q931mes_RESUME_ACKNOWLEDGE, 8, "RESUME ACKNOWLEDGE", {
00219                         { Q931ie_CHANNEL_IDENTIFICATION, 3,  0, Q931_IE_CODESET_0, Q931_IEF_TO_USER | Q931_IEF_MANDATORY },
00220                         { Q931ie_DISPLAY,                2, 34, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00221                         { 0, 0, 0, 0 },
00222         }},
00223 
00224         /* RESUME REJECT */
00225         { Q931mes_RESUME_REJECT, 8, "RESUME REJECT", {
00226                         { Q931ie_CAUSE,    4, 32, Q931_IE_CODESET_0, Q931_IEF_TO_USER | Q931_IEF_MANDATORY },
00227                         { Q931ie_DISPLAY,  4, 34, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00228                         { 0, 0, 0, 0 },
00229         }},
00230 
00231         /* SETUP */
00232         { Q931mes_SETUP, 8, "SETUP", {
00233                         { Q931ie_SENDING_COMPLETE,            1,  1, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00234                         { Q931ie_REPEAT_INDICATOR,            1,  1, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },             /* Multiple occurrences possible, context! */
00235                         { Q931ie_BEARER_CAPABILITY,           4, 12, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH | Q931_IEF_MANDATORY },
00236                         { Q931ie_CHANNEL_IDENTIFICATION,      3,  0, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00237                         { Q931ie_PROGRESS_INDICATOR,          2,  4, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00238                         { Q931ie_NETWORK_SPECIFIC_FACILITIES, 2,  0, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00239                         { Q931ie_DISPLAY,                     2, 34, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00240                         { Q931ie_DATETIME,                    5,  8, Q931_IE_CODESET_0, Q931_IEF_TO_NET },
00241                         { Q931ie_KEYPAD_FACILITY,             2, 34, Q931_IE_CODESET_0, Q931_IEF_TO_NET },
00242                         { Q931ie_SIGNAL,                      2,  3, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00243                         { Q931ie_CALLING_PARTY_NUMBER,        2, 34, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00244                         { Q931ie_CALLING_PARTY_SUBADDRESS,    2, 23, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00245                         { Q931ie_CALLED_PARTY_NUMBER,         2, 34, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00246                         { Q931ie_CALLED_PARTY_SUBADDRESS,     2, 23, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00247                         { Q931ie_TRANSIT_NETWORK_SELECTION,   2, 34, Q931_IE_CODESET_0, Q931_IEF_TO_NET },
00248                         { Q931ie_LOW_LAYER_COMPATIBILITY,     2, 18, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00249                         { Q931ie_HIGH_LAYER_COMPATIBILITY,    2,  5, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00250 
00251                         { Q932ie_FACILITY,                    2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00252                         { Q932ie_EXTENDED_FACILITY,           2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00253 
00254 /* Q.952 */
00255                         { Q931ie_REDIRECTING_NUMBER,          2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00256 
00257                         { 0, 0, 0, 0 },
00258         }},
00259 
00260         /* SETUP ACKNOWLEDGE */
00261         { Q931mes_SETUP_ACKNOWLEDGE, 8, "SETUP ACKNOWLEDGE", {
00262                         { Q931ie_CHANNEL_IDENTIFICATION, 3,  0, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00263                         { Q931ie_PROGRESS_INDICATOR,     2,  4, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00264                         { Q931ie_DISPLAY,                2, 34, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00265                         { Q931ie_SIGNAL,                 2,  3, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00266 
00267                         { Q932ie_FACILITY,               2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00268                         { Q932ie_EXTENDED_FACILITY,      2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00269 
00270                         { 0, 0, 0, 0 },
00271         }},
00272 
00273         /* STATUS */
00274         { Q931mes_STATUS, 8, "STATUS", {
00275                         { Q931ie_CAUSE,      4, 32, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH | Q931_IEF_MANDATORY },
00276                         { Q931ie_CALL_STATE, 3,  3, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH | Q931_IEF_MANDATORY },
00277                         { Q931ie_DISPLAY,    2, 34, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00278                         { 0, 0, 0, 0 },
00279         }},
00280 
00281         /* STATUS ENQUIRY */
00282         { Q931mes_STATUS_ENQUIRY, 8, "STATUS ENQUIRY", {
00283                         { Q931ie_DISPLAY, 2, 34, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00284                         { 0, 0, 0, 0 },
00285         }},
00286 
00287         /* SUSPEND */
00288         { Q931mes_SUSPEND, 8, "SUSPEND", {
00289                         { Q931ie_CALL_IDENTITY, 2, 10, Q931_IE_CODESET_0, Q931_IEF_TO_NET },
00290                         { 0, 0, 0, 0 },
00291         }},
00292 
00293         /* SUSPEND ACKNOWLEDGE */
00294         { Q931mes_SUSPEND_ACKNOWLEDGE, 8, "SUSPEND ACKNOWLEDGE", {
00295                         { Q931ie_DISPLAY, 2, 34, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00296                         { 0, 0, 0, 0 },
00297         }},
00298 
00299         /* SUSPEND REJECT */
00300         { Q931mes_SUSPEND_REJECT, 8, "SUSPEND REJECT", {
00301                         { Q931ie_CAUSE,   4, 32, Q931_IE_CODESET_0, Q931_IEF_TO_USER | Q931_IEF_MANDATORY },
00302                         { Q931ie_DISPLAY, 4, 34, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00303                         { 0, 0, 0, 0 },
00304         }},
00305 
00306         /* RESTART */
00307         { Q931mes_RESTART, 8, "RESTART", {
00308                         { Q931ie_RESTART_INDICATOR,      3,  3, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH | Q931_IEF_MANDATORY },
00309                         { Q931ie_CHANNEL_IDENTIFICATION, 3,  0, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00310                         { Q931ie_DISPLAY,                4, 34, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00311                         { 0, 0, 0, 0 },
00312         }},
00313 
00314         /* RESTART ACKNOWLEDGE */
00315         { Q931mes_RESTART_ACKNOWLEDGE, 8, "RESTART ACKNOWLEDGE", {
00316                         { Q931ie_RESTART_INDICATOR,      3,  3, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH | Q931_IEF_MANDATORY },
00317                         { Q931ie_CHANNEL_IDENTIFICATION, 3,  0, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00318                         { Q931ie_DISPLAY,                4, 34, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00319                         { 0, 0, 0, 0 },
00320         }},
00321 
00322 
00323         /*
00324          * ITU-T Q.932 IE table
00325          */
00326 
00327         /* HOLD */
00328         { Q932mes_HOLD, 8, "HOLD", {
00329                         { Q931ie_DISPLAY,           2, 34, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00330 
00331                         { Q932ie_FACILITY,          2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00332                         { Q932ie_EXTENDED_FACILITY, 2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00333                         { 0, 0, 0, 0 },
00334         }},
00335 
00336         /* HOLD ACKNOWLEDGE */
00337         { Q932mes_HOLD_ACKNOWLEDGE, 8, "HOLD ACKNOWLEDGE", {
00338                         { Q931ie_DISPLAY,           2, 34, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00339 
00340                         { Q932ie_FACILITY,          2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00341                         { Q932ie_EXTENDED_FACILITY, 2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00342                         { 0, 0, 0, 0 },
00343         }},
00344 
00345         /* HOLD REJECT */
00346         { Q932mes_HOLD_REJECT, 8, "HOLD REJECT", {
00347                         { Q931ie_CAUSE,             4, 32, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH | Q931_IEF_MANDATORY },
00348                         { Q931ie_DISPLAY,           2, 34, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00349 
00350                         { Q932ie_FACILITY,          2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00351                         { Q932ie_EXTENDED_FACILITY, 2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00352                         { 0, 0, 0, 0 },
00353         }},
00354 
00355         /* REGISTER */
00356         { Q932mes_REGISTER, 8, "REGISTER", {
00357                         { Q932ie_FACILITY,          2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH | Q931_IEF_MANDATORY },
00358                         { Q932ie_EXTENDED_FACILITY, 2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00359                         { Q931ie_DISPLAY,           2, 34, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00360 
00361                         { 0, 0, 0, 0 },
00362         }},
00363 
00364         /* RETRIEVE */
00365         { Q932mes_RETRIEVE, 8, "RETRIEVE", {
00366                         { Q931ie_CHANNEL_IDENTIFICATION, 3,  0, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00367                         { Q931ie_DISPLAY,                2, 34, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00368 
00369                         { Q932ie_FACILITY,               2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00370                         { Q932ie_EXTENDED_FACILITY,      2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00371                         { 0, 0, 0, 0 },
00372         }},
00373 
00374         /* RETRIEVE ACKNOWLEDGE */
00375         { Q932mes_RETRIEVE_ACKNOWLEDGE, 8, "RETRIEVE ACKNOWLEDGE", {
00376                         { Q931ie_CHANNEL_IDENTIFICATION, 3,  0, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00377                         { Q931ie_DISPLAY,                2, 34, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00378 
00379                         { Q932ie_FACILITY,               2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00380                         { Q932ie_EXTENDED_FACILITY,      2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00381                         { 0, 0, 0, 0 },
00382         }},
00383 
00384         /* RETRIEVE REJECT */
00385         { Q932mes_RETRIEVE_REJECT, 8, "RETRIEVE REJECT", {
00386                         { Q931ie_CAUSE,             4, 32, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH | Q931_IEF_MANDATORY },
00387                         { Q931ie_DISPLAY,           2, 34, Q931_IE_CODESET_0, Q931_IEF_TO_USER },
00388 
00389                         { Q932ie_FACILITY,          2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00390                         { Q932ie_EXTENDED_FACILITY, 2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00391                         { 0, 0, 0, 0 },
00392         }},
00393 
00394         /* FACILITY */
00395         { Q932mes_FACILITY, 8, "FACILITY", {
00396                         { Q932ie_FACILITY,          8, 99, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH | Q931_IEF_MANDATORY },
00397                         { Q932ie_EXTENDED_FACILITY, 2, 99, Q931_IE_CODESET_0, Q931_IEF_TO_BOTH },
00398                         { 0, 0, 0, 0 },
00399         }},
00400 
00401         /* TODO... */
00402         { 0, 0, 0, {{ 0, 0, 0, 0 }}},
00403 };
00404 
00414 static const struct Q931MessageIEEntry *Q931MesgIEsGetEntry(struct Q931Dialect *dialect, L3INT MesType, L3UCHAR ProtDisc, L3UCHAR id, L3UCHAR *index)
00415 {
00416         const struct Q931MessageIE *mes = NULL;
00417         const struct Q931MessageIE *map = NULL;
00418         const struct Q931MessageIEEntry *ie;
00419         int i, offset = 0;
00420 
00421         assert(dialect);
00422 
00423         map = Q931DialectGetMesIEMap(dialect);
00424         if (!map) {
00425                 return NULL;
00426         }
00427 
00428         if (index) {
00429                 offset = *index;
00430         }
00431 
00432         for (i = offset; map[i].id; i++) {
00433                 if(map[i].id == MesType && map[i].protdisc == ProtDisc) {
00434                         mes = &map[i];
00435                         break;
00436                 }
00437         }
00438         if (!mes) {
00439                 /* Message not found */
00440                 return NULL;
00441         }
00442 
00443         if (index) {
00444                 *index = i;
00445         }
00446 
00447         ie = mes->ies;
00448         while (ie->id) {
00449                 if (ie->id == id) {
00450                         return ie;
00451                 }
00452                 ie++;
00453         }
00454         return NULL;
00455 }
00456 
00464 static const struct Q931MessageIEEntry *Q931MesgIEsGetFirstEntry(struct Q931Dialect *dialect, L3INT MesType, L3UCHAR ProtDisc)
00465 {
00466         struct Q931MessageIE *map = NULL;
00467 
00468         assert(dialect);
00469 
00470         map = Q931DialectGetMesIEMap(dialect);
00471         if (!map) {
00472                 return NULL;
00473         }
00474 
00475         while (map->id) {
00476                 if(map->id == MesType && map->protdisc == ProtDisc)
00477                         break;
00478                 map++;
00479         }
00480         if (!map->id) {
00481                 /* Message not found */
00482                 return NULL;
00483         }
00484         return map->ies;
00485 }
00486 
00497 static L3INT Q931MesgIEsGetMandatory(struct Q931Dialect *dialect, L3INT MesType, L3UCHAR ProtDisc, L3UCHAR *list, L3INT size)
00498 {
00499         const struct Q931MessageIE *map = NULL;
00500         const struct Q931MessageIEEntry *ie;
00501         int i = 0;
00502 
00503         assert(dialect);
00504 
00505         map = Q931DialectGetMesIEMap(dialect);
00506         if (!map) {
00507                 return -1;
00508         }
00509 
00510         while (map->id) {
00511                 if(map->id == MesType && map->protdisc == ProtDisc)
00512                         break;
00513                 map++;
00514         }
00515         if (!map->id) {
00516                 /* Message not found */
00517                 return -1;
00518         }
00519 
00520         ie = map->ies;
00521         while (ie->id) {
00522                 if (ie->flags & Q931_IEF_MANDATORY) {
00523                         if (i >= size) {
00524                                 return -1;
00525                         }
00526                         list[i++] = ie->id;
00527                 }
00528                 ie++;
00529         }
00530         return i;
00531 }
00532 
00540 static L3INT Q931MesgIEsMandatoryMissing(L3UCHAR *list, L3INT size)
00541 {
00542         int count = 0;
00543         int i;
00544 
00545         for (i = 0; i < size; i++) {
00546                 if (list[i]) {
00547                         count++;
00548                 }
00549         }
00550         return count;
00551 }
00552 
00560 static void Q931MesgIEsMandatoryClear(L3UCHAR *list, L3INT size, L3UCHAR id)
00561 {
00562         int i;
00563 
00564         for (i = 0; i < size; i++) {
00565                 if (list[i] == id) {
00566                         list[i] = 0;
00567                         return;
00568                 }
00569         }
00570 }
00571 
00580 static L3BOOL Q931MesgIEIsDirectionValid(const struct Q931MessageIEEntry *ie, const L3INT mode, const L3BOOL outgoing)
00581 {
00582         L3INT flags = Q931_IEF_NONE;
00583 
00584         if (mode == Q931_NT) {
00585                 flags |= (outgoing) ? Q931_IEF_TO_USER : Q931_IEF_TO_NET;
00586         } else {
00587                 flags |= (outgoing) ? Q931_IEF_TO_NET : Q931_IEF_TO_USER;
00588         }
00589 
00590         if (!(ie->flags & flags)) {     /* IE not allowed in this direction */
00591                 return L3FALSE;
00592         }
00593         return L3TRUE;
00594 }
00595 
00603 static L3BOOL Q931MesgIEIsCodesetValid(const struct Q931MessageIEEntry *ie, const L3INT codeset)
00604 {
00605         L3INT flags = Q931_IE_CODESET_0;
00606 
00607         /* only check if any codesets have been specified at all */
00608         if (ie->codeset & Q931_IE_CODESET_ALL) {
00609                 flags <<= codeset;
00610 
00611                 if (!(ie->codeset & flags)) {   /* IE not allowed in this codeset */
00612                         return L3FALSE;
00613                 }
00614         }
00615         return L3TRUE;
00616 }
00617 
00624 static L3UCHAR Q931MesgIEGetCodeset(const struct Q931MessageIEEntry *ie)
00625 {
00626         L3INT mask = Q931_IE_CODESET_0;
00627         L3UCHAR codeset = 0;
00628 
00629         while (mask <= Q931_IE_CODESET_7) {
00630                 if (ie->codeset & mask) {
00631                         return codeset;
00632                 }
00633 
00634                 mask <<= 1;
00635                 codeset++;
00636         }
00637         return 0;
00638 }
00639 
00647 static L3BOOL Q931MesgIEIsSizeValid(const struct Q931MessageIEEntry *ie, L3UCHAR size)
00648 {
00649         if (ie->id & 0x80) {    /* Fixed size IE */
00650                 return (L3BOOL)(size == 1);
00651         }
00652         if (!ie->maxsize) {
00653                 return (L3BOOL)(size >= ie->minsize);
00654         }
00655         return (L3BOOL)(size >= ie->minsize && size <= ie->maxsize);
00656 }
00657 
00664 static L3BOOL Q931MesgIEIsMandatory(const struct Q931MessageIEEntry *ie)
00665 {
00666         return (L3BOOL)((ie->flags & Q931_IEF_MANDATORY) != 0);
00667 }
00668 
00677 static const char *Q931MesgGetName(struct Q931Dialect *dialect, const L3INT MesType, const L3INT ProtDisc)
00678 {
00679         const struct Q931MessageIE *map = NULL;
00680 
00681         assert(dialect);
00682 
00683         map = Q931DialectGetMesIEMap(dialect);
00684         if (!map) {
00685                 return NULL;
00686         }
00687 
00688         for (int i = 0; map[i].id; i++) {
00689                 if (map[i].id == MesType && map[i].protdisc == ProtDisc)
00690                         return map[i].name;
00691         }
00692         return NULL;
00693 }
00694 
00699 L3INT Q931MesgHeader(Q931_TrunkInfo_t *trunk, Q931mes_Generic *mes, L3UCHAR *OBuf, L3INT Size, L3INT *IOff)
00700 {
00701         L3INT Octet = *IOff;
00702 
00703         Q931Log(trunk, Q931_LOG_DEBUG, "Creating Q.931 Message Header:\n    ProtDisc %d (%#x), CRV %d (%#x), CRVflag: %d (%#x), MesType: %d (%#x)\n",
00704                          mes->ProtDisc, mes->ProtDisc, mes->CRV, mes->CRV, mes->CRVFlag, mes->CRVFlag, mes->MesType, mes->MesType);
00705 
00706         OBuf[Octet++] = mes->ProtDisc;                          /* Protocol discriminator */
00707         if (!Q931_IS_BRI(trunk)) {
00708                 OBuf[Octet++] = 2;                                                                      /* length is 2 octets */
00709                 OBuf[Octet++] = (L3UCHAR)((mes->CRV >> 8) & 0x7f) | ((mes->CRVFlag << 7) & 0x80);       /* msb */
00710                 OBuf[Octet++] = (L3UCHAR) (mes->CRV & 0xff);                                            /* lsb */
00711         } else {
00712                 OBuf[Octet++] = 1;                                                                      /* length is 1 octet */
00713                 OBuf[Octet++] = (L3UCHAR) (mes->CRV & 0x7f) | ((mes->CRVFlag << 7) & 0x80);             /* CRV & flag */
00714         }
00715         OBuf[Octet++] = mes->MesType;                           /* message header */
00716 
00717         *IOff = Octet;
00718         return 0;
00719 }
00720 
00721 /*****************************************************************************
00722  *
00723  * Muahahaha, a generic Q931Umes implementation!!!
00724  *
00725  *****************************************************************************/
00726 
00739 L3INT Q931Umes_Generic(Q931_TrunkInfo_t *trunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size, struct Q931MesgErrors *Errs)
00740 {
00741         L3INT ir = 0;
00742         L3INT OOff = 0;
00743         L3INT rc = Q931E_NO_ERROR;
00744         L3UCHAR last_codeset = 0, codeset = 0;
00745         L3UCHAR shift_nolock = 1;
00746         L3UCHAR mandatoryIEs[Q931MAXIE];
00747         L3UCHAR msgidx = 0;
00748         L3INT   mandsize = 0, missing_count;
00749 
00750         if (!mes->MesType) {
00751                 Q931Log(trunk, Q931_LOG_ERROR, "Nationally specified message types not supported\n");
00752                 return Q931E_UNEXPECTED_MESSAGE;
00753         }
00754 
00755         memset(mandatoryIEs, 0, sizeof(mandatoryIEs));
00756 
00757         mandsize = Q931MesgIEsGetMandatory(trunk->Dialect, mes->MesType, mes->ProtDisc, mandatoryIEs, sizeof(mandatoryIEs));
00758         if (mandsize < 0) {
00759                 Q931Log(trunk, Q931_LOG_DEBUG, "Unable to load mandatory IEs for message\n");
00760                 return Q931E_UNKNOWN_MESSAGE;   /* this one ok?? */
00761         }
00762 
00763         /* TODO: handle codeset shifts (more) correctly */
00764         /* TODO: improve error handling... */
00765 
00766         while (IOff < Size) {
00767                 const struct Q931MessageIEEntry *entry;
00768                 L3UCHAR id, size;
00769 
00770                 /* Codeset shift */
00771                 if ((IBuf[IOff] & 0xf0) == Q931ie_SHIFT) {
00772                         shift_nolock = (IBuf[IOff] & 0x08);
00773                         if (shift_nolock) {
00774                                 last_codeset = codeset;
00775                         }
00776                         codeset = (IBuf[IOff++] & 0x07);
00777 #ifdef __TODO__
00778                         /* TODO: Check if target codeset is valid */
00779                         if (!Q931MesgCodesetIsValid(trunk, codeset)) {
00780                                 Q931Log(trunk, Q931_LOG_ERROR, "Shift to invalid codeset %d\n", codeset);
00781                                 Q931MesgErrorsAddIE(Errs, Q931ie_SHIFT, 1, IOff, Q931_MSGE_INVALID_CODESET);
00782                         }
00783 #endif
00784                         continue;
00785                 }
00786 
00787                 /* Grab IE */
00788                 id = IBuf[IOff];
00789 
00790                 if (!(id & 0x80)) {
00791                         /* Variable size IE, get length */
00792                         size = IBuf[IOff + 1] + 2;      /* header + body */
00793                 } else {
00794                         /* Single octet IE */
00795                         size = 1;
00796                 }
00797 
00798                 /* IE supported? */
00799                 if (Q931UieIsNull(trunk, id)) {
00800                         /* congrats, no idea how to cope with this */
00801                         Q931Log(trunk, Q931_LOG_DEBUG, "Unhandled IE %02u (%#02x)\n", id, id);
00802                         Q931MesgErrorsAddIE(Errs, id, size, IOff, Q931_MSGE_UNKNOWN);
00803 
00804                         if (Q931TrunkIsSetFlag(trunk, Q931_TFLAG_IGNORE_UNKNOWN_IE)) {
00805                                 IOff += size;   /* "consume" IE */
00806                                 goto skip;
00807                         } else {
00808                                 return Q931E_UNKNOWN_IE;
00809                         }
00810                 }
00811 
00812                 /* Lookup IE in table and perform checks */
00813                 entry = Q931MesgIEsGetEntry(trunk->Dialect, mes->MesType, mes->ProtDisc, id, &msgidx);
00814                 if (!entry) {
00815                         /* aww, not found */
00816                         Q931Log(trunk, Q931_LOG_DEBUG, "IE %02u (%#02x) not allowed for message type\n", id, id);
00817                         Q931MesgErrorsAddIE(Errs, id, size, IOff, Q931_MSGE_NOT_ALLOWED);
00818 
00819                         if (Q931TrunkIsSetFlag(trunk, Q931_TFLAG_IGNORE_ILLEGAL_IE)) {
00820                                 IOff += size;   /* "consume" IE */
00821                                 goto skip;
00822                         } else {
00823                                 return Q931E_ILLEGAL_IE;
00824                         }
00825                 }
00826 
00827                 if (!Q931MesgIEIsDirectionValid(entry, trunk->NetUser, 0)) {
00828                         /* oops, we shouldn't be getting this ie from our peer in this mode of operation */
00829                         Q931Log(trunk, Q931_LOG_DEBUG, "IE %02u (%#02x) in wrong direction (flags: 0x%x, mode: %d, incoming)\n", id, id, entry->flags, trunk->NetUser);
00830                         Q931MesgErrorsAddIE(Errs, id, size, IOff, Q931_MSGE_INVALID_DIRECTION);
00831                         return Q931E_ILLEGAL_IE;
00832                 }
00833 
00834                 if (size > (Size - IOff)) {
00835                         /* Overflow, IE larger than bytes in buffer */
00836                         Q931Log(trunk, Q931_LOG_DEBUG, "IE %02u (%#02x) not enough bytes left\n", id, id);
00837                         Q931MesgErrorsAddIE(Errs, id, size, IOff, Q931_MSGE_OVERFLOW);
00838                         return Q931E_ILLEGAL_IE;
00839                 }
00840 
00841                 if (!Q931MesgIEIsSizeValid(entry, size)) {
00842                         /* oops, IE is too large or short */
00843                         Q931Log(trunk, Q931_LOG_DEBUG, "IE %02u (%#02x) size error [%02u octets]\n", id, id, size);
00844                         Q931MesgErrorsAddIE(Errs, id, size, IOff, Q931_MSGE_INVALID_SIZE);
00845                         return Q931E_ILLEGAL_IE;        /* meh, s*cks */
00846                 }
00847 
00848                 if (!Q931MesgIEIsCodesetValid(entry, codeset)) {
00849                         /* arrrr, IE is not allowed in this codest */
00850                         Q931Log(trunk, Q931_LOG_DEBUG, "IE %02u (%#02x) not allowed in codeset %d\n", id, id, codeset);
00851                         Q931MesgErrorsAddIE(Errs, id, size, IOff, Q931_MSGE_INVALID_CODESET);
00852                         return Q931E_ILLEGAL_IE;
00853                 }
00854 
00855                 switch (id) {
00856                 case Q931ie_REPEAT_INDICATOR:   /* TODO: handle this one better... */
00857                         if (ir < 2) {
00858                                 rc = Q931Uie(trunk, id, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
00859                                 ir++;
00860                         } else {
00861                                 Q931MesgErrorsAddIE(Errs, id, size, IOff, Q931_MSGE_NOT_ALLOWED);
00862                                 return Q931E_ILLEGAL_IE;
00863                         }
00864                         break;
00865                 default:
00866                         rc = Q931Uie(trunk, id, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
00867                         if (rc != Q931E_NO_ERROR)
00868                                 return rc;
00869                         break;
00870                 }
00871 
00872                 /* Remove mandatory IE from list, if we've found one */
00873                 if (Q931MesgIEIsMandatory(entry)) {
00874                         Q931MesgIEsMandatoryClear(mandatoryIEs, mandsize, id);
00875                 }
00876 
00877                 /* increate message's ie counter */
00878                 mes->nr_ie++;
00879 skip:
00880                 /* drop back to old codeset!? */
00881                 if (shift_nolock) {
00882                         codeset = last_codeset;
00883                 }
00884         }
00885 
00886         if ((missing_count = Q931MesgIEsMandatoryMissing(mandatoryIEs, mandsize)) > 0) {
00887                 L3INT i = 0;
00888 
00889                 /* tadaa, at least one of the mandatory IEs is missing */
00890                 Q931Log(trunk, Q931_LOG_ERROR, "%d Mandatory IEs missing in this incoming message\n", missing_count);
00891 
00892                 /* Add missing mandatory IEs to error report */
00893                 for (i = 0; i < mandsize; i++) {
00894                         if (mandatoryIEs[i]) {
00895                                 Q931MesgErrorsAddIE(Errs, mandatoryIEs[i], 0, 0, Q931_MSGE_MANDATORY_MISSING);
00896                         }
00897                 }
00898                 return Q931E_MANDATORY_IE_MISSING;
00899         }
00900 
00901         mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
00902 
00903         /* */
00904         Q931Dmes_Generic(trunk, mes, Q931_MSG_INCOMING);
00905 
00906         return Q931E_NO_ERROR;
00907 }
00908 
00909 #include "utils/strstream.h"
00910 
00918 L3INT Q931Dmes_Generic(Q931_TrunkInfo_t *trunk, Q931mes_Generic *msg, q931_msg_direction_t direction)
00919 {
00920         L3INT ret = Q931E_NO_ERROR;
00921         L3INT offset = 0;
00922         struct strstream stream;
00923         char buf[STRSTREAM_SIZE];
00924         const char *name = NULL;
00925 
00926         if (trunk->loglevel != Q931_LOG_DEBUG)
00927                 return Q931E_NO_ERROR;
00928 
00929         strstream_init_static(&stream, buf, sizeof(buf));
00930 
00931         name = Q931MesgGetName(trunk->Dialect, msg->MesType, msg->ProtDisc);
00932         if (!name) {
00933                 name = "UNKNOWN MESSAGE";
00934         }
00935 
00936         strstream_puts(&stream, "\n----\n");
00937 
00938         /* print message header */
00939         strstream_printf(&stream,
00940                         "%s\n"
00941                         "\tMessage-ID:  0x%02x\n"
00942                         "\tDirection:   %s\n"
00943                         "\tCall Ref:    0x%04x (%s)\n"
00944                         "\tL2 Link ID:  %u\n",
00945                         name, msg->MesType, ((direction == Q931_MSG_INCOMING) ? "Incoming" : "Outgoing"),
00946                         msg->CRV, (msg->CRVFlag ? "Terminator" : "Originator"), msg->Tei);
00947 
00948         strstream_puts(&stream, "\t---------------------\n");
00949 
00950         /* print IE information */
00951         while (offset < msg->Size && ret == Q931E_NO_ERROR) {
00952                 Q931ie_Generic *ie = (Q931ie_Generic *)&msg->buf[offset];
00953 
00954                 if (!ie->IEId && !ie->Size)
00955                         break;
00956 
00957                 if (!(ie->IEId & 0x80) && ie->Size)
00958                         offset += ie->Size;
00959                 else
00960                         offset += sizeof(*ie);
00961 
00962                 /* IE supported? */
00963                 if (Q931DieIsNull(trunk, ie->IEId))
00964                         ret = Q931Die_Generic(trunk, ie, &stream);
00965                 else
00966                         ret = Q931Die(trunk, ie, &stream);
00967         }
00968 
00969         strstream_puts(&stream, "\n----\n");
00970 
00971         /* output final string */
00972         Q931LogRaw(trunk, Q931_LOG_DEBUG, strstream_get(&stream));
00973         return ret;
00974 }
00975 
00976 
00977 /*
00978  * BIG FAT TODO:
00979  *
00980  * Yeah, this _IS_ ugly, but it's needed until we change the way IEs refs are handled in the message
00981  * (or we're going to do a full (= slow) lookup in the buffer...)
00982  *
00983  */
00984 static Q931ie_Generic * Q931MesgGetIE(Q931_TrunkInfo_t *trunk, Q931mes_Generic *mes, L3UCHAR id)
00985 {
00986         ie ie = 0;
00987 
00988         switch (id) {
00989         case Q931ie_SENDING_COMPLETE:
00990                 ie = mes->SendComplete;
00991                 break;
00992         case Q931ie_REPEAT_INDICATOR:
00993                 ie = mes->RepeatInd;
00994                 break;
00995         case Q931ie_BEARER_CAPABILITY:
00996                 ie = mes->BearerCap;
00997                 break;
00998         case Q931ie_CHANNEL_IDENTIFICATION:
00999                 ie = mes->ChanID;
01000                 break;
01001         case Q931ie_NETWORK_SPECIFIC_FACILITIES:
01002                 ie = mes->NetFac;
01003                 break;
01004         case Q931ie_DISPLAY:
01005                 ie = mes->Display;
01006                 break;
01007         case Q931ie_DATETIME:
01008                 ie = mes->DateTime;
01009                 break;
01010         case Q931ie_KEYPAD_FACILITY:
01011                 ie = mes->KeypadFac;
01012                 break;
01013         case Q931ie_SIGNAL:
01014                 ie = mes->Signal;
01015                 break;
01016         case Q931ie_CALLING_PARTY_NUMBER:
01017                 ie = mes->CallingNum;
01018                 break;
01019         case Q931ie_CALLING_PARTY_SUBADDRESS:
01020                 ie = mes->CallingSub;
01021                 break;
01022         case Q931ie_CALLED_PARTY_NUMBER:
01023                 ie = mes->CalledNum;
01024                 break;
01025         case Q931ie_CALLED_PARTY_SUBADDRESS:
01026                 ie = mes->CalledSub;
01027                 break;
01028         case Q931ie_TRANSIT_NETWORK_SELECTION:
01029                 ie = mes->TransNetSel;
01030                 break;
01031         case Q931ie_LOW_LAYER_COMPATIBILITY:
01032                 ie = mes->LLComp;
01033                 break;
01034         case Q931ie_HIGH_LAYER_COMPATIBILITY:
01035                 ie = mes->HLComp;
01036                 break;
01037         case Q931ie_PROGRESS_INDICATOR:
01038                 ie = mes->ProgInd;
01039                 break;
01040         case Q931ie_CAUSE:
01041                 ie = mes->Cause;
01042                 break;
01043         case Q931ie_CHANGE_STATUS:
01044                 ie = mes->ChangeStatus;
01045                 break;
01046         case Q931ie_RESTART_INDICATOR:
01047                 ie = mes->RestartInd;
01048                 break;
01049         case Q931ie_CALL_STATE:
01050                 ie = mes->CallState;
01051                 break;
01052         default:
01053                 Q931Log(trunk, Q931_LOG_DEBUG, "Unable to get reference for IE %02u (%#02x)\n", id, id);
01054                 return NULL;
01055         }
01056 
01057         if(Q931IsIEPresent(ie)) {
01058                 return Q931GetIEPtr(ie, mes->buf);
01059         }
01060 
01061         return NULL;
01062 }
01063 
01064 L3INT Q931Pmes_Generic(Q931_TrunkInfo_t *trunk, Q931mes_Generic *msg, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
01065 {
01066         const struct Q931MessageIEEntry *entry;
01067         L3UCHAR mandatoryIEs[Q931MAXIE];
01068         L3UCHAR codeset = 0;
01069         L3INT rc = Q931E_NO_ERROR;
01070         L3INT Octet = 0;
01071         L3INT mandsize = 0, missing_count;
01072 
01073         memset(mandatoryIEs, 0, sizeof(mandatoryIEs));
01074 
01075         /* */
01076         Q931Dmes_Generic(trunk, msg, Q931_MSG_OUTGOING);
01077 
01078         /* Q931 Message Header */
01079         Q931MesgHeader(trunk, msg, OBuf, *OSize, &Octet);
01080 
01081         /* Get mandatory IE list */
01082         mandsize = Q931MesgIEsGetMandatory(trunk->Dialect, msg->MesType, msg->ProtDisc, mandatoryIEs, sizeof(mandatoryIEs));
01083         if (mandsize < 0) {
01084                 Q931Log(trunk, Q931_LOG_DEBUG, "Unable to load mandatory IEs for message\n");
01085                 return Q931E_UNKNOWN_MESSAGE;   /* TODO: this one ok?? */
01086         }
01087 
01088         /* Walk list of allowed IEs */
01089         entry = Q931MesgIEsGetFirstEntry(trunk->Dialect, msg->MesType, msg->ProtDisc);
01090 
01091         while (entry && entry->id) {
01092                 L3UCHAR ie_codeset = 0;
01093                 Q931ie_Generic *pIE;
01094 
01095                 pIE = Q931MesgGetIE(trunk, msg, entry->id);
01096 
01097                 /* Check + encode IE */
01098                 if (pIE) {
01099                         L3INT ieOffset;
01100 
01101                         /* Direction check */
01102                         if (!Q931MesgIEIsDirectionValid(entry, trunk->NetUser, 1)) {
01103                                 /* oops, we shouldn't be getting this ie from our peer in this mode of operation */
01104                                 Q931Log(trunk, Q931_LOG_DEBUG, "IE %02u (%#02x) in wrong direction\n", entry->id, entry->id);
01105                                 return Q931E_ILLEGAL_IE;
01106                         }
01107 
01108                         /* IE supported? */
01109                         if (Q931PieIsNull(trunk, entry->id)) {
01110                                 /* congrats, no idea how to cope with this */
01111                                 Q931Log(trunk, Q931_LOG_DEBUG, "Unhandled IE %u (%#02x)\n", entry->id, entry->id);
01112                                 return Q931E_UNKNOWN_IE;
01113                         }
01114 
01115                         /* Check IEs codeset and change codeset if neccessary (non-locking shift only!) */
01116                         ie_codeset = Q931MesgIEGetCodeset(entry);
01117                         if (ie_codeset != codeset) {
01118 #ifdef __TODO__
01119                                 if (dialect->flags & Q931_DIALECT_LOCKING_SHIFT_ONLY) {
01120                                         /* emit locking shift to target codeset */
01121                                         codeset       = rc;
01122                                         OBuf[Octet++] = Q931ie_SHIFT | (codeset & 0x07);
01123                                 } else {
01124 #endif
01125                                         /* emit non-locking shift to target codeset */
01126                                         OBuf[Octet++] = Q931ie_SHIFT | 0x08 | (rc & 0x07);
01127 #ifdef __TODO__
01128                                 }
01129 #endif
01130                         }
01131 
01132                         /* TODO: repeat indicator? */
01133 
01134                         /* Store current offset in output buffer */
01135                         ieOffset = Octet;
01136 
01137                         /* Encode IE */
01138                         if ((rc = Q931Pie(trunk, entry->id, (L3UCHAR *)pIE, OBuf, &Octet)) != Q931E_NO_ERROR) {
01139                                 return rc;
01140                         }
01141 
01142                         /* Check encoded(!) size */
01143                         if (!Q931MesgIEIsSizeValid(entry, Octet - ieOffset)) {
01144                                 /* oops, IE is too large or short */
01145                                 Q931Log(trunk, Q931_LOG_DEBUG, "IE %02u (%#02x) size error [%d octets]\n", entry->id, entry->id, Octet - ieOffset);
01146                                 return Q931E_ILLEGAL_IE;        /* meh, s*cks */
01147                         }
01148 
01149                         /* Remove mandatory IE from list, if we've found one */
01150                         if (Q931MesgIEIsMandatory(entry)) {
01151                                 Q931MesgIEsMandatoryClear(mandatoryIEs, mandsize, entry->id);
01152                         }
01153                 }
01154 
01155                 entry++;
01156         }
01157 
01158         if ((missing_count = Q931MesgIEsMandatoryMissing(mandatoryIEs, mandsize)) > 0) {
01159                 /* tadaa, at least one of the mandatory IEs is missing */
01160                 Q931Log(trunk, Q931_LOG_ERROR, "%d Mandatory IEs missing in this outgoing message\n", missing_count);
01161 
01162                 return Q931E_MANDATORY_IE_MISSING;
01163         }
01164 
01165         *OSize = Octet;
01166         return rc;
01167 }
01168 
01172 const static struct Q931MesgErrorName {
01173         const char id;
01174         const char *name;
01175         const char *diag;
01176 } Q931MesgErrorNames[] = {
01177         /* Order is important here! */
01178         { Q931_MSGE_NONE,               "None",                      NULL },
01179         { Q931_MSGE_UNKNOWN,            "Unknown/unhandled",         "Message element is unknown (or invalid) and not handled by parser" },
01180         { Q931_MSGE_OVERFLOW,           "Not enough octets left",    "Message element is larger than octets left in buffer" },
01181         { Q931_MSGE_NOT_ALLOWED,        "Not allowed here",          "Message element is not allowed in this state/message" },
01182         { Q931_MSGE_INVALID_DIRECTION,  "Wrong direction",           "Message element is sent to or coming from the wrong direction" },
01183         { Q931_MSGE_INVALID_SIZE,       "Size invalid",              "Message element is either too small or too large" },
01184         { Q931_MSGE_INVALID_CODESET,    "Wrong codeset",             "Message element is in the wrong codeset (wrong dialect?)" },
01185         { Q931_MSGE_MANDATORY_MISSING,  "Mandatory element missing", "A mandatory message element is missing" }
01186 };
01187 
01193 static const char *Q931MesgErrorGetName(const int id)
01194 {
01195         if (id < 0 || id > Q931_MSGE_COUNT)
01196                 return "- Invalid error id -";
01197 
01198         return Q931MesgErrorNames[id].name;
01199 }
01200 
01206 static const char *Q931MesgErrorGetDiagnostic(const int id)
01207 {
01208         if (id < 0 || id > Q931_MSGE_COUNT)
01209                 return NULL;
01210 
01211         return Q931MesgErrorNames[id].diag;
01212 }
01213 
01220 L3INT Q931MesgErrorsInit(struct Q931MesgErrors *merrs, const char id)
01221 {
01222         if (!merrs) {
01223                 return Q931E_NO_ERROR;
01224         }
01225 
01226         memset(merrs, 0, sizeof(struct Q931MesgErrors));
01227         merrs->id = id;
01228         return Q931E_NO_ERROR;
01229 }
01230 
01240 L3INT Q931MesgErrorsAddIE(struct Q931MesgErrors *merrs, const char id, const char size, const int offset, const int error)
01241 {
01242         if (!merrs || !id || !error) {
01243                 return Q931E_NO_ERROR;
01244         }
01245 
01246         if (merrs->nr_errors == Q931_MSGE_ERR_MAX) {
01247                 /* overflow, at least count them */
01248                 merrs->nr_overflow++;
01249                 return Q931E_NO_ERROR;
01250         }
01251 
01252         merrs->ie_errors[merrs->nr_errors].id     = id;
01253         merrs->ie_errors[merrs->nr_errors].size   = size;
01254         merrs->ie_errors[merrs->nr_errors].offset = (offset < UCHAR_MAX) ? offset : UCHAR_MAX;
01255         merrs->ie_errors[merrs->nr_errors].error  = error;
01256         merrs->nr_errors++;
01257         return Q931E_NO_ERROR;
01258 }
01259 
01265 L3INT Q931MesgErrorsCount(struct Q931MesgErrors *merrs)
01266 {
01267         return merrs->nr_errors;
01268 }
01269 
01270 
01271 #define TMP_BUFSIZE     4096
01272 #define TMP_PUTS(fmt) \
01273         strncat(tmp + offset, fmt, sizeof(tmp) - offset - 1); \
01274         offset += strlen(tmp + offset);
01275 #define TMP_APPEND(fmt, args...) \
01276         offset += snprintf(tmp + offset, sizeof(tmp) - offset, fmt, ##args);
01277 
01278 #ifdef HAVE_ALLOCA_H
01279 #include <alloca.h>
01280 #elif defined(PLATFORM_WIN32) || defined(PLATFORM_WIN64)
01281 #include <malloc.h>
01282 #endif
01283 
01284 #ifdef HAVE_ALLOCA
01285 #define TMP_APPEND_HEX(fmt, buf, size)                                          \
01286         do {                                                                    \
01287                 char *__tmp = NULL;                                             \
01288                 static const char hex[16] = { '0', '1', '2', '3', '4', '5',     \
01289                                         '6', '7', '8', '9', 'a', 'b', 'c',      \
01290                                         'e', 'f' };                             \
01291                                                                                 \
01292                 __tmp = alloca((size << 1) + size);                             \
01293                 if (__tmp) {                                                    \
01294                         int off = 0, x = 0;                                     \
01295                                                                                 \
01296                         for (x = 0; x < size; x++) {                            \
01297                                 __tmp[off++] = hex[((buf)[x] & 0xf0) >> 4];     \
01298                                 __tmp[off++] = hex[((buf)[x] & 0x0f)];          \
01299                                 if (x + 1 < size) {                             \
01300                                         __tmp[off++] = ' ';                     \
01301                                 }                                               \
01302                         }                                                       \
01303                         __tmp[off] = '\0';                                      \
01304                         offset += snprintf(tmp + offset, sizeof(tmp) - offset, fmt, __tmp);     \
01305                 }                                                               \
01306         } while (0);
01307 
01308 #endif /* HAVE_ALLOCA */
01309 
01310 #define TMP_MIN(x, y)  \
01311         ((x) < (y)) ? (x) : (y)
01312 
01321 L3INT Q931MesgErrorsPrint(Q931_TrunkInfo_t *trunk, const struct Q931MesgErrors *merrs, const unsigned char *IBuf, const int Size)
01322 {
01323         char tmp[TMP_BUFSIZE] = { 0 };
01324         char last_ie = 0;
01325         char errcnt  = 0;
01326         int  offset  = 0;
01327         int  i;
01328 
01329         if (!trunk || !merrs) {
01330                 return Q931E_NO_ERROR;  /* TODO: which error code here? */
01331         }
01332 
01333         /* skip if not in debug loglevel */
01334         if (trunk->loglevel != Q931_LOG_DEBUG) {
01335                 return Q931E_NO_ERROR;
01336         }
01337 
01338         if (merrs->nr_errors == 0) {
01339                 Q931Log(trunk, Q931_LOG_DEBUG, "Message parser did not report any errors\n");
01340                 return Q931E_NO_ERROR;
01341         }
01342 
01343         /* report header */
01344         TMP_PUTS("Message parser error(s)\n");
01345         TMP_APPEND("=================== Errors reported for message - %3u (%#02x) ===================\n", merrs->id, merrs->id);
01346 
01347         /* detailed report of ie errors */
01348         for (i = 0; i < merrs->nr_errors; i++) {
01349                 const struct Q931MessageIEEntry *entry;
01350                 const char *diag;
01351 
01352                 if (last_ie != merrs->ie_errors[i].id) {
01353                         /* new ie, print header, TODO: add codeset */
01354                         TMP_APPEND("* IE id: %3u (%#02x), name: \"%s\", size: %3u, offset: %3u\n\n",
01355                                 merrs->ie_errors[i].id, merrs->ie_errors[i].id, "N/A",
01356                                 merrs->ie_errors[i].size,
01357                                 merrs->ie_errors[i].offset);
01358 
01359                         /* new ie, update */
01360                         last_ie = merrs->ie_errors[i].id;
01361                         errcnt  = 1;
01362                 }
01363                 TMP_APPEND("  <%02d>  error message: %s\n", errcnt, Q931MesgErrorGetName(merrs->ie_errors[i].error));
01364 
01365                 /* print diagnostic information */
01366                 if ((diag = Q931MesgErrorGetDiagnostic(merrs->ie_errors[i].error))) {
01367                         TMP_APPEND("\tdescription:   %s\n", diag);
01368                 }
01369 
01370                 /*
01371                  * extended diagnostic info
01372                  * NOTE: protocol discriminator hardcoded to "8"!
01373                  */
01374                 TMP_PUTS("\tdetails:       ");
01375                 switch (merrs->ie_errors[i].error) {
01376                 case Q931_MSGE_INVALID_SIZE:
01377                         if ((entry = Q931MesgIEsGetEntry(trunk->Dialect, merrs->id, 8, merrs->ie_errors[i].id, NULL)) != NULL) {
01378                                 if (merrs->id & 0x80) {
01379                                         TMP_PUTS("expected size: 1 octet [fixed size '1xxx xxxx']\n");
01380                                 }
01381                                 else if (entry->minsize == entry->maxsize) {
01382                                         TMP_APPEND("expected size: %d octet(s) [fixed size '0xxx xxxx']\n", entry->minsize);
01383                                 }
01384                                 else if (!entry->maxsize) {
01385                                         TMP_APPEND("expected size: at least %d octet(s)\n", entry->minsize);
01386                                 }
01387                                 else {
01388                                         TMP_APPEND("expected size: %d - %d octet(s)\n", entry->minsize, entry->maxsize);
01389                                 }
01390                         }
01391                         break;
01392 
01393                 case Q931_MSGE_INVALID_CODESET:
01394                         if ((entry = Q931MesgIEsGetEntry(trunk->Dialect, merrs->id, 8, merrs->ie_errors[i].id, NULL)) != NULL) {
01395                                 TMP_APPEND("expected codeset: %d\n", Q931MesgIEGetCodeset(entry));
01396                         }
01397                         break;
01398 
01399                 default:
01400                         TMP_PUTS("N/A\n");
01401                         break;
01402                 }
01403 
01404                 /* last line of this ie? */
01405                 if ((i + 1 == merrs->nr_errors) || (last_ie != merrs->ie_errors[i + 1].id)) {
01406 #ifdef HAVE_ALLOCA
01407                         /*
01408                          * print hex, omit if this is an overflow error
01409                          */
01410                         if (merrs->ie_errors[i].offset) {
01411                                 int length = TMP_MIN((Size - merrs->ie_errors[i].offset), merrs->ie_errors[i].size);
01412 
01413                                 TMP_PUTS("\traw octets:\n");
01414                                 TMP_APPEND_HEX("\t\t[ %s ]\n", IBuf + merrs->ie_errors[i].offset, length);
01415                         }
01416 #endif
01417                         /* IE separating footer? */
01418                         TMP_PUTS("\n");
01419                 }
01420                 errcnt++;
01421         }
01422 
01423         if (merrs->nr_overflow > 0) {
01424                 TMP_APPEND("* %d Additional errors have not been logged\n", merrs->nr_overflow);
01425         }
01426 
01427         /* print report footer */
01428         TMP_APPEND("---------------------------------------------------------------[ %2d error(s) ]--\n", merrs->nr_errors + merrs->nr_overflow);
01429 
01430         Q931Log(trunk, Q931_LOG_ERROR, "%s\n", tmp);
01431         return Q931E_NO_ERROR;
01432 }
01433