/***************************************************************************** FileName: Q931.c Contents: Implementation of Q.931 stack main interface functions. See q931.h for description. License/Copyright: Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved. email:janvb@caselaboratories.com Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Case Labs, Ltd nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ #include "Q931.h" #include "national.h" /***************************************************************************** Dialect function pointers tables. The following function pointer arrays define pack/unpack functions and processing furnctions for the different Q.931 based dialects. The arrays are initialized with pointers to dummy functions and later overrided with pointers to actual functions as new dialects are added. The initial Q.931 will as an example define 2 dielects as it treats User and Network mode as separate ISDN dialects. The API messages Q931AddProc, Q931AddMes, Q931AddIE are used to initialize these table entries during system inititialization of a stack. *****************************************************************************/ L3INT (*Q931Proc [Q931MAXDLCT][Q931MAXMES]) (Q931_TrunkInfo_t *pTrunk, L3UCHAR *,L3INT); L3INT (*Q931Umes [Q931MAXDLCT][Q931MAXMES]) (Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT IOff, L3INT Size); L3INT (*Q931Pmes [Q931MAXDLCT][Q931MAXMES]) (Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize); L3INT (*Q931Uie [Q931MAXDLCT][Q931MAXIE]) (Q931_TrunkInfo_t *pTrunk, ie *pIE, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff); L3INT (*Q931Pie [Q931MAXDLCT][Q931MAXIE]) (Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet); L3UINT Q931MsgieOffset[Q931MAXIE]; void Q931Initialize_MsgieOffset() { L3INT x; Q931mes_Generic msg; ie *index; for(x=0; x 0 : Warning see q931errors.h for details. *****************************************************************************/ L3INT Q931Rx23(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT Size) { L3UCHAR *Mes = &buf[Q931L2HeaderSpace]; L3INT RetCode = Q931E_NO_ERROR; Q931mes_Generic *m = (Q931mes_Generic *) pTrunk->L3Buf; L3INT ISize; L3INT IOff = 0; /* Protocol Discriminator */ m->ProtDisc = Mes[IOff++]; /* CRV */ m->CRV = Q931Uie_CRV(pTrunk, Mes, m->buf, &IOff, &ISize); /* Message Type */ m->MesType = Mes[IOff++]; /* Call table proc to unpack codec message */ RetCode = Q931Umes[pTrunk->Dialect][m->MesType](pTrunk, Mes, (Q931mes_Generic *)pTrunk->L3Buf, Q931L4HeaderSpace + IOff , Size - Q931L4HeaderSpace - IOff + 1); if(RetCode >= Q931E_NO_ERROR) { RetCode = Q931Proc[pTrunk->Dialect][m->MesType](pTrunk, pTrunk->L3Buf, 2); } return RetCode; } /***************************************************************************** Function: Q931Tx34 Description: Called from the stac to send a message to layer 4. Parameters: Mes[IN] Ptr to message buffer. Size[IN] Message size in bytes. Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning see q931errors.h for details. *****************************************************************************/ L3INT Q931Tx34(Q931_TrunkInfo_t *pTrunk, L3UCHAR * Mes, L3INT Size) { if (pTrunk->Q931Tx34CBProc) { return pTrunk->Q931Tx34CBProc(pTrunk->PrivateData34, Mes, Size); } return Q931E_MISSING_CB; } /***************************************************************************** Function: Q931Rx43 Description: Receive message from Layer 4 (application). Parameters: pTrunk[IN] Trunk #. buf[IN] Message Pointer. Size[IN] Message size in bytes. Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning see q931errors.h for details. *****************************************************************************/ L3INT Q931Rx43(Q931_TrunkInfo_t *pTrunk,L3UCHAR * buf, L3INT Size) { Q931mes_Header *ptr = (Q931mes_Header*)&buf[Q931L4HeaderSpace]; L3INT RetCode = Q931E_NO_ERROR; RetCode=Q931Proc[pTrunk->Dialect][ptr->MesType](pTrunk,buf,4); return RetCode; } /***************************************************************************** Function: Q931Tx32 Description: Called from the stack to send a message to L2. The input is always a non-packed message so it will first make a proper call to create a packed message before it transmits that message to layer 2. Parameters: pTrunk[IN] Trunk # buf[IN] Ptr to message buffer. Size[IN] Message size in bytes. Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning see q931errors.h for details. *****************************************************************************/ L3INT Q931Tx32(Q931_TrunkInfo_t *pTrunk, L3UCHAR * Mes, L3INT Size) { L3INT OSize; Q931mes_Generic *ptr = (Q931mes_Generic*)Mes; L3INT RetCode = Q931E_NO_ERROR; L3INT iDialect = pTrunk->Dialect; /* Call pack function through table. */ RetCode = Q931Pmes[iDialect][ptr->MesType](pTrunk, (Q931mes_Generic *)Mes, Size, &pTrunk->L2Buf[Q931L2HeaderSpace], &OSize); if(RetCode >= Q931E_NO_ERROR) { if (pTrunk->Q931Tx32CBProc) { RetCode = pTrunk->Q931Tx32CBProc(pTrunk->PrivateData32, pTrunk->L2Buf, OSize + Q931L2HeaderSpace); } else { RetCode = Q931E_MISSING_CB; } } return RetCode; } /***************************************************************************** Function: Q931SetError Description: Called from the stack to indicate an error. Parameters: ErrID ID of ie or message causing error. ErrPar1 Error parameter 1 ErrPar2 Error parameter 2. *****************************************************************************/ void Q931SetError(Q931_TrunkInfo_t *pTrunk,L3INT ErrID, L3INT ErrPar1, L3INT ErrPar2) { if (pTrunk->Q931ErrorCBProc) { pTrunk->Q931ErrorCBProc(pTrunk->PrivateData34, ErrID, ErrPar1, ErrPar2); } else { Q931ErrorProc(pTrunk->PrivateData34, ErrID, ErrPar1, ErrPar2); } } void Q931SetDefaultErrorCB(Q931ErrorCB_t Q931ErrorPar) { Q931ErrorProc = Q931ErrorPar; } /***************************************************************************** Function: Q931CreateCRV Description: Create a CRV entry and return it's index. The function will locate a free entry in the call tables allocate it and allocate a unique CRV value attached to it. Parameters: pTrunk [IN] Trunk number callindex [OUT] return call table index. Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning see q931errors.h for details. *****************************************************************************/ L3INT Q931CreateCRV(Q931_TrunkInfo_t *pTrunk, L3INT * callIndex) { L3INT CRV = Q931GetUniqueCRV(pTrunk); return Q931AllocateCRV(pTrunk, CRV, callIndex); } /***************************************************************************** Function: Q931AllocateCRV Description: Allocate a call table entry and assigns the given CRV value to it. Parameters: pTrunk [IN] Trunk number iCRV [IN] Call Reference Value. callindex [OUT] return call table index. Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning see q931errors.h for details. *****************************************************************************/ L3INT Q931AllocateCRV(Q931_TrunkInfo_t *pTrunk, L3INT iCRV, L3INT * callIndex) { L3INT x; for(x=0; x < Q931MAXCALLPERTRUNK; x++) { if(!pTrunk->call[x].InUse) { pTrunk->call[x].CRV = iCRV; pTrunk->call[x].BChan = 255; pTrunk->call[x].State = 0; /* null state - idle */ pTrunk->call[x].TimerID = 0; /* no timer running */ pTrunk->call[x].Timer = 0; pTrunk->call[x].InUse = 1; /* mark as used */ *callIndex = x; return Q931E_NO_ERROR; } } return Q931E_TOMANYCALLS; } /***************************************************************************** Function: Q931GetCallState Description: Look up CRV and return current call state. A non existing CRV is the same as state zero (0). Parameters: pTrunk [IN] Trunk number. iCRV [IN] CRV Return Value: Call State. *****************************************************************************/ L3INT Q931GetCallState(Q931_TrunkInfo_t *pTrunk, L3INT iCRV) { L3INT x; for(x=0; x < Q931MAXCALLPERTRUNK; x++) { if(!pTrunk->call[x].InUse) { if(pTrunk->call[x].CRV == iCRV) { return pTrunk->call[x].State; } } } return 0; /* assume state zero for non existing CRV's */ } /***************************************************************************** Function: Q931StartTimer Description: Start a timer. Parameters: pTrunk Trunk number callindex call index. iTimer timer id *****************************************************************************/ L3INT Q931StartTimer(Q931_TrunkInfo_t *pTrunk, L3INT callIndex, L3USHORT iTimerID) { pTrunk->call[callIndex].Timer = Q931GetTime(); pTrunk->call[callIndex].TimerID = iTimerID; return 0; } L3INT Q931StopTimer(Q931_TrunkInfo_t *pTrunk, L3INT callindex, L3USHORT iTimerID) { if(pTrunk->call[callindex].TimerID == iTimerID) pTrunk->call[callindex].TimerID = 0; return 0; } L3INT Q931SetState(Q931_TrunkInfo_t *pTrunk, L3INT callIndex, L3INT iState) { pTrunk->call[callIndex].State = iState; return 0; } L3ULONG Q931GetTime() { L3ULONG tNow = 0; static L3ULONG tLast={0}; if(Q931GetTimeProc != NULL) { tNow = Q931GetTimeProc(); if(tNow < tLast) /* wrapped */ { /* TODO */ } tLast = tNow; } return tNow; } void Q931SetGetTimeCB(L3ULONG (*callback)()) { Q931GetTimeProc = callback; } L3INT Q931FindCRV(Q931_TrunkInfo_t *pTrunk, L3INT crv, L3INT *callindex) { L3INT x; for(x=0; x < Q931MAXCALLPERTRUNK; x++) { if(!pTrunk->call[x].InUse) { if(pTrunk->call[x].CRV == crv) { *callindex = x; return Q931E_NO_ERROR; } } } return Q931E_INVALID_CRV; } void Q931AddDialect(L3UCHAR i, void (*callback)(L3UCHAR iD )) { if(i < Q931MAXDLCT) { Q931CreateDialectCB[i] = callback; } } /***************************************************************************** Function: Q931AddStateEntry Description: Find an empty entry in the dialects state table and add this entry. *****************************************************************************/ void Q931AddStateEntry(L3UCHAR iD, L3INT iState, L3INT iMes, L3UCHAR cDir) { int x; for(x=0; x < Q931MAXSTATE; x++) { if(Q931st[x].Message == 0) { Q931st[x].State = iState; Q931st[x].Message = iMes; Q931st[x].Direction = cDir; /* TODO Sort table and use bsearch */ return; } } } /***************************************************************************** Function: Q931IsEventLegal Description: Check state table for matching criteria to indicate if this Message is legal in this state or not. Note: Someone write a bsearch or invent something smart here please - sequensial is ok for now. *****************************************************************************/ L3BOOL Q931IsEventLegal(L3UCHAR iD, L3INT iState, L3INT iMes, L3UCHAR cDir) { int x; /* TODO Sort table and use bsearch */ for(x=0; x < Q931MAXSTATE; x++) { if( Q931st[x].State == iState && Q931st[x].Message == iMes && Q931st[x].Direction == cDir) { return L3TRUE; } } return L3FALSE; } /***************************************************************************** Function: q931_error_to_name() Description: Check state table for matching criteria to indicate if this Message is legal in this state or not. Note: Someone write a bsearch or invent something smart here please - sequensial is ok for now. *****************************************************************************/ static const char *q931_error_names[] = { "Q931E_NO_ERROR", /* 0 */ "Q931E_UNKNOWN_MESSAGE", /* -3001 */ "Q931E_ILLEGAL_IE", /* -3002 */ "Q931E_UNKNOWN_IE", /* -3003 */ "Q931E_BEARERCAP", /* -3004 */ "Q931E_HLCOMP", /* -3005 */ "Q931E_LLCOMP", /* -3006 */ "Q931E_INTERNAL", /* -3007 */ "Q931E_MISSING_CB", /* -3008 */ "Q931E_UNEXPECTED_MESSAGE", /* -3009 */ "Q931E_ILLEGAL_MESSAGE", /* -3010 */ "Q931E_TOMANYCALLS", /* -3011 */ "Q931E_INVALID_CRV", /* -3012 */ "Q931E_CALLID", /* -3013 */ "Q931E_CALLSTATE", /* -3014 */ "Q931E_CALLEDSUB", /* -3015 */ "Q931E_CALLEDNUM", /* -3016 */ "Q931E_CALLINGNUM", /* -3017 */ "Q931E_CALLINGSUB", /* -3018 */ "Q931E_CAUSE", /* -3019 */ "Q931E_CHANID", /* -3020 */ "Q931E_DATETIME", /* -3021 */ "Q931E_DISPLAY", /* -3022 */ "Q931E_KEYPADFAC", /* -3023 */ "Q931E_NETFAC", /* -3024 */ "Q931E_NOTIFIND", /* -3025 */ "Q931E_PROGIND", /* -3026 */ "Q931E_RESTARTIND", /* -3027 */ "Q931E_SEGMENT", /* -3028 */ "Q931E_SIGNAL", /* -3029 */ }; #define Q931_MAX_ERROR 29 const char *q931_error_to_name(q931_error_t error) { int index = 0; if ((int)error < 0) { index = (((int)error * -1) -3000); } if (index < 0 || index > Q931_MAX_ERROR) { return ""; } return q931_error_names[index]; }