isdn4k-utils/capi20.new/capi_mod_std.c

457 lines
11 KiB
C

/*****************************************************************
* 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 <sys/socket.h>
#include <fcntl.h>
#include <errno.h>
#include <limits.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <linux/capi.h>
#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 = 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( 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( 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( 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( 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( 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( applid2fd( nApplId ), CAPI_NCCI_OPENCOUNT, &nNcci );
}
/** Module operations structure */
static struct sModuleOperations sStandard = {
standardIsInstalled,
standardRegister,
NULL,
standardPutMessage,
standardGetMessage,
standardGetManufactor,
standardGetVersion,
standardGetSerialNumber,
standardGetProfile,
standardGetFlags,
standardSetFlags,
standardClearFlags,
standardGetTtyDeviceName,
standardGetRawDeviceName,
standardGetNcciOpenCount
};
MODULE_INIT( "standard", &sStandard );