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