isdn4k-utils/capi20/convert.c

485 lines
14 KiB
C

/*
* $Id: convert.c,v 1.6 1999/09/10 17:20:33 calle Exp $
*
* $Log: convert.c,v $
* Revision 1.6 1999/09/10 17:20:33 calle
* Last changes for proposed standards (CAPI 2.0):
* - AK1-148 "Linux Extention"
* - AK1-155 "Support of 64-bit Applications"
*
* Revision 1.5 1999/09/06 17:40:07 calle
* Changes for CAPI 2.0 Spec.
*
* Revision 1.4 1998/10/23 12:20:44 fritz
* Added some missing functions.
*
* Revision 1.3 1998/08/30 09:57:21 calle
* I hope it is know readable for everybody.
*
* Revision 1.1 1998/08/25 16:33:23 calle
* Added CAPI2.0 library. First Version.
*
*/
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <stddef.h>
#include <time.h>
#include <ctype.h>
#include "capi20.h"
typedef struct {
int typ;
unsigned off;
} _cdef;
#define _CBYTE 1
#define _CWORD 2
#define _CDWORD 3
#define _CQWORD 4
#define _CSTRUCT 5
#define _CMSTRUCT 6
#define _CEND 7
static _cdef cdef[] = {
/*00*/{_CEND},
/*01*/{_CEND},
/*02*/{_CEND},
/*03*/{_CDWORD, offsetof(_cmsg,adr.adrController) },
/*04*/{_CMSTRUCT, offsetof(_cmsg,AdditionalInfo) },
/*05*/{_CSTRUCT, offsetof(_cmsg,B1configuration) },
/*06*/{_CWORD, offsetof(_cmsg,B1protocol) },
/*07*/{_CSTRUCT, offsetof(_cmsg,B2configuration) },
/*08*/{_CWORD, offsetof(_cmsg,B2protocol) },
/*09*/{_CSTRUCT, offsetof(_cmsg,B3configuration) },
/*0a*/{_CWORD, offsetof(_cmsg,B3protocol) },
/*0b*/{_CSTRUCT, offsetof(_cmsg,BC) },
/*0c*/{_CSTRUCT, offsetof(_cmsg,BChannelinformation) },
/*0d*/{_CMSTRUCT, offsetof(_cmsg,BProtocol) },
/*0e*/{_CSTRUCT, offsetof(_cmsg,CalledPartyNumber) },
/*0f*/{_CSTRUCT, offsetof(_cmsg,CalledPartySubaddress) },
/*10*/{_CSTRUCT, offsetof(_cmsg,CallingPartyNumber) },
/*11*/{_CSTRUCT, offsetof(_cmsg,CallingPartySubaddress) },
/*12*/{_CDWORD, offsetof(_cmsg,CIPmask) },
/*13*/{_CDWORD, offsetof(_cmsg,CIPmask2) },
/*14*/{_CWORD, offsetof(_cmsg,CIPValue) },
/*15*/{_CDWORD, offsetof(_cmsg,Class) },
/*16*/{_CSTRUCT, offsetof(_cmsg,ConnectedNumber) },
/*17*/{_CSTRUCT, offsetof(_cmsg,ConnectedSubaddress) },
/*18*/{_CDWORD, offsetof(_cmsg,Data32) },
/*19*/{_CWORD, offsetof(_cmsg,DataHandle) },
/*1a*/{_CWORD, offsetof(_cmsg,DataLength) },
/*1b*/{_CSTRUCT, offsetof(_cmsg,FacilityConfirmationParameter) },
/*1c*/{_CSTRUCT, offsetof(_cmsg,Facilitydataarray) },
/*1d*/{_CSTRUCT, offsetof(_cmsg,FacilityIndicationParameter) },
/*1e*/{_CSTRUCT, offsetof(_cmsg,FacilityRequestParameter) },
/*1f*/{_CSTRUCT, offsetof(_cmsg,FacilityResponseParameters) },
/*20*/{_CWORD, offsetof(_cmsg,FacilitySelector) },
/*21*/{_CWORD, offsetof(_cmsg,Flags) },
/*22*/{_CDWORD, offsetof(_cmsg,Function) },
/*23*/{_CSTRUCT, offsetof(_cmsg,HLC) },
/*24*/{_CWORD, offsetof(_cmsg,Info) },
/*25*/{_CSTRUCT, offsetof(_cmsg,InfoElement) },
/*26*/{_CDWORD, offsetof(_cmsg,InfoMask) },
/*27*/{_CWORD, offsetof(_cmsg,InfoNumber) },
/*28*/{_CSTRUCT, offsetof(_cmsg,Keypadfacility) },
/*29*/{_CSTRUCT, offsetof(_cmsg,LLC) },
/*2a*/{_CSTRUCT, offsetof(_cmsg,ManuData) },
/*2b*/{_CDWORD, offsetof(_cmsg,ManuID) },
/*2c*/{_CSTRUCT, offsetof(_cmsg,NCPI) },
/*2d*/{_CWORD, offsetof(_cmsg,Reason) },
/*2e*/{_CWORD, offsetof(_cmsg,Reason_B3) },
/*2f*/{_CWORD, offsetof(_cmsg,Reject) },
/*30*/{_CSTRUCT, offsetof(_cmsg,Useruserdata) },
};
static unsigned char *cpars[] = {
/*00*/ 0,
/*01 ALERT_REQ*/
(unsigned char*)"\x03\x04\x0c\x28\x30\x1c\x01\x01",
/*02 CONNECT_REQ*/
(unsigned char*)"\x03\x14\x0e\x10\x0f\x11\x0d\x06\x08\x0a\x05\x07\x09\x01\x0b\x29\x23\x04\x0c\x28\x30\x1c\x01\x01",
/*03*/ 0,
/*04 DISCONNECT_REQ*/
(unsigned char*)"\x03\x04\x0c\x28\x30\x1c\x01\x01",
/*05 LISTEN_REQ*/
(unsigned char*)"\x03\x26\x12\x13\x10\x11\x01",
/*06*/ 0,
/*07*/ 0,
/*08 INFO_REQ*/
(unsigned char*)"\x03\x0e\x04\x0c\x28\x30\x1c\x01\x01",
/*09 FACILITY_REQ*/
(unsigned char*)"\x03\x20\x1e\x01",
/*0a SELECT_B_PROTOCOL_REQ*/
(unsigned char*)"\x03\x0d\x06\x08\x0a\x05\x07\x09\x01\x01",
/*0b CONNECT_B3_REQ*/
(unsigned char*)"\x03\x2c\x01",
/*0c*/ 0,
/*0d DISCONNECT_B3_REQ*/
(unsigned char*)"\x03\x2c\x01",
/*0e*/ 0,
/*0f DATA_B3_REQ*/
(unsigned char*)"\x03\x18\x1a\x19\x21\x31\x01",
/*10 RESET_B3_REQ*/
(unsigned char*)"\x03\x2c\x01",
/*11*/ 0,
/*12*/ 0,
/*13 ALERT_CONF*/
(unsigned char*)"\x03\x24\x01",
/*14 CONNECT_CONF*/
(unsigned char*)"\x03\x24\x01",
/*15*/ 0,
/*16 DISCONNECT_CONF*/
(unsigned char*)"\x03\x24\x01",
/*17 LISTEN_CONF*/
(unsigned char*)"\x03\x24\x01",
/*18 MANUFACTURER_REQ*/
(unsigned char*)"\x03\x2b\x15\x22\x2a\x01",
/*19*/ 0,
/*1a INFO_CONF*/
(unsigned char*)"\x03\x24\x01",
/*1b FACILITY_CONF*/
(unsigned char*)"\x03\x24\x20\x1b\x01",
/*1c SELECT_B_PROTOCOL_CONF*/
(unsigned char*)"\x03\x24\x01",
/*1d CONNECT_B3_CONF*/
(unsigned char*)"\x03\x24\x01",
/*1e*/ 0,
/*1f DISCONNECT_B3_CONF*/
(unsigned char*)"\x03\x24\x01",
/*20*/ 0,
/*21 DATA_B3_CONF*/
(unsigned char*)"\x03\x19\x24\x01",
/*22 RESET_B3_CONF*/
(unsigned char*)"\x03\x24\x01",
/*23*/ 0,
/*24*/ 0,
/*25*/ 0,
/*26 CONNECT_IND*/
(unsigned char*)"\x03\x14\x0e\x10\x0f\x11\x0b\x29\x23\x04\x0c\x28\x30\x1c\x01\x01",
/*27 CONNECT_ACTIVE_IND*/
(unsigned char*)"\x03\x16\x17\x29\x01",
/*28 DISCONNECT_IND*/
(unsigned char*)"\x03\x2d\x01",
/*29*/ 0,
/*2a MANUFACTURER_CONF*/
(unsigned char*)"\x03\x2b\x15\x22\x2a\x01",
/*2b*/ 0,
/*2c INFO_IND*/
(unsigned char*)"\x03\x27\x25\x01",
/*2d FACILITY_IND*/
(unsigned char*)"\x03\x20\x1d\x01",
/*2e*/ 0,
/*2f CONNECT_B3_IND*/
(unsigned char*)"\x03\x2c\x01",
/*30 CONNECT_B3_ACTIVE_IND*/
(unsigned char*)"\x03\x2c\x01",
/*31 DISCONNECT_B3_IND*/
(unsigned char*)"\x03\x2e\x2c\x01",
/*32*/ 0,
/*33 DATA_B3_IND*/
(unsigned char*)"\x03\x18\x1a\x19\x21\x31\x01",
/*34 RESET_B3_IND*/
(unsigned char*)"\x03\x2c\x01",
/*35 CONNECT_B3_T90_ACTIVE_IND*/
(unsigned char*)"\x03\x2c\x01",
/*36*/ 0,
/*37*/ 0,
/*38 CONNECT_RESP*/
(unsigned char*)"\x03\x2f\x0d\x06\x08\x0a\x05\x07\x09\x01\x16\x17\x29\x04\x0c\x28\x30\x1c\x01\x01",
/*39 CONNECT_ACTIVE_RESP*/
(unsigned char*)"\x03\x01",
/*3a DISCONNECT_RESP*/
(unsigned char*)"\x03\x01",
/*3b*/ 0,
/*3c MANUFACTURER_IND*/
(unsigned char*)"\x03\x2b\x15\x22\x2a\x01",
/*3d*/ 0,
/*3e INFO_RESP*/
(unsigned char*)"\x03\x01",
/*3f FACILITY_RESP*/
(unsigned char*)"\x03\x20\x1f\x01",
/*40*/ 0,
/*41 CONNECT_B3_RESP*/
(unsigned char*)"\x03\x2f\x2c\x01",
/*42 CONNECT_B3_ACTIVE_RESP*/
(unsigned char*)"\x03\x01",
/*43 DISCONNECT_B3_RESP*/
(unsigned char*)"\x03\x01",
/*44*/ 0,
/*45 DATA_B3_RESP*/
(unsigned char*)"\x03\x19\x01",
/*46 RESET_B3_RESP*/
(unsigned char*)"\x03\x01",
/*47 CONNECT_B3_T90_ACTIVE_RESP*/
(unsigned char*)"\x03\x01",
/*48*/ 0,
/*49*/ 0,
/*4a*/ 0,
/*4b*/ 0,
/*4c*/ 0,
/*4d*/ 0,
/*4e MANUFACTURER_RESP*/
(unsigned char*)"\x03\x2b\x15\x22\x2a\x01",
};
/*-------------------------------------------------------*/
#define byteTLcpy(x,y) *(_cbyte *)(x)=*(_cbyte *)(y);
#define wordTLcpy(x,y) *(_cword *)(x)=*(_cword *)(y);
#define dwordTLcpy(x,y) memcpy(x,y,4);
#define qwordTLcpy(x,y) memcpy(x,y,8);
#define structTLcpy(x,y,l) memcpy (x,y,l)
#define structTLcpyovl(x,y,l) memmove (x,y,l)
#define byteTRcpy(x,y) *(_cbyte *)(y)=*(_cbyte *)(x);
#define wordTRcpy(x,y) *(_cword *)(y)=*(_cword *)(x);
#define dwordTRcpy(x,y) memcpy(y,x,4);
#define qwordTRcpy(x,y) memcpy(y,x,8);
#define structTRcpy(x,y,l) memcpy (y,x,l)
#define structTRcpyovl(x,y,l) memmove (y,x,l)
/*-------------------------------------------------------*/
static unsigned command_2_index (unsigned c, unsigned sc) {
if (c & 0x80) c = 0x9+(c&0x0f);
else if (c<=0x0f) ;
else if (c==0x41) c = 0x9+0x1;
else if (c==0xff) c = 0x00;
return (sc&3)*(0x9+0x9)+c;
}
/*-------------------------------------------------------*/
#define TYP (cdef[cmsg->par[cmsg->p]].typ)
#define OFF (((char *)cmsg)+cdef[cmsg->par[cmsg->p]].off)
static void jumpcstruct (_cmsg *cmsg) {
unsigned layer;
for (cmsg->p++,layer=1; layer;) {
assert (cmsg->p);
cmsg->p++;
switch (TYP) {
case _CMSTRUCT:
layer++;
break;
case _CEND:
layer--;
break;
}
}
}
/*-------------------------------------------------------*/
static void PARS_2_MESSAGE (_cmsg *cmsg) {
for (;TYP != _CEND; cmsg->p++) {
switch (TYP) {
case _CBYTE:
byteTLcpy (cmsg->m+cmsg->l, OFF);
cmsg->l++;
break;
case _CWORD:
wordTLcpy (cmsg->m+cmsg->l, OFF);
cmsg->l+=2;
break;
case _CDWORD:
dwordTLcpy (cmsg->m+cmsg->l, OFF);
cmsg->l+=4;
break;
case _CQWORD:
qwordTLcpy (cmsg->m+cmsg->l, OFF);
cmsg->l+=4;
break;
case _CSTRUCT:
if (*(CAPI_MESSAGE *) OFF == 0) {
*(cmsg->m+cmsg->l)='\0';
cmsg->l++;
}
else if(**(_cstruct*)OFF != 0xff) {
structTLcpy (cmsg->m+cmsg->l, *(_cstruct*)OFF, 1+**(_cstruct*)OFF);
cmsg->l+=1+**(_cstruct*)OFF;
}
else {
_cstruct s = *(_cstruct*)OFF;
structTLcpy (cmsg->m+cmsg->l, s, 3+*(_cword*)(s+1));
cmsg->l+= 3+*(_cword*)(s+1);
}
break;
case _CMSTRUCT:
/*----- Metastruktur 0 -----*/
if (*(_cmstruct*)OFF == CAPI_DEFAULT) {
*(cmsg->m+cmsg->l)='\0';
cmsg->l++;
jumpcstruct (cmsg);
}
/*----- Metastruktur wird composed -----*/
else {
unsigned _l = cmsg->l;
unsigned _ls;
cmsg->l++;
cmsg->p++;
PARS_2_MESSAGE (cmsg);
_ls = cmsg->l-_l-1;
if (_ls < 255)
(cmsg->m+_l)[0] = (_cbyte)_ls;
else {
structTLcpyovl (cmsg->m+_l+3, cmsg->m+_l+1, _ls);
(cmsg->m+_l)[0] = 0xff;
wordTLcpy (cmsg->m+_l+1, &_ls);
cmsg->l+=2;
}
}
break;
}
}
}
/*-------------------------------------------------------*/
unsigned capi_cmsg2message (_cmsg *cmsg, CAPI_MESSAGE msg)
{
cmsg->m = msg;
cmsg->l = 8;
cmsg->p = 0;
cmsg->par = cpars [command_2_index (cmsg->Command,cmsg->Subcommand)];
if ( cmsg->Command == CAPI_DATA_B3
&& (cmsg->Subcommand == CAPI_REQ || cmsg->Subcommand == CAPI_IND)) {
if (sizeof(void *) == 4) {
cmsg->Data32 = (_cdword)cmsg->Data;
cmsg->Data64 = 0;
} else {
cmsg->Data32 = 0;
cmsg->Data64 = (_cqword)cmsg->Data;
}
}
PARS_2_MESSAGE (cmsg);
wordTLcpy (msg+0, &cmsg->l);
byteTLcpy (cmsg->m+4, &cmsg->Command);
byteTLcpy (cmsg->m+5, &cmsg->Subcommand);
wordTLcpy (cmsg->m+2, &cmsg->ApplId);
wordTLcpy (cmsg->m+6, &cmsg->Messagenumber);
return 0;
}
/*-------------------------------------------------------*/
static void MESSAGE_2_PARS (_cmsg *cmsg) {
for (;TYP != _CEND; cmsg->p++) {
switch (TYP) {
case _CBYTE:
byteTRcpy (cmsg->m+cmsg->l, OFF);
cmsg->l++;
break;
case _CWORD:
wordTRcpy (cmsg->m+cmsg->l, OFF);
cmsg->l+=2;
break;
case _CDWORD:
dwordTRcpy (cmsg->m+cmsg->l, OFF);
cmsg->l+=4;
break;
case _CQWORD:
qwordTRcpy (cmsg->m+cmsg->l, OFF);
cmsg->l+=8;
break;
case _CSTRUCT:
*(CAPI_MESSAGE *)OFF = cmsg->m+cmsg->l;
if (cmsg->m[cmsg->l] != 0xff)
cmsg->l+= 1+ cmsg->m[cmsg->l];
else
cmsg->l+= 3+ *(_cword *)(cmsg->m+cmsg->l+1);
break;
case _CMSTRUCT:
/*----- Metastruktur 0 -----*/
if (cmsg->m[cmsg->l] == '\0') {
*(_cmstruct*)OFF = CAPI_DEFAULT;
cmsg->l++;
jumpcstruct (cmsg);
}
else {
unsigned _l = cmsg->l;
*(_cmstruct*)OFF = CAPI_COMPOSE;
cmsg->l = (cmsg->m+_l)[0] == 255 ? cmsg->l+3 : cmsg->l+1;
cmsg->p++;
MESSAGE_2_PARS (cmsg);
}
break;
}
}
}
/*-------------------------------------------------------*/
unsigned capi_message2cmsg (_cmsg *cmsg, CAPI_MESSAGE msg)
{
memset (cmsg, 0, sizeof(_cmsg));
cmsg->m = msg;
cmsg->l = 8;
cmsg->p = 0;
byteTRcpy (cmsg->m+4, &cmsg->Command);
byteTRcpy (cmsg->m+5, &cmsg->Subcommand);
cmsg->par = cpars [command_2_index (cmsg->Command,cmsg->Subcommand)];
MESSAGE_2_PARS (cmsg);
if ( cmsg->Command == CAPI_DATA_B3
&& (cmsg->Subcommand == CAPI_REQ || cmsg->Subcommand == CAPI_IND)) {
if (sizeof(void *) == 4) {
cmsg->Data = (void *)cmsg->Data32;
} else {
cmsg->Data = (void *)cmsg->Data64;
}
}
wordTRcpy (msg+0, &cmsg->l);
wordTRcpy (cmsg->m+2, &cmsg->ApplId);
wordTRcpy (cmsg->m+6, &cmsg->Messagenumber);
return 0;
}
/*-------------------------------------------------------*/
unsigned capi_cmsg_answer (_cmsg *cmsg)
{
cmsg->Subcommand |= 0x01;
return 0;
}
/*-------------------------------------------------------*/
unsigned capi20_cmsg_header (_cmsg *cmsg, unsigned _ApplId,
_cbyte _Command, _cbyte _Subcommand,
_cword _Messagenumber, _cdword _Controller) {
memset (cmsg, 0, sizeof(_cmsg));
cmsg->ApplId = _ApplId ;
cmsg->Command = _Command ;
cmsg->Subcommand = _Subcommand ;
cmsg->Messagenumber = _Messagenumber;
cmsg->adr.adrController = _Controller ;
return 0;
}
/*-------------------------------------------------------*/
unsigned capi20_put_cmsg (_cmsg *cmsg)
{
static unsigned char msg[2048];
capi_cmsg2message(cmsg, (CAPI_MESSAGE)msg);
return capi20_put_message((CAPI_MESSAGE)msg, cmsg->ApplId);
}
/*-------------------------------------------------------*/
unsigned capi20_get_cmsg (_cmsg *cmsg, unsigned applid)
{
MESSAGE_EXCHANGE_ERROR rtn;
CAPI_MESSAGE msg;
rtn = capi20_get_message(applid, &msg);
if (rtn == 0x0000)
capi_message2cmsg(cmsg, msg);
return rtn;
}