1 /*****************************************************************************
2
3 FileName: Q931.c
4
5 Contents: Implementation of Q.931 stack main interface functions.
6 See q931.h for description.
7
8 License/Copyright:
9
10 Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
11 email:janvb@caselaboratories.com
12
13 Redistribution and use in source and binary forms, with or without
14 modification, are permitted provided that the following conditions are
15 met:
16
17 * Redistributions of source code must retain the above copyright notice,
18 this list of conditions and the following disclaimer.
19 * Redistributions in binary form must reproduce the above copyright notice,
20 this list of conditions and the following disclaimer in the documentation
21 and/or other materials provided with the distribution.
22 * Neither the name of the Case Labs, Ltd nor the names of its contributors
23 may be used to endorse or promote products derived from this software
24 without specific prior written permission.
25
26 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
30 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 POSSIBILITY OF SUCH DAMAGE.
37 *****************************************************************************/
38
39 #include "Q921.h"
40 #include "Q931.h"
41 #include "national.h"
42 #include "DMS.h"
43 #include "5ESS.h"
44
45
46 /*****************************************************************************
47
48 Dialect function pointers tables.
49
50 The following function pointer arrays define pack/unpack functions and
51 processing furnctions for the different Q.931 based dialects.
52
53 The arrays are initialized with pointers to dummy functions and later
54 overrided with pointers to actual functions as new dialects are added.
55
56 The initial Q.931 will as an example define 2 dialects as it treats User
57 and Network mode as separate ISDN dialects.
58
59 The API messages Q931AddProc, Q931AddMes, Q931AddIE are used to initialize
60 these table entries during system inititialization of a stack.
61
62 *****************************************************************************/
63 q931proc_func_t *Q931Proc[Q931MAXDLCT][Q931MAXMES];
64
65 q931umes_func_t *Q931Umes[Q931MAXDLCT][Q931MAXMES];
66 q931pmes_func_t *Q931Pmes[Q931MAXDLCT][Q931MAXMES];
67
68 q931uie_func_t *Q931Uie[Q931MAXDLCT][Q931MAXIE];
69 q931pie_func_t *Q931Pie[Q931MAXDLCT][Q931MAXIE];
70
71 q931timeout_func_t *Q931Timeout[Q931MAXDLCT][Q931MAXTIMER];
72 q931timer_t Q931Timer[Q931MAXDLCT][Q931MAXTIMER];
73
74 void (*Q931CreateDialectCB[Q931MAXDLCT])(L3UCHAR iDialect) = { NULL, NULL };
75
76 Q931State Q931st[Q931MAXSTATE];
77
78 /*****************************************************************************
79
80 Core system tables and variables.
81
82 *****************************************************************************/
83
84 L3INT Q931L4HeaderSpace = {0}; /* header space to be ignoder/inserted */
85 /* at head of each message. */
86
87 L3INT Q931L2HeaderSpace = {4}; /* Q921 header space, sapi, tei etc */
88
89 /*****************************************************************************
90
91 Main interface callback functions.
92
93 *****************************************************************************/
94
95 Q931ErrorCB_t Q931ErrorProc; /* callback for error messages. */
96 L3ULONG (*Q931GetTimeProc) (void) = NULL; /* callback for func reading time in ms */
97
98 /*****************************************************************************
99
100 Function: Q931SetL4HeaderSpace
101
102 Description: Set the # of bytes to be inserted/ignored at the head of
103 each message. Q931 will issue a message with space for header
104 and the user will use this to fill in whatever header info
105 is required to support the architecture used.
106
107 *****************************************************************************/
Q931SetL4HeaderSpace(L3INT space)108 void Q931SetL4HeaderSpace(L3INT space)
109 {
110 Q931L4HeaderSpace = space;
111 }
112
113 /*****************************************************************************
114
115 Function: Q931SetL2HeaderSpace
116
117 Description: Set the # of bytes to be inserted/ignored at the head of
118 each message. Q931 will issue a message with space for header
119 and the user will use this to fill in whatever header info
120 is required to support the architecture used.
121
122 *****************************************************************************/
Q931SetL2HeaderSpace(L3INT space)123 void Q931SetL2HeaderSpace(L3INT space)
124 {
125 Q931L2HeaderSpace = space;
126 }
127
128 /*****************************************************************************
129
130 Function: Q931ProcDummy
131
132 Description: Dummy function for message processing.
133
134 *****************************************************************************/
Q931ProcDummy(Q931_TrunkInfo_t * pTrunk,L3UCHAR * b,L3INT c)135 L3INT Q931ProcDummy(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b,L3INT c)
136 {
137 return Q931E_INTERNAL;
138 }
139
140 /*****************************************************************************
141
142 Function: Q931UmesDummy
143
144 Description: Dummy function for message processing
145
146 *****************************************************************************/
Q931UmesDummy(Q931_TrunkInfo_t * pTrunk,L3UCHAR * IBuf,Q931mes_Generic * OBuf,L3INT IOff,L3INT Size)147 L3INT Q931UmesDummy(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT IOff, L3INT Size)
148 {
149 return Q931E_UNKNOWN_MESSAGE;
150 }
151
152 /*****************************************************************************
153
154 Function: Q931UieDummy
155
156 Description: Dummy function for message processing
157
158 *****************************************************************************/
Q931UieDummy(Q931_TrunkInfo_t * pTrunk,Q931mes_Generic * pMsg,L3UCHAR * IBuf,L3UCHAR * OBuf,L3INT * IOff,L3INT * OOff)159 L3INT Q931UieDummy(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
160 {
161 return Q931E_UNKNOWN_IE;
162 }
163
164 /*****************************************************************************
165
166 Function: Q931PmesDummy
167
168 Description: Dummy function for message processing
169
170 *****************************************************************************/
Q931PmesDummy(Q931_TrunkInfo_t * pTrunk,Q931mes_Generic * IBuf,L3INT ISize,L3UCHAR * OBuf,L3INT * OSize)171 L3INT Q931PmesDummy(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
172 {
173 return Q931E_UNKNOWN_MESSAGE;
174 }
175
176 /*****************************************************************************
177
178 Function: Q931PieDummy
179
180 Description: Dummy function for message processing
181
182 *****************************************************************************/
Q931PieDummy(Q931_TrunkInfo_t * pTrunk,L3UCHAR * IBuf,L3UCHAR * OBuf,L3INT * Octet)183 L3INT Q931PieDummy(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
184 {
185 return Q931E_UNKNOWN_IE;
186 }
187
188 /*****************************************************************************
189
190 Function: Q931TxDummy
191
192 Description: Dummy function for message processing
193
194 *****************************************************************************/
Q931TxDummy(Q931_TrunkInfo_t * pTrunk,L3UCHAR * b,L3INT n)195 L3INT Q931TxDummy(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT n)
196 {
197 return Q931E_MISSING_CB;
198 }
199
200 /*****************************************************************************
201
202 Function: Q931ErrorDummy
203
204 Description: Dummy function for error processing
205
206 *****************************************************************************/
Q931ErrorDummy(void * priv,L3INT a,L3INT b,L3INT c)207 L3INT Q931ErrorDummy(void *priv, L3INT a, L3INT b, L3INT c)
208 {
209 return 0;
210 }
211
212 /*****************************************************************************
213
214 Function: Q931Initialize
215
216 Description: This function Initialize the stack.
217
218 Will set up the trunk array, channel
219 arrays and initialize Q931 function arrays before it finally
220 set up EuroISDN processing with User as dialect 0 and
221 Network as dialect 1.
222
223 Note: Initialization of other stacks should be inserted after
224 the initialization of EuroISDN.
225
226 *****************************************************************************/
Q931Initialize()227 void Q931Initialize()
228 {
229 L3INT x,y;
230
231 /* Secure the callbacks to default procs */
232 Q931ErrorProc = Q931ErrorDummy;
233
234 /* The user will only add the message handlers and IE handlers he need,
235 * so we need to initialize every single entry to a default function
236 * that will throw an appropriate error if they are ever called.
237 */
238 for (x = 0; x < Q931MAXDLCT; x++) {
239 for (y = 0; y < Q931MAXMES; y++) {
240 Q931Proc[x][y] = Q931ProcDummy;
241 Q931Umes[x][y] = Q931UmesDummy;
242 Q931Pmes[x][y] = Q931PmesDummy;
243 }
244 for (y = 0; y < Q931MAXIE; y++) {
245 Q931Pie[x][y] = Q931PieDummy;
246 Q931Uie[x][y] = Q931UieDummy;
247 }
248 for (y = 0; y < Q931MAXTIMER; y++) {
249 Q931Timeout[x][y] = Q931TimeoutDummy;
250 Q931Timer[x][y] = 0;
251 }
252 }
253
254 if (Q931CreateDialectCB[Q931_Dialect_Q931 + Q931_TE] == NULL)
255 Q931AddDialect(Q931_Dialect_Q931 + Q931_TE, Q931CreateTE);
256
257 if (Q931CreateDialectCB[Q931_Dialect_Q931 + Q931_NT] == NULL)
258 Q931AddDialect(Q931_Dialect_Q931 + Q931_NT, Q931CreateNT);
259
260 if (Q931CreateDialectCB[Q931_Dialect_National + Q931_TE] == NULL)
261 Q931AddDialect(Q931_Dialect_National + Q931_TE, nationalCreateTE);
262
263 if (Q931CreateDialectCB[Q931_Dialect_National + Q931_NT] == NULL)
264 Q931AddDialect(Q931_Dialect_National + Q931_NT, nationalCreateNT);
265
266 if (Q931CreateDialectCB[Q931_Dialect_DMS + Q931_TE] == NULL)
267 Q931AddDialect(Q931_Dialect_DMS + Q931_TE, DMSCreateTE);
268
269 if (Q931CreateDialectCB[Q931_Dialect_DMS + Q931_NT] == NULL)
270 Q931AddDialect(Q931_Dialect_DMS + Q931_NT, DMSCreateNT);
271
272 if (Q931CreateDialectCB[Q931_Dialect_5ESS + Q931_TE] == NULL)
273 Q931AddDialect(Q931_Dialect_5ESS + Q931_TE, ATT5ESSCreateTE);
274
275 if (Q931CreateDialectCB[Q931_Dialect_5ESS + Q931_NT] == NULL)
276 Q931AddDialect(Q931_Dialect_5ESS + Q931_NT, ATT5ESSCreateNT);
277
278 /* The last step we do is to call the callbacks to create the dialects */
279 for (x = 0; x < Q931MAXDLCT; x++) {
280 if (Q931CreateDialectCB[x] != NULL) {
281 Q931CreateDialectCB[x]((L3UCHAR)x);
282 }
283 }
284 }
285
286 /**
287 * Q931TimerTick
288 * \brief Periodically called to update and check for expired timers
289 * \param pTrunk Q.931 trunk
290 */
Q931TimerTick(Q931_TrunkInfo_t * pTrunk)291 void Q931TimerTick(Q931_TrunkInfo_t *pTrunk)
292 {
293 struct Q931_Call *call = NULL;
294 L3ULONG now = 0;
295 L3INT x;
296
297 /* TODO: Loop through all active calls, check timers and call timout procs
298 * if timers are expired.
299 * Implement a function array so each dialect can deal with their own
300 * timeouts.
301 */
302 now = Q931GetTime();
303
304 for (x = 0; x < Q931MAXCALLPERTRUNK; x++) {
305 call = &pTrunk->call[x];
306
307 if (!call->InUse || !call->Timer || !call->TimerID)
308 continue;
309
310 if (call->Timer <= now) {
311 /* Stop Timer */
312 Q931StopTimer(pTrunk, x, call->TimerID);
313
314 /* Invoke dialect timeout callback */
315 Q931Timeout[pTrunk->Dialect][call->TimerID](pTrunk, x);
316 }
317 }
318 }
319
320 /*****************************************************************************
321
322 Function: Q931Rx23
323
324 Description: Receive message from layer 2 (LAPD). Receiving a message
325 is always done in 2 steps. First the message must be
326 interpreted and translated to a static struct. Secondly
327 the message is processed and responded to.
328
329 The Q.931 message contains a static header that is
330 interpreted in this function. The rest is interpreted
331 in a sub function according to mestype.
332
333 Parameters: pTrunk [IN] Ptr to trunk info.
334 buf [IN] Ptr to buffer containing message.
335 Size [IN] Size of message.
336
337 Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning
338 see q931errors.h for details.
339
340 *****************************************************************************/
Q931Rx23(Q931_TrunkInfo_t * pTrunk,L3INT ind,L3UCHAR tei,L3UCHAR * buf,L3INT Size)341 L3INT Q931Rx23(Q931_TrunkInfo_t *pTrunk, L3INT ind, L3UCHAR tei, L3UCHAR * buf, L3INT Size)
342 {
343 L3UCHAR *Mes = NULL;
344 L3INT RetCode = Q931E_NO_ERROR;
345 Q931mes_Generic *m = (Q931mes_Generic *) pTrunk->L3Buf;
346 L3INT ISize;
347 L3INT IOff = 0;
348 L3INT L2HSize = Q931L2HeaderSpace;
349
350 switch (ind) {
351 case Q921_DL_UNIT_DATA: /* DL-UNITDATA indication (UI frame, 3 byte header) */
352 L2HSize = 3;
353
354 case Q921_DL_DATA: /* DL-DATA indication (I frame, 4 byte header) */
355 /* Reset our decode buffer */
356 memset(pTrunk->L3Buf, 0, sizeof(pTrunk->L3Buf));
357
358 /* L2 Header Offset */
359 Mes = &buf[L2HSize];
360
361 /* Protocol Discriminator */
362 m->ProtDisc = Mes[IOff++];
363
364 /* CRV */
365 m->CRVFlag = (Mes[IOff + 1] >> 7) & 0x01;
366 m->CRV = Q931Uie_CRV(pTrunk, Mes, m->buf, &IOff, &ISize);
367
368 /* Message Type */
369 m->MesType = Mes[IOff++];
370
371 /* Store tei */
372 m->Tei = tei;
373
374 /* d'oh a little ugly but this saves us from:
375 * a) doing Q.921 work in the lower levels (extracting the TEI ourselves)
376 * b) adding a tei parameter to _all_ Proc functions
377 */
378 if (tei) {
379 L3INT callIndex = 0;
380
381 /* Find the call using CRV */
382 RetCode = Q931FindCRV(pTrunk, m->CRV, &callIndex);
383 if (RetCode == Q931E_NO_ERROR && !pTrunk->call[callIndex].Tei) {
384 pTrunk->call[callIndex].Tei = tei;
385 }
386 }
387
388 Q931Log(pTrunk, Q931_LOG_DEBUG, "Received message from Q.921 (ind %d, tei %d, size %d)\nMesType: %d, CRVFlag %d (%s), CRV %d (Dialect: %d)\n", ind, m->Tei, Size,
389 m->MesType, m->CRVFlag, m->CRVFlag ? "Terminator" : "Originator", m->CRV, pTrunk->Dialect);
390
391 RetCode = Q931Umes[pTrunk->Dialect][m->MesType](pTrunk, Mes, (Q931mes_Generic *)pTrunk->L3Buf, IOff, Size - L2HSize);
392 if (RetCode >= Q931E_NO_ERROR) {
393 RetCode = Q931Proc[pTrunk->Dialect][m->MesType](pTrunk, pTrunk->L3Buf, 2);
394 }
395 break;
396
397 default:
398 break;
399 }
400
401 return RetCode;
402 }
403
404 /*****************************************************************************
405
406 Function: Q931Tx34
407
408 Description: Called from the stack to send a message to layer 4.
409
410 Parameters: Mes[IN] Ptr to message buffer.
411 Size[IN] Message size in bytes.
412
413 Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning
414 see q931errors.h for details.
415
416 *****************************************************************************/
Q931Tx34(Q931_TrunkInfo_t * pTrunk,L3UCHAR * Mes,L3INT Size)417 L3INT Q931Tx34(Q931_TrunkInfo_t *pTrunk, L3UCHAR * Mes, L3INT Size)
418 {
419 Q931Log(pTrunk, Q931_LOG_DEBUG, "Sending message to Layer4 (size: %d)\n", Size);
420
421 if (pTrunk->Q931Tx34CBProc) {
422 return pTrunk->Q931Tx34CBProc(pTrunk->PrivateData34, Mes, Size);
423 }
424 return Q931E_MISSING_CB;
425 }
426
427 /*****************************************************************************
428
429 Function: Q931Rx43
430
431 Description: Receive message from Layer 4 (application).
432
433 Parameters: pTrunk[IN] Trunk #.
434 buf[IN] Message Pointer.
435 Size[IN] Message size in bytes.
436
437 Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning
438 see q931errors.h for details.
439
440 *****************************************************************************/
Q931Rx43(Q931_TrunkInfo_t * pTrunk,L3UCHAR * buf,L3INT Size)441 L3INT Q931Rx43(Q931_TrunkInfo_t *pTrunk,L3UCHAR * buf, L3INT Size)
442 {
443 Q931mes_Header *ptr = (Q931mes_Header*)&buf[Q931L4HeaderSpace];
444 L3INT RetCode = Q931E_NO_ERROR;
445
446 Q931Log(pTrunk, Q931_LOG_DEBUG, "Receiving message from Layer4 (size: %d, type: %d)\n", Size, ptr->MesType);
447
448 RetCode = Q931Proc[pTrunk->Dialect][ptr->MesType](pTrunk, buf, 4);
449
450 Q931Log(pTrunk, Q931_LOG_DEBUG, "Q931Rx43 return code: %d\n", RetCode);
451
452 return RetCode;
453 }
454
455 /*****************************************************************************
456
457 Function: Q931Tx32
458
459 Description: Called from the stack to send a message to L2. The input is
460 always a non-packed message so it will first make a proper
461 call to create a packed message before it transmits that
462 message to layer 2.
463
464 Parameters: pTrunk[IN] Trunk #
465 buf[IN] Ptr to message buffer.
466 Size[IN] Message size in bytes.
467
468 Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning
469 see q931errors.h for details.
470
471 *****************************************************************************/
Q931Tx32Data(Q931_TrunkInfo_t * pTrunk,L3UCHAR bcast,L3UCHAR * Mes,L3INT Size)472 L3INT Q931Tx32Data(Q931_TrunkInfo_t *pTrunk, L3UCHAR bcast, L3UCHAR * Mes, L3INT Size)
473 {
474 Q931mes_Generic *ptr = (Q931mes_Generic*)Mes;
475 L3INT RetCode = Q931E_NO_ERROR;
476 L3INT iDialect = pTrunk->Dialect;
477 L3INT Offset = bcast ? (Q931L2HeaderSpace - 1) : Q931L2HeaderSpace;
478 L3INT OSize;
479
480 Q931Log(pTrunk, Q931_LOG_DEBUG, "Sending message to Q.921 (size: %d)\n", Size);
481
482 memset(pTrunk->L2Buf, 0, sizeof(pTrunk->L2Buf));
483
484 /* Call pack function through table. */
485 RetCode = Q931Pmes[iDialect][ptr->MesType](pTrunk, (Q931mes_Generic *)Mes, Size, &pTrunk->L2Buf[Offset], &OSize);
486 if (RetCode >= Q931E_NO_ERROR) {
487 L3INT callIndex;
488 L3UCHAR tei = 0;
489
490 if (ptr->CRV) {
491 /* Find the call using CRV */
492 RetCode = Q931FindCRV(pTrunk, ptr->CRV, &callIndex);
493 if (RetCode != Q931E_NO_ERROR)
494 return RetCode;
495
496 tei = pTrunk->call[callIndex].Tei;
497 }
498
499 if (pTrunk->Q931Tx32CBProc) {
500 RetCode = pTrunk->Q931Tx32CBProc(pTrunk->PrivateData32, bcast ? Q921_DL_UNIT_DATA : Q921_DL_DATA, tei, pTrunk->L2Buf, OSize + Offset);
501 } else {
502 RetCode = Q931E_MISSING_CB;
503 }
504 }
505
506 return RetCode;
507 }
508
509
510 /*****************************************************************************
511
512 Function: Q931SetError
513
514 Description: Called from the stack to indicate an error.
515
516 Parameters: ErrID ID of ie or message causing error.
517 ErrPar1 Error parameter 1
518 ErrPar2 Error parameter 2.
519
520
521 *****************************************************************************/
Q931SetError(Q931_TrunkInfo_t * pTrunk,L3INT ErrID,L3INT ErrPar1,L3INT ErrPar2)522 void Q931SetError(Q931_TrunkInfo_t *pTrunk,L3INT ErrID, L3INT ErrPar1, L3INT ErrPar2)
523 {
524 if (pTrunk->Q931ErrorCBProc) {
525 pTrunk->Q931ErrorCBProc(pTrunk->PrivateData34, ErrID, ErrPar1, ErrPar2);
526 } else {
527 Q931ErrorProc(pTrunk->PrivateData34, ErrID, ErrPar1, ErrPar2);
528 }
529 }
530
Q931SetDefaultErrorCB(Q931ErrorCB_t Q931ErrorPar)531 void Q931SetDefaultErrorCB(Q931ErrorCB_t Q931ErrorPar)
532 {
533 Q931ErrorProc = Q931ErrorPar;
534 }
535
536 /*****************************************************************************
537
538 Function: Q931CreateCRV
539
540 Description: Create a CRV entry and return it's index. The function will
541 locate a free entry in the call tables allocate it and
542 allocate a unique CRV value attached to it.
543
544 Parameters: pTrunk [IN] Trunk number
545 callindex [OUT] return call table index.
546
547 Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning
548 see q931errors.h for details.
549 ****************************************************************************/
Q931CreateCRV(Q931_TrunkInfo_t * pTrunk,L3INT * callIndex)550 L3INT Q931CreateCRV(Q931_TrunkInfo_t *pTrunk, L3INT * callIndex)
551 {
552 L3INT CRV = Q931GetUniqueCRV(pTrunk);
553
554 return Q931AllocateCRV(pTrunk, CRV, callIndex);
555 }
556
557
Q931ReleaseCRV(Q931_TrunkInfo_t * pTrunk,L3INT CRV)558 L3INT Q931ReleaseCRV(Q931_TrunkInfo_t *pTrunk, L3INT CRV)
559 {
560 int callIndex;
561
562 if ((Q931FindCRV(pTrunk, CRV, &callIndex)) == Q931E_NO_ERROR) {
563 pTrunk->call[callIndex].InUse = 0;
564 return Q931E_NO_ERROR;
565 }
566
567 return Q931E_INVALID_CRV;
568 }
569
570 /*****************************************************************************
571
572 Function: Q931AllocateCRV
573
574 Description: Allocate a call table entry and assigns the given CRV value
575 to it.
576
577 Parameters: pTrunk [IN] Trunk number
578 iCRV [IN] Call Reference Value.
579 callindex [OUT] return call table index.
580
581 Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning
582 see q931errors.h for details.
583
584 *****************************************************************************/
Q931AllocateCRV(Q931_TrunkInfo_t * pTrunk,L3INT iCRV,L3INT * callIndex)585 L3INT Q931AllocateCRV(Q931_TrunkInfo_t *pTrunk, L3INT iCRV, L3INT * callIndex)
586 {
587 L3INT x;
588 for (x = 0; x < Q931MAXCALLPERTRUNK; x++) {
589 if (!pTrunk->call[x].InUse) {
590 pTrunk->call[x].CRV = iCRV;
591 pTrunk->call[x].BChan = 255;
592 pTrunk->call[x].State = 0; /* null state - idle */
593 pTrunk->call[x].TimerID = 0; /* no timer running */
594 pTrunk->call[x].Timer = 0;
595 pTrunk->call[x].InUse = 1; /* mark as used */
596 *callIndex = x;
597 return Q931E_NO_ERROR;
598 }
599 }
600 return Q931E_TOMANYCALLS;
601 }
602
603 /*****************************************************************************
604
605 Function: Q931GetCallState
606
607 Description: Look up CRV and return current call state. A non existing
608 CRV is the same as state zero (0).
609
610 Parameters: pTrunk [IN] Trunk number.
611 iCRV [IN] CRV
612
613 Return Value: Call State.
614
615 *****************************************************************************/
Q931GetCallState(Q931_TrunkInfo_t * pTrunk,L3INT iCRV)616 L3INT Q931GetCallState(Q931_TrunkInfo_t *pTrunk, L3INT iCRV)
617 {
618 L3INT x;
619 for (x = 0; x < Q931MAXCALLPERTRUNK; x++) {
620 if (pTrunk->call[x].InUse) {
621 if (pTrunk->call[x].CRV == iCRV) {
622 return pTrunk->call[x].State;
623 }
624 }
625 }
626 return 0; /* assume state zero for non existing CRV's */
627 }
628
629 /**
630 * Q931StartTimer
631 * \brief Start a timer
632 * \param pTrunk Q.931 trunk
633 * \param callindex Index of the call
634 * \param iTimerID ID of timer
635 * \return always 0
636 */
Q931StartTimer(Q931_TrunkInfo_t * pTrunk,L3INT callIndex,L3USHORT iTimerID)637 L3INT Q931StartTimer(Q931_TrunkInfo_t *pTrunk, L3INT callIndex, L3USHORT iTimerID)
638 {
639 #if 0
640 L3ULONG duration = Q931Timer[pTrunk->Dialect][iTimerID];
641
642 if (duration) {
643 pTrunk->call[callIndex].Timer = Q931GetTime() + duration;
644 pTrunk->call[callIndex].TimerID = iTimerID;
645 }
646 #endif
647 return 0;
648 }
649
650 /**
651 * Q931StopTimer
652 * \brief Stop a timer
653 * \param pTrunk Q.931 trunk
654 * \param callindex Index of the call
655 * \param iTimerID ID of timer
656 * \return always 0
657 */
Q931StopTimer(Q931_TrunkInfo_t * pTrunk,L3INT callindex,L3USHORT iTimerID)658 L3INT Q931StopTimer(Q931_TrunkInfo_t *pTrunk, L3INT callindex, L3USHORT iTimerID)
659 {
660 if (pTrunk->call[callindex].TimerID == iTimerID)
661 pTrunk->call[callindex].TimerID = 0;
662
663 return 0;
664 }
665
Q931SetState(Q931_TrunkInfo_t * pTrunk,L3INT callIndex,L3INT iState)666 L3INT Q931SetState(Q931_TrunkInfo_t *pTrunk, L3INT callIndex, L3INT iState)
667 {
668 pTrunk->call[callIndex].State = iState;
669
670 return 0;
671 }
672
Q931GetTime()673 L3ULONG Q931GetTime()
674 {
675 L3ULONG tNow = 0;
676 static L3ULONG tLast = 0;
677
678 if (Q931GetTimeProc != NULL) {
679 tNow = Q931GetTimeProc();
680 if (tNow < tLast) { /* wrapped */
681 /* TODO */
682 }
683 tLast = tNow;
684 }
685 return tNow;
686 }
687
Q931SetGetTimeCB(L3ULONG (* callback)(void))688 void Q931SetGetTimeCB(L3ULONG (*callback)(void))
689 {
690 Q931GetTimeProc = callback;
691 }
692
Q931FindCRV(Q931_TrunkInfo_t * pTrunk,L3INT crv,L3INT * callindex)693 L3INT Q931FindCRV(Q931_TrunkInfo_t *pTrunk, L3INT crv, L3INT *callindex)
694 {
695 L3INT x;
696 for (x = 0; x < Q931MAXCALLPERTRUNK; x++) {
697 if (pTrunk->call[x].InUse) {
698 if (pTrunk->call[x].CRV == crv) {
699 *callindex = x;
700 return Q931E_NO_ERROR;
701 }
702 }
703 }
704 return Q931E_INVALID_CRV;
705 }
706
707
Q931AddDialect(L3UCHAR i,void (* callback)(L3UCHAR iD))708 void Q931AddDialect(L3UCHAR i, void (*callback)(L3UCHAR iD ))
709 {
710 if (i < Q931MAXDLCT) {
711 Q931CreateDialectCB[i] = callback;
712 }
713 }
714
715 /*****************************************************************************
716 Function: Q931AddStateEntry
717
718 Description: Find an empty entry in the dialects state table and add this
719 entry.
720 *****************************************************************************/
Q931AddStateEntry(L3UCHAR iD,L3INT iState,L3INT iMes,L3UCHAR cDir)721 void Q931AddStateEntry(L3UCHAR iD, L3INT iState, L3INT iMes, L3UCHAR cDir)
722 {
723 int x;
724 for (x = 0; x < Q931MAXSTATE; x++) {
725 if (Q931st[x].Message == 0) {
726 Q931st[x].State = iState;
727 Q931st[x].Message = iMes;
728 Q931st[x].Direction = cDir;
729 /* TODO Sort table and use bsearch */
730 return;
731 }
732 }
733 }
734
735 /*****************************************************************************
736 Function: Q931IsEventLegal
737
738 Description: Check state table for matching criteria to indicate if this
739 Message is legal in this state or not.
740
741 Note: Someone write a bsearch or invent something smart here
742 please - sequential is ok for now.
743 *****************************************************************************/
Q931IsEventLegal(L3UCHAR iD,L3INT iState,L3INT iMes,L3UCHAR cDir)744 L3BOOL Q931IsEventLegal(L3UCHAR iD, L3INT iState, L3INT iMes, L3UCHAR cDir)
745 {
746 int x;
747 /* TODO Sort table and use bsearch */
748 for (x = 0; x < Q931MAXSTATE; x++) {
749 if (Q931st[x].State == iState && Q931st[x].Message == iMes &&
750 Q931st[x].Direction == cDir) {
751 return L3TRUE;
752 }
753 }
754 return L3FALSE;
755 }
756
757 /*****************************************************************************
758 Function: q931_error_to_name()
759
760 Description: Check state table for matching criteria to indicate if this
761 Message is legal in this state or not.
762
763 Note: Someone write a bsearch or invent something smart here
764 please - sequential is ok for now.
765 *****************************************************************************/
766 static const char *q931_error_names[] = {
767 "Q931E_NO_ERROR", /* 0 */
768
769 "Q931E_UNKNOWN_MESSAGE", /* -3001 */
770 "Q931E_ILLEGAL_IE", /* -3002 */
771 "Q931E_UNKNOWN_IE", /* -3003 */
772 "Q931E_BEARERCAP", /* -3004 */
773 "Q931E_HLCOMP", /* -3005 */
774 "Q931E_LLCOMP", /* -3006 */
775 "Q931E_INTERNAL", /* -3007 */
776 "Q931E_MISSING_CB", /* -3008 */
777 "Q931E_UNEXPECTED_MESSAGE", /* -3009 */
778 "Q931E_ILLEGAL_MESSAGE", /* -3010 */
779 "Q931E_TOMANYCALLS", /* -3011 */
780 "Q931E_INVALID_CRV", /* -3012 */
781 "Q931E_CALLID", /* -3013 */
782 "Q931E_CALLSTATE", /* -3014 */
783 "Q931E_CALLEDSUB", /* -3015 */
784 "Q931E_CALLEDNUM", /* -3016 */
785 "Q931E_CALLINGNUM", /* -3017 */
786 "Q931E_CALLINGSUB", /* -3018 */
787 "Q931E_CAUSE", /* -3019 */
788 "Q931E_CHANID", /* -3020 */
789 "Q931E_DATETIME", /* -3021 */
790 "Q931E_DISPLAY", /* -3022 */
791 "Q931E_KEYPADFAC", /* -3023 */
792 "Q931E_NETFAC", /* -3024 */
793 "Q931E_NOTIFIND", /* -3025 */
794 "Q931E_PROGIND", /* -3026 */
795 "Q931E_RESTARTIND", /* -3027 */
796 "Q931E_SEGMENT", /* -3028 */
797 "Q931E_SIGNAL", /* -3029 */
798 "Q931E_GENERIC_DIGITS" /* -3030 */
799
800 };
801
802 #define Q931_MAX_ERROR 30
803
q931_error_to_name(q931_error_t error)804 const char *q931_error_to_name(q931_error_t error)
805 {
806 int index = 0;
807 if ((int)error < 0) {
808 index = (((int)error * -1) -3000);
809 }
810 if (index < 0 || index > Q931_MAX_ERROR) {
811 return "";
812 }
813 return q931_error_names[index];
814 }
815 /*
816 * Logging
817 */
818 #include <stdarg.h>
819
Q931Log(Q931_TrunkInfo_t * trunk,Q931LogLevel_t level,const char * fmt,...)820 L3INT Q931Log(Q931_TrunkInfo_t *trunk, Q931LogLevel_t level, const char *fmt, ...)
821 {
822 char buf[Q931_LOGBUFSIZE];
823 L3INT len;
824 va_list ap;
825
826 if (!trunk->Q931LogCBProc)
827 return 0;
828
829 if (trunk->loglevel < level)
830 return 0;
831
832 va_start(ap, fmt);
833
834 len = vsnprintf(buf, sizeof(buf)-1, fmt, ap);
835 if (len <= 0) {
836 /* TODO: error handling */
837 return -1;
838 }
839 if (len >= sizeof(buf))
840 len = sizeof(buf) - 1;
841
842 buf[len] = '\0';
843
844 va_end(ap);
845
846 return trunk->Q931LogCBProc(trunk->PrivateDataLog, level, buf, len);
847 }
848
849 /**
850 * Q921SetLogCB
851 * \brief Set Logging callback function and private data
852 */
Q931SetLogCB(Q931_TrunkInfo_t * trunk,Q931LogCB_t func,void * priv)853 void Q931SetLogCB(Q931_TrunkInfo_t *trunk, Q931LogCB_t func, void *priv)
854 {
855 trunk->Q931LogCBProc = func;
856 trunk->PrivateDataLog = priv;
857 }
858
859 /**
860 * Q921SetLogLevel
861 * \brief Set Loglevel
862 */
Q931SetLogLevel(Q931_TrunkInfo_t * trunk,Q931LogLevel_t level)863 void Q931SetLogLevel(Q931_TrunkInfo_t *trunk, Q931LogLevel_t level)
864 {
865 if(!trunk)
866 return;
867
868 if (level < Q931_LOG_NONE) {
869 level = Q931_LOG_NONE;
870 } else if (level > Q931_LOG_DEBUG) {
871 level = Q931_LOG_DEBUG;
872 }
873
874 trunk->loglevel = level;
875 }
876
877 /**
878 * Q931TimeoutDummy
879 * \brief Dummy handler for timeouts
880 * \param pTrunk Q.931 trunk
881 * \param callIndex Index of call
882 */
Q931TimeoutDummy(Q931_TrunkInfo_t * pTrunk,L3INT callIndex)883 L3INT Q931TimeoutDummy(Q931_TrunkInfo_t *pTrunk, L3INT callIndex)
884 {
885 Q931Log(pTrunk, Q931_LOG_DEBUG, "Timer %d of call %d (CRV: %d) timed out\n", pTrunk->call[callIndex].TimerID, callIndex, pTrunk->call[callIndex].CRV);
886
887 return 0;
888 }
889