isdn4k-utils/capi20/capi20.c

1164 lines
26 KiB
C

/*
* CAPI 2.0 library
*
* 2002-03-27 - Added remote capi features.
* Armin Schindler <armin@melware.de>
*
* This program is free software and may be modified and
* distributed under the terms of the GNU Public License.
*
*/
#include <sys/types.h>
#include <sys/ioctl.h>
#include <dirent.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <errno.h>
#include <limits.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <ctype.h>
#include <assert.h>
#include <stdarg.h>
#define _LINUX_LIST_H
#include <linux/capi.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <semaphore.h>
#include "capi20.h"
#include "capi_mod.h"
#include "capi_debug.h"
/*
* We will use shared memory to allow unique application IDs in the system
*
*/
#define CAPI20_SHARED_MEM_VERSION 0x01000010
#define CAPI20_SHARED_MEM_NAME "/CAPI20_shared_memory"
#define CAPI20_SEMAPHORE_NAME "/CAPI20_shared_sem"
#define CAPI20_SHARED_MEM_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
#define MAX_APPL 1024
static sem_t *capi_sem;
static int shm_mem_fd = -1;
static struct shr_applids {
unsigned int init_done :1;
unsigned int usage;
unsigned int max_id;
struct {
unsigned int inuse:1;
int fd;
pid_t pid;
unsigned long long para;
} id[MAX_APPL];
unsigned int reserved[16 * MAX_APPL];
} *appids;
#define CAPI20_SHARED_MEM_SIZE sizeof(*appids)
static pid_t my_pid;
static int capi_fd = -1;
static char *globalconfigfilename = "/etc/capi20.conf";
static char *userconfigfilename = ".capi20rc";
static short port = -1;
static char driver[1024] = "";
static char hostname[1024] = "";
static int tracelevel;
static char *tracefile;
static void lock_capi_shared(void)
{
while (sem_wait(capi_sem)) {
if (errno != EINTR) {
fprintf(stderr, "sem_wait() returned error %d - %s\n", errno, strerror(errno));
}
}
}
static void unlock_capi_shared(void)
{
if (sem_post(capi_sem))
fprintf(stderr, "sem_post() returned error %d - %s\n", errno, strerror(errno));
}
/** debug level, for debugging purpose */
static int nDebugLevel = 0;
static int stderr_vprint(const char *file, int line, const char *func, const char *fmt, va_list va)
{
int ret;
fprintf(stderr, "%20s:%4d %22s():", file, line, func);
ret = vfprintf(stderr, fmt, va);
fflush(stderr);
return ret;
}
static capi_debug_t dbg_vprintf = stderr_vprint;
int _capi_dprintf(const char *file, int line, const char *func, const char *fmt, ...)
{
va_list args;
int ret;
va_start(args, fmt);
ret = dbg_vprintf(file, line, func, fmt, args);
va_end(args);
return ret;
}
void register_dbg_vprintf(capi_debug_t fn)
{
dbg_vprintf = fn;
}
/**
* \brief CapiDebug output functions
* \param nLevel debug level of following message
* \param pnFormat formatted string
*/
void CapiDebug(int nLevel, const char *pnFormat, ...) {
if (nLevel <= nDebugLevel) {
va_list pArgs;
va_start(pArgs, pnFormat);
dbg_vprintf(__FILE__, __LINE__, __PRETTY_FUNCTION__, pnFormat, pArgs);
va_end(pArgs);
}
}
void capi_dump_shared(void)
{
int i, val, ret;
capi_dprintf("MapAddress: %p\n", appids);
capi_dprintf("MapSize: %zd\n", CAPI20_SHARED_MEM_SIZE);
if (capi_sem) {
ret = sem_getvalue(capi_sem, &val);
} else {
ret = 0;
val = 9999999;
}
capi_dprintf("Semaphore: %d (ret=%d)\n", val, ret);
if (appids) {
capi_dprintf("Shared memory %s\n", appids->init_done ? "initialized" : "not initialized");
capi_dprintf("Usage count: %d\n", appids->usage);
capi_dprintf("Max used Id: %d\n", appids->max_id);
for (i = 1; i <= appids->max_id; i++) {
if (i == MAX_APPL)
break;
capi_dprintf("AppId:%4d: fd: %d pid: %d %s\n", i, appids->id[i].fd, appids->id[i].pid,
appids->id[i].inuse ? "(used)" : "(not used)");
}
} else {
capi_dprintf("Shared memory not available\n");
}
capi_dprintf("End of dump\n");
}
/**
* \brief Get byte from data buffer and increase buffer pointer
* \param ppnPtr data buffer pointer
* \return byte from buffer
*/
unsigned short get_byte( unsigned char **ppnPtr ) {
*ppnPtr += 1;
return ( ( unsigned char ) *( *ppnPtr - 1 ) );
}
/**
* \brief Get word from data buffer and increase buffer pointer
* \param ppnPtr data buffer pointer
* \return word from buffer
*/
unsigned short get_word( unsigned char **ppnPtr ) {
return ( ( get_byte( ppnPtr ) ) | get_byte( ppnPtr ) << 8 );
}
/**
* \brief Get netword (lo/hi switch) from data buffer and increase
* \param ppnPtr data buffer pointer
* \brief buffer pointer
* \return networdword from buffer
*/
unsigned short get_netword( unsigned char **ppnPtr ) {
return ( ( get_byte( ppnPtr ) << 8 ) | get_byte( ppnPtr ) );
}
/**
* \brief Put byte to data buffer and increase buffer pointer
* \param ppnPtr data buffer pointer
* \param nVal byte number
* \return byte from buffer
*/
unsigned char *put_byte( unsigned char **ppnPtr, _cbyte nVal ) {
**ppnPtr = nVal;
*ppnPtr += 1;
return *ppnPtr;
}
/**
* \brief Put word to data buffer and increase buffer pointer
* \param ppnPtr data buffer pointer
* \param nVal word number
* \return word from buffer
*/
unsigned char *put_word( unsigned char **ppnPtr, _cword nVal ) {
put_byte( ppnPtr, nVal & 0xFF );
put_byte( ppnPtr, ( nVal & 0xFF00 ) >> 8 );
return *ppnPtr;
}
/**
* \brief Put dword to data buffer and increase buffer pointer
* \param ppnPtr data buffer pointer
* \param nVal dword number
* \return dword from buffer
*/
unsigned char *put_dword( unsigned char **ppnPtr, _cdword nVal ) {
put_byte( ppnPtr, nVal & 0xFF );
put_byte( ppnPtr, ( nVal & 0xFF00 ) >> 8 );
put_byte( ppnPtr, ( nVal & 0xFF0000 ) >> 16 );
put_byte( ppnPtr, ( nVal & 0xFF000000 ) >> 24 );
return *ppnPtr;
}
/**
* \brief Put netword to data buffer and increase buffer pointer
* \param ppnPtr data buffer pointer
* \param nVal netword number
* \return netword from buffer
*/
unsigned char *put_netword( unsigned char **ppnPtr, _cword nVal ) {
put_byte( ppnPtr, ( nVal & 0xFF00 ) >> 8 );
put_byte( ppnPtr, nVal & 0xFF );
return *ppnPtr;
}
static char *skip_whitespace( char *s ) {
while ( *s && isspace( *s ) ) {
s++;
}
return s;
}
static char *skip_nonwhitespace(char *s)
{
while (*s && !isspace(*s)) s++;
return s;
}
/*
* read config file
*/
static int read_config(void)
{
FILE *fp = NULL;
char *s, *t;
char buf[1024];
if ((s = getenv("HOME")) != NULL) {
strcpy(buf, s);
strcat(buf, "/");
strcat(buf, userconfigfilename);
fp = fopen(buf, "r");
}
if ((!fp) && ((fp = fopen(globalconfigfilename, "r")) == NULL))
return(0);
while(fgets(buf, sizeof(buf), fp)) {
buf[strlen(buf)-1] = 0;
s = skip_whitespace(buf);
if (*s == 0 || *s == '#')
continue;
if (!(strncmp(s, "REMOTE", 6))) {
s = skip_nonwhitespace(s);
t = skip_whitespace(s);
s = skip_nonwhitespace(t);
if (*s) *s++ = 0;
strncpy(driver, t, (sizeof(driver) - 1));
t = skip_whitespace(s);
s = skip_nonwhitespace(t);
if (*s) *s++ = 0;
strncpy(hostname, t, (sizeof(hostname) - 1));
t = skip_whitespace(s);
s = skip_nonwhitespace(t);
if (*s) *s++ = 0;
port = strtol(t, NULL, 10);
if (!port)
port = 2662;
continue;
} else if (!(strncmp(s, "TRACELEVEL", 10))) {
t = skip_nonwhitespace(s);
s = skip_whitespace(t);
tracelevel = (int)strtol(s, NULL, 10);
continue;
} else if (!(strncmp(s, "TRACEFILE", 9))) {
t = skip_nonwhitespace(s);
s = skip_whitespace(t);
t = skip_nonwhitespace(s);
if (*t) *t++ = 0;
tracefile = strdup(s);
continue;
}
}
fclose(fp);
return(1);
}
int getPort( void ) {
return port;
}
void setPort( int nPortNumber ) {
port = nPortNumber;
}
char *getHostName( void ) {
return hostname;
}
void setHostName( char *pnHostName ) {
snprintf( hostname, sizeof( hostname ), "%s", pnHostName );
}
/*
* managment of application ids
*/
int capi_remember_applid(unsigned applid, int fd)
{
if (applid >= MAX_APPL)
return -1;
lock_capi_shared();
appids->id[applid].fd = fd;
appids->id[applid].inuse = 1;
unlock_capi_shared();
return 0;
}
unsigned capi_alloc_applid(int fd)
{
unsigned applid;
lock_capi_shared();
for (applid = 1; applid < MAX_APPL; applid++) {
if (appids->id[applid].inuse == 0) {
appids->id[applid].inuse = 1;
appids->id[applid].fd = fd;
appids->id[applid].pid = my_pid;
if (appids->max_id < applid)
appids->max_id = applid;
break;
}
}
if (applid == MAX_APPL)
applid = 0;
unlock_capi_shared();
return applid;
}
void capi_freeapplid(unsigned applid)
{
if (applid < MAX_APPL) {
lock_capi_shared();
appids->id[applid].fd = -1;
appids->id[applid].inuse = 0;
appids->id[applid].pid = 0;
if (appids->max_id == applid) {
for (applid = appids->max_id; applid > 0; applid--) {
if (appids->id[applid].inuse)
break;
}
appids->max_id = applid;
}
unlock_capi_shared();
}
}
int capi_validapplid(unsigned applid)
{
/* no need to lock here */
return ((applid > 0) && (applid < MAX_APPL) && (appids->id[applid].inuse));
}
int capi_applid2fd(unsigned applid)
{
/* no need to lock here */
if (applid < MAX_APPL)
return appids->id[applid].fd;
return -1;
}
/*
* buffer management
*/
struct recvbuffer {
struct recvbuffer *next;
unsigned int datahandle;
unsigned int used;
unsigned int ncci;
unsigned char *buf; /* 128 + MaxSizeB3 */
};
struct applinfo {
unsigned maxbufs;
unsigned nbufs;
size_t recvbuffersize;
struct recvbuffer *buffers;
struct recvbuffer *firstfree;
struct recvbuffer *lastfree;
unsigned char *bufferstart;
};
static struct applinfo *alloc_buffers(
unsigned MaxB3Connection,
unsigned MaxB3Blks,
unsigned MaxSizeB3)
{
struct applinfo *ap;
unsigned nbufs = 2 + MaxB3Connection * (MaxB3Blks + 1);
size_t recvbuffersize = 128 + MaxSizeB3;
unsigned i;
size_t size;
if (recvbuffersize < 2048)
recvbuffersize = 2048;
size = sizeof(struct applinfo);
size += sizeof(struct recvbuffer) * nbufs;
size += recvbuffersize * nbufs;
ap = (struct applinfo *)malloc(size);
if (ap == 0)
return 0;
memset(ap, 0, size);
ap->maxbufs = nbufs;
ap->recvbuffersize = recvbuffersize;
ap->buffers = (struct recvbuffer *)(ap+1);
ap->firstfree = ap->buffers;
ap->bufferstart = (unsigned char *)(ap->buffers+nbufs);
for (i = 0; i < ap->maxbufs; i++) {
ap->buffers[i].next = &ap->buffers[i+1];
ap->buffers[i].used = 0;
ap->buffers[i].ncci = 0;
ap->buffers[i].buf = ap->bufferstart+(recvbuffersize*i);
}
ap->lastfree = &ap->buffers[ap->maxbufs-1];
ap->lastfree->next = 0;
return ap;
}
static void free_buffers(struct applinfo *ap)
{
free(ap);
}
static struct applinfo *applinfo[MAX_APPL];
unsigned char *capi_get_buffer(unsigned applid, size_t *sizep, unsigned *handle)
{
struct applinfo *ap;
struct recvbuffer *buf;
assert(capi_validapplid(applid));
ap = applinfo[applid];
if ((buf = ap->firstfree) == 0)
return 0;
ap->firstfree = buf->next;
buf->next = 0;
buf->used = 1;
ap->nbufs++;
*sizep = ap->recvbuffersize;
*handle = (buf->buf-ap->bufferstart)/ap->recvbuffersize;
return buf->buf;
}
void capi_save_datahandle(unsigned applid, unsigned offset, unsigned datahandle, unsigned ncci)
{
struct applinfo *ap;
struct recvbuffer *buf;
assert(capi_validapplid(applid));
ap = applinfo[applid];
assert(offset < ap->maxbufs);
buf = ap->buffers+offset;
buf->datahandle = datahandle;
buf->ncci = ncci;
}
unsigned capi_return_buffer(unsigned applid, unsigned offset)
{
struct applinfo *ap;
struct recvbuffer *buf;
assert(capi_validapplid(applid));
ap = applinfo[applid];
assert(offset < ap->maxbufs);
buf = ap->buffers+offset;
assert(buf->used == 1);
assert(buf->next == 0);
if (ap->lastfree) {
ap->lastfree->next = buf;
ap->lastfree = buf;
} else {
ap->firstfree = ap->lastfree = buf;
}
buf->used = 0;
buf->ncci = 0;
assert(ap->nbufs-- > 0);
return buf->datahandle;
}
void cleanup_buffers_for_ncci(unsigned applid, unsigned ncci)
{
struct applinfo *ap;
unsigned i;
assert(capi_validapplid(applid));
ap = applinfo[applid];
for (i = 0; i < ap->maxbufs; i++) {
if (ap->buffers[i].used) {
assert(ap->buffers[i].ncci != 0);
if (ap->buffers[i].ncci == ncci) {
capi_return_buffer(applid, i);
}
}
}
}
void cleanup_buffers_for_plci(unsigned applid, unsigned plci)
{
struct applinfo *ap;
unsigned i;
assert(capi_validapplid(applid));
ap = applinfo[applid];
for (i = 0; i < ap->maxbufs; i++) {
if (ap->buffers[i].used) {
assert(ap->buffers[i].ncci != 0);
if ((ap->buffers[i].ncci & 0xffff) == plci) {
capi_return_buffer(applid, i);
}
}
}
}
/*
* CAPI2.0 functions
*/
/** Simple single-linked list for modules */
struct sList {
struct sModule *psMod;
struct sList *psNext;
};
/* Active module pointer */
static struct sModule *psModule = NULL;
/* Global loaded module list */
static struct sList *psModuleList = NULL;
/**
* \brief Register Module - add it to psModuleList
* \param psMod new module pointer
* \return error code. 0 on success, else error occurred
*/
static int RegisterModule( struct sModule *psMod ) {
struct sList *psList;
if ( psMod == NULL || psMod -> pnName == NULL || psMod -> nVersion != MODULE_LOADER_VERSION || psMod -> psOperations == NULL ) {
return -1;
}
if ( psModuleList == NULL ) {
psModuleList = malloc( sizeof( struct sList ) );
if ( psModuleList != NULL ) {
psModuleList -> psMod = psMod;
psModuleList -> psNext = NULL;
}
return psModuleList != NULL ? 0 : -1;
}
psList = psModuleList;
while ( psList -> psNext ) {
psList = psList -> psNext;
}
psList -> psNext = malloc( sizeof( struct sList ) );
if ( psList -> psNext != NULL ) {
psList -> psNext -> psMod = psMod;
psList -> psNext -> psNext = NULL;
return 0;
}
return -2;
}
/**
* \brief Try to load the module and register it
* \param pnName full path name to module
* \return error code, see RegisterModule
*/
static int LoadModule( char *pnName ) {
struct sModule *psMod;
void *pHandle;
typedef int ( *InitModule )( struct sModule *psModule );
InitModule initModule;
/* Try to open module */
pHandle = dlopen( pnName, RTLD_GLOBAL | RTLD_LAZY );
if ( pHandle == NULL ) {
char etxt[1024];
snprintf(etxt, 1024, "Could not open module %s - %s!\n", pnName, dlerror());
CapiDebug(1, etxt);
return -1;
}
/* Find InitModule function within module */
initModule = dlsym( pHandle, "InitModule" );
if ( initModule == NULL ) {
CapiDebug( 1, "Module has no InitModule!\n" );
dlclose( pHandle );
return -2;
}
/* Create new module structure */
psMod = malloc( sizeof( struct sModule ) );
if ( psMod == NULL ) {
CapiDebug( 1, "Could not alloc memory for module structure!\n" );
dlclose( pHandle );
return -2;
}
/* Initialize module */
if ( initModule( psMod ) != 0 ) {
CapiDebug( 1, "Could not init!\n" );
free( psMod );
psMod = NULL;
dlclose( pHandle );
return -3;
}
/* Success, add handle to module structure */
psMod -> pHandle = pHandle;
/* register module */
return RegisterModule( psMod );
}
/**
* \brief Initialize module
* \param pnModuleDir directory where we can find the modules
*/
static void InitModules( char *pnModuleDir ) {
DIR *psDir;
struct dirent *psEntry;
char *pnFullName;
int nLen, pf_len;
char mod_vers[8];
/* try to open module directory */
psDir = opendir( pnModuleDir );
if ( psDir != NULL ) {
/* read entry by entry */
pf_len = snprintf(mod_vers, 8, ".so.%d", MODULE_LOADER_VERSION);
while ( ( psEntry = readdir( psDir ) ) != NULL ) {
/* skip ".", ".." and files which do not end with "so" */
nLen = strlen( psEntry -> d_name );
switch ( nLen ) {
case 1:
if ( psEntry -> d_name[ 0 ] == '.' ) {
continue;
}
break;
case 2:
if ( psEntry -> d_name[ 0 ] == '.' && psEntry -> d_name[ 1 ] == '.' ) {
continue;
}
break;
default:
if ( strcmp( psEntry -> d_name + nLen - pf_len, mod_vers) ) {
continue;
}
break;
}
/* len of complete path + filename */
nLen = strlen( pnModuleDir ) + strlen( psEntry -> d_name ) + 2;
pnFullName = malloc( nLen );
if ( pnFullName != NULL ) {
/* create full name */
snprintf( pnFullName, nLen, "%s/%s", pnModuleDir, psEntry -> d_name );
/* load module */
LoadModule( pnFullName );
/* free full name */
free( pnFullName );
pnFullName = NULL;
}
}
/* close directory */
closedir( psDir );
}
}
unsigned capi20_isinstalled( void ) {
struct sList *psList;
/* check if we are already opened */
if ( capi_fd >= 0 ) {
return CapiNoError;
}
/* Load and initialize modules */
InitModules( LIBDIR );
if ( psModuleList == NULL ) {
/* if no modules are loaded, psModuleList is NULL, abort */
return CapiRegNotInstalled;
}
/* read configuration file */
read_config();
/* no special driver requested, auto-detect */
if ( strlen( driver ) <= 0 ) {
/* backwards-compatible: check standard interface fist */
psList = psModuleList;
while ( psList != NULL ) {
if ( !strcasecmp( psList -> psMod -> pnName, "standard" ) ) {
psModule = psList -> psMod;
capi_fd = psModule -> psOperations -> IsInstalled();
if ( capi_fd >= 0 ) {
/* no error */
return CapiNoError;
}
}
psList = psList -> psNext;
}
/* no standard device detect, try the other modules */
psList = psModuleList;
while ( psList != NULL ) {
if ( strcasecmp( psList -> psMod -> pnName, "standard" ) ) {
psModule = psList -> psMod;
capi_fd = psModule -> psOperations -> IsInstalled();
if ( capi_fd >= 0 ) {
/* no error */
return CapiNoError;
}
}
psList = psList -> psNext;
}
} else {
/* Find requested driver in list */
psList = psModuleList;
while ( psList != NULL ) {
if ( !strcasecmp( psList -> psMod -> pnName, driver ) ) {
psModule = psList -> psMod;
capi_fd = psModule -> psOperations -> IsInstalled();
if ( capi_fd >= 0 ) {
/* no error */
return CapiNoError;
}
break;
}
psList = psList -> psNext;
}
}
/* uhh, not installed */
return CapiRegNotInstalled;
}
unsigned capi20_register( unsigned MaxB3Connection, unsigned MaxB3Blks, unsigned MaxSizeB3, unsigned *ApplID ) {
unsigned int applid = 0;
int fd = -1;
*ApplID = 0;
if (capi20_isinstalled() != CapiNoError)
return CapiRegNotInstalled;
fd = psModule -> psOperations -> Register( MaxB3Connection, MaxB3Blks, MaxSizeB3, &applid );
if ( fd < 0 ) {
return CapiRegOSResourceErr;
}
if (capi_remember_applid(applid, fd) < 0) {
close(fd);
return CapiRegOSResourceErr;
}
applinfo[applid] = alloc_buffers(MaxB3Connection, MaxB3Blks, MaxSizeB3);
if (applinfo[applid] == 0) {
close(fd);
return CapiRegOSResourceErr;
}
*ApplID = applid;
return CapiNoError;
}
unsigned
capi20_release (unsigned ApplID)
{
int fd;
if (capi20_isinstalled() != CapiNoError)
return CapiRegNotInstalled;
if (!capi_validapplid(ApplID))
return CapiIllAppNr;
if (psModule -> psOperations -> Release != NULL) {
psModule -> psOperations -> Release(capi_applid2fd(ApplID), ApplID);
}
fd = capi_applid2fd(ApplID);
/* maybe closed by the lower level */
if (fd > -1)
(void)close(fd);
capi_freeapplid(ApplID);
free_buffers(applinfo[ApplID]);
applinfo[ApplID] = NULL;
return CapiNoError;
}
/**
* \brief Process data message (should be moved up to capi20.c as it is general)
* \param pnMsg message data pointer
* \param nApplId application id
* \param nCommand major packet command
* \param nSubCommand minor packet command
* \param nLen len of message
* \return length of full packet
*/
int capi_processMessage( unsigned char *pnMsg, unsigned nApplId, unsigned nCommand, unsigned nSubCommand, int nLen ) {
/* DATA_B3_REQ specific:
* we have to copy the buffer and patch the buffer address!
*/
if ( nCommand == CAPI_DATA_B3 ) {
if ( nSubCommand == CAPI_REQ ) {
int nDataLen = CAPIMSG_DATALEN( pnMsg );
void *pDataPtr;
if ( sizeof( void * ) != 4 ) {
if ( nLen >= 30 ) {
/* 64Bit CAPI-extension */
u_int64_t nData64;
memcpy( &nData64, pnMsg + 22, sizeof( u_int64_t ) );
if ( nData64 != 0 ) {
pDataPtr = ( void * )( unsigned long ) nData64;
} else {
/* Assume data after message */
pDataPtr = pnMsg + nLen;
}
} else {
/* Assume data after message */
pDataPtr = pnMsg + nLen;
}
} else {
u_int32_t nData;
memcpy( &nData, pnMsg + 12, sizeof( u_int32_t ) );
if ( nData != 0 ) {
pDataPtr = ( void * )( ( unsigned long ) nData );
} else {
pDataPtr = pnMsg + nLen;
}
}
if ( nLen + nDataLen > SEND_BUFSIZ ) {
return CapiMsgOSResourceErr;
}
memcpy( pnMsg + nLen, pDataPtr, nDataLen );
nLen += nDataLen;
} else if ( nSubCommand == CAPI_RESP ) {
capimsg_setu16( pnMsg, 12, capi_return_buffer( nApplId, CAPIMSG_U16( pnMsg, 12 ) ) );
}
}
if ( nCommand == CAPI_DISCONNECT_B3 && nSubCommand == CAPI_RESP ) {
cleanup_buffers_for_ncci( nApplId, CAPIMSG_U32( pnMsg, 8 ) );
}
return nLen;
}
unsigned capi20_put_message( unsigned ApplID, unsigned char *Msg ) {
if (capi20_isinstalled() != CapiNoError) {
return CapiRegNotInstalled;
}
if (!capi_validapplid(ApplID)) {
return CapiIllAppNr;
}
return psModule->psOperations->PutMessage(capi_applid2fd(ApplID), ApplID, Msg);
}
unsigned capi20_get_message( unsigned ApplID, unsigned char **Buf ) {
if (capi20_isinstalled() != CapiNoError)
return CapiRegNotInstalled;
if (!capi_validapplid(ApplID))
return CapiIllAppNr;
return psModule->psOperations->GetMessage(capi_applid2fd(ApplID), ApplID, Buf);
}
unsigned char *capi20_get_manufacturer( unsigned Ctrl, unsigned char *Buf ) {
if (capi20_isinstalled() != CapiNoError)
return 0;
return psModule -> psOperations -> GetManufactor( capi_fd, Ctrl, Buf );
}
unsigned char *
capi20_get_version(unsigned Ctrl, unsigned char *Buf)
{
if (capi20_isinstalled() != CapiNoError)
return 0;
return psModule -> psOperations -> GetVersion( capi_fd, Ctrl, Buf );
}
unsigned char *
capi20_get_serial_number(unsigned Ctrl, unsigned char *Buf)
{
if (capi20_isinstalled() != CapiNoError)
return 0;
return psModule -> psOperations -> GetSerialNumber( capi_fd, Ctrl, Buf );
}
unsigned
capi20_get_profile(unsigned Ctrl, unsigned char *Buf)
{
if (capi20_isinstalled() != CapiNoError)
return CapiMsgNotInstalled;
return psModule -> psOperations -> GetProfile( capi_fd, Ctrl, Buf );
}
/*
* functions added to the CAPI2.0 spec
*/
unsigned
capi20_waitformessage(unsigned ApplID, struct timeval *TimeOut)
{
int fd;
fd_set rfds;
if (capi20_isinstalled() != CapiNoError)
return CapiRegNotInstalled;
if (!capi_validapplid(ApplID))
return CapiIllAppNr;
/* default method */
fd = capi_applid2fd(ApplID);
if (psModule->psOperations->waitformessage)
return psModule->psOperations->waitformessage(fd, ApplID, TimeOut);
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
if (select(fd + 1, &rfds, NULL, NULL, TimeOut) < 1)
return CapiReceiveQueueEmpty;
return CapiNoError;
}
int
capi20_fileno(unsigned ApplID)
{
return capi_applid2fd(ApplID);
}
/*
* Extensions for middleware
*/
int
capi20ext_get_flags(unsigned ApplID, unsigned *flagsptr)
{
if ( psModule && psModule -> psOperations -> GetFlags ) {
return psModule -> psOperations -> GetFlags( ApplID, flagsptr );
}
return CapiMsgOSResourceErr;
}
int
capi20ext_set_flags(unsigned ApplID, unsigned flags)
{
if ( psModule && psModule -> psOperations -> SetFlags ) {
return psModule -> psOperations -> SetFlags( ApplID, flags );
}
return CapiMsgOSResourceErr;
}
int
capi20ext_clr_flags(unsigned ApplID, unsigned flags)
{
if ( psModule && psModule -> psOperations -> ClearFlags ) {
return psModule -> psOperations -> ClearFlags( ApplID, flags );
}
return CapiMsgOSResourceErr;
}
char *
capi20ext_get_tty_devname(unsigned applid, unsigned ncci, char *buf, size_t size)
{
if ( psModule && psModule -> psOperations -> GetTtyDeviceName ) {
return psModule -> psOperations -> GetTtyDeviceName( applid, ncci, buf, size );
}
return NULL;
}
char *capi20ext_get_raw_devname( unsigned applid, unsigned ncci, char *buf, size_t size ) {
if ( psModule && psModule -> psOperations -> GetRawDeviceName ) {
return psModule -> psOperations -> GetRawDeviceName( applid, ncci, buf, size );
}
return NULL;
}
int capi20ext_ncci_opencount( unsigned applid, unsigned ncci ) {
if ( psModule && psModule -> psOperations -> GetNcciOpenCount ) {
return psModule -> psOperations -> GetNcciOpenCount( applid, ncci );
}
return CapiMsgOSResourceErr;
}
static void initlib( void ) __attribute__( ( constructor ) );
static void exitlib( void ) __attribute__( ( destructor ) );
static void initlib( void ) {
int i, ret;
mode_t old_um;
struct stat stats;
int need_init = 0;
char sem_name[40], shr_name[40];
if (!capi_sem) {
snprintf(sem_name, 32, "%s.v%08x", CAPI20_SEMAPHORE_NAME, CAPI20_SHARED_MEM_VERSION);
snprintf(shr_name, 32, "%s.v%08x", CAPI20_SHARED_MEM_NAME, CAPI20_SHARED_MEM_VERSION);
old_um = umask(0);
capi_sem = sem_open(sem_name, O_CREAT, CAPI20_SHARED_MEM_MODE, 1);
shm_mem_fd = shm_open(shr_name, O_CREAT | O_RDWR, CAPI20_SHARED_MEM_MODE);
umask(old_um);
if (capi_sem == SEM_FAILED) {
fprintf(stderr, "sem_open(%s, ...) failed - %s\n", sem_name, strerror(errno));
exit(1);
}
if (shm_mem_fd < 0) {
fprintf(stderr, "shm_open(%s, ...) failed - %s\n", shr_name, strerror(errno));
exit(1);
}
lock_capi_shared();
ret = fstat(shm_mem_fd, &stats);
if (ret) {
fprintf(stderr, "fstat(shm_mem_fd, &stats) failed - %s\n", strerror(errno));
exit(1);
}
if (stats.st_size == 0) {
/* We are the first user - so set size and init it */
ret = ftruncate(shm_mem_fd, CAPI20_SHARED_MEM_SIZE);
if (ret) {
fprintf(stderr, "ftruncate(shm_mem_fd, %zd) failed - %s\n", CAPI20_SHARED_MEM_SIZE, strerror(errno));
exit(1);
}
need_init = 1;
}
appids = mmap(NULL, CAPI20_SHARED_MEM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_mem_fd, 0);
if (appids == MAP_FAILED) {
fprintf(stderr, "mmap shm_mem_fd (%d) failed - %s\n", shm_mem_fd, strerror(errno));
exit(1);
}
if (need_init) {
for ( i = 0; i < MAX_APPL; i++ ) {
appids->id[i].fd = -1;
}
appids->init_done = 1;
}
} else
lock_capi_shared();
appids->usage++;
my_pid = getpid();
unlock_capi_shared();
}
static void exitlib( void ) {
int i, last_inuse = 0;
if ( capi_fd >= 0 ) {
close( capi_fd );
capi_fd = -1;
}
lock_capi_shared();
appids->usage--;
for (i = 0; i < MAX_APPL; i++ ) {
if (appids->id[i].pid == my_pid) {
appids->id[i].pid = 0;
appids->id[i].inuse = 0;
appids->id[i].fd = -1;
} else if (appids->id[i].inuse)
last_inuse = i;
}
appids->max_id = last_inuse;
munmap(appids, CAPI20_SHARED_MEM_SIZE);
unlock_capi_shared();
}