/***************************************************************** * CAPI 2.0 Library * * All parts are distributed under the terms of GPL. See COPYING * *****************************************************************/ /** * \file capi_mod_standard.c * \brief Standard CAPI interface */ #include #include #include #include #include #include #include #include #include #include #include #include "capi20.h" #include "capi_mod.h" #define CAPI_DEVICE_NAME "/dev/capi20" #define CAPI_DEVICE_NAME_NEW "/dev/isdn/capi20" static capi_ioctl_struct ioctl_data; /** * \brief Check if standard interface is available * \return file descriptor of socket */ static unsigned standardIsInstalled( void ) { int nHandle; if ( ( nHandle = open( CAPI_DEVICE_NAME, O_RDWR, 0666 ) ) < 0 && ( errno == ENOENT ) ) { nHandle = open( CAPI_DEVICE_NAME_NEW, O_RDWR, 0666 ); } if ( nHandle >= 0 ) { if ( ioctl( nHandle, CAPI_INSTALLED, 0 ) != 0 ) { nHandle = -1; } } return nHandle; } /** * \brief Register standard capi device * \param nMaxB3Connection maximum b3 connection * \param nMaxB3Blks maximum b3 blocks * \param nMaxSizeB3 maximum b3 size * \param pnApplId pointer where to store the new application id * \return new file handle */ static unsigned standardRegister( unsigned nMaxB3Connection, unsigned nMaxB3Blks, unsigned nMaxSizeB3, unsigned *pnApplId ) { char anBuf[ PATH_MAX ]; int nApplId; int nIndex; int nHandle; if ( ( nHandle = open( CAPI_DEVICE_NAME, O_RDWR | O_NONBLOCK, 0666 ) ) < 0 && ( errno == ENOENT ) ) { nHandle = open( CAPI_DEVICE_NAME_NEW, O_RDWR | O_NONBLOCK, 0666 ); } if (nHandle < 0) { return nHandle; } ioctl_data.rparams.level3cnt = nMaxB3Connection; ioctl_data.rparams.datablkcnt = nMaxB3Blks; ioctl_data.rparams.datablklen = nMaxSizeB3; if ( ( nApplId = ioctl(nHandle, CAPI_REGISTER, &ioctl_data ) ) < 0 ) { if ( errno == EIO ) { if ( ioctl( nHandle, CAPI_GET_ERRCODE, &ioctl_data ) < 0 ) { close( nHandle ); return -2; } close( nHandle ); return -2; } else if ( errno == EINVAL ) { /* old kernel driver */ close( nHandle ); nHandle = -1; for ( nIndex = 0; nHandle < 0; nIndex++ ) { /*----- open pseudo-clone device -----*/ snprintf( anBuf, sizeof( anBuf ), "/dev/capi20.%02d", nIndex ); if ( ( nHandle = open( anBuf, O_RDWR | O_NONBLOCK, 0666 ) ) < 0 ) { switch ( errno ) { case EEXIST: break; default: return -3; } } } if ( nHandle < 0 ) { return -3; } ioctl_data.rparams.level3cnt = nMaxB3Connection; ioctl_data.rparams.datablkcnt = nMaxB3Blks; ioctl_data.rparams.datablklen = nMaxSizeB3; if ( ( nApplId = ioctl( nHandle, CAPI_REGISTER, &ioctl_data ) ) < 0 ) { if ( errno == EIO ) { if ( ioctl( nHandle, CAPI_GET_ERRCODE, &ioctl_data ) < 0 ) { close( nHandle ); return -4; } close( nHandle ); return -5; } close( nHandle ); return -6; } nApplId = capi_alloc_applid(nHandle); } } *pnApplId = nApplId; return nHandle; } /** * \brief Put capi message * \param nHandle file handle * \param nApplId application id * \param pnMsg message pointer * \return error code */ static unsigned standardPutMessage( int nHandle, unsigned nApplId, unsigned char *pnMsg ) { int nLen = CAPIMSG_LEN( pnMsg ); int nCommand = CAPIMSG_COMMAND( pnMsg ); int nSubCommand = CAPIMSG_SUBCOMMAND( pnMsg ); int nNum; nLen = processMessage( pnMsg, nApplId, nCommand, nSubCommand, nLen ); nNum = write( nHandle, pnMsg, nLen ); if ( nNum != nLen ) { switch ( errno ) { case EFAULT: case EINVAL: return CapiIllCmdOrSubcmdOrMsgToSmall; case EBADF: return CapiIllAppNr; case EIO: if ( ioctl( nHandle, CAPI_GET_ERRCODE, &ioctl_data ) < 0 ) { return CapiMsgOSResourceErr; } else { return ioctl_data.errcode; } default: return CapiMsgOSResourceErr; } } return CapiNoError; } /** * \brief Get capi message * \param nHandle file handle * \param nApplId application id * \param pnMsg message pointer * \return error code */ static unsigned standardGetMessage( int nHandle, unsigned nApplId, unsigned char **ppnBuffer ) { unsigned char *pnBuffer; unsigned nOffset; int nRet; size_t nBufSize; if ( ( *ppnBuffer = pnBuffer = ( unsigned char * ) get_buffer( nApplId, &nBufSize, &nOffset ) ) == 0 ) { return CapiMsgOSResourceErr; } nRet = read( nHandle, pnBuffer, nBufSize ); if ( nRet > 0 ) { /* workaround for old driver */ CAPIMSG_SETAPPID( pnBuffer, nApplId ); if ( ( CAPIMSG_COMMAND( pnBuffer ) == CAPI_DATA_B3 ) && ( CAPIMSG_SUBCOMMAND( pnBuffer ) == CAPI_IND ) ) { save_datahandle( nApplId, nOffset, CAPIMSG_U16( pnBuffer, 18 ), CAPIMSG_U32( pnBuffer, 8 ) ); /* patch datahandle */ capimsg_setu16( pnBuffer, 18, nOffset ); if ( sizeof( void * ) == 4 ) { u_int32_t nData = ( u_int32_t ) pnBuffer + CAPIMSG_LEN( pnBuffer ); pnBuffer[ 12 ] = nData & 0xFF; pnBuffer[ 13 ] = ( nData >> 8 ) & 0xFF; pnBuffer[ 14 ] = ( nData >> 16 ) & 0xFF; pnBuffer[ 15 ] = ( nData >> 24 ) & 0xFF; } else { u_int64_t nData; if ( CAPIMSG_LEN( pnBuffer ) < 30 ) { memmove( pnBuffer + 30, pnBuffer + CAPIMSG_LEN( pnBuffer ), CAPIMSG_DATALEN( pnBuffer ) ); pnBuffer[ 0 ] = 30; pnBuffer[ 1 ] = 0; } nData = ( ( ( ulong ) pnBuffer ) + CAPIMSG_LEN( pnBuffer ) ); pnBuffer[ 12 ] = pnBuffer[ 13 ] = pnBuffer[ 14 ] = pnBuffer[ 15 ] = 0; pnBuffer[ 22 ] = nData & 0xFF; pnBuffer[ 23 ] = ( nData >> 8 ) & 0xFF; pnBuffer[ 24 ] = ( nData >> 16 ) & 0xFF; pnBuffer[ 25 ] = ( nData >> 24 ) & 0xFF; pnBuffer[ 26 ] = ( nData >> 32 ) & 0xFF; pnBuffer[ 27 ] = ( nData >> 40 ) & 0xFF; pnBuffer[ 28 ] = ( nData >> 48 ) & 0xFF; pnBuffer[ 29 ] = ( nData >> 56 ) & 0xFF; } /* keep buffer */ return CapiNoError; } return_buffer( nApplId, nOffset ); if ( ( CAPIMSG_COMMAND( pnBuffer ) == CAPI_DISCONNECT) && ( CAPIMSG_SUBCOMMAND( pnBuffer ) == CAPI_IND ) ) { cleanup_buffers_for_plci( nApplId, CAPIMSG_U32( pnBuffer, 8 ) ); } return CapiNoError; } return_buffer( nApplId, nOffset ); if ( nRet == 0 ) { return CapiReceiveQueueEmpty; } switch ( errno ) { case EMSGSIZE: nRet = CapiIllCmdOrSubcmdOrMsgToSmall; break; case EAGAIN: nRet = CapiReceiveQueueEmpty; break; default: nRet = CapiMsgOSResourceErr; break; } return nRet; } /** * \brief Get manufactor * \param nHandle file handle * \param nController controller number * \param pnBuffer where to store the information * \return pnBuffer or NULL on error */ static unsigned char *standardGetManufactor( int nHandle, unsigned nController, unsigned char *pnBuffer ) { ioctl_data.contr = nController; if ( ioctl( nHandle, CAPI_GET_MANUFACTURER, &ioctl_data ) < 0 ) { return NULL; } memcpy( pnBuffer, ioctl_data.manufacturer, CAPI_MANUFACTURER_LEN ); pnBuffer[ CAPI_MANUFACTURER_LEN - 1 ] = 0; return pnBuffer; } /** * \brief Get version * \param nHandle file handle * \param nController controller number * \param pnBuffer where to store the information * \return pnBuffer or NULL on error */ static unsigned char *standardGetVersion( int nHandle, unsigned nController, unsigned char *pnBuffer ) { ioctl_data.contr = nController; if ( ioctl( nHandle, CAPI_GET_VERSION, &ioctl_data ) < 0 ) { return NULL; } memcpy( pnBuffer, &ioctl_data.version, sizeof( capi_version ) ); return pnBuffer; } /** * \brief Get serial number * \param nHandle file handle * \param nController controller number * \param pnBuffer where to store the information * \return pnBuffer or NULL on error */ static unsigned char *standardGetSerialNumber( int nHandle, unsigned nController, unsigned char *pnBuffer ) { ioctl_data.contr = nController; if ( ioctl( nHandle, CAPI_GET_SERIAL, &ioctl_data ) < 0 ) { return NULL; } memcpy( pnBuffer, &ioctl_data.serial, CAPI_SERIAL_LEN ); pnBuffer[ CAPI_SERIAL_LEN - 1 ] = 0; return pnBuffer; } /** * \brief Get profile from standard * \param nHandle socket handle * \param nController controller * \param pnBuffer buffer * \return error code */ static unsigned standardGetProfile( int nHandle, unsigned nController, unsigned char *pnBuffer ) { ioctl_data.contr = nController; if ( ioctl( nHandle, CAPI_GET_PROFILE, &ioctl_data ) < 0 ) { if ( errno != EIO ) { return CapiMsgOSResourceErr; } if ( ioctl( nHandle, CAPI_GET_ERRCODE, &ioctl_data ) < 0 ) { return CapiMsgOSResourceErr; } return ( unsigned ) ioctl_data.errcode; } if ( nController ) { memcpy( pnBuffer, &ioctl_data.profile, sizeof( struct capi_profile ) ); } else { memcpy( pnBuffer, &ioctl_data.profile.ncontroller, sizeof( ioctl_data.profile.ncontroller ) ); } return CapiNoError; } /** * \brief Get flags * \param nApplId application id * \param pnFlags where to save flags * \return error code */ static int standardGetFlags( unsigned nApplId, unsigned *pnFlags ) { if ( ioctl(capi_applid2fd( nApplId ), CAPI_GET_FLAGS, pnFlags) < 0) { return CapiMsgOSResourceErr; } return CapiNoError; } /** * \brief Set flags * \param nApplId application id * \param nFlags flags to set * \return error code */ static int standardSetFlags( unsigned nApplId, unsigned nFlags ) { if ( ioctl(capi_applid2fd( nApplId ), CAPI_SET_FLAGS, &nFlags) < 0) { return CapiMsgOSResourceErr; } return CapiNoError; } /** * \brief Clear flags * \param nApplId application id * \param nFlags flags to clear * \return error code */ static int standardClearFlags( unsigned nApplId, unsigned nFlags ) { if ( ioctl(capi_applid2fd( nApplId ), CAPI_CLR_FLAGS, &nFlags) < 0) { return CapiMsgOSResourceErr; } return CapiNoError; } /** * \brief Get tty device name * \param nApplId application id * \param nNcci network control connection identifier * \param pnBuffer buffer pointer * \param nSize size of buffer * \return pnBuffer or NULL on error */ static char *standardGetTtyDeviceName( unsigned nApplId, unsigned nNcci, char *pnBuffer, size_t nSize ) { int nUnit; nUnit = ioctl(capi_applid2fd( nApplId ), CAPI_NCCI_GETUNIT, &nNcci); if ( nUnit < 0 ) { return NULL; } snprintf( pnBuffer, nSize, "/dev/capi/%d", nUnit ); return pnBuffer; } /** * \brief Get raw device name * \param nApplId application id * \param nNcci network control connection identifier * \param pnBuffer buffer pointer * \param nSize size of buffer * \return pnBuffer or NULL on error */ static char *standardGetRawDeviceName( unsigned nApplId, unsigned nNcci, char *pnBuffer, size_t nSize ) { int nUnit; nUnit = ioctl(capi_applid2fd( nApplId ), CAPI_NCCI_GETUNIT, &nNcci); if ( nUnit < 0 ) { return NULL; } snprintf( pnBuffer, nSize, "/dev/capi/r%d", nUnit ); return pnBuffer; } /** * \brief Get NCCI Open count * \param nApplId application id * \param nNcci network control connection identifier * \return error code */ static int standardGetNcciOpenCount( unsigned nApplId, unsigned nNcci ) { return ioctl(capi_applid2fd( nApplId ), CAPI_NCCI_OPENCOUNT, &nNcci); } /** Module operations structure */ static struct sModuleOperations sStandard = { standardIsInstalled, standardRegister, NULL, standardPutMessage, standardGetMessage, standardGetManufactor, standardGetVersion, standardGetSerialNumber, standardGetProfile, NULL, standardGetFlags, standardSetFlags, standardClearFlags, standardGetTtyDeviceName, standardGetRawDeviceName, standardGetNcciOpenCount }; MODULE_INIT( "standard", &sStandard );