libisdn
|
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