mISDN/drivers/isdn/hardware/mISDN/supp_serv.c

721 lines
18 KiB
C

/* $Id$
*
*/
#include "hisax_capi.h"
#include "asn1_comp.h"
#include "asn1_enc.h"
#include "dss1.h"
#include "helper.h"
#define T_ACTIVATE 4000
#define T_DEACTIVATE 4000
#define T_INTERROGATE 4000
static __inline__ int capiGetWord(__u8 *p, __u8 *end, __u16 *word)
{
if (p + 2 > end) {
return -1;
}
*word = *p + (*(p+1) << 8);
return 2;
}
static __inline__ int capiGetDWord(__u8 *p, __u8 *end, __u32 *dword)
{
if (p + 4 > end) {
return -1;
}
*dword = *p + (*(p+1) << 8) + (*(p+2) << 16) + (*(p+3) << 24);
return 4;
}
static __inline__ int capiGetStruct(__u8 *p, __u8 *_end, __u8 **strct)
{
int len = *p++;
__u8 *end = p + len;
if (end > _end) return -1;
*strct = p - 1;
return len + 1;
}
#define CAPI_GET(func, parm) \
ret = func(p, end, parm); \
if (ret < 0) return -1; \
p += ret
static __inline__ int capiGetFacReqListen(__u8 *p, __u8 *_end, struct FacReqListen *listen)
{
int len = *p++;
int ret;
__u8 *end = p + len;
if (end > _end) return -1;
CAPI_GET(capiGetDWord, &listen->NotificationMask);
if (p != end) return -1;
return len + 1;
}
static __inline__ int capiGetFacReqSuspend(__u8 *p, __u8 *_end, struct FacReqSuspend *suspend)
{
int len = *p++;
int ret;
__u8 *end = p + len;
if (end > _end) return -1;
CAPI_GET(capiGetStruct, &suspend->CallIdentity);
if (p != end) return -1;
return len + 1;
}
static __inline__ int capiGetFacReqResume(__u8 *p, __u8 *_end, struct FacReqResume *resume)
{
int len = *p++;
int ret;
__u8 *end = p + len;
if (end > _end) return -1;
CAPI_GET(capiGetStruct, &resume->CallIdentity);
if (p != end) return -1;
return len + 1;
}
static __inline__ int capiGetFacReqCFActivate(__u8 *p, __u8 *_end, struct FacReqCFActivate *CFActivate)
{
int len = *p++;
int ret;
__u8 *end = p + len;
if (end > _end) return -1;
CAPI_GET(capiGetDWord, &CFActivate->Handle);
CAPI_GET(capiGetWord, &CFActivate->Procedure);
CAPI_GET(capiGetWord, &CFActivate->BasicService);
CAPI_GET(capiGetStruct, &CFActivate->ServedUserNumber);
CAPI_GET(capiGetStruct, &CFActivate->ForwardedToNumber);
CAPI_GET(capiGetStruct, &CFActivate->ForwardedToSubaddress);
if (p != end) return -1;
return len + 1;
}
static __inline__ int capiGetFacReqCFDeactivate(__u8 *p, __u8 *_end, struct FacReqCFDeactivate *CFDeactivate)
{
int len = *p++;
int ret;
__u8 *end = p + len;
if (end > _end) return -1;
CAPI_GET(capiGetDWord, &CFDeactivate->Handle);
CAPI_GET(capiGetWord, &CFDeactivate->Procedure);
CAPI_GET(capiGetWord, &CFDeactivate->BasicService);
CAPI_GET(capiGetStruct, &CFDeactivate->ServedUserNumber);
if (p != end) return -1;
return len + 1;
}
#define capiGetFacReqCFInterrogateParameters capiGetFacReqCFDeactivate
static __inline__ int capiGetFacReqCFInterrogateNumbers(__u8 *p, __u8 *_end, struct FacReqCFInterrogateNumbers *CFInterrogateNumbers)
{
int len = *p++;
int ret;
__u8 *end = p + len;
if (end > _end) return -1;
CAPI_GET(capiGetDWord, &CFInterrogateNumbers->Handle);
if (p != end) return -1;
return len + 1;
}
static __inline__ int capiGetFacReqParm(__u8 *p, struct FacReqParm *facReqParm)
{
int len = *p++;
int ret;
__u8 *end = p + len;
CAPI_GET(capiGetWord, &facReqParm->Function);
switch (facReqParm->Function) {
case 0x0000: // GetSupportedServices
if (*p++ != 0x00) return -1; // empty struct
break;
case 0x0001: // Listen
CAPI_GET(capiGetFacReqListen, &facReqParm->u.Listen);
break;
case 0x0004: // Suspend
CAPI_GET(capiGetFacReqSuspend, &facReqParm->u.Suspend);
break;
case 0x0005: // Resume
CAPI_GET(capiGetFacReqResume, &facReqParm->u.Resume);
break;
case 0x0009: // CF Activate
CAPI_GET(capiGetFacReqCFActivate, &facReqParm->u.CFActivate);
break;
case 0x000a: // CF Deactivate
CAPI_GET(capiGetFacReqCFDeactivate, &facReqParm->u.CFDeactivate);
break;
case 0x000b: // CF Interrogate Parameters
CAPI_GET(capiGetFacReqCFInterrogateParameters, &facReqParm->u.CFInterrogateParameters);
break;
case 0x000c: // CF Interrogate Numbers
CAPI_GET(capiGetFacReqCFInterrogateNumbers, &facReqParm->u.CFInterrogateNumbers);
break;
default:
return len + 1;
}
if (p != end) return -1;
return len + 1;
}
void applSuppFacilityReq(Appl_t *appl, _cmsg *cmsg)
{
__u8 tmp[10];
__u16 Info;
struct FacReqParm facReqParm;
struct FacConfParm facConfParm;
Plci_t *plci;
Cplci_t *cplci;
if (capiGetFacReqParm(cmsg->FacilityRequestParameter, &facReqParm) < 0) {
contrAnswerCmsg(appl->contr, cmsg, CapiIllMessageParmCoding);
return;
}
facConfParm.Function = facReqParm.Function;
switch (facReqParm.Function) {
case 0x0000: // GetSupportedServices
Info = applGetSupportedServices(appl, &facReqParm, &facConfParm);
break;
case 0x0001: // Listen
Info = applFacListen(appl, &facReqParm, &facConfParm);
break;
case 0x0004: // Suspend
cplci = applAdr2cplci(appl, cmsg->adr.adrPLCI);
if (!cplci) {
Info = CapiIllContrPlciNcci;
break;
}
Info = cplciFacSuspendReq(cplci, &facReqParm, &facConfParm);
break;
case 0x0005: // Resume
plci = contrNewPlci(appl->contr);
if (!plci) {
Info = CapiNoPlciAvailable;
break;
}
cplci = applNewCplci(appl, plci);
if (!cplci) {
contrDelPlci(appl->contr, plci);
Info = CapiNoPlciAvailable;
break;
}
Info = cplciFacResumeReq(cplci, &facReqParm, &facConfParm);
if (Info == CapiSuccess)
cmsg->adr.adrPLCI = plci->adrPLCI;
break;
case 0x0009: // CF Activate
Info = applFacCFActivate(appl, &facReqParm, &facConfParm);
break;
case 0x000a: // CF Deactivate
Info = applFacCFDeactivate(appl, &facReqParm, &facConfParm);
break;
case 0x000b: // CF Interrogate Parameters
Info = applFacCFInterrogateParameters(appl, &facReqParm, &facConfParm);
break;
case 0x000c: // CF Interrogate Numbers
Info = applFacCFInterrogateNumbers(appl, &facReqParm, &facConfParm);
break;
default:
Info = CapiSuccess;
facConfParm.u.Info.SupplementaryServiceInfo = CapiSupplementaryServiceNotSupported;
}
capi_cmsg_answer(cmsg);
cmsg->Info = Info;
if (Info == 0x0000)
capiEncodeFacConfParm(tmp, &facConfParm);
else
tmp[0] = 0;
cmsg->FacilityConfirmationParameter = tmp;
contrRecvCmsg(appl->contr, cmsg);
}
__u8 *encodeInvokeComponentHead(__u8 *p)
{
*p++ = 0; // length -- not known yet
*p++ = 0x91; // remote operations protocol
*p++ = 0xa1; // invoke component
*p++ = 0; // length -- not known yet
return p;
}
void encodeInvokeComponentLength(__u8 *msg, __u8 *p)
{
msg[3] = p - &msg[5];
msg[0] = p - &msg[1];
}
static int dummy_L4L3(DummyProcess_t *dpc, __u32 prim, int len, void *arg) {
Contr_t *contr = dpc->contr;
return(contrL4L3(contr, prim, contr->adrController | DUMMY_CR_FLAG,
len, arg));
}
DummyProcess_t *applNewDummyPc(Appl_t *appl, __u16 Function, __u32 Handle)
{
DummyProcess_t *dummy_pc;
dummy_pc = contrNewDummyPc(appl->contr);
if (!dummy_pc)
return 0;
dummy_pc->ApplId = appl->ApplId;
dummy_pc->Function = Function;
dummy_pc->Handle = Handle;
return dummy_pc;
}
int applGetSupportedServices(Appl_t *appl, struct FacReqParm *facReqParm,
struct FacConfParm *facConfParm)
{
facConfParm->u.GetSupportedServices.SupplementaryServiceInfo = CapiSuccess;
facConfParm->u.GetSupportedServices.SupportedServices = HiSaxSupportedServices;
return CapiSuccess;
}
int applFacListen(Appl_t *appl, struct FacReqParm *facReqParm,
struct FacConfParm *facConfParm)
{
if (facReqParm->u.Listen.NotificationMask &~ HiSaxSupportedServices) {
facConfParm->u.Info.SupplementaryServiceInfo = CapiSupplementaryServiceNotSupported;
} else {
appl->NotificationMask = facReqParm->u.Listen.NotificationMask;
facConfParm->u.Info.SupplementaryServiceInfo = CapiSuccess;
}
return CapiSuccess;
}
int applFacCFActivate(Appl_t *appl, struct FacReqParm *facReqParm,
struct FacConfParm *facConfParm)
{
DummyProcess_t *dummy_pc;
FACILITY_t fac;
__u8 *p;
memset(&fac, 0, sizeof(FACILITY_t));
dummy_pc = applNewDummyPc(appl, facReqParm->Function, facReqParm->u.CFActivate.Handle);
if (!dummy_pc)
return CAPI_MSGOSRESOURCEERR;
p = encodeInvokeComponentHead(dummy_pc->buf);
p += encodeInt(p, dummy_pc->invokeId);
p += encodeInt(p, 0x07); // activationDiversion
p += encodeActivationDiversion(p, &facReqParm->u.CFActivate);
encodeInvokeComponentLength(dummy_pc->buf, p);
fac.FACILITY = dummy_pc->buf;
dummy_L4L3(dummy_pc, CC_FACILITY | REQUEST, sizeof(FACILITY_t), &fac);
dummyPcAddTimer(dummy_pc, T_ACTIVATE);
facConfParm->u.Info.SupplementaryServiceInfo = CapiSuccess;
return CapiSuccess;
}
int applFacCFDeactivate(Appl_t *appl, struct FacReqParm *facReqParm,
struct FacConfParm *facConfParm)
{
DummyProcess_t *dummy_pc;
FACILITY_t fac;
__u8 *p;
memset(&fac, 0, sizeof(FACILITY_t));
dummy_pc = applNewDummyPc(appl, facReqParm->Function, facReqParm->u.CFDeactivate.Handle);
if (!dummy_pc)
return CAPI_MSGOSRESOURCEERR;
p = encodeInvokeComponentHead(dummy_pc->buf);
p += encodeInt(p, dummy_pc->invokeId);
p += encodeInt(p, 0x08); // dectivationDiversion
p += encodeDeactivationDiversion(p, &facReqParm->u.CFDeactivate);
encodeInvokeComponentLength(dummy_pc->buf, p);
fac.FACILITY = dummy_pc->buf;
dummy_L4L3(dummy_pc, CC_FACILITY | REQUEST, sizeof(FACILITY_t), &fac);
dummyPcAddTimer(dummy_pc, T_DEACTIVATE);
facConfParm->u.Info.SupplementaryServiceInfo = CapiSuccess;
return CapiSuccess;
}
int applFacCFInterrogateParameters(Appl_t *appl, struct FacReqParm *facReqParm,
struct FacConfParm *facConfParm)
{
DummyProcess_t *dummy_pc;
FACILITY_t fac;
__u8 *p;
memset(&fac, 0, sizeof(FACILITY_t));
dummy_pc = applNewDummyPc(appl, facReqParm->Function,
facReqParm->u.CFInterrogateParameters.Handle);
if (!dummy_pc)
return CAPI_MSGOSRESOURCEERR;
p = encodeInvokeComponentHead(dummy_pc->buf);
p += encodeInt(p, dummy_pc->invokeId);
p += encodeInt(p, 0x0b); // interrogationDiversion
p += encodeInterrogationDiversion(p, &facReqParm->u.CFInterrogateParameters);
encodeInvokeComponentLength(dummy_pc->buf, p);
fac.FACILITY = dummy_pc->buf;
dummy_L4L3(dummy_pc, CC_FACILITY | REQUEST, sizeof(FACILITY_t), &fac);
dummyPcAddTimer(dummy_pc, T_INTERROGATE);
facConfParm->u.Info.SupplementaryServiceInfo = CapiSuccess;
return CapiSuccess;
}
int applFacCFInterrogateNumbers(Appl_t *appl, struct FacReqParm *facReqParm,
struct FacConfParm *facConfParm)
{
DummyProcess_t *dummy_pc;
FACILITY_t fac;
__u8 *p;
memset(&fac, 0, sizeof(FACILITY_t));
dummy_pc = applNewDummyPc(appl, facReqParm->Function,
facReqParm->u.CFInterrogateNumbers.Handle);
if (!dummy_pc)
return CAPI_MSGOSRESOURCEERR;
p = encodeInvokeComponentHead(dummy_pc->buf);
p += encodeInt(p, dummy_pc->invokeId);
p += encodeInt(p, 0x11); // InterrogateServedUserNumbers
encodeInvokeComponentLength(dummy_pc->buf, p);
fac.FACILITY = dummy_pc->buf;
dummy_L4L3(dummy_pc, CC_FACILITY | REQUEST, sizeof(FACILITY_t), &fac);
dummyPcAddTimer(dummy_pc, T_INTERROGATE);
facConfParm->u.Info.SupplementaryServiceInfo = CapiSuccess;
return CapiSuccess;
}
void dummyProcessTimeout(unsigned long arg);
void dummyPcConstr(DummyProcess_t *dummy_pc, Contr_t *contr, __u16 invokeId)
{
memset(dummy_pc, 0, sizeof(DummyProcess_t));
dummy_pc->contr = contr;
dummy_pc->invokeId = invokeId;
}
void dummyPcDestr(DummyProcess_t *dummy_pc)
{
del_timer(&dummy_pc->tl);
}
void dummyPcAddTimer(DummyProcess_t *dummy_pc, int msec)
{
dummy_pc->tl.function = dummyProcessTimeout;
dummy_pc->tl.data = (unsigned long) dummy_pc;
init_timer(&dummy_pc->tl);
dummy_pc->tl.expires = jiffies + (msec * HZ) / 1000;
add_timer(&dummy_pc->tl);
}
DummyProcess_t *contrNewDummyPc(Contr_t* contr)
{
DummyProcess_t *dummy_pc;
int i;
for (i = 0; i < CAPI_MAXDUMMYPCS; i++) {
if (!contr->dummy_pcs[i])
break;
}
if (i == CAPI_MAXDUMMYPCS)
return 0;
dummy_pc = kmalloc(sizeof(DummyProcess_t), GFP_ATOMIC);
if (!dummy_pc) {
int_error();
return 0;
}
contr->dummy_pcs[i] = dummy_pc;
dummyPcConstr(dummy_pc, contr, ++contr->lastInvokeId);
return dummy_pc;
}
void contrDelDummyPc(Contr_t* contr, DummyProcess_t *dummy_pc)
{
int i;
for (i = 0; i < CAPI_MAXDUMMYPCS; i++) {
if (contr->dummy_pcs[i] == dummy_pc)
break;
}
if (i == CAPI_MAXDUMMYPCS) {
int_error();
return;
}
contr->dummy_pcs[i] = 0;
dummyPcDestr(dummy_pc);
kfree(dummy_pc);
}
DummyProcess_t *contrId2DummyPc(Contr_t* contr, __u16 invokeId)
{
int i;
for (i = 0; i < CAPI_MAXDUMMYPCS; i++) {
if (contr->dummy_pcs[i])
if (contr->dummy_pcs[i]->invokeId == invokeId)
break;
}
if (i == CAPI_MAXDUMMYPCS)
return 0;
return contr->dummy_pcs[i];
}
void dummyProcessTimeout(unsigned long arg)
{
DummyProcess_t *dummy_pc = (DummyProcess_t *) arg;
Contr_t* contr = dummy_pc->contr;
Appl_t *appl;
__u8 tmp[10], *p;
_cmsg cmsg;
del_timer(&dummy_pc->tl);
appl = contrId2appl(contr, dummy_pc->ApplId);
if (!appl)
return;
capi_cmsg_header(&cmsg, dummy_pc->ApplId, CAPI_FACILITY, CAPI_IND,
appl->MsgId++, contr->adrController);
p = &tmp[1];
p += capiEncodeWord(p, dummy_pc->Function);
p += capiEncodeFacIndCFact(p, CapiTimeOut, dummy_pc->Handle);
tmp[0] = p - &tmp[1];
contrDelDummyPc(contr, dummy_pc);
cmsg.FacilityIndicationParameter = tmp;
contrRecvCmsg(contr, &cmsg);
}
#if 0
void printPublicPartyNumber(struct PublicPartyNumber *publicPartyNumber)
{
printk("(%d) %s\n", publicPartyNumber->publicTypeOfNumber,
publicPartyNumber->numberDigits);
}
void printPartyNumber(struct PartyNumber *partyNumber)
{
switch (partyNumber->type) {
case 0:
printk("unknown %s\n", partyNumber->p.unknown);
break;
case 1:
printPublicPartyNumber(&partyNumber->p.publicPartyNumber);
break;
}
}
void printServedUserNr(struct ServedUserNr *servedUserNr)
{
if (servedUserNr->all) {
printk("all\n");
} else {
printPartyNumber(&servedUserNr->partyNumber);
}
}
void printAddress(struct Address *address)
{
printPartyNumber(&address->partyNumber);
if (address->partySubaddress[0]) {
printk("sub %s\n", address->partySubaddress);
}
}
#endif
void contrDummyFacility(Contr_t *contr, FACILITY_t *fac)
{
Appl_t *appl;
int ie_len;
struct asn1_parm parm;
DummyProcess_t *dummy_pc;
_cmsg cmsg;
__u8 tmp[255];
__u8 *p, *end;
__u16 ApplId;
if (!(p = fac->FACILITY)) {
int_error();
return;
}
ie_len = *p++;
end = p + ie_len;
// if (end > skb->data + skb->len) {
// int_error();
// return;
// }
if (*p++ != 0x91) { // Supplementary Service Applications
int_error();
return;
}
ParseComponent(&parm, p, end);
switch (parm.comp) {
case invoke:
#if 0
printk("invokeId %d\n", parm.u.inv.invokeId);
printk("operationValue %d\n", parm.u.inv.operationValue);
#endif
switch (parm.u.inv.operationValue) {
case 0x0009:
#if 0
printk("procedure %d basicService %d\n", parm.c.inv.o.actNot.procedure,
parm.c.inv.o.actNot.basicService);
printServedUserNr(&parm.c.inv.o.actNot.servedUserNr);
printAddress(&parm.c.inv.o.actNot.address);
#endif
for (ApplId = 1; ApplId <= CAPI_MAXAPPL; ApplId++) {
appl = contrId2appl(contr, ApplId);
if (!appl)
continue;
if (!(appl->NotificationMask & 0x00000010))
continue;
capi_cmsg_header(&cmsg, ApplId, CAPI_FACILITY, CAPI_IND,
appl->MsgId++, contr->adrController);
p = &tmp[1];
p += capiEncodeWord(p, 0x8006);
p += capiEncodeFacIndCFNotAct(p, &parm.u.inv.o.actNot);
tmp[0] = p - &tmp[1];
cmsg.FacilitySelector = 0x0003;
cmsg.FacilityIndicationParameter = tmp;
contrRecvCmsg(contr, &cmsg);
}
break;
case 0x000a:
#if 0
printk("procedure %d basicService %d\n", parm.c.inv.o.deactNot.procedure,
parm.c.inv.o.deactNot.basicService);
printServedUserNr(&parm.c.inv.o.deactNot.servedUserNr);
#endif
for (ApplId = 1; ApplId <= CAPI_MAXAPPL; ApplId++) {
appl = contrId2appl(contr, ApplId);
if (!appl)
continue;
if (!(appl->NotificationMask & 0x00000010))
continue;
capi_cmsg_header(&cmsg, ApplId, CAPI_FACILITY, CAPI_IND,
appl->MsgId++, contr->adrController);
p = &tmp[1];
p += capiEncodeWord(p, 0x8007);
p += capiEncodeFacIndCFNotDeact(p, &parm.u.inv.o.deactNot);
tmp[0] = p - &tmp[1];
cmsg.FacilitySelector = 0x0003;
cmsg.FacilityIndicationParameter = tmp;
contrRecvCmsg(contr, &cmsg);
}
break;
default:
int_error();
}
break;
case returnResult:
dummy_pc = contrId2DummyPc(contr, parm.u.retResult.invokeId);
if (!dummy_pc)
return;
appl = contrId2appl(contr, dummy_pc->ApplId);
if (!appl)
return;
capi_cmsg_header(&cmsg, dummy_pc->ApplId, CAPI_FACILITY, CAPI_IND,
appl->MsgId++, contr->adrController);
p = &tmp[1];
p += capiEncodeWord(p, dummy_pc->Function);
switch (dummy_pc->Function) {
case 0x0009:
p += capiEncodeFacIndCFact(p, 0, dummy_pc->Handle);
break;
case 0x000a:
p += capiEncodeFacIndCFdeact(p, 0, dummy_pc->Handle);
break;
case 0x000b:
p += capiEncodeFacIndCFinterParameters(p, 0, dummy_pc->Handle,
&parm.u.retResult.o.resultList);
break;
case 0x000c:
p += capiEncodeFacIndCFinterNumbers(p, 0, dummy_pc->Handle,
&parm.u.retResult.o.list);
break;
default:
int_error();
break;
}
tmp[0] = p - &tmp[1];
cmsg.FacilityIndicationParameter = tmp;
contrRecvCmsg(contr, &cmsg);
contrDelDummyPc(contr, dummy_pc);
break;
case returnError:
dummy_pc = contrId2DummyPc(contr, parm.u.retResult.invokeId);
if (!dummy_pc)
return;
appl = contrId2appl(contr, dummy_pc->ApplId);
if (!appl)
return;
capi_cmsg_header(&cmsg, dummy_pc->ApplId, CAPI_FACILITY, CAPI_IND,
appl->MsgId++, contr->adrController);
p = &tmp[1];
p += capiEncodeWord(p, dummy_pc->Function);
p += capiEncodeFacIndCFact(p, 0x3600 | (parm.u.retError.errorValue &0xff),
dummy_pc->Handle);
tmp[0] = p - &tmp[1];
cmsg.FacilityIndicationParameter = tmp;
contrRecvCmsg(contr, &cmsg);
contrDelDummyPc(contr, dummy_pc);
break;
default:
int_error();
}
}
void contrDummyInd(Contr_t *contr, __u32 prim, void *arg)
{
switch (prim) {
case CC_FACILITY | INDICATION:
contrDummyFacility(contr, arg);
break;
default:
int_error();
}
}