big rewrite of the CAPI 2.0 implementation

- hopefully easier to understand and follow the dataflow
- no limitations in application count
- clean shutdown on errors
- use own kmem caches
- reduce stack usage, use dynamic allocated cmsg
This commit is contained in:
Karsten Keil 2003-11-21 22:29:41 +00:00
parent ffa91934b6
commit 85337c9851
15 changed files with 4020 additions and 3061 deletions

View File

@ -46,7 +46,7 @@ mISDN_core-objs := core.o stack.o udevice.o helper.o
mISDN_l1-objs := layer1.o helper.o debug.o fsm.o
mISDN_l2-objs := layer2.o tei.o helper.o debug.o fsm.o
l3udss1-objs := layer3.o helper.o l3helper.o debug.o fsm.o l3_udss1.o
mISDN_capi-objs := capi.o contr.o listen.o appl.o plci.o cplci.o ncci.o asn1.o \
mISDN_capi-objs := capi.o contr.o listen.o appl.o plci.o app_plci.o ncci.o asn1.o \
asn1_aoc.o asn1_comp.o asn1_generic.o asn1_diversion.o \
asn1_basic_service.o asn1_address.o asn1_enc.o capi_enc.o \
supp_serv.o helper.o l3helper.o debug.o fsm.o

View File

@ -46,7 +46,7 @@ mISDN_core-objs := core.o stack.o udevice.o helper.o
mISDN_l1-objs := layer1.o helper.o debug.o fsm.o
mISDN_l2-objs := layer2.o tei.o helper.o debug.o fsm.o
l3udss1-objs := layer3.o helper.o l3helper.o debug.o fsm.o l3_udss1.o
mISDN_capi-objs := capi.o contr.o listen.o appl.o plci.o cplci.o ncci.o asn1.o \
mISDN_capi-objs := capi.o contr.o listen.o appl.o plci.o app_plci.o ncci.o asn1.o \
asn1_aoc.o asn1_comp.o asn1_generic.o asn1_diversion.o \
asn1_basic_service.o asn1_address.o asn1_enc.o capi_enc.o \
supp_serv.o helper.o l3helper.o debug.o fsm.o

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,14 @@
/* $Id$
*
* Applications are owned by the controller and only
* handle this controller, multiplexing multiple
* controller with one application is done in the higher
* driver independ CAPI driver. The application contain
* the Listen state machine.
*
*/
#include "capi.h"
#include "m_capi.h"
#include "helper.h"
#include "debug.h"
#include "mISDNManufacturer.h"
@ -10,188 +16,370 @@
#define applDebug(appl, lev, fmt, args...) \
capidebug(lev, fmt, ## args)
void applConstr(Appl_t *appl, Contr_t *contr, __u16 ApplId, capi_register_params *rp)
static struct list_head garbage_applications = LIST_HEAD_INIT(garbage_applications);
int
ApplicationConstr(Controller_t *contr, __u16 ApplId, capi_register_params *rp)
{
memset(appl, 0, sizeof(Appl_t));
Application_t *appl = kmalloc(sizeof(Application_t), GFP_KERNEL);
if (!appl) {
return(-ENOMEM);
}
memset(appl, 0, sizeof(Application_t));
INIT_LIST_HEAD(&appl->head);
appl->contr = contr;
appl->maxplci = contr->maxplci;
appl->AppPlcis = kmalloc(appl->maxplci * sizeof(AppPlci_t *), GFP_KERNEL);
if (!appl->AppPlcis) {
kfree(appl);
return(-ENOMEM);
}
memset(appl->AppPlcis, 0, appl->maxplci * sizeof(AppPlci_t *));
appl->ApplId = ApplId;
appl->MsgId = 1;
appl->NotificationMask = 0;
memcpy(&appl->rp, rp, sizeof(capi_register_params));
listenConstr(&appl->listen, contr, ApplId);
memcpy(&appl->reg_params, rp, sizeof(capi_register_params));
listenConstr(appl);
list_add(&appl->head, &contr->Applications);
test_and_set_bit(APPL_STATE_ACTIV, &appl->state);
return(0);
}
void applDestr(Appl_t *appl)
/*
* Destroy the Application
*
* depending who initiate this we cannot release imediatly, if
* any AppPlci is still in use.
*
* @who: 0 - a AppPlci is released in state APPL_STATE_RELEASE
* 1 - Application is released from CAPI application
* 2 - the controller is resetted
* 3 - the controller is removed
* 4 - the CAPI module will be unload
*/
int
ApplicationDestr(Application_t *appl, int who)
{
int i;
int i, used = 0;
AppPlci_t **aplci_p = appl->AppPlcis;
listenDestr(&appl->listen);
for (i = 0; i < CAPI_MAXPLCI; i++) {
if (appl->cplcis[i]) {
cplciDestr(appl->cplcis[i]);
kfree(appl->cplcis[i]);
appl->cplcis[i] = NULL;
if (test_and_set_bit(APPL_STATE_DESTRUCTOR, &appl->state)) {
// we are allready in this function
return(-EBUSY);
}
test_and_set_bit(APPL_STATE_RELEASE, &appl->state);
test_and_clear_bit(APPL_STATE_ACTIV, &appl->state);
listenDestr(appl);
if (who > 2) {
appl->contr = NULL;
}
if (aplci_p) {
for (i = 0; i < appl->maxplci; i++) {
if (*aplci_p) {
switch (who) {
case 4:
AppPlciDestr(*aplci_p);
*aplci_p = NULL;
break;
case 1:
case 2:
case 3:
AppPlciRelease(*aplci_p);
case 0:
if ((volatile AppPlci_t *)(*aplci_p))
used++;
break;
}
}
aplci_p++;
}
}
}
Cplci_t *applAdr2cplci(Appl_t *appl, __u32 adr)
{
int i = (adr >> 8) & 0xff;
if ((i < 1) || (i > CAPI_MAXPLCI)) {
int_error();
return 0;
if (used) {
if (who == 3) {
list_del_init(&appl->head);
list_add(&appl->head, &garbage_applications);
}
test_and_clear_bit(APPL_STATE_DESTRUCTOR, &appl->state);
return(-EBUSY);
}
return appl->cplcis[i - 1];
list_del_init(&appl->head);
appl->maxplci = 0;
kfree(appl->AppPlcis);
appl->AppPlcis = NULL;
kfree(appl);
return(0);
}
void applSendMessage(Appl_t *appl, struct sk_buff *skb)
AppPlci_t *
getAppPlci4addr(Application_t *appl, __u32 addr)
{
Plci_t *plci;
Cplci_t *cplci;
int plci_idx = (addr >> 8) & 0xff;
if ((plci_idx < 1) || (plci_idx >= appl->maxplci)) {
int_error();
return NULL;
}
return(appl->AppPlcis[plci_idx - 1]);
}
static void
FacilityReq(Application_t *appl, struct sk_buff *skb)
{
_cmsg *cmsg;
AppPlci_t *aplci;
cmsg = cmsg_alloc();
if (!cmsg) {
int_error();
dev_kfree_skb(skb);
return;
}
capi_message2cmsg(cmsg, skb->data);
switch (cmsg->FacilitySelector) {
case 0x0000: // Handset
case 0x0001: // DTMF
aplci = getAppPlci4addr(appl, CAPIMSG_CONTROL(skb->data));
if (aplci && aplci->ncci) {
ncciGetCmsg(aplci->ncci, cmsg);
break;
}
SendCmsgAnswer2Application(appl, cmsg, CapiIllContrPlciNcci);
break;
case 0x0003: // SupplementaryServices
SupplementaryFacilityReq(appl, cmsg);
break;
default:
int_error();
SendCmsgAnswer2Application(appl, cmsg, CapiFacilityNotSupported);
break;
}
dev_kfree_skb(skb);
}
void
ApplicationSendMessage(Application_t *appl, struct sk_buff *skb)
{
Plci_t *plci;
AppPlci_t *aplci;
switch (CAPICMD(CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data))) {
// for NCCI state machine
case CAPI_DATA_B3_REQ:
case CAPI_DATA_B3_RESP:
case CAPI_CONNECT_B3_REQ:
case CAPI_CONNECT_B3_RESP:
case CAPI_CONNECT_B3_ACTIVE_RESP:
case CAPI_DISCONNECT_B3_REQ:
case CAPI_DISCONNECT_B3_RESP:
aplci = getAppPlci4addr(appl, CAPIMSG_CONTROL(skb->data));
if (!aplci) {
AnswerMessage2Application(appl, skb, CapiIllContrPlciNcci);
goto free;
}
if (!aplci->ncci) {
int_error();
AnswerMessage2Application(appl, skb, CapiIllContrPlciNcci);
goto free;
}
ncciSendMessage(aplci->ncci, skb);
break;
// for PLCI state machine
case CAPI_INFO_REQ:
case CAPI_ALERT_REQ:
case CAPI_CONNECT_RESP:
case CAPI_CONNECT_ACTIVE_RESP:
case CAPI_DISCONNECT_REQ:
case CAPI_DISCONNECT_RESP:
case CAPI_SELECT_B_PROTOCOL_REQ:
aplci = getAppPlci4addr(appl, CAPIMSG_CONTROL(skb->data));
if (!aplci) {
AnswerMessage2Application(appl, skb, CapiIllContrPlciNcci);
goto free;
}
AppPlciSendMessage(aplci, skb);
break;
case CAPI_CONNECT_REQ:
if (ControllerNewPlci(appl->contr, &plci, MISDN_ID_ANY)) {
AnswerMessage2Application(appl, skb, CapiNoPlciAvailable);
goto free;
}
aplci = ApplicationNewAppPlci(appl, plci);
if (!aplci) {
AnswerMessage2Application(appl, skb, CapiNoPlciAvailable);
goto free;
}
AppPlciSendMessage(aplci, skb);
break;
// for NCCI state machine
case CAPI_DATA_B3_REQ:
case CAPI_DATA_B3_RESP:
case CAPI_CONNECT_B3_REQ:
case CAPI_CONNECT_B3_RESP:
case CAPI_CONNECT_B3_ACTIVE_RESP:
case CAPI_DISCONNECT_B3_REQ:
case CAPI_DISCONNECT_B3_RESP:
cplci = applAdr2cplci(appl, CAPIMSG_CONTROL(skb->data));
if (!cplci) {
contrAnswerMessage(appl->contr, skb, CapiIllContrPlciNcci);
goto free;
}
if (!cplci->ncci) {
int_error();
contrAnswerMessage(appl->contr, skb, CapiIllContrPlciNcci);
goto free;
}
ncciSendMessage(cplci->ncci, skb);
break;
// for PLCI state machine
case CAPI_INFO_REQ:
case CAPI_ALERT_REQ:
case CAPI_CONNECT_RESP:
case CAPI_CONNECT_ACTIVE_RESP:
case CAPI_DISCONNECT_REQ:
case CAPI_DISCONNECT_RESP:
case CAPI_SELECT_B_PROTOCOL_REQ:
cplci = applAdr2cplci(appl, CAPIMSG_CONTROL(skb->data));
if (!cplci) {
contrAnswerMessage(appl->contr, skb, CapiIllContrPlciNcci);
goto free;
}
cplciSendMessage(cplci, skb);
break;
case CAPI_CONNECT_REQ:
plci = contrNewPlci(appl->contr, MISDN_ID_ANY);
if (!plci) {
contrAnswerMessage(appl->contr, skb, CapiNoPlciAvailable);
goto free;
}
cplci = applNewCplci(appl, plci);
if (!cplci) {
contrDelPlci(appl->contr, plci);
contrAnswerMessage(appl->contr, skb, CapiNoPlciAvailable);
goto free;
}
cplciSendMessage(cplci, skb);
break;
// for LISTEN state machine
case CAPI_LISTEN_REQ:
listenSendMessage(appl, skb);
break;
// for LISTEN state machine
case CAPI_LISTEN_REQ:
listenSendMessage(&appl->listen, skb);
break;
// other
case CAPI_FACILITY_REQ:
applFacilityReq(appl, skb);
break;
case CAPI_FACILITY_RESP:
goto free;
case CAPI_MANUFACTURER_REQ:
applManufacturerReq(appl, skb);
break;
case CAPI_INFO_RESP:
goto free;
default:
applDebug(appl, CAPI_DBG_WARN, "applSendMessage: %#x %#x not handled!",
CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data));
if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_REQ)
contrAnswerMessage(appl->contr, skb,
CapiMessageNotSupportedInCurrentState);
goto free;
// other
case CAPI_FACILITY_REQ:
FacilityReq(appl, skb);
break;
case CAPI_FACILITY_RESP:
goto free;
case CAPI_MANUFACTURER_REQ:
applManufacturerReq(appl, skb);
break;
case CAPI_INFO_RESP:
goto free;
default:
applDebug(appl, CAPI_DBG_WARN, "applSendMessage: %#x %#x not handled!",
CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data));
if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_REQ)
AnswerMessage2Application(appl, skb,
CapiMessageNotSupportedInCurrentState);
goto free;
}
return;
free:
dev_kfree_skb(skb);
}
void applFacilityReq(Appl_t *appl, struct sk_buff *skb)
AppPlci_t *
ApplicationNewAppPlci(Application_t *appl, Plci_t *plci)
{
_cmsg cmsg;
Cplci_t *cplci;
AppPlci_t *aplci;
int plci_idx = (plci->addr >> 8) & 0xff;
capi_message2cmsg(&cmsg, skb->data);
switch (cmsg.FacilitySelector) {
case 0x0000: // Handset
case 0x0001: // DTMF
cplci = applAdr2cplci(appl, CAPIMSG_CONTROL(skb->data));
if (cplci && cplci->ncci) {
ncciSendMessage(cplci->ncci, skb);
return;
}
contrAnswerMessage(appl->contr, skb, CapiIllContrPlciNcci);
break;
case 0x0003: // SupplementaryServices
applSuppFacilityReq(appl, &cmsg);
break;
default:
int_error();
contrAnswerMessage(appl->contr, skb, CapiFacilityNotSupported);
break;
}
dev_kfree_skb(skb);
}
Cplci_t *applNewCplci(Appl_t *appl, Plci_t *plci)
{
Cplci_t *cplci;
int i = (plci->adrPLCI >> 8);
if (appl->cplcis[i - 1]) {
if (test_bit(APPL_STATE_RELEASE, &appl->state))
return(NULL);
if ((plci_idx < 1) || (plci_idx >= appl->maxplci)) {
int_error();
return 0;
return(NULL);
}
cplci = kmalloc(sizeof(Cplci_t), GFP_ATOMIC);
cplciConstr(cplci, appl, plci);
appl->cplcis[i - 1] = cplci;
plciAttachCplci(plci, cplci);
return cplci;
if (appl->AppPlcis[plci_idx - 1]) {
int_error();
return(NULL);
}
if (AppPlciConstr(&aplci, appl, plci)) {
int_error();
return(NULL);
}
applDebug(appl, CAPI_DBG_APPL_INFO, "ApplicationNewAppPlci: idx(%d) aplci(%p) appl(%p) plci(%p)",
plci_idx, aplci, appl, plci);
appl->AppPlcis[plci_idx - 1] = aplci;
plciAttachAppPlci(plci, aplci);
return(aplci);
}
void applDelCplci(Appl_t *appl, Cplci_t *cplci)
void
ApplicationDelAppPlci(Application_t *appl, AppPlci_t *aplci)
{
int i = cplci->adrPLCI >> 8;
int plci_idx = (aplci->addr >> 8) & 0xff;
if ((i < 1) || (i > CAPI_MAXPLCI)) {
if ((plci_idx < 1) || (plci_idx >= appl->maxplci)) {
int_error();
return;
}
if (appl->cplcis[i-1] != cplci) {
if (appl->AppPlcis[plci_idx - 1] != aplci) {
int_error();
return;
}
cplciDestr(cplci);
kfree(cplci);
appl->cplcis[i-1] = NULL;
appl->AppPlcis[plci_idx - 1] = NULL;
if (test_bit(APPL_STATE_RELEASE, &appl->state) &&
!test_bit(APPL_STATE_DESTRUCTOR, &appl->state))
ApplicationDestr(appl, 0);
}
void
SendCmsg2Application(Application_t *appl, _cmsg *cmsg)
{
struct sk_buff *skb;
if (test_bit(APPL_STATE_RELEASE, &appl->state)) {
/* Application is released and cannot receive messages
* anymore. To avoid stalls in the state machines we
* must answer INDICATIONS.
*/
AppPlci_t *aplci;
if (CAPI_IND != cmsg->Subcommand)
goto free;
switch(cmsg->Command) {
// for NCCI state machine
case CAPI_CONNECT_B3:
cmsg->Reject = 2;
case CAPI_CONNECT_B3_ACTIVE:
case CAPI_DISCONNECT_B3:
aplci = getAppPlci4addr(appl, (cmsg->adr.adrNCCI & 0xffff));
if (!aplci)
goto free;
if (!aplci->ncci) {
int_error();
goto free;
}
capi_cmsg_answer(cmsg);
ncciGetCmsg(aplci->ncci, cmsg);
break;
// for PLCI state machine
case CAPI_CONNECT:
cmsg->Reject = 2;
case CAPI_CONNECT_ACTIVE:
case CAPI_DISCONNECT:
aplci = getAppPlci4addr(appl, (cmsg->adr.adrPLCI & 0xffff));
if (!aplci)
goto free;
capi_cmsg_answer(cmsg);
AppPlciGetCmsg(aplci, cmsg);
break;
case CAPI_FACILITY:
case CAPI_MANUFACTURER:
case CAPI_INFO:
goto free;
default:
int_error();
goto free;
}
return;
}
if (!(skb = alloc_skb(CAPI_MSG_DEFAULT_LEN, GFP_ATOMIC))) {
printk(KERN_WARNING "%s: no mem for %d bytes\n", __FUNCTION__, CAPI_MSG_DEFAULT_LEN);
int_error();
goto free;
}
capi_cmsg2message(cmsg, skb->data);
applDebug(appl, CAPI_DBG_APPL_MSG, "%s: len(%d) applid(%x) %s msgnr(%d) addr(%08x)",
__FUNCTION__, CAPIMSG_LEN(skb->data), cmsg->ApplId, capi_cmd2str(cmsg->Command, cmsg->Subcommand),
cmsg->Messagenumber, cmsg->adr.adrController);
if (CAPI_MSG_DEFAULT_LEN < CAPIMSG_LEN(skb->data)) {
printk(KERN_ERR "%s: CAPI_MSG_DEFAULT_LEN overrun (%d/%d)\n", __FUNCTION__,
CAPIMSG_LEN(skb->data), CAPI_MSG_DEFAULT_LEN);
int_error();
dev_kfree_skb(skb);
goto free;
}
skb_put(skb, CAPIMSG_LEN(skb->data));
#ifdef OLDCAPI_DRIVER_INTERFACE
appl->contr->ctrl->handle_capimsg(appl->contr->ctrl, cmsg->ApplId, skb);
#else
capi_ctr_handle_message(appl->contr->ctrl, cmsg->ApplId, skb);
#endif
free:
cmsg_free(cmsg);
}
void
SendCmsgAnswer2Application(Application_t *appl, _cmsg *cmsg, __u16 Info)
{
capi_cmsg_answer(cmsg);
cmsg->Info = Info;
SendCmsg2Application(appl, cmsg);
}
void
AnswerMessage2Application(Application_t *appl, struct sk_buff *skb, __u16 Info)
{
_cmsg *cmsg;
CMSG_ALLOC(cmsg);
capi_message2cmsg(cmsg, skb->data);
SendCmsgAnswer2Application(appl, cmsg, Info);
}
#define AVM_MANUFACTURER_ID 0x214D5641 /* "AVM!" */
@ -203,12 +391,13 @@ struct AVMD2Trace {
__u8 data[4];
};
void applManufacturerReqAVM(Appl_t *appl, _cmsg *cmsg, struct sk_buff *skb)
void applManufacturerReqAVM(Application_t *appl, _cmsg *cmsg, struct sk_buff *skb)
{
struct AVMD2Trace *at;
if (cmsg->Class != CLASS_AVM) {
applDebug(appl, CAPI_DBG_APPL_INFO, "CAPI: unknown class %#x\n", cmsg->Class);
cmsg_free(cmsg);
dev_kfree_skb(skb);
return;
}
@ -220,9 +409,9 @@ void applManufacturerReqAVM(Appl_t *appl, _cmsg *cmsg, struct sk_buff *skb)
break;
}
if (memcmp(at->data, "\200\014\000\000", 4) == 0) {
test_and_set_bit(APPL_FLAG_D2TRACE, &appl->flags);
test_and_set_bit(APPL_STATE_D2TRACE, &appl->state);
} else if (memcmp(at->data, "\000\000\000\000", 4) == 0) {
test_and_clear_bit(APPL_FLAG_D2TRACE, &appl->flags);
test_and_clear_bit(APPL_STATE_D2TRACE, &appl->state);
} else {
int_error();
}
@ -230,73 +419,101 @@ void applManufacturerReqAVM(Appl_t *appl, _cmsg *cmsg, struct sk_buff *skb)
default:
applDebug(appl, CAPI_DBG_APPL_INFO, "CAPI: unknown function %#x\n", cmsg->Function);
}
cmsg_free(cmsg);
dev_kfree_skb(skb);
}
void applManufacturerReqmISDN(Appl_t *appl, _cmsg *cmsg, struct sk_buff *skb)
void applManufacturerReqmISDN(Application_t *appl, _cmsg *cmsg, struct sk_buff *skb)
{
Cplci_t *cplci;
AppPlci_t *aplci;
switch (cmsg->Class) {
case mISDN_MF_CLASS_HANDSET:
/* Note normally MANUFATURER messages are only defined for
* controller address we extent it here to PLCI/NCCI
*/
cplci = applAdr2cplci(appl, CAPIMSG_CONTROL(skb->data));
if (cplci && cplci->ncci) {
ncciSendMessage(cplci->ncci, skb);
aplci = getAppPlci4addr(appl, CAPIMSG_CONTROL(skb->data));
if (aplci && aplci->ncci) {
cmsg_free(cmsg);
ncciSendMessage(aplci->ncci, skb);
return;
}
contrAnswerMessage(appl->contr, skb, CapiIllContrPlciNcci);
SendCmsgAnswer2Application(appl, cmsg, CapiIllContrPlciNcci);
break;
default:
dev_kfree_skb(skb);
cmsg_free(cmsg);
break;
}
dev_kfree_skb(skb);
}
void applManufacturerReq(Appl_t *appl, struct sk_buff *skb)
void
applManufacturerReq(Application_t *appl, struct sk_buff *skb)
{
_cmsg cmsg;
_cmsg *cmsg;
if (skb->len < 16 + 8) {
dev_kfree_skb(skb);
return;
}
capi_message2cmsg(&cmsg, skb->data);
switch (cmsg.ManuID) {
cmsg = cmsg_alloc();
if (!cmsg) {
int_error();
dev_kfree_skb(skb);
return;
}
capi_message2cmsg(cmsg, skb->data);
switch (cmsg->ManuID) {
case mISDN_MANUFACTURER_ID:
applManufacturerReqmISDN(appl, &cmsg, skb);
applManufacturerReqmISDN(appl, cmsg, skb);
break;
case AVM_MANUFACTURER_ID:
applManufacturerReqAVM(appl, &cmsg, skb);
applManufacturerReqAVM(appl, cmsg, skb);
break;
default:
applDebug(appl, CAPI_DBG_APPL_INFO, "CAPI: unknown ManuID %#x\n", cmsg.ManuID);
applDebug(appl, CAPI_DBG_APPL_INFO, "CAPI: unknown ManuID %#x\n", cmsg->ManuID);
cmsg_free(cmsg);
dev_kfree_skb(skb);
break;
}
}
void applD2Trace(Appl_t *appl, u_char *buf, int len)
void applD2Trace(Application_t *appl, u_char *buf, int len)
{
_cmsg cmsg;
__u8 manuData[255];
_cmsg *cmsg;
__u8 manuData[255];
if (!test_bit(APPL_FLAG_D2TRACE, &appl->flags))
if (!test_bit(APPL_STATE_D2TRACE, &appl->state))
return;
memset(&cmsg, 0, sizeof(_cmsg));
capi_cmsg_header(&cmsg, appl->ApplId, CAPI_MANUFACTURER, CAPI_IND,
appl->MsgId++, appl->contr->adrController);
cmsg.ManuID = AVM_MANUFACTURER_ID;
cmsg.Class = CLASS_AVM;
cmsg.Function = FUNCTION_AVM_D2_TRACE;
cmsg.ManuData = (_cstruct) &manuData;
CMSG_ALLOC(cmsg);
capi_cmsg_header(cmsg, appl->ApplId, CAPI_MANUFACTURER, CAPI_IND,
appl->MsgId++, appl->contr->addr);
cmsg->ManuID = AVM_MANUFACTURER_ID;
cmsg->Class = CLASS_AVM;
cmsg->Function = FUNCTION_AVM_D2_TRACE;
cmsg->ManuData = (_cstruct) &manuData;
manuData[0] = 2 + len; // length
manuData[1] = 0x80;
manuData[2] = 0x0f;
memcpy(&manuData[3], buf, len);
contrRecvCmsg(appl->contr, &cmsg);
SendCmsg2Application(appl, cmsg);
}
void
free_Application(void)
{
struct list_head *item, *next;
int n = 0;
if (list_empty(&garbage_applications)) {
printk(KERN_DEBUG "%s: no garbage\n", __FUNCTION__);
return;
}
list_for_each_safe(item, next, &garbage_applications) {
ApplicationDestr((Application_t *)item, 4);
n++;
}
printk(KERN_WARNING"%s: %d garbage items\n", __FUNCTION__, n);
}

View File

@ -2,7 +2,7 @@
*
*/
#include "capi.h"
#include "m_capi.h"
#include "helper.h"
#include "asn1_enc.h"

View File

@ -3,7 +3,7 @@
*/
#include <linux/module.h>
#include "capi.h"
#include "m_capi.h"
#include "helper.h"
#include "debug.h"
@ -40,17 +40,267 @@ void capidebug(int level, char *fmt, ...)
struct capi_driver_interface *cdrv_if;
#endif
int CapiNew(void)
kmem_cache_t *mISDN_cmsg_cp;
kmem_cache_t *mISDN_AppPlci_cp;
kmem_cache_t *mISDN_ncci_cp;
kmem_cache_t *mISDN_sspc_cp;
#ifdef MISDN_KMEM_DEBUG
static struct list_head mISDN_kmem_garbage = LIST_HEAD_INIT(mISDN_kmem_garbage);
_cmsg *
_kd_cmsg_alloc(char *fn, int line)
{
_kd_cmsg_t *ki = kmem_cache_alloc(mISDN_cmsg_cp, GFP_ATOMIC);
if (!ki)
return(NULL);
ki->kdi.typ = KM_DBG_TYP_CM;
INIT_LIST_HEAD(&ki->kdi.head);
ki->kdi.line = line;
ki->kdi.file = fn;
list_add_tail(&ki->kdi.head, &mISDN_kmem_garbage);
return(&ki->cm);
}
void
cmsg_free(_cmsg *cm)
{
km_dbg_item_t *kdi;
if (!cm) {
int_errtxt("zero pointer free at %p", __builtin_return_address(0));
return;
}
kdi = KDB_GET_KDI(cm);
list_del(&kdi->head);
kmem_cache_free(mISDN_cmsg_cp, kdi);
}
AppPlci_t *
_kd_AppPlci_alloc(char *fn, int line)
{
_kd_AppPlci_t *ki = kmem_cache_alloc(mISDN_AppPlci_cp, GFP_ATOMIC);
if (!ki)
return(NULL);
ki->kdi.typ = KM_DBG_TYP_AP;
INIT_LIST_HEAD(&ki->kdi.head);
ki->kdi.line = line;
ki->kdi.file = fn;
list_add_tail(&ki->kdi.head, &mISDN_kmem_garbage);
return(&ki->ap);
}
void
AppPlci_free(AppPlci_t *ap)
{
km_dbg_item_t *kdi;
if (!ap) {
int_errtxt("zero pointer free at %p", __builtin_return_address(0));
return;
}
kdi = KDB_GET_KDI(ap);
list_del(&kdi->head);
kmem_cache_free(mISDN_AppPlci_cp, kdi);
}
Ncci_t *
_kd_ncci_alloc(char *fn, int line)
{
_kd_Ncci_t *ki = kmem_cache_alloc(mISDN_ncci_cp, GFP_ATOMIC);
if (!ki)
return(NULL);
ki->kdi.typ = KM_DBG_TYP_NI;
INIT_LIST_HEAD(&ki->kdi.head);
ki->kdi.line = line;
ki->kdi.file = fn;
list_add_tail(&ki->kdi.head, &mISDN_kmem_garbage);
return(&ki->ni);
}
void
ncci_free(Ncci_t *ni)
{
km_dbg_item_t *kdi;
if (!ni) {
int_errtxt("zero pointer free at %p", __builtin_return_address(0));
return;
}
kdi = KDB_GET_KDI(ni);
list_del(&kdi->head);
kmem_cache_free(mISDN_ncci_cp, kdi);
}
SSProcess_t *
_kd_SSProcess_alloc(char *fn, int line)
{
_kd_SSProcess_t *ki = kmem_cache_alloc(mISDN_sspc_cp, GFP_ATOMIC);
if (!ki)
return(NULL);
ki->kdi.typ = KM_DBG_TYP_SP;
INIT_LIST_HEAD(&ki->kdi.head);
ki->kdi.line = line;
ki->kdi.file = fn;
list_add_tail(&ki->kdi.head, &mISDN_kmem_garbage);
return(&ki->sp);
}
void
SSProcess_free(SSProcess_t *sp)
{
km_dbg_item_t *kdi;
if (!sp) {
int_errtxt("zero pointer free at %p", __builtin_return_address(0));
return;
}
kdi = KDB_GET_KDI(sp);
list_del(&kdi->head);
kmem_cache_free(mISDN_sspc_cp, kdi);
}
static void
free_garbage(void)
{
struct list_head *item, *next;
_kd_all_t *kda;
list_for_each_safe(item, next, &mISDN_kmem_garbage) {
kda = (_kd_all_t *)item;
printk(KERN_DEBUG "garbage item found (%p <- %p -> %p) type%ld allocated at %s:%d\n",
kda->kdi.head.prev, item, kda->kdi.head.next, kda->kdi.typ, kda->kdi.file, kda->kdi.line);
list_del(item);
switch(kda->kdi.typ) {
case KM_DBG_TYP_CM:
printk(KERN_DEBUG "cmsg cmd(%x,%x) appl(%x) addr(%x) nr(%d)\n",
kda->a.cm.Command,
kda->a.cm.Subcommand,
kda->a.cm.ApplId,
kda->a.cm.adr.adrController,
kda->a.cm.Messagenumber);
kmem_cache_free(mISDN_cmsg_cp, item);
break;
case KM_DBG_TYP_AP:
printk(KERN_DEBUG "AppPlci: PLCI(%x) m.state(%x) appl(%p)\n",
kda->a.ap.addr,
kda->a.ap.plci_m.state,
kda->a.ap.appl);
kmem_cache_free(mISDN_AppPlci_cp, item);
break;
case KM_DBG_TYP_NI:
printk(KERN_DEBUG "Ncci: NCCI(%x) state(%x) m.state(%x) aplci(%p)\n",
kda->a.ni.addr,
kda->a.ni.state,
kda->a.ni.ncci_m.state,
kda->a.ni.AppPlci);
kmem_cache_free(mISDN_ncci_cp, item);
break;
case KM_DBG_TYP_SP:
printk(KERN_DEBUG "SSPc: addr(%x) id(%x) apid(%x) func(%x)\n",
kda->a.sp.addr,
kda->a.sp.invokeId,
kda->a.sp.ApplId,
kda->a.sp.Function);
kmem_cache_free(mISDN_sspc_cp, item);
break;
default:
printk(KERN_DEBUG "unknown garbage item(%p) type %ld\n",
item, kda->kdi.typ);
break;
}
}
}
#endif
static void CapiCachesFree(void)
{
#ifdef MISDN_KMEM_DEBUG
free_garbage();
#endif
if (mISDN_cmsg_cp) {
kmem_cache_destroy(mISDN_cmsg_cp);
mISDN_cmsg_cp = NULL;
}
if (mISDN_AppPlci_cp) {
kmem_cache_destroy(mISDN_AppPlci_cp);
mISDN_AppPlci_cp = NULL;
}
if (mISDN_ncci_cp) {
kmem_cache_destroy(mISDN_ncci_cp);
mISDN_ncci_cp = NULL;
}
if (mISDN_sspc_cp) {
kmem_cache_destroy(mISDN_sspc_cp);
mISDN_sspc_cp = NULL;
}
}
static int CapiNew(void)
{
mISDN_cmsg_cp = NULL;
mISDN_AppPlci_cp = NULL;
mISDN_ncci_cp = NULL;
mISDN_sspc_cp = NULL;
mISDN_cmsg_cp = kmem_cache_create("mISDN_cmesg",
#ifdef MISDN_KMEM_DEBUG
sizeof(_kd_cmsg_t),
#else
sizeof(_cmsg),
#endif
0, 0, NULL, NULL);
if (!mISDN_cmsg_cp) {
CapiCachesFree();
return(-ENOMEM);
}
mISDN_AppPlci_cp = kmem_cache_create("mISDN_AppPlci",
#ifdef MISDN_KMEM_DEBUG
sizeof(_kd_AppPlci_t),
#else
sizeof(AppPlci_t),
#endif
0, 0, NULL, NULL);
if (!mISDN_AppPlci_cp) {
CapiCachesFree();
return(-ENOMEM);
}
mISDN_ncci_cp = kmem_cache_create("mISDN_Ncci",
#ifdef MISDN_KMEM_DEBUG
sizeof(_kd_Ncci_t),
#else
sizeof(Ncci_t),
#endif
0, 0, NULL, NULL);
if (!mISDN_ncci_cp) {
CapiCachesFree();
return(-ENOMEM);
}
mISDN_sspc_cp = kmem_cache_create("mISDN_SSProc",
#ifdef MISDN_KMEM_DEBUG
sizeof(_kd_SSProcess_t),
#else
sizeof(SSProcess_t),
#endif
0, 0, NULL, NULL);
if (!mISDN_sspc_cp) {
CapiCachesFree();
return(-ENOMEM);
}
#ifdef OLDCAPI_DRIVER_INTERFACE
cdrv_if = attach_capi_driver(&mISDN_driver);
if (!cdrv_if) {
CapiCachesFree();
printk(KERN_ERR "mISDN: failed to attach capi_driver\n");
return -EIO;
}
#endif
init_listen();
init_cplci();
init_AppPlci();
init_ncci();
return 0;
}
@ -60,7 +310,7 @@ capi20_manager(void *data, u_int prim, void *arg) {
mISDNinstance_t *inst = data;
int found=0;
BInst_t *binst = NULL;
Contr_t *ctrl = (Contr_t *)capi_obj.ilist;
Controller_t *ctrl = (Controller_t *)capi_obj.ilist;
if (CAPI_DBG_INFO & debug)
printk(KERN_DEBUG "capi20_manager data:%p prim:%x arg:%p\n", data, prim, arg);
@ -85,11 +335,10 @@ capi20_manager(void *data, u_int prim, void *arg) {
ctrl = ctrl->next;
}
if (prim == (MGR_NEWLAYER | REQUEST)) {
ctrl = newContr(&capi_obj, data, arg);
if (!ctrl)
return(-EINVAL);
ctrl->debug = debug;
return(0);
int ret = ControllerConstr(&ctrl, data, arg, &capi_obj);
if (!ret)
ctrl->debug = debug;
return(ret);
}
if (!ctrl) {
if (CAPI_DBG_WARN & debug)
@ -105,7 +354,7 @@ capi20_manager(void *data, u_int prim, void *arg) {
case MGR_SETIF | INDICATION:
case MGR_SETIF | REQUEST:
if (&ctrl->inst == inst)
return(SetIF(inst, arg, prim, NULL, contrL3L4, ctrl));
return(SetIF(inst, arg, prim, NULL, ControllerL3L4, ctrl));
else
return(SetIF(inst, arg, prim, NULL, ncci_l3l4, inst->data));
case MGR_DISCONNECT | REQUEST:
@ -114,8 +363,7 @@ capi20_manager(void *data, u_int prim, void *arg) {
case MGR_RELEASE | INDICATION:
if (CAPI_DBG_INFO & debug)
printk(KERN_DEBUG "release_capi20 id %x\n", ctrl->inst.st->id);
contrDestr(ctrl);
kfree(ctrl);
ControllerDestr(ctrl);
break;
case MGR_UNREGLAYER | REQUEST:
if (binst) {
@ -127,7 +375,7 @@ capi20_manager(void *data, u_int prim, void *arg) {
case MGR_CTRLREADY | INDICATION:
if (CAPI_DBG_INFO & debug)
printk(KERN_DEBUG "ctrl %x ready\n", ctrl->inst.st->id);
contrRun(ctrl);
ControllerRun(ctrl);
break;
default:
if (CAPI_DBG_WARN & debug)
@ -158,9 +406,11 @@ int Capi20Init(void)
#ifdef OLDCAPI_DRIVER_INTERFACE
detach_capi_driver(&mISDN_driver);
#endif
CapiCachesFree();
free_listen();
free_cplci();
free_AppPlci();
free_ncci();
free_Application();
}
return(err);
}
@ -168,24 +418,24 @@ int Capi20Init(void)
#ifdef MODULE
static void Capi20cleanup(void)
{
int err;
Contr_t *contr;
int err;
Controller_t *contr;
if ((err = mISDN_unregister(&capi_obj))) {
printk(KERN_ERR "Can't unregister User DSS1 error(%d)\n", err);
printk(KERN_ERR "Can't unregister CAPI20 error(%d)\n", err);
}
if (capi_obj.ilist) {
printk(KERN_WARNING "mISDNl3 contrlist not empty\n");
while((contr = capi_obj.ilist)) {
contrDestr(contr);
kfree(contr);
}
printk(KERN_WARNING "mISDN controller list not empty\n");
while((contr = capi_obj.ilist))
ControllerDestr(contr);
}
#ifdef OLDCAPI_DRIVER_INTERFACE
detach_capi_driver(&mISDN_driver);
#endif
free_Application();
CapiCachesFree();
free_listen();
free_cplci();
free_AppPlci();
free_ncci();
}

View File

@ -1,393 +0,0 @@
/* $Id$
*
*/
#ifndef __mISDN_CAPI_H__
#define __mISDN_CAPI_H__
#include <linux/mISDNif.h>
#include <linux/skbuff.h>
#include <linux/timer.h>
#include <linux/capi.h>
#include <linux/kernelcapi.h>
#ifdef OLDCAPI_DRIVER_INTERFACE
#include "../avmb1/capiutil.h"
#include "../avmb1/capicmd.h"
#include "../avmb1/capilli.h"
#else
#include <linux/list.h>
#include <linux/isdn/capiutil.h>
#include <linux/isdn/capicmd.h>
#include <linux/isdn/capilli.h>
#endif
#include "asn1.h"
#include "fsm.h"
#ifdef MEMDBG
#include "memdbg.h"
#endif
// ---------------------------------------------------------------------------
// common stuff
#define CAPI_DBG_WARN 0x00000001
#define CAPI_DBG_INFO 0x00000004
#define CAPI_DBG_APPL 0x00000010
#define CAPI_DBG_APPL_INFO 0x00000040
#define CAPI_DBG_LISTEN 0x00000100
#define CAPI_DBG_LISTEN_STATE 0x00000200
#define CAPI_DBG_LISTEN_INFO 0x00000400
#define CAPI_DBG_CONTR 0x00010000
#define CAPI_DBG_CONTR_INFO 0x00040000
#define CAPI_DBG_CONTR_MSG 0x00080000
#define CAPI_DBG_PLCI 0x00100000
#define CAPI_DBG_PLCI_STATE 0x00200000
#define CAPI_DBG_PLCI_INFO 0x00400000
#define CAPI_DBG_PLCI_L3 0x00800000
#define CAPI_DBG_NCCI 0x01000000
#define CAPI_DBG_NCCI_STATE 0x02000000
#define CAPI_DBG_NCCI_INFO 0x04000000
#define CAPI_DBG_NCCI_L3 0x08000000
#ifdef OLDCAPI_DRIVER_INTERFACE
extern struct capi_driver_interface *cdrv_if;
extern struct capi_driver mISDN_driver;
#endif
void init_listen(void);
void init_cplci(void);
void init_ncci(void);
void free_listen(void);
void free_cplci(void);
void free_ncci(void);
void capidebug(int, char *, ...);
/* we implement 64 bit extentions */
#define CAPI_B3_DATA_IND_HEADER_SIZE 30
#define SuppServiceCF 0x00000010
#define SuppServiceTP 0x00000002
#define mISDNSupportedServices (SuppServiceCF | SuppServiceTP)
#define CAPIMSG_REQ_DATAHANDLE(m) (m[18] | (m[19]<<8))
#define CAPIMSG_RESP_DATAHANDLE(m) (m[12] | (m[13]<<8))
#define CMSGCMD(cmsg) CAPICMD((cmsg)->Command, (cmsg)->Subcommand)
#define CAPI_MAXPLCI 5
#define CAPI_MAXDUMMYPCS 16
struct Bprotocol {
__u16 B1protocol;
__u16 B2protocol;
__u16 B3protocol;
};
__u16 q931CIPValue(Q931_info_t *);
typedef struct _DummyProcess {
__u16 invokeId;
__u16 Function;
__u32 Handle;
__u32 adrDummy;
__u16 ApplId;
struct _Contr *contr;
struct timer_list tl;
__u8 buf[128];
} DummyProcess_t;
void dummyPcConstr(DummyProcess_t *dummy_pc, struct _Contr *contr, __u16 invokeId);
void dummyPcDestr(DummyProcess_t *dummy_pc);
void dummyPcAddTimer(DummyProcess_t *dummy_pc, int msec);
int capiEncodeFacIndSuspend(__u8 *dest, __u16 SupplementaryServiceReason);
struct FacReqListen {
__u32 NotificationMask;
};
struct FacReqSuspend {
__u8 *CallIdentity;
};
struct FacReqResume {
__u8 *CallIdentity;
};
struct FacReqCFActivate {
__u32 Handle;
__u16 Procedure;
__u16 BasicService;
__u8 *ServedUserNumber;
__u8 *ForwardedToNumber;
__u8 *ForwardedToSubaddress;
};
struct FacReqCFDeactivate {
__u32 Handle;
__u16 Procedure;
__u16 BasicService;
__u8 *ServedUserNumber;
};
#define FacReqCFInterrogateParameters FacReqCFDeactivate
struct FacReqCFInterrogateNumbers {
__u32 Handle;
};
struct FacReqParm {
__u16 Function;
union {
struct FacReqListen Listen;
struct FacReqSuspend Suspend;
struct FacReqResume Resume;
struct FacReqCFActivate CFActivate;
struct FacReqCFDeactivate CFDeactivate;
struct FacReqCFInterrogateParameters CFInterrogateParameters;
struct FacReqCFInterrogateNumbers CFInterrogateNumbers;
} u;
};
struct FacConfGetSupportedServices {
__u16 SupplementaryServiceInfo;
__u32 SupportedServices;
};
struct FacConfInfo {
__u16 SupplementaryServiceInfo;
};
struct FacConfParm {
__u16 Function;
union {
struct FacConfGetSupportedServices GetSupportedServices;
struct FacConfInfo Info;
} u;
};
// ---------------------------------------------------------------------------
// struct Contr
typedef struct _BInst {
struct _BInst *prev;
struct _BInst *next;
mISDNstack_t *bst;
mISDNinstance_t inst;
} BInst_t;
typedef struct _Contr {
struct _Contr *prev;
struct _Contr *next;
mISDNinstance_t inst;
BInst_t *binst;
struct capi_ctr *ctrl;
__u32 adrController;
int b3_mode;
int entity;
u_int debug;
char infobuf[128];
char msgbuf[128];
struct _Plci *plcis[CAPI_MAXPLCI];
struct _Appl *appls[CAPI_MAXAPPL];
DummyProcess_t *dummy_pcs[CAPI_MAXDUMMYPCS];
__u16 lastInvokeId;
} Contr_t;
Contr_t *newContr(mISDNobject_t *, mISDNstack_t *, mISDN_pid_t *);
void contrDestr(Contr_t *);
void contrRun(Contr_t *);
void contrDebug(Contr_t *, __u32, char *, ...);
void contrRecvCmsg(Contr_t *, _cmsg *);
void contrAnswerCmsg(Contr_t *, _cmsg *, __u16);
void contrAnswerMessage(Contr_t *, struct sk_buff *, __u16);
struct _Plci *contrNewPlci(Contr_t *, u_int);
struct _Appl *contrId2appl(Contr_t *, __u16);
struct _Plci *contrAdr2plci(Contr_t *, __u32);
void contrDelPlci(Contr_t *, struct _Plci *);
int contrDummyInd(Contr_t *, __u32, struct sk_buff *);
DummyProcess_t *contrNewDummyPc(Contr_t *);
DummyProcess_t *contrId2DummyPc(Contr_t *, __u16);
int contrL4L3(Contr_t *, u_int, int, struct sk_buff *);
int contrL3L4(mISDNif_t *, struct sk_buff *);
BInst_t *contrSelChannel(Contr_t *, u_int);
// ---------------------------------------------------------------------------
// struct Listen
#define CAPI_INFOMASK_CAUSE (0x0001)
#define CAPI_INFOMASK_DATETIME (0x0002)
#define CAPI_INFOMASK_DISPLAY (0x0004)
#define CAPI_INFOMASK_USERUSER (0x0008)
#define CAPI_INFOMASK_PROGRESS (0x0010)
#define CAPI_INFOMASK_FACILITY (0x0020)
//#define CAPI_INFOMASK_CHARGE (0x0040)
//#define CAPI_INFOMASK_CALLEDPN (0x0080)
#define CAPI_INFOMASK_CHANNELID (0x0100)
#define CAPI_INFOMASK_EARLYB3 (0x0200)
//#define CAPI_INFOMASK_REDIRECT (0x0400)
typedef struct _Listen {
Contr_t *contr;
__u16 ApplId;
__u32 InfoMask;
__u32 CIPmask;
__u32 CIPmask2;
struct FsmInst listen_m;
} Listen_t;
void listenConstr(Listen_t *listen, Contr_t *contr, __u16 ApplId);
void listenDestr(Listen_t *listen);
void listenDebug(Listen_t *listen, __u32 level, char *fmt, ...);
void listenSendMessage(Listen_t *listen, struct sk_buff *skb);
int listenHandle(Listen_t *listen, __u16 CIPValue);
// ---------------------------------------------------------------------------
// struct Appl
#define APPL_FLAG_D2TRACE 1
typedef struct _Appl {
Contr_t *contr;
__u16 ApplId;
__u16 MsgId;
Listen_t listen;
struct _Cplci *cplcis[CAPI_MAXPLCI];
__u32 NotificationMask;
u_long flags;
capi_register_params rp;
} Appl_t;
void applConstr(Appl_t *appl, Contr_t *contr, __u16 ApplId, capi_register_params *rp);
void applDestr(Appl_t *appl);
void applDebug(Appl_t *appl, __u32 level, char *fmt, ...);
void applSendMessage(Appl_t *appl, struct sk_buff *skb);
void applFacilityReq(Appl_t *appl, struct sk_buff *skb);
void applSuppFacilityReq(Appl_t *appl, _cmsg *cmsg);
int applGetSupportedServices(Appl_t *appl, struct FacReqParm *facReqParm,
struct FacConfParm *facConfParm);
int applFacListen(Appl_t *appl, struct FacReqParm *facReqParm,
struct FacConfParm *facConfParm);
int applFacCFActivate(Appl_t *appl, struct FacReqParm *facReqParm,
struct FacConfParm *facConfParm);
int applFacCFDeactivate(Appl_t *appl, struct FacReqParm *facReqParm,
struct FacConfParm *facConfParm);
int applFacCFInterrogateNumbers(Appl_t *appl, struct FacReqParm *facReqParm,
struct FacConfParm *facConfParm);
int applFacCFInterrogateParameters(Appl_t *appl, struct FacReqParm *facReqParm,
struct FacConfParm *facConfParm);
void applManufacturerReq(Appl_t *appl, struct sk_buff *skb);
void applD2Trace(Appl_t *appl, u_char *buf, int len);
DummyProcess_t *applNewDummyPc(Appl_t *appl, __u16 Function, __u32 Handle);
struct _Cplci *applNewCplci(Appl_t *appl, struct _Plci *plci);
struct _Cplci *applAdr2cplci(Appl_t *appl, __u32 adr);
void applDelCplci(Appl_t *appl, struct _Cplci *cplci);
// ---------------------------------------------------------------------------
// struct Plci
#define PLCI_FLAG_ALERTING 1
#define PLCI_FLAG_OUTGOING 2
typedef struct _Plci {
Contr_t *contr;
__u32 adrPLCI;
u_int id;
u_long flags;
int nAppl;
struct _Cplci *cplcis[CAPI_MAXAPPL];
} Plci_t;
void plciConstr(Plci_t *plci, Contr_t *contr, __u32 adrPLCI, u_int id);
void plciDestr(Plci_t *plci);
void plciDebug(Plci_t *plci, __u32 level, char *fmt, ...);
int plci_l3l4(Plci_t *, int, struct sk_buff *);
void plciAttachCplci(Plci_t *plci, struct _Cplci *cplci);
void plciDetachCplci(Plci_t *plci, struct _Cplci *cplci);
void plciNewCrInd(Plci_t *plci, void *);
void plciNewCrReq(Plci_t *plci);
int plciL4L3(Plci_t *, __u32, struct sk_buff *);
// ---------------------------------------------------------------------------
// struct Cplci
typedef struct _Cplci {
__u32 adrPLCI;
Plci_t *plci;
Appl_t *appl;
struct _Ncci *ncci;
Contr_t *contr;
struct FsmInst plci_m;
u_char cause[4]; // we may get a cause from l3 DISCONNECT message
// which we'll need send in DISCONNECT_IND caused by
// l3 RELEASE message
int bchannel;
struct Bprotocol Bprotocol;
} Cplci_t;
void cplciConstr(Cplci_t *cplci, Appl_t *appl, Plci_t *plci);
void cplciDestr(Cplci_t *cplci);
void cplciDebug(Cplci_t *cplci, __u32 level, char *fmt, ...);
void cplci_l3l4(Cplci_t *cplci, int pr, void *arg);
void cplciSendMessage(Cplci_t *cplci, struct sk_buff *skb);
void cplciClearOtherApps(Cplci_t *cplci);
void cplciInfoIndMsg(Cplci_t *, __u32, unsigned char);
void cplciInfoIndIE(Cplci_t *, unsigned char, __u32, Q931_info_t *);
void cplciRecvCmsg(Cplci_t *cplci, _cmsg *cmsg);
void cplciCmsgHeader(Cplci_t *cplci, _cmsg *cmsg, __u8 cmd, __u8 subcmd);
void cplciLinkUp(Cplci_t *cplci);
void cplciLinkDown(Cplci_t *cplci);
int cplciFacSuspendReq(Cplci_t *cplci, struct FacReqParm *facReqParm,
struct FacConfParm *facConfParm);
int cplciFacResumeReq(Cplci_t *cplci, struct FacReqParm *facReqParm,
struct FacConfParm *facConfParm);
// ---------------------------------------------------------------------------
// Ncci_t
typedef struct _Ncci {
BInst_t *binst;
__u32 adrNCCI;
Contr_t *contr;
Cplci_t *cplci;
Appl_t *appl;
struct FsmInst ncci_m;
int window;
u_long Flags;
struct {
struct sk_buff *skb;
__u16 DataHandle;
__u16 MsgId;
} xmit_skb_handles[CAPI_MAXDATAWINDOW];
struct sk_buff *recv_skb_handles[CAPI_MAXDATAWINDOW];
struct sk_buff_head squeue;
_cmsg tmpmsg;
} Ncci_t;
#define NCCI_FLG_FCTRL 1
#define NCCI_FLG_BUSY 2
void ncciConstr(Ncci_t *ncci, Cplci_t *cplci);
void ncciDestr(Ncci_t *ncci);
void ncciSendMessage(Ncci_t *, struct sk_buff *);
int ncci_l3l4(mISDNif_t *, struct sk_buff *);
void ncciLinkUp(Ncci_t *ncci);
void ncciLinkDown(Ncci_t *ncci);
void ncciInitSt(Ncci_t *ncci);
void ncciReleaseSt(Ncci_t *ncci);
__u16 ncciSelectBprotocol(Ncci_t *ncci);
void ncciRecvCmsg(Ncci_t *ncci, _cmsg *cmsg);
void ncciCmsgHeader(Ncci_t *ncci, _cmsg *cmsg, __u8 cmd, __u8 subcmd);
int capiEncodeWord(__u8 *dest, __u16 i);
int capiEncodeDWord(__u8 *dest, __u32 i);
int capiEncodeFacIndCFact(__u8 *dest, __u16 SupplementaryServiceReason, __u32 Handle);
int capiEncodeFacIndCFdeact(__u8 *dest, __u16 SupplementaryServiceReason, __u32 Handle);
int capiEncodeFacIndCFNotAct(__u8 *dest, struct ActDivNotification *actNot);
int capiEncodeFacIndCFNotDeact(__u8 *dest, struct DeactDivNotification *deactNot);
int capiEncodeFacIndCFinterParameters(__u8 *dest, __u16 SupplementaryServiceReason, __u32 Handle,
struct IntResultList *intResultList);
int capiEncodeFacIndCFinterNumbers(__u8 *dest, __u16 SupplementaryServiceReason, __u32 Handle,
struct ServedUserNumberList *list);
int capiEncodeFacConfParm(__u8 *dest, struct FacConfParm *facConfParm);
#endif

View File

@ -2,7 +2,7 @@
*
*/
#include "capi.h"
#include "m_capi.h"
#include "asn1.h"
int capiEncodeWord(__u8 *p, __u16 i)

View File

@ -4,7 +4,7 @@
#include <linux/vmalloc.h>
#include <asm/uaccess.h>
#include "capi.h"
#include "m_capi.h"
#include "helper.h"
#include "debug.h"
@ -12,45 +12,52 @@
if (contr->debug & lev) capidebug(lev, fmt, ## args)
void
contrDestr(Contr_t *contr)
ControllerDestr(Controller_t *contr)
{
int i;
mISDNinstance_t *inst = &contr->inst;
mISDNinstance_t *inst = &contr->inst;
struct list_head *item, *next;
u_long flags;
for (i = 0; i < CAPI_MAXAPPL; i++) {
if (contr->appls[i]) {
applDestr(contr->appls[i]);
kfree(contr->appls[i]);
contr->appls[i] = NULL;
}
spin_lock_irqsave(&contr->list_lock, flags);
list_for_each_safe(item, next, &contr->Applications) {
ApplicationDestr((Application_t *)item, 3);
}
for (i = 0; i < CAPI_MAXPLCI; i++) {
if (contr->plcis[i]) {
plciDestr(contr->plcis[i]);
kfree(contr->plcis[i]);
contr->plcis[i] = NULL;
if (contr->plcis) {
Plci_t *plci = contr->plcis;
int i;
for (i = 0; i < contr->maxplci; i++) {
AppPlci_t *aplci;
if (test_bit(PLCI_STATE_ACTIV, &plci->state)) {
if (plci->nAppl) {
printk(KERN_ERR "%s: PLCI(%x) still busy (%d)\n",
__FUNCTION__, plci->addr, plci->nAppl);
list_for_each_safe(item, next, &plci->AppPlcis) {
aplci = (AppPlci_t *)item;
aplci->contr = NULL;
plciDetachAppPlci(plci, aplci);
AppPlciDestr(aplci);
}
}
}
plci++;
}
kfree(contr->plcis);
contr->plcis = NULL;
}
for (i = 0; i < CAPI_MAXDUMMYPCS; i++) {
if (contr->dummy_pcs[i]) {
dummyPcDestr(contr->dummy_pcs[i]);
kfree(contr->dummy_pcs[i]);
contr->dummy_pcs[i] = NULL;
}
list_for_each_safe(item, next, &contr->SSProcesse) {
SSProcessDestr((SSProcess_t *)item);
}
#ifdef OLDCAPI_DRIVER_INTERFACE
if (contr->ctrl)
cdrv_if->detach_ctr(contr->ctrl);
#else
detach_capi_ctr(contr->ctrl);
kfree(contr->ctrl);
contr->ctrl = NULL;
#endif
while (contr->binst) {
BInst_t *binst = contr->binst;
REMOVE_FROM_LISTBASE(binst, contr->binst);
kfree(binst);
if (contr->ctrl) {
detach_capi_ctr(contr->ctrl);
kfree(contr->ctrl);
}
#endif
contr->ctrl = NULL;
if (inst->up.peer) {
inst->up.peer->obj->ctrl(inst->up.peer,
MGR_DISCONNECT | REQUEST, &inst->up);
@ -59,24 +66,25 @@ contrDestr(Contr_t *contr)
inst->down.peer->obj->ctrl(inst->down.peer,
MGR_DISCONNECT | REQUEST, &inst->down);
}
inst->obj->ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
REMOVE_FROM_LISTBASE(contr, ((Contr_t *)inst->obj->ilist));
while (contr->binst) {
BInst_t *binst = contr->binst;
REMOVE_FROM_LISTBASE(binst, contr->binst);
kfree(binst);
}
if (contr->entity != MISDN_ENTITY_NONE)
inst->obj->ctrl(inst, MGR_DELENTITY | REQUEST, (void *)contr->entity);
inst->obj->ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
REMOVE_FROM_LISTBASE(contr, ((Controller_t *)inst->obj->ilist));
spin_unlock_irqrestore(&contr->list_lock, flags);
kfree(contr);
}
void
contrRun(Contr_t *contr)
ControllerRun(Controller_t *contr)
{
BInst_t *binst;
int nb, ret;
int ret;
nb = 0;
binst = contr->binst;
while(binst) {
nb++;
binst = binst->next;
}
if (contr->inst.st && contr->inst.st->mgr)
sprintf(contr->ctrl->manu, "mISDN CAPI controller %s", contr->inst.st->mgr->name);
else
@ -88,7 +96,7 @@ contrRun(Contr_t *contr)
contr->ctrl->version.minormanuversion = 0;
memset(&contr->ctrl->profile, 0, sizeof(struct capi_profile));
contr->ctrl->profile.ncontroller = 1;
contr->ctrl->profile.nbchannel = nb;
contr->ctrl->profile.nbchannel = contr->nr_bc;
contrDebug(contr, CAPI_DBG_INFO, "%s: %s version(%s)",
__FUNCTION__, contr->ctrl->manu, contr->ctrl->serial);
// FIXME
@ -101,7 +109,7 @@ contrRun(Contr_t *contr)
contr->ctrl->profile.goptions |= GLOBALOPT_DTMF |
GLOBALOPT_SUPPLEMENTARY_SERVICE;
if (nb) {
if (contr->nr_bc) {
mISDN_pid_t pidmask;
memset(&pidmask, 0, sizeof(mISDN_pid_t));
@ -132,67 +140,76 @@ contrRun(Contr_t *contr)
#endif
}
Appl_t
*contrId2appl(Contr_t *contr, __u16 ApplId)
Application_t
*getApplication4Id(Controller_t *contr, __u16 ApplId)
{
if ((ApplId < 1) || (ApplId > CAPI_MAXAPPL)) {
int_error();
return 0;
struct list_head *item;
Application_t *ap = NULL;
list_for_each(item, &contr->Applications) {
ap = (Application_t *)item;
if (ap->ApplId == ApplId)
break;
ap = NULL;
}
return contr->appls[ApplId - 1];
return(ap);
}
Plci_t
*contrAdr2plci(Contr_t *contr, __u32 adr)
*getPlci4Addr(Controller_t *contr, __u32 addr)
{
int i = (adr >> 8);
int i = (addr >> 8) & 0xff;
if ((i < 1) || (i > CAPI_MAXPLCI)) {
if ((i < 1) || (i > contr->maxplci)) {
int_error();
return 0;
return(NULL);
}
return contr->plcis[i - 1];
return(&contr->plcis[i - 1]);
}
static void
RegisterAppl(struct capi_ctr *ctrl, __u16 ApplId, capi_register_params *rp)
RegisterApplication(struct capi_ctr *ctrl, __u16 ApplId, capi_register_params *rp)
{
Contr_t *contr = ctrl->driverdata;
Appl_t *appl;
Controller_t *contr = ctrl->driverdata;
Application_t *appl;
u_long flags;
int ret;
contrDebug(contr, CAPI_DBG_APPL, "%s: ApplId(%x)", __FUNCTION__, ApplId);
appl = contrId2appl(contr, ApplId);
appl = getApplication4Id(contr, ApplId);
if (appl) {
int_error();
return;
}
appl = kmalloc(sizeof(Appl_t), GFP_ATOMIC);
if (!appl) {
spin_lock_irqsave(&contr->list_lock, flags);
ret = ApplicationConstr(contr, ApplId, rp);
spin_unlock_irqrestore(&contr->list_lock, flags);
if (ret) {
int_error();
return;
}
contr->appls[ApplId - 1] = appl;
applConstr(appl, contr, ApplId, rp);
#ifdef OLDCAPI_DRIVER_INTERFACE
contr->ctrl->appl_registered(contr->ctrl, ApplId);
#endif
}
static void
ReleaseAppl(struct capi_ctr *ctrl, __u16 ApplId)
ReleaseApplication(struct capi_ctr *ctrl, __u16 ApplId)
{
Contr_t *contr = ctrl->driverdata;
Appl_t *appl;
Controller_t *contr = ctrl->driverdata;
Application_t *appl;
u_long flags;
contrDebug(contr, CAPI_DBG_APPL, "%s: ApplId(%x) caller:%lx", __FUNCTION__, ApplId, __builtin_return_address(0));
appl = contrId2appl(contr, ApplId);
spin_lock_irqsave(&contr->list_lock, flags);
appl = getApplication4Id(contr, ApplId);
if (!appl) {
spin_unlock_irqrestore(&contr->list_lock, flags);
int_error();
return;
}
applDestr(appl);
kfree(appl);
contr->appls[ApplId - 1] = NULL;
ApplicationDestr(appl, 1);
spin_unlock_irqrestore(&contr->list_lock, flags);
#ifdef OLDCAPI_DRIVER_INTERFACE
contr->ctrl->appl_released(contr->ctrl, ApplId);
#endif
@ -205,18 +222,18 @@ static u16
#endif
SendMessage(struct capi_ctr *ctrl, struct sk_buff *skb)
{
Contr_t *contr = ctrl->driverdata;
Appl_t *appl;
int ApplId;
int err = CAPI_NOERROR;
Controller_t *contr = ctrl->driverdata;
Application_t *appl;
int ApplId;
int err = CAPI_NOERROR;
ApplId = CAPIMSG_APPID(skb->data);
appl = contrId2appl(contr, ApplId);
appl = getApplication4Id(contr, ApplId);
if (!appl) {
int_error();
err = CAPI_ILLAPPNR;
} else
applSendMessage(appl, skb);
ApplicationSendMessage(appl, skb);
#ifndef OLDCAPI_DRIVER_INTERFACE
return(err);
#endif
@ -225,7 +242,7 @@ SendMessage(struct capi_ctr *ctrl, struct sk_buff *skb)
static int
LoadFirmware(struct capi_ctr *ctrl, capiloaddata *data)
{
Contr_t *contr = ctrl->driverdata;
Controller_t *contr = ctrl->driverdata;
struct firm {
int len;
void *data;
@ -253,7 +270,7 @@ LoadFirmware(struct capi_ctr *ctrl, capiloaddata *data)
static char *
procinfo(struct capi_ctr *ctrl)
{
Contr_t *contr = ctrl->driverdata;
Controller_t *contr = ctrl->driverdata;
if (CAPI_DBG_INFO & contr->debug)
printk(KERN_DEBUG "%s\n", __FUNCTION__);
@ -279,20 +296,20 @@ read_proc(char *page, char **start, off_t off, int count, int *eof, struct capi_
static void
ResetContr(struct capi_ctr *ctrl)
ResetController(struct capi_ctr *ctrl)
{
Contr_t *contr = ctrl->driverdata;
int ApplId;
Appl_t *appl;
Controller_t *contr = ctrl->driverdata;
struct list_head *item, *next;
u_long flags;
for (ApplId = 1; ApplId <= CAPI_MAXAPPL; ApplId++) {
appl = contrId2appl(contr, ApplId);
if (appl) {
applDestr(appl);
kfree(appl);
}
contr->appls[ApplId - 1] = NULL;
spin_lock_irqsave(&contr->list_lock, flags);
list_for_each_safe(item, next, &contr->Applications) {
ApplicationDestr((Application_t *)item, 2);
}
list_for_each_safe(item, next, &contr->SSProcesse) {
SSProcessDestr((SSProcess_t *)item);
}
spin_unlock_irqrestore(&contr->list_lock, flags);
#ifdef OLDCAPI_DRIVER_INTERFACE
contr->ctrl->reseted(contr->ctrl);
#else
@ -302,9 +319,9 @@ ResetContr(struct capi_ctr *ctrl)
#ifdef OLDCAPI_DRIVER_INTERFACE
static void
Remove_Contr(struct capi_ctr *ctrl)
Remove_Controller(struct capi_ctr *ctrl)
{
Contr_t *contr = ctrl->driverdata;
Controller_t *contr = ctrl->driverdata;
if (CAPI_DBG_INFO & contr->debug)
printk(KERN_DEBUG "%s\n", __FUNCTION__);
@ -314,10 +331,10 @@ struct capi_driver mISDN_driver = {
"mISDN",
"0.01",
LoadFirmware,
ResetContr,
Remove_Contr,
RegisterAppl,
ReleaseAppl,
ResetController,
Remove_Controller,
RegisterApplication,
ReleaseApplication,
SendMessage,
procinfo,
read_proc,
@ -327,136 +344,129 @@ struct capi_driver mISDN_driver = {
#endif
void
contrD2Trace(Contr_t *contr, u_char *buf, int len)
ControllerD2Trace(Controller_t *contr, u_char *buf, int len)
{
Appl_t *appl;
__u16 applId;
struct list_head *item;
for (applId = 1; applId <= CAPI_MAXAPPL; applId++) {
appl = contrId2appl(contr, applId);
if (appl) {
applD2Trace(appl, buf, len);
}
list_for_each(item, &contr->Applications) {
applD2Trace((Application_t *)item, buf, len);
}
}
void
contrRecvCmsg(Contr_t *contr, _cmsg *cmsg)
{
struct sk_buff *skb;
int len;
capi_cmsg2message(cmsg, contr->msgbuf);
len = CAPIMSG_LEN(contr->msgbuf);
contrDebug(contr, CAPI_DBG_CONTR_MSG, "%s: len(%d) applid(%x) %s msgnr(%d) addr(%08x)",
__FUNCTION__, len, cmsg->ApplId, capi_cmd2str(cmsg->Command, cmsg->Subcommand),
cmsg->Messagenumber, cmsg->adr.adrController);
if (!(skb = alloc_skb(len, GFP_ATOMIC))) {
printk(KERN_ERR "%s: no mem for %d bytes\n", __FUNCTION__, len);
int_error();
return;
}
memcpy(skb_put(skb, len), contr->msgbuf, len);
#ifdef OLDCAPI_DRIVER_INTERFACE
contr->ctrl->handle_capimsg(contr->ctrl, cmsg->ApplId, skb);
#else
capi_ctr_handle_message(contr->ctrl, cmsg->ApplId, skb);
#endif
}
void
contrAnswerCmsg(Contr_t *contr, _cmsg *cmsg, __u16 Info)
{
capi_cmsg_answer(cmsg);
cmsg->Info = Info;
contrRecvCmsg(contr, cmsg);
}
void
contrAnswerMessage(Contr_t *contr, struct sk_buff *skb, __u16 Info)
{
_cmsg cmsg;
capi_message2cmsg(&cmsg, skb->data);
contrAnswerCmsg(contr, &cmsg, Info);
}
static Plci_t *
contrGetPLCI4ID(Contr_t *contr, u_int id)
static __inline__ Plci_t *
getPlci4L3id(Controller_t *contr, u_int l3id)
{
Plci_t *plci = contr->plcis;
int i;
for (i = 0; i < CAPI_MAXPLCI; i++) {
if (!contr->plcis[i])
continue;
if (contr->plcis[i]->id == id)
return(contr->plcis[i]);
for (i = 0; i < contr->maxplci; i++) {
if (test_bit(PLCI_STATE_ACTIV, &plci->state) &&
(plci->l3id == l3id))
return(plci);
plci++;
}
return(NULL);
}
Plci_t *
contrNewPlci(Contr_t *contr, u_int id)
int
ControllerNewPlci(Controller_t *contr, Plci_t **plci_p, u_int l3id)
{
Plci_t *plci;
int i;
Plci_t *plci = contr->plcis;
for (i = 0; i < CAPI_MAXPLCI; i++) {
if (!contr->plcis[i])
for (i = 0; i < contr->maxplci; i++) {
if (!test_and_set_bit(PLCI_STATE_ACTIV, &plci->state))
break;
plci++;
}
if (i == CAPI_MAXPLCI) {
return 0;
if (i == contr->maxplci) {
contrDebug(contr, CAPI_DBG_PLCI, "%s: no free PLCI",
__FUNCTION__);
return(-EBUSY); //FIXME
}
if (id == MISDN_ID_ANY) {
*plci_p = plci;
if (l3id == MISDN_ID_ANY) {
if (contr->entity == MISDN_ENTITY_NONE) {
printk(KERN_ERR "mISDN %s: no ENTITY id\n",
__FUNCTION__);
return NULL;
test_and_clear_bit(PLCI_STATE_ACTIV, &plci->state);
return(-EINVAL); //FIXME
}
id = (contr->entity << 16) | ((i+1) << 8) | (contr->adrController & 0xFF);
plci->l3id = (contr->entity << 16) | plci->addr;
} else {
plci = getPlci4L3id(contr, l3id);
if (plci) {
printk(KERN_WARNING "mISDN %s: PLCI(%x) allready has l3id(%x)\n",
__FUNCTION__, plci->addr, l3id);
test_and_clear_bit(PLCI_STATE_ACTIV, &(*plci_p)->state);
return(-EBUSY);
}
plci = *plci_p;
plci->l3id = l3id;
}
plci = contrGetPLCI4ID(contr, id);
if (plci) {
printk(KERN_ERR "mISDN %s: PLCI(%x) allready has id(%x)\n",
__FUNCTION__, plci->adrPLCI, id);
return NULL;
}
plci = kmalloc(sizeof(Plci_t), GFP_ATOMIC);
if (!plci) {
int_error();
return NULL;
}
contr->plcis[i] = plci;
plciConstr(plci, contr, (i+1) << 8 | contr->adrController, id);
contrDebug(contr, CAPI_DBG_PLCI, "%s: PLCI(%x) plci(%p,%d) id(%x)",
__FUNCTION__, plci->adrPLCI, plci, sizeof(*plci), plci->id);
return plci;
}
void
contrDelPlci(Contr_t *contr, Plci_t *plci)
{
int i = plci->adrPLCI >> 8;
contrDebug(contr, CAPI_DBG_PLCI, "%s: PLCI(%x) plci(%p)", __FUNCTION__, plci->adrPLCI, plci);
if ((i < 1) || (i > CAPI_MAXPLCI)) {
int_error();
return;
}
if (contr->plcis[i-1] != plci) {
int_error();
return;
}
plciDestr(plci);
kfree(plci);
contr->plcis[i-1] = NULL;
__FUNCTION__, plci->addr, plci, sizeof(*plci), plci->l3id);
return(0);
}
int
contrL3L4(mISDNif_t *hif, struct sk_buff *skb)
ControllerReleasePlci(Plci_t *plci)
{
Contr_t *contr;
if (!plci->contr) {
int_error();
return(-EINVAL);
}
if (plci->nAppl) {
contrDebug(plci->contr, CAPI_DBG_PLCI, "%s: PLCI(%x) still has %d Applications",
__FUNCTION__, plci->addr, plci->nAppl);
return(-EBUSY);
}
if (!list_empty(&plci->AppPlcis)) {
int_errtxt("PLCI(%x) AppPlcis list not empty", plci->addr);
return(-EBUSY);
}
test_and_clear_bit(PLCI_STATE_ALERTING, &plci->state);
test_and_clear_bit(PLCI_STATE_OUTGOING, &plci->state);
plci->l3id = MISDN_ID_NONE;
if (!test_and_clear_bit(PLCI_STATE_ACTIV, &plci->state))
int_errtxt("PLCI(%x) was not activ", plci->addr);
return(0);
}
void
ControllerAddSSProcess(Controller_t *contr, SSProcess_t *sp)
{
u_long flags;
INIT_LIST_HEAD(&sp->head);
sp->contr = contr;
sp->addr = contr->addr;
spin_lock_irqsave(&contr->list_lock, flags);
contr->LastInvokeId++;
sp->invokeId = contr->LastInvokeId;
list_add(&sp->head, &contr->SSProcesse);
spin_unlock_irqrestore(&contr->list_lock, flags);
}
SSProcess_t
*getSSProcess4Id(Controller_t *contr, __u16 id)
{
struct list_head *item;
SSProcess_t *sp = NULL;
list_for_each(item, &contr->SSProcesse) {
sp = (SSProcess_t *)item;
if (sp->invokeId == id)
break;
sp = NULL;
}
return(sp);
}
int
ControllerL3L4(mISDNif_t *hif, struct sk_buff *skb)
{
Controller_t *contr;
Plci_t *plci;
int ret = -EINVAL;
mISDN_head_t *hh;
@ -468,66 +478,103 @@ contrL3L4(mISDNif_t *hif, struct sk_buff *skb)
contrDebug(contr, CAPI_DBG_CONTR_INFO, "%s: prim(%x) id(%x)",
__FUNCTION__, hh->prim, hh->dinfo);
if (hh->prim == (CC_NEW_CR | INDICATION)) {
plci = contrNewPlci(contr, hh->dinfo);
if (plci) {
ret = 0;
ret = ControllerNewPlci(contr, &plci, hh->dinfo);
if(!ret)
dev_kfree_skb(skb);
} else
ret = -EBUSY;
} else if (hh->dinfo == MISDN_ID_DUMMY) {
ret = contrDummyInd(contr, hh->prim, skb);
ret = Supplementary_l3l4(contr, hh->prim, skb);
} else {
if (!(plci = contrGetPLCI4ID(contr, hh->dinfo))) {
if (!(plci = getPlci4L3id(contr, hh->dinfo))) {
contrDebug(contr, CAPI_DBG_WARN, "%s: unknown plci prim(%x) id(%x)",
__FUNCTION__, hh->prim, hh->dinfo);
return(-ENODEV);
}
contrDebug(contr, CAPI_DBG_PLCI, "%s: PLCI(%x) plci(%p)", __FUNCTION__, plci->adrPLCI, plci);
contrDebug(contr, CAPI_DBG_PLCI, "%s: PLCI(%x) plci(%p)", __FUNCTION__, plci->addr, plci);
ret = plci_l3l4(plci, hh->prim, skb);
}
return(ret);
}
int
contrL4L3(Contr_t *contr, u_int prim, int dinfo, struct sk_buff *skb)
ControllerL4L3(Controller_t *contr, u_int prim, int dinfo, struct sk_buff *skb)
{
return(if_newhead(&contr->inst.down, prim, dinfo, skb));
}
void
contrPutStatus(Contr_t *contr, char *msg)
ControllerPutStatus(Controller_t *contr, char *msg)
{
contrDebug(contr, CAPI_DBG_CONTR, "%s: %s", __FUNCTION__, msg);
}
static int
contrConstr(Contr_t *contr, mISDNstack_t *st, mISDN_pid_t *pid, mISDNobject_t *ocapi)
{
int
ControllerConstr(Controller_t **contr_p, mISDNstack_t *st, mISDN_pid_t *pid, mISDNobject_t *ocapi)
{
Controller_t *contr;
int retval;
mISDNstack_t *cst = st->child;
mISDNstack_t *cst;
BInst_t *binst;
memset(contr, 0, sizeof(Contr_t));
if (!st)
return(-EINVAL);
if (!pid)
return(-EINVAL);
contr = kmalloc(sizeof(Controller_t), GFP_KERNEL);
if (!contr)
return(-ENOMEM);
memset(contr, 0, sizeof(Controller_t));
INIT_LIST_HEAD(&contr->Applications);
INIT_LIST_HEAD(&contr->SSProcesse);
spin_lock_init(&contr->list_lock);
memcpy(&contr->inst.pid, pid, sizeof(mISDN_pid_t));
#ifndef OLDCAPI_DRIVER_INTERFACE
if (!(contr->ctrl = kmalloc(sizeof(struct capi_ctr), GFP_ATOMIC))) {
if (!(contr->ctrl = kmalloc(sizeof(struct capi_ctr), GFP_KERNEL))) {
printk(KERN_ERR "no mem for contr->ctrl\n");
int_error();
ControllerDestr(contr);
return -ENOMEM;
}
memset(contr->ctrl, 0, sizeof(struct capi_ctr));
#endif
contr->adrController = st->id;
cst = st->child;
while(cst) {
contr->nr_bc++;
cst = cst->next;
}
if (!contr->nr_bc) {
printk(KERN_ERR "no bchannels\n");
ControllerDestr(contr);
return(-EINVAL); // FIXME
}
if (contr->nr_bc <= 2)
contr->maxplci = CAPI_MAXPLCI_BRI;
else if (contr->nr_bc <= 8)
contr->maxplci = contr->nr_bc * 2 + 4;
else
contr->maxplci = CAPI_MAXPLCI_PRI;
contr->plcis = kmalloc(contr->maxplci*sizeof(Plci_t), GFP_KERNEL);
if (!contr->plcis) {
printk(KERN_ERR "no mem for contr->plcis\n");
int_error();
contr->maxplci = 0;
ControllerDestr(contr);
return -ENOMEM;
}
// FIXME ???
contr->addr = st->id;
sprintf(contr->inst.name, "CAPI %d", st->id);
init_mISDNinstance(&contr->inst, ocapi, contr);
if (!SetHandledPID(ocapi, &contr->inst.pid)) {
int_error();
ControllerDestr(contr);
return(-ENOPROTOOPT);
}
cst = st->child;
while(cst) {
if (!(binst = kmalloc(sizeof(BInst_t), GFP_ATOMIC))) {
if (!(binst = kmalloc(sizeof(BInst_t), GFP_KERNEL))) {
printk(KERN_ERR "no mem for Binst\n");
int_error();
ControllerDestr(contr);
return -ENOMEM;
}
memset(binst, 0, sizeof(BInst_t));
@ -540,7 +587,7 @@ contrConstr(Contr_t *contr, mISDNstack_t *st, mISDN_pid_t *pid, mISDNobject_t *o
cst = cst->next;
}
APPEND_TO_LIST(contr, ocapi->ilist);
contr->entity =
contr->entity = MISDN_ENTITY_NONE;
retval = ocapi->ctrl(&contr->inst, MGR_NEWENTITY | REQUEST, NULL);
if (retval) {
printk(KERN_WARNING "mISDN %s: MGR_NEWENTITY REQUEST failed err(%x)\n",
@ -571,38 +618,19 @@ contrConstr(Contr_t *contr, mISDNstack_t *st, mISDN_pid_t *pid, mISDNobject_t *o
retval = attach_capi_ctr(contr->ctrl);
#endif
if (!retval) {
contr->adrController = contr->ctrl->cnr;
contr->addr = contr->ctrl->cnr;
plciInit(contr);
ocapi->ctrl(st, MGR_REGLAYER | INDICATION, &contr->inst);
contr->inst.up.stat = IF_DOWN;
*contr_p = contr;
} else {
ControllerDestr(contr);
}
return retval;
}
Contr_t *
newContr(mISDNobject_t *ocapi, mISDNstack_t *st, mISDN_pid_t *pid)
{
Contr_t *contr;
if (!pid)
return(NULL);
if (!st) {
printk(KERN_ERR "newContr no stack\n");
return(NULL);
}
contr = kmalloc(sizeof(Contr_t), GFP_KERNEL);
if (!contr)
return(NULL);
if (contrConstr(contr, st, pid, ocapi) != 0) {
contrDestr(contr);
kfree(contr);
return(NULL);
}
return contr;
}
BInst_t *
contrSelChannel(Contr_t *contr, u_int channel)
ControllerSelChannel(Controller_t *contr, u_int channel)
{
mISDNstack_t *cst;
BInst_t *binst;
@ -610,25 +638,8 @@ contrSelChannel(Contr_t *contr, u_int channel)
int ret;
if (!contr->binst) {
cst = contr->inst.st->child;
if (!cst)
return(NULL);
while(cst) {
if (!(binst = kmalloc(sizeof(BInst_t), GFP_ATOMIC))) {
printk(KERN_ERR "no mem for Binst\n");
int_error();
return(NULL);
}
memset(binst, 0, sizeof(BInst_t));
binst->bst = cst;
binst->inst.st = cst;
binst->inst.data = binst;
binst->inst.obj = contr->inst.obj;
binst->inst.pid.layermask = ISDN_LAYER(4);
binst->inst.down.stat = IF_NOACTIV;
APPEND_TO_LIST(binst, contr->binst);
cst = cst->next;
}
int_errtxt("no binst for controller(%x)", contr->addr);
return(NULL);
}
ci.channel = channel;
ci.st.p = NULL;
@ -652,13 +663,13 @@ contrSelChannel(Contr_t *contr, u_int channel)
static void
d2_listener(struct IsdnCardState *cs, u_char *buf, int len)
{
Contr_t *contr = cs->contr;
Controller_t *contr = cs->contr;
if (!contr) {
int_error();
return;
}
contrD2Trace(contr, buf, len);
ControllerD2Trace(contr, buf, len);
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,7 @@
*
*/
#include "capi.h"
#include "m_capi.h"
#include "helper.h"
#include "debug.h"
@ -43,77 +43,87 @@ static char* str_ev_listen[] = {
static struct Fsm listen_fsm =
{ 0, 0, 0, 0, 0 };
static void listen_debug(struct FsmInst *fi, char *fmt, ...)
static void
listen_debug(struct FsmInst *fi, char *fmt, ...)
{
char tmp[128];
char *p = tmp;
va_list args;
Listen_t *listen = fi->userdata;
Application_t *app = fi->userdata;
if (!fi->debug)
return;
va_start(args, fmt);
p += sprintf(p, "Controller 0x%x ApplId %d listen ",
listen->contr->adrController, listen->ApplId);
app->contr->addr, app->ApplId);
p += vsprintf(p, fmt, args);
*p = 0;
listenDebug(listen, CAPI_DBG_LISTEN_STATE, tmp);
listenDebug(app, CAPI_DBG_LISTEN_STATE, tmp);
va_end(args);
}
static void listen_req_l_x(struct FsmInst *fi, int event, void *arg, int state)
static void
listen_req_l_x(struct FsmInst *fi, int event, void *arg, int state)
{
Listen_t *listen = fi->userdata;
_cmsg *cmsg = arg;
Application_t *app = fi->userdata;
_cmsg *cmsg = arg;
FsmChangeState(fi, state);
listen->InfoMask = cmsg->InfoMask;
listen->CIPmask = cmsg->CIPmask;
listen->CIPmask2 = cmsg->CIPmask2;
listenDebug(listen, CAPI_DBG_LISTEN_INFO, "set InfoMask to 0x%x", listen->InfoMask);
listenDebug(listen, CAPI_DBG_LISTEN_INFO, "set CIP to 0x%x,0x%x", listen->CIPmask,
listen->CIPmask2);
app->InfoMask = cmsg->InfoMask;
app->CIPmask = cmsg->CIPmask;
app->CIPmask2 = cmsg->CIPmask2;
listenDebug(app, CAPI_DBG_LISTEN_INFO, "set InfoMask to 0x%x", app->InfoMask);
listenDebug(app, CAPI_DBG_LISTEN_INFO, "set CIP to 0x%x,0x%x", app->CIPmask,
app->CIPmask2);
capi_cmsg_answer(cmsg);
cmsg->Info = CAPI_NOERROR;
FsmEvent(&listen->listen_m, EV_LISTEN_CONF, cmsg);
contrRecvCmsg(listen->contr, cmsg);
if (FsmEvent(&app->listen_m, EV_LISTEN_CONF, cmsg))
cmsg_free(cmsg);
}
static void listen_req_l_0(struct FsmInst *fi, int event, void *arg)
static void
listen_req_l_0(struct FsmInst *fi, int event, void *arg)
{
listen_req_l_x(fi, event, arg, ST_LISTEN_L_0_1);
}
static void listen_req_l_1(struct FsmInst *fi, int event, void *arg)
static void
listen_req_l_1(struct FsmInst *fi, int event, void *arg)
{
listen_req_l_x(fi, event, arg, ST_LISTEN_L_1_1);
}
static void listen_conf_l_x_1(struct FsmInst *fi, int event, void *arg,
int state)
static void
listen_conf_l_x_1(struct FsmInst *fi, int event, void *arg, int state)
{
Listen_t *listen = fi->userdata;
_cmsg *cmsg = arg;
Application_t *app = fi->userdata;
_cmsg *cmsg = arg;
if (cmsg->Info != CAPI_NOERROR) {
FsmChangeState(fi, state);
} else { // Info == 0
if (listen->CIPmask == 0)
if (app->CIPmask == 0) {
test_and_clear_bit(APPL_STATE_LISTEN, &app->state);
FsmChangeState(fi, ST_LISTEN_L_0);
else
} else {
test_and_set_bit(APPL_STATE_LISTEN, &app->state);
FsmChangeState(fi, ST_LISTEN_L_1);
}
}
SendCmsg2Application(app, cmsg);
}
static void listen_conf_l_0_1(struct FsmInst *fi, int event, void *arg)
static void
listen_conf_l_0_1(struct FsmInst *fi, int event, void *arg)
{
listen_conf_l_x_1(fi, event, arg, ST_LISTEN_L_0);
}
static void listen_conf_l_1_1(struct FsmInst *fi, int event, void *arg)
static void
listen_conf_l_1_1(struct FsmInst *fi, int event, void *arg)
{
listen_conf_l_x_1(fi, event, arg, ST_LISTEN_L_1);
}
@ -131,53 +141,56 @@ const int FN_LISTEN_COUNT = sizeof(fn_listen_list)/sizeof(struct FsmNode);
// ----------------------------------------------------------------------
// Methods
void listenConstr(Listen_t *listen, Contr_t *contr, __u16 ApplId)
void listenConstr(Application_t *app)
{
listen->listen_m.fsm = &listen_fsm;
listen->listen_m.state = ST_LISTEN_L_0;
listen->listen_m.debug = contr->debug & CAPI_DBG_LISTEN_STATE;
listen->listen_m.userdata = listen;
listen->listen_m.printdebug = listen_debug;
listen->contr = contr;
listen->ApplId = ApplId;
listen->InfoMask = 0;
listen->CIPmask = 0;
listen->CIPmask2 = 0;
app->listen_m.fsm = &listen_fsm;
app->listen_m.state = ST_LISTEN_L_0;
app->listen_m.debug = app->contr->debug & CAPI_DBG_LISTEN_STATE;
app->listen_m.userdata = app;
app->listen_m.printdebug = listen_debug;
app->InfoMask = 0;
app->CIPmask = 0;
app->CIPmask2 = 0;
}
void listenDestr(Listen_t *listen)
void listenDestr(Application_t *app)
{
listenDebug(listen, CAPI_DBG_LISTEN, "%s", __FUNCTION__);
test_and_clear_bit(APPL_STATE_LISTEN, &app->state);
listenDebug(app, CAPI_DBG_LISTEN, "%s", __FUNCTION__);
}
void listenSendMessage(Listen_t *listen, struct sk_buff *skb)
void
listenSendMessage(Application_t *app, struct sk_buff *skb)
{
_cmsg cmsg;
capi_message2cmsg(&cmsg, skb->data);
switch (CMSGCMD(&cmsg)) {
case CAPI_LISTEN_REQ:
FsmEvent(&listen->listen_m, EV_LISTEN_REQ, &cmsg);
break;
default:
int_error();
}
dev_kfree_skb(skb);
_cmsg *cmsg;
cmsg = cmsg_alloc();
if (!cmsg) {
int_error();
dev_kfree_skb(skb);
return;
}
capi_message2cmsg(cmsg, skb->data);
switch (CMSGCMD(cmsg)) {
case CAPI_LISTEN_REQ:
if (FsmEvent(&app->listen_m, EV_LISTEN_REQ, cmsg))
cmsg_free(cmsg);
break;
default:
int_error();
cmsg_free(cmsg);
}
dev_kfree_skb(skb);
}
int listenHandle(Listen_t *listen, __u16 CIPValue)
int listenHandle(Application_t *app, __u16 CIPValue)
{
if ((listen->CIPmask & 1) ||
(listen -> CIPmask & (1 << CIPValue)))
if ((app->CIPmask & 1) ||
(app->CIPmask & (1 << CIPValue)))
return 1;
return 0;
}
// ---------------------------------------------------------------------
//
void init_listen(void)
{
listen_fsm.state_count = ST_LISTEN_COUNT;

View File

@ -0,0 +1,619 @@
/* $Id$
*
* Rewritten CAPI Layer (Layer4 in mISDN)
*
* The CAPI layer knows following basic Objects
*
* - Controller_t : the contoller instance
* - Application_t : applications object
* - Plci_t : PLCI object
* - AppPlci_t : per application PLCI object
* - Ncci_t : NCCI object
*
* For Supplementary Services
* - SSProcess_t : a process handling a service request
*
* The controller is a Layer4 (D-channel) stack instance of
* mISDN.
*
* Applications are owned by the controller and only
* handle this controller, multiplexing multiple
* controller with one application is done in the higher
* driver independ CAPI driver. The application contain
* the Listen state machine.
*
* Plcis are owned by the controller and are static (allocated
* together with the controller). They maybe in use or inactiv.
* Currently 8 PLCIs are available on a BRI (2 B-channel) controller
* and 40 on a PRI (30 B-channel). They have a list of the associated
* application PLCIs.
*
* AppPlcis are owned by the application and are
* instance of the PLCI per application. They contain the
* CAPI2.0 PCLI state machine
*
* Nccis are owned by the application Plcis. In the first version
* this driver supports only one NCCI per PLCI.
*
*
*/
#ifndef __mISDN_CAPI_H__
#define __mISDN_CAPI_H__
#include <linux/mISDNif.h>
#include <linux/skbuff.h>
#include <linux/timer.h>
#include <linux/capi.h>
#include <linux/kernelcapi.h>
#ifdef OLDCAPI_DRIVER_INTERFACE
#include "../avmb1/capiutil.h"
#include "../avmb1/capicmd.h"
#include "../avmb1/capilli.h"
#else
#include <linux/list.h>
#include <linux/isdn/capiutil.h>
#include <linux/isdn/capicmd.h>
#include <linux/isdn/capilli.h>
#endif
#include "asn1.h"
#include "fsm.h"
#ifdef MISDN_MEMDEBUG
#include "memdbg.h"
#define MISDN_KMEM_DEBUG 1
#endif
// ---------------------------------------------------------------------------
// common stuff
// debuging levels and functions
// ---------------------------------------------------------------------------
#define CAPI_DBG_WARN 0x00000001
#define CAPI_DBG_INFO 0x00000004
#define CAPI_DBG_APPL 0x00000010
#define CAPI_DBG_APPL_INFO 0x00000040
#define CAPI_DBG_APPL_MSG 0x00000080
#define CAPI_DBG_LISTEN 0x00000100
#define CAPI_DBG_LISTEN_STATE 0x00000200
#define CAPI_DBG_LISTEN_INFO 0x00000400
#define CAPI_DBG_CONTR 0x00010000
#define CAPI_DBG_CONTR_INFO 0x00040000
#define CAPI_DBG_CONTR_MSG 0x00080000
#define CAPI_DBG_PLCI 0x00100000
#define CAPI_DBG_PLCI_STATE 0x00200000
#define CAPI_DBG_PLCI_INFO 0x00400000
#define CAPI_DBG_PLCI_L3 0x00800000
#define CAPI_DBG_NCCI 0x01000000
#define CAPI_DBG_NCCI_STATE 0x02000000
#define CAPI_DBG_NCCI_INFO 0x04000000
#define CAPI_DBG_NCCI_L3 0x08000000
void capidebug(int, char *, ...);
#ifdef OLDCAPI_DRIVER_INTERFACE
extern struct capi_driver_interface *cdrv_if;
extern struct capi_driver mISDN_driver;
#endif
// ---------------------------------------------------------------------------
// Init/Exit functions
// ---------------------------------------------------------------------------
void init_listen(void);
void init_AppPlci(void);
void init_ncci(void);
void free_Application(void);
void free_listen(void);
void free_AppPlci(void);
void free_ncci(void);
// ---------------------------------------------------------------------------
// More CAPI defines
// ---------------------------------------------------------------------------
/* we implement 64 bit extentions */
#define CAPI_B3_DATA_IND_HEADER_SIZE 30
#define CAPI_MSG_DEFAULT_LEN 256
#define CAPIMSG_REQ_DATAHANDLE(m) (m[18] | (m[19]<<8))
#define CAPIMSG_RESP_DATAHANDLE(m) (m[12] | (m[13]<<8))
#define CMSGCMD(cmsg) CAPICMD((cmsg)->Command, (cmsg)->Subcommand)
#define CAPI_MAXPLCI_BRI 8
#define CAPI_MAXPLCI_PRI 40
__u16 q931CIPValue(Q931_info_t *);
// ---------------------------------------------------------------------------
// Basic CAPI types
// ---------------------------------------------------------------------------
typedef struct _Controller Controller_t;
typedef struct _Application Application_t;
typedef struct _Ncci Ncci_t;
typedef struct _Plci Plci_t;
typedef struct _AppPlci AppPlci_t;
typedef struct _SSProcess SSProcess_t;
// some helper types
typedef struct _ConfQueue ConfQueue_t;
typedef struct _BInst BInst_t;
// Facility types
typedef struct FacReqParm FacReqParm_t;
typedef struct FacConfParm FacConfParm_t;
// ---------------------------------------------------------------------------
// Helper structs
// ---------------------------------------------------------------------------
struct _BInst {
struct _BInst *prev;
struct _BInst *next;
mISDNstack_t *bst;
mISDNinstance_t inst;
};
struct _ConfQueue {
struct sk_buff *skb;
__u16 DataHandle;
__u16 MsgId;
};
struct Bprotocol {
__u16 B1;
__u16 B2;
__u16 B3;
};
// ---------------------------------------------------------------------------
// struct Controller
// ---------------------------------------------------------------------------
struct _Controller {
struct _Controller *prev;
struct _Controller *next;
mISDNinstance_t inst;
int nr_bc;
BInst_t *binst;
struct capi_ctr *ctrl;
__u32 addr;
int entity;
u_int debug;
int maxplci;
Plci_t *plcis;
struct list_head Applications;
struct list_head SSProcesse;
spinlock_t list_lock;
__u32 NotificationMask;
__u16 LastInvokeId;
char infobuf[128];
};
// ---------------------------------------------------------------------------
// struct Application
// ---------------------------------------------------------------------------
struct _Application {
struct list_head head;
Controller_t *contr;
__u16 ApplId;
__u16 MsgId;
__u32 InfoMask;
__u32 CIPmask;
__u32 CIPmask2;
__u32 NotificationMask;
__u32 state;
struct FsmInst listen_m;
int maxplci;
AppPlci_t **AppPlcis;
capi_register_params reg_params;
};
#define APPL_STATE_ACTIV 1
#define APPL_STATE_RELEASE 2
#define APPL_STATE_LISTEN 3
#define APPL_STATE_DESTRUCTOR 4
#define APPL_STATE_D2TRACE 8
// ---------------------------------------------------------------------------
// struct Plci
// ---------------------------------------------------------------------------
struct _Plci {
Controller_t *contr;
__u32 addr;
__u32 l3id;
__u32 state;
int nAppl;
struct list_head AppPlcis;
};
#define PLCI_STATE_ACTIV 1
#define PLCI_STATE_ALERTING 2
#define PLCI_STATE_OUTGOING 3
// ---------------------------------------------------------------------------
// struct AppPlci
// ---------------------------------------------------------------------------
struct _AppPlci {
struct list_head head;
__u32 addr;
Plci_t *plci;
Application_t *appl;
Ncci_t *ncci;
Controller_t *contr;
struct FsmInst plci_m;
u_char cause[4];
int channel;
struct Bprotocol Bprotocol;
};
// ---------------------------------------------------------------------------
// struct Ncci
// ---------------------------------------------------------------------------
struct _Ncci {
__u32 addr;
BInst_t *binst;
Controller_t *contr;
AppPlci_t *AppPlci;
Application_t *appl;
struct FsmInst ncci_m;
int window;
__u32 state;
ConfQueue_t xmit_skb_handles[CAPI_MAXDATAWINDOW];
struct sk_buff *recv_skb_handles[CAPI_MAXDATAWINDOW];
struct sk_buff_head squeue;
};
#define NCCI_STATE_FCTRL 1
#define NCCI_STATE_BUSY 2
#define NCCI_STATE_APPLRELEASED 3
// ---------------------------------------------------------------------------
// struct SSProcess_t
// ---------------------------------------------------------------------------
struct _SSProcess {
struct list_head head;
__u16 invokeId;
__u16 Function;
__u32 Handle;
__u32 addr;
__u16 ApplId;
Controller_t *contr;
struct timer_list tl;
__u8 buf[128];
};
// ---------------------------------------------------------------------------
// FUNCTION prototypes
//
// Controller prototypes
// ---------------------------------------------------------------------------
int ControllerConstr(Controller_t **, mISDNstack_t *, mISDN_pid_t *, mISDNobject_t *);
void ControllerDestr(Controller_t *);
void ControllerRun(Controller_t *);
void ControllerDebug(Controller_t *, __u32, char *, ...);
int ControllerNewPlci(Controller_t *, Plci_t **, u_int);
int ControllerReleasePlci(Plci_t *);
Application_t *getApplication4Id(Controller_t *, __u16);
Plci_t *getPlci4Addr(Controller_t *, __u32);
int ControllerL4L3(Controller_t *, u_int, int, struct sk_buff *);
int ControllerL3L4(mISDNif_t *, struct sk_buff *);
BInst_t *ControllerSelChannel(Controller_t *, u_int);
void ControllerAddSSProcess(Controller_t *, SSProcess_t *);
SSProcess_t *getSSProcess4Id(Controller_t *, __u16);
// ---------------------------------------------------------------------------
// Application prototypes
// ---------------------------------------------------------------------------
int ApplicationConstr(Controller_t *, __u16, capi_register_params *);
int ApplicationDestr(Application_t *, int);
void ApplicationDebug(Application_t *appl, __u32 level, char *fmt, ...);
void ApplicationSendMessage(Application_t *appl, struct sk_buff *skb);
void SendCmsg2Application(Application_t *, _cmsg *);
void SendCmsgAnswer2Application(Application_t *, _cmsg *, __u16);
void AnswerMessage2Application(Application_t *, struct sk_buff *, __u16);
void applManufacturerReq(Application_t *appl, struct sk_buff *skb);
void applD2Trace(Application_t *appl, u_char *buf, int len);
AppPlci_t *ApplicationNewAppPlci(Application_t *, Plci_t *);
AppPlci_t *getAppPlci4addr(Application_t *, __u32);
void ApplicationDelAppPlci(Application_t *, AppPlci_t *);
void listenConstr(Application_t *);
void listenDestr(Application_t *);
void listenSendMessage(Application_t *, struct sk_buff *);
int listenHandle(Application_t *, __u16);
// ---------------------------------------------------------------------------
// PLCI prototypes
// ---------------------------------------------------------------------------
void plciInit(Controller_t *);
void plciDebug(Plci_t *, __u32, char *, ...);
int plci_l3l4(Plci_t *, int, struct sk_buff *);
void plciAttachAppPlci(Plci_t *, AppPlci_t *);
void plciDetachAppPlci(Plci_t *, AppPlci_t *);
void plciNewCrInd(Plci_t *, void *);
void plciNewCrReq(Plci_t *);
int plciL4L3(Plci_t *, __u32, struct sk_buff *);
// ---------------------------------------------------------------------------
// AppPLCI prototypes
// ---------------------------------------------------------------------------
int AppPlciConstr(AppPlci_t **, Application_t *, Plci_t *);
void AppPlciDestr(AppPlci_t *);
void AppPlciDelNCCI(AppPlci_t *);
void AppPlci_l3l4(AppPlci_t *, int, void *);
void AppPlciSendMessage(AppPlci_t *, struct sk_buff *);
void AppPlciRelease(AppPlci_t *);
int AppPlciFacSuspendReq(AppPlci_t *, FacReqParm_t *, FacConfParm_t *);
int AppPlciFacResumeReq(AppPlci_t *, FacReqParm_t *, FacConfParm_t *);
void AppPlciGetCmsg(AppPlci_t *, _cmsg *);
// ---------------------------------------------------------------------------
// NCCI prototypes
// ---------------------------------------------------------------------------
Ncci_t *ncciConstr(AppPlci_t *);
void ncciDestr(Ncci_t *);
void ncciLinkUp(Ncci_t *);
void ncciLinkDown(Ncci_t *);
void ncciApplRelease(Ncci_t *);
void ncciDelAppPlci(Ncci_t *);
void ncciSendMessage(Ncci_t *, struct sk_buff *);
int ncci_l3l4(mISDNif_t *, struct sk_buff *);
__u16 ncciSelectBprotocol(Ncci_t *);
void ncciGetCmsg(Ncci_t *, _cmsg *);
// ---------------------------------------------------------------------------
// SSProcess prototypes
// ---------------------------------------------------------------------------
SSProcess_t *SSProcessConstr(Application_t *, __u16, __u32);
void SSProcessDestr(SSProcess_t *);
int Supplementary_l3l4(Controller_t *, __u32, struct sk_buff *);
void SupplementaryFacilityReq(Application_t *, _cmsg *);
// ---------------------------------------------------------------------------
// INFOMASK defines (LISTEN commands)
// ---------------------------------------------------------------------------
#define CAPI_INFOMASK_CAUSE (0x0001)
#define CAPI_INFOMASK_DATETIME (0x0002)
#define CAPI_INFOMASK_DISPLAY (0x0004)
#define CAPI_INFOMASK_USERUSER (0x0008)
#define CAPI_INFOMASK_PROGRESS (0x0010)
#define CAPI_INFOMASK_FACILITY (0x0020)
//#define CAPI_INFOMASK_CHARGE (0x0040)
//#define CAPI_INFOMASK_CALLEDPN (0x0080)
#define CAPI_INFOMASK_CHANNELID (0x0100)
#define CAPI_INFOMASK_EARLYB3 (0x0200)
//#define CAPI_INFOMASK_REDIRECT (0x0400)
// ---------------------------------------------------------------------------
// Supplementary Services
// ---------------------------------------------------------------------------
#define SuppServiceTP 0x00000002
#define SuppServiceCF 0x00000010
#define mISDNSupportedServices (SuppServiceCF | SuppServiceTP)
// ---------------------------------------------------------------------------
// structs for Facillity requests
// ---------------------------------------------------------------------------
struct FacReqListen {
__u32 NotificationMask;
};
struct FacReqSuspend {
__u8 *CallIdentity;
};
struct FacReqResume {
__u8 *CallIdentity;
};
struct FacReqCFActivate {
__u32 Handle;
__u16 Procedure;
__u16 BasicService;
__u8 *ServedUserNumber;
__u8 *ForwardedToNumber;
__u8 *ForwardedToSubaddress;
};
struct FacReqCFDeactivate {
__u32 Handle;
__u16 Procedure;
__u16 BasicService;
__u8 *ServedUserNumber;
};
#define FacReqCFInterrogateParameters FacReqCFDeactivate
struct FacReqCFInterrogateNumbers {
__u32 Handle;
};
struct FacReqParm {
__u16 Function;
union {
struct FacReqListen Listen;
struct FacReqSuspend Suspend;
struct FacReqResume Resume;
struct FacReqCFActivate CFActivate;
struct FacReqCFDeactivate CFDeactivate;
struct FacReqCFInterrogateParameters CFInterrogateParameters;
struct FacReqCFInterrogateNumbers CFInterrogateNumbers;
} u;
};
// ---------------------------------------------------------------------------
// structs for Facillity confirms
// ---------------------------------------------------------------------------
struct FacConfGetSupportedServices {
__u16 SupplementaryServiceInfo;
__u32 SupportedServices;
};
struct FacConfInfo {
__u16 SupplementaryServiceInfo;
};
struct FacConfParm {
__u16 Function;
union {
struct FacConfGetSupportedServices GetSupportedServices;
struct FacConfInfo Info;
} u;
};
int capiEncodeWord(__u8 *dest, __u16 i);
int capiEncodeDWord(__u8 *dest, __u32 i);
int capiEncodeFacIndCFact(__u8 *dest, __u16 SupplementaryServiceReason, __u32 Handle);
int capiEncodeFacIndCFdeact(__u8 *dest, __u16 SupplementaryServiceReason, __u32 Handle);
int capiEncodeFacIndCFNotAct(__u8 *dest, struct ActDivNotification *actNot);
int capiEncodeFacIndCFNotDeact(__u8 *dest, struct DeactDivNotification *deactNot);
int capiEncodeFacIndCFinterParameters(__u8 *dest, __u16 SupplementaryServiceReason, __u32 Handle,
struct IntResultList *intResultList);
int capiEncodeFacIndCFinterNumbers(__u8 *dest, __u16 SupplementaryServiceReason, __u32 Handle,
struct ServedUserNumberList *list);
int capiEncodeFacConfParm(__u8 *dest, struct FacConfParm *facConfParm);
int capiEncodeFacIndSuspend(__u8 *dest, __u16 SupplementaryServiceReason);
// ---------------------------------------------------------------------------
// mISDN kmem cache managment functions
// ---------------------------------------------------------------------------
/* kmem caches */
extern kmem_cache_t *mISDN_cmsg_cp;
extern kmem_cache_t *mISDN_AppPlci_cp;
extern kmem_cache_t *mISDN_ncci_cp;
extern kmem_cache_t *mISDN_sspc_cp;
#ifdef MISDN_KMEM_DEBUG
typedef struct _kd_cmsg _kd_cmsg_t;
typedef struct _kd_Ncci _kd_Ncci_t;
typedef struct _kd_AppPlci _kd_AppPlci_t;
typedef struct _kd_SSProcess _kd_SSProcess_t;
typedef struct _kd_all _kd_all_t;
typedef struct __km_dbg_item {
struct list_head head;
long typ;
char *file;
u_int line;
} km_dbg_item_t;
struct _kd_cmsg {
km_dbg_item_t kdi;
_cmsg cm;
};
struct _kd_AppPlci {
km_dbg_item_t kdi;
AppPlci_t ap;
};
struct _kd_Ncci {
km_dbg_item_t kdi;
Ncci_t ni;
};
struct _kd_SSProcess {
km_dbg_item_t kdi;
SSProcess_t sp;
};
struct _kd_all {
km_dbg_item_t kdi;
union {
_cmsg cm;
AppPlci_t ap;
Ncci_t ni;
SSProcess_t sp;
} a;
};
#define KDB_GET_KDI(kd) ((km_dbg_item_t *)(((u_char *)kd) - sizeof(km_dbg_item_t)))
#define KDB_GET_KDALL(kd) ((_kd_all_t *)(((u_char *)kd) - sizeof(km_dbg_item_t)))
#define KM_DBG_TYP_CM 1
#define KM_DBG_TYP_AP 2
#define KM_DBG_TYP_NI 3
#define KM_DBG_TYP_SP 4
#define cmsg_alloc() _kd_cmsg_alloc(__FILE__, __LINE__)
extern _cmsg *_kd_cmsg_alloc(char *, int);
extern void cmsg_free(_cmsg *cm);
#define AppPlci_alloc() _kd_AppPlci_alloc(__FILE__, __LINE__)
extern AppPlci_t *_kd_AppPlci_alloc(char *, int);
extern void AppPlci_free(AppPlci_t *ap);
#define ncci_alloc() _kd_ncci_alloc(__FILE__, __LINE__)
extern Ncci_t *_kd_ncci_alloc(char *, int);
extern void ncci_free(Ncci_t *ni);
#define SSProcess_alloc() _kd_SSProcess_alloc(__FILE__, __LINE__)
extern SSProcess_t *_kd_SSProcess_alloc(char *, int);
extern void SSProcess_free(SSProcess_t *sp);
#else /* ! MISDN_KMEM_DEBUG */
static __inline__ _cmsg *cmsg_alloc(void)
{
return(kmem_cache_alloc(mISDN_cmsg_cp, GFP_ATOMIC));
}
static __inline__ void cmsg_free(_cmsg *cm)
{
kmem_cache_free(mISDN_cmsg_cp, cm);
}
static __inline__ AppPlci_t *AppPlci_alloc(void)
{
return(kmem_cache_alloc(mISDN_AppPlci_cp, GFP_ATOMIC));
}
static __inline__ void AppPlci_free(AppPlci_t *ap)
{
kmem_cache_free(mISDN_AppPlci_cp, ap);
}
static __inline__ Ncci_t *ncci_alloc(void)
{
return(kmem_cache_alloc(mISDN_ncci_cp, GFP_ATOMIC));
}
static __inline__ void ncci_free(Ncci_t *ni)
{
kmem_cache_free(mISDN_ncci_cp, ni);
}
static __inline__ SSProcess_t *SSProcess_alloc(void)
{
return(kmem_cache_alloc(mISDN_sspc_cp, GFP_ATOMIC));
}
static __inline__ void SSProcess_free(SSProcess_t *sp)
{
kmem_cache_free(mISDN_sspc_cp, sp);
}
#endif /* MISDN_KMEM_DEBUG */
// cmsg_alloc with error handling for void functions
#define CMSG_ALLOC(cm) if (!(cm = cmsg_alloc())) {int_error();return;}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,7 @@
*
*/
#include "capi.h"
#include "m_capi.h"
#include "dss1.h"
#include "helper.h"
#include "debug.h"
@ -11,47 +11,46 @@
capidebug(lev, fmt, ## args)
void plciConstr(Plci_t *plci, Contr_t *contr, __u32 adrPLCI, u_int id)
void plciInit(Controller_t *contr)
{
memset(plci, 0, sizeof(Plci_t));
plci->adrPLCI = adrPLCI;
plci->id = id;
plci->contr = contr;
}
Plci_t *plci = contr->plcis;
int i;
void plciDestr(Plci_t *plci)
{
#if 0
if (plci->l4_pc.l3pc) {
// FIXME: we need to kill l3_process, actually
plci->l4_pc.l3pc->l4pc = 0;
for (i = 0; i < contr->maxplci; i++) {
memset(plci, 0, sizeof(Plci_t));
plci->addr = ((i + 1) << 8) | contr->addr;
plci->l3id = MISDN_ID_NONE;
INIT_LIST_HEAD(&plci->AppPlcis);
plci->contr = contr;
printk(KERN_WARNING "%s: %p PLCI(%x) l3id(%x)\n",
__FUNCTION__, plci, plci->addr, plci->l3id);
plci++;
}
#endif
}
void plciHandleSetupInd(Plci_t *plci, int pr, Q931_info_t *qi)
{
int ApplId;
__u16 CIPValue;
Appl_t *appl;
Cplci_t *cplci;
__u16 CIPValue;
Application_t *appl;
AppPlci_t *aplci;
struct list_head *item, *next;
if (!qi) {
if (!qi || !plci->contr) {
int_error();
return;
}
for (ApplId = 1; ApplId <= CAPI_MAXAPPL; ApplId++) {
appl = contrId2appl(plci->contr, ApplId);
if (appl) {
CIPValue = q931CIPValue(qi);
if (listenHandle(&appl->listen, CIPValue)) {
cplci = applNewCplci(appl, plci);
if (!cplci) {
int_error();
break;
}
cplci_l3l4(cplci, pr, qi);
CIPValue = q931CIPValue(qi);
list_for_each_safe(item, next, &plci->contr->Applications) {
appl = (Application_t *)item;
if (test_bit(APPL_STATE_RELEASE, &appl->state))
continue;
if (listenHandle(appl, CIPValue)) {
aplci = ApplicationNewAppPlci(appl, plci);
if (!aplci) {
int_error();
break;
}
AppPlci_l3l4(aplci, pr, qi);
}
}
if (plci->nAppl == 0) {
@ -62,14 +61,15 @@ void plciHandleSetupInd(Plci_t *plci, int pr, Q931_info_t *qi)
AddvarIE(skb,cause);
plciL4L3(plci, CC_RELEASE_COMPLETE | REQUEST, skb);
}
ControllerReleasePlci(plci);
}
}
int plci_l3l4(Plci_t *plci, int pr, struct sk_buff *skb)
{
__u16 applId;
Cplci_t *cplci;
Q931_info_t *qi;
AppPlci_t *aplci;
Q931_info_t *qi;
struct list_head *item, *next;
if (skb->len)
qi = (Q931_info_t *)skb->data;
@ -80,47 +80,51 @@ int plci_l3l4(Plci_t *plci, int pr, struct sk_buff *skb)
plciHandleSetupInd(plci, pr, qi);
break;
case CC_RELEASE_CR | INDICATION:
if (plci->nAppl == 0) {
contrDelPlci(plci->contr, plci);
}
break;
default:
for (applId = 1; applId <= CAPI_MAXAPPL; applId++) {
cplci = plci->cplcis[applId - 1];
if (cplci)
cplci_l3l4(cplci, pr, qi);
list_for_each_safe(item, next, &plci->AppPlcis) {
aplci = (AppPlci_t *)item;
AppPlci_l3l4(aplci, pr, qi);
}
if (plci->nAppl == 0)
contrDelPlci(plci->contr, plci);
break;
}
dev_kfree_skb(skb);
return(0);
}
void plciAttachCplci(Plci_t *plci, Cplci_t *cplci)
{
__u16 applId = cplci->appl->ApplId;
AppPlci_t *
getAppPlci4Id(Plci_t *plci, __u16 appId) {
struct list_head *item;
AppPlci_t *aplci;
if (plci->cplcis[applId - 1]) {
list_for_each(item, &plci->AppPlcis) {
aplci = (AppPlci_t *)item;
if (appId == aplci->appl->ApplId)
return(aplci);
}
return(NULL);
}
void plciAttachAppPlci(Plci_t *plci, AppPlci_t *aplci)
{
AppPlci_t *test = getAppPlci4Id(plci, aplci->appl->ApplId);
if (test) {
int_error();
return;
}
plci->cplcis[applId - 1] = cplci;
list_add(&aplci->head, &plci->AppPlcis);
plci->nAppl++;
}
void plciDetachCplci(Plci_t *plci, Cplci_t *cplci)
void
plciDetachAppPlci(Plci_t *plci, AppPlci_t *aplci)
{
__u16 applId = cplci->appl->ApplId;
if (plci->cplcis[applId - 1] != cplci) {
int_error();
return;
}
cplci->plci = 0;
plci->cplcis[applId - 1] = 0;
aplci->plci = NULL;
list_del_init(&aplci->head);
plci->nAppl--;
if (!plci->nAppl)
ControllerReleasePlci(plci);
}
void plciNewCrReq(Plci_t *plci)
@ -128,7 +132,8 @@ void plciNewCrReq(Plci_t *plci)
plciL4L3(plci, CC_NEW_CR | REQUEST, NULL);
}
int plciL4L3(Plci_t *plci, __u32 prim, struct sk_buff *skb)
int
plciL4L3(Plci_t *plci, __u32 prim, struct sk_buff *skb)
{
#define MY_RESERVE 8
int err;
@ -141,7 +146,7 @@ int plciL4L3(Plci_t *plci, __u32 prim, struct sk_buff *skb)
} else
skb_reserve(skb, MY_RESERVE);
}
err = contrL4L3(plci->contr, prim, plci->id, skb);
err = ControllerL4L3(plci->contr, prim, plci->l3id, skb);
if (err)
dev_kfree_skb(skb);
return(err);

View File

@ -2,7 +2,7 @@
*
*/
#include "capi.h"
#include "m_capi.h"
#include "asn1_comp.h"
#include "asn1_enc.h"
#include "dss1.h"
@ -12,6 +12,37 @@
#define T_DEACTIVATE 4000
#define T_INTERROGATE 4000
static void SSProcessAddTimer(SSProcess_t *, int);
static __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;
}
static void
encodeInvokeComponentLength(__u8 *msg, __u8 *p)
{
msg[3] = p - &msg[5];
msg[0] = p - &msg[1];
}
static int
SSProcess_L4L3(SSProcess_t *spc, __u32 prim, struct sk_buff *skb) {
int err;
// FIXME err = ControllerL4L3(contr, prim, contr->addr | DUMMY_CR_FLAG, skb);
err = ControllerL4L3(spc->contr, prim, MISDN_ID_DUMMY, skb);
if (err)
dev_kfree_skb(skb);
return(err);
}
static __inline__ int capiGetWord(__u8 *p, __u8 *end, __u16 *word)
{
if (p + 2 > end) {
@ -139,8 +170,9 @@ static __inline__ int capiGetFacReqCFInterrogateNumbers(__u8 *p, __u8 *_end, str
CAPI_GET(capiGetDWord, &CFInterrogateNumbers->Handle);
if (p != end) return -1;
return len + 1;
if (p != end)
return(-1);
return(len + 1);
}
@ -153,161 +185,48 @@ static __inline__ int capiGetFacReqParm(__u8 *p, struct FacReqParm *facReqParm)
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;
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;
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, MISDN_ID_ANY);
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, struct sk_buff *skb) {
Contr_t *contr = dpc->contr;
int err;
// err = contrL4L3(contr, prim, contr->adrController | DUMMY_CR_FLAG, skb);
err = contrL4L3(contr, prim, MISDN_ID_DUMMY, skb);
if (err)
dev_kfree_skb(skb);
return(err);
}
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)
static int
GetSupportedServices(FacReqParm_t *facReqParm, FacConfParm_t *facConfParm)
{
facConfParm->u.GetSupportedServices.SupplementaryServiceInfo = CapiSuccess;
facConfParm->u.GetSupportedServices.SupportedServices = mISDNSupportedServices;
return CapiSuccess;
}
int applFacListen(Appl_t *appl, struct FacReqParm *facReqParm,
struct FacConfParm *facConfParm)
static int
FacListen(Application_t *appl, FacReqParm_t *facReqParm, FacConfParm_t *facConfParm)
{
if (facReqParm->u.Listen.NotificationMask &~ mISDNSupportedServices) {
facConfParm->u.Info.SupplementaryServiceInfo = CapiSupplementaryServiceNotSupported;
@ -318,221 +237,272 @@ int applFacListen(Appl_t *appl, struct FacReqParm *facReqParm,
return CapiSuccess;
}
int applFacCFActivate(Appl_t *appl, struct FacReqParm *facReqParm,
struct FacConfParm *facConfParm)
static int
FacCFInterrogateParameters(Application_t *appl, FacReqParm_t *facReqParm, FacConfParm_t *facConfParm)
{
DummyProcess_t *dummy_pc;
SSProcess_t *sspc;
struct sk_buff *skb = alloc_l3msg(260, MT_FACILITY);
__u8 *p;
if (!skb)
return CAPI_MSGOSRESOURCEERR;
dummy_pc = applNewDummyPc(appl, facReqParm->Function, facReqParm->u.CFActivate.Handle);
if (!dummy_pc) {
kfree_skb(skb);
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);
AddIE(skb, IE_FACILITY, dummy_pc->buf);
dummy_L4L3(dummy_pc, CC_FACILITY | REQUEST, skb);
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;
struct sk_buff *skb = alloc_l3msg(260, MT_FACILITY);
__u8 *p;
if (!skb)
return CAPI_MSGOSRESOURCEERR;
dummy_pc = applNewDummyPc(appl, facReqParm->Function, facReqParm->u.CFDeactivate.Handle);
if (!dummy_pc) {
kfree_skb(skb);
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);
AddIE(skb, IE_FACILITY, dummy_pc->buf);
dummy_L4L3(dummy_pc, CC_FACILITY | REQUEST, skb);
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;
struct sk_buff *skb = alloc_l3msg(260, MT_FACILITY);
__u8 *p;
if (!skb)
return CAPI_MSGOSRESOURCEERR;
dummy_pc = applNewDummyPc(appl, facReqParm->Function,
sspc = SSProcessConstr(appl, facReqParm->Function,
facReqParm->u.CFInterrogateParameters.Handle);
if (!dummy_pc) {
if (!sspc) {
kfree_skb(skb);
return CAPI_MSGOSRESOURCEERR;
}
p = encodeInvokeComponentHead(dummy_pc->buf);
p += encodeInt(p, dummy_pc->invokeId);
p = encodeInvokeComponentHead(sspc->buf);
p += encodeInt(p, sspc->invokeId);
p += encodeInt(p, 0x0b); // interrogationDiversion
p += encodeInterrogationDiversion(p, &facReqParm->u.CFInterrogateParameters);
encodeInvokeComponentLength(dummy_pc->buf, p);
AddIE(skb, IE_FACILITY, dummy_pc->buf);
encodeInvokeComponentLength(sspc->buf, p);
AddIE(skb, IE_FACILITY, sspc->buf);
dummy_L4L3(dummy_pc, CC_FACILITY | REQUEST, skb);
dummyPcAddTimer(dummy_pc, T_INTERROGATE);
SSProcess_L4L3(sspc, CC_FACILITY | REQUEST, skb);
SSProcessAddTimer(sspc, T_INTERROGATE);
facConfParm->u.Info.SupplementaryServiceInfo = CapiSuccess;
return CapiSuccess;
}
int applFacCFInterrogateNumbers(Appl_t *appl, struct FacReqParm *facReqParm,
struct FacConfParm *facConfParm)
static int
FacCFInterrogateNumbers(Application_t *appl, FacReqParm_t *facReqParm, FacConfParm_t *facConfParm)
{
DummyProcess_t *dummy_pc;
SSProcess_t *sspc;
struct sk_buff *skb = alloc_l3msg(260, MT_FACILITY);
__u8 *p;
if (!skb)
return CAPI_MSGOSRESOURCEERR;
dummy_pc = applNewDummyPc(appl, facReqParm->Function,
sspc = SSProcessConstr(appl, facReqParm->Function,
facReqParm->u.CFInterrogateNumbers.Handle);
if (!dummy_pc) {
if (!sspc) {
kfree_skb(skb);
return CAPI_MSGOSRESOURCEERR;
}
p = encodeInvokeComponentHead(dummy_pc->buf);
p += encodeInt(p, dummy_pc->invokeId);
p = encodeInvokeComponentHead(sspc->buf);
p += encodeInt(p, sspc->invokeId);
p += encodeInt(p, 0x11); // InterrogateServedUserNumbers
encodeInvokeComponentLength(dummy_pc->buf, p);
AddIE(skb, IE_FACILITY, dummy_pc->buf);
dummy_L4L3(dummy_pc, CC_FACILITY | REQUEST, skb);
dummyPcAddTimer(dummy_pc, T_INTERROGATE);
encodeInvokeComponentLength(sspc->buf, p);
AddIE(skb, IE_FACILITY, sspc->buf);
SSProcess_L4L3(sspc, CC_FACILITY | REQUEST, skb);
SSProcessAddTimer(sspc, 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)
static int
FacCFActivate(Application_t *appl, FacReqParm_t *facReqParm, FacConfParm_t *facConfParm)
{
memset(dummy_pc, 0, sizeof(DummyProcess_t));
dummy_pc->contr = contr;
dummy_pc->invokeId = invokeId;
}
SSProcess_t *sspc;
struct sk_buff *skb = alloc_l3msg(260, MT_FACILITY);
__u8 *p;
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 (!skb)
return CAPI_MSGOSRESOURCEERR;
sspc = SSProcessConstr(appl, facReqParm->Function, facReqParm->u.CFActivate.Handle);
if (!sspc) {
kfree_skb(skb);
return CAPI_MSGOSRESOURCEERR;
}
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;
p = encodeInvokeComponentHead(sspc->buf);
p += encodeInt(p, sspc->invokeId);
p += encodeInt(p, 0x07); // activationDiversion
p += encodeActivationDiversion(p, &facReqParm->u.CFActivate);
encodeInvokeComponentLength(sspc->buf, p);
AddIE(skb, IE_FACILITY, sspc->buf);
SSProcess_L4L3(sspc, CC_FACILITY | REQUEST, skb);
SSProcessAddTimer(sspc, T_ACTIVATE);
facConfParm->u.Info.SupplementaryServiceInfo = CapiSuccess;
return CapiSuccess;
}
void contrDelDummyPc(Contr_t* contr, DummyProcess_t *dummy_pc)
static int
FacCFDeactivate(Application_t *appl, FacReqParm_t *facReqParm, FacConfParm_t *facConfParm)
{
int i;
SSProcess_t *sspc;
struct sk_buff *skb = alloc_l3msg(260, MT_FACILITY);
__u8 *p;
for (i = 0; i < CAPI_MAXDUMMYPCS; i++) {
if (contr->dummy_pcs[i] == dummy_pc)
break;
if (!skb)
return CAPI_MSGOSRESOURCEERR;
sspc = SSProcessConstr(appl, facReqParm->Function, facReqParm->u.CFDeactivate.Handle);
if (!sspc) {
kfree_skb(skb);
return CAPI_MSGOSRESOURCEERR;
}
if (i == CAPI_MAXDUMMYPCS) {
int_error();
p = encodeInvokeComponentHead(sspc->buf);
p += encodeInt(p, sspc->invokeId);
p += encodeInt(p, 0x08); // dectivationDiversion
p += encodeDeactivationDiversion(p, &facReqParm->u.CFDeactivate);
encodeInvokeComponentLength(sspc->buf, p);
AddIE(skb, IE_FACILITY, sspc->buf);
SSProcess_L4L3(sspc, CC_FACILITY | REQUEST, skb);
SSProcessAddTimer(sspc, T_DEACTIVATE);
facConfParm->u.Info.SupplementaryServiceInfo = CapiSuccess;
return CapiSuccess;
}
void
SupplementaryFacilityReq(Application_t *appl, _cmsg *cmsg)
{
__u8 tmp[10];
__u16 Info;
FacReqParm_t facReqParm;
FacConfParm_t facConfParm;
Plci_t *plci;
AppPlci_t *aplci;
int ret;
if (capiGetFacReqParm(cmsg->FacilityRequestParameter, &facReqParm) < 0) {
SendCmsgAnswer2Application(appl, cmsg, CapiIllMessageParmCoding);
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)
facConfParm.Function = facReqParm.Function;
switch (facReqParm.Function) {
case 0x0000: // GetSupportedServices
Info = GetSupportedServices(&facReqParm, &facConfParm);
break;
case 0x0001: // Listen
Info = FacListen(appl, &facReqParm, &facConfParm);
break;
case 0x0004: // Suspend
aplci = getAppPlci4addr(appl, cmsg->adr.adrPLCI);
if (!aplci) {
Info = CapiIllContrPlciNcci;
break;
}
Info = AppPlciFacSuspendReq(aplci, &facReqParm, &facConfParm);
break;
case 0x0005: // Resume
ret = ControllerNewPlci(appl->contr, &plci, MISDN_ID_ANY);
if (ret) {
Info = CapiNoPlciAvailable;
break;
}
aplci = ApplicationNewAppPlci(appl, plci);
if (!aplci) {
ControllerReleasePlci(plci);
Info = CapiNoPlciAvailable;
break;
}
Info = AppPlciFacResumeReq(aplci, &facReqParm, &facConfParm);
if (Info == CapiSuccess)
cmsg->adr.adrPLCI = plci->addr;
break;
case 0x0009: // CF Activate
Info = FacCFActivate(appl, &facReqParm, &facConfParm);
break;
case 0x000a: // CF Deactivate
Info = FacCFDeactivate(appl, &facReqParm, &facConfParm);
break;
case 0x000b: // CF Interrogate Parameters
Info = FacCFInterrogateParameters(appl, &facReqParm, &facConfParm);
break;
case 0x000c: // CF Interrogate Numbers
Info = FacCFInterrogateNumbers(appl, &facReqParm, &facConfParm);
break;
default:
Info = CapiSuccess;
facConfParm.u.Info.SupplementaryServiceInfo = CapiSupplementaryServiceNotSupported;
}
if (i == CAPI_MAXDUMMYPCS)
return 0;
return contr->dummy_pcs[i];
if (Info == 0x0000)
capiEncodeFacConfParm(tmp, &facConfParm);
else
tmp[0] = 0;
cmsg->FacilityConfirmationParameter = tmp;
SendCmsgAnswer2Application(appl, cmsg, Info);
}
void dummyProcessTimeout(unsigned long arg)
SSProcess_t *
SSProcessConstr(Application_t *appl, __u16 Function, __u32 Handle)
{
DummyProcess_t *dummy_pc = (DummyProcess_t *) arg;
Contr_t* contr = dummy_pc->contr;
Appl_t *appl;
__u8 tmp[10], *p;
_cmsg cmsg;
SSProcess_t *sspc;
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);
sspc = SSProcess_alloc();
if (!sspc)
return(NULL);
memset(sspc, 0, sizeof(SSProcess_t));
sspc->ApplId = appl->ApplId;
sspc->Function = Function;
sspc->Handle = Handle;
ControllerAddSSProcess(appl->contr, sspc);
return(sspc);
}
void SSProcessDestr(SSProcess_t *sspc)
{
del_timer(&sspc->tl);
list_del_init(&sspc->head);
SSProcess_free(sspc);
}
static void
SendSSFacilityInd(Application_t *appl, __u32 addr, __u8 *para)
{
_cmsg *cmsg;
CMSG_ALLOC(cmsg);
capi_cmsg_header(cmsg, appl->ApplId, CAPI_FACILITY, CAPI_IND, appl->MsgId++, addr);
cmsg->FacilitySelector = 0x0003;
cmsg->FacilityIndicationParameter = para;
SendCmsg2Application(appl, cmsg);
}
static void
SendSSFacilityInd2All(Controller_t *contr, __u32 nMask, __u8 *para)
{
struct list_head *item;
Application_t *appl;
list_for_each(item, &contr->Applications) {
appl = (Application_t *)item;
if (test_bit(APPL_STATE_RELEASE, &appl->state))
continue;
if (!(appl->NotificationMask & nMask))
continue;
SendSSFacilityInd(appl, contr->addr, para);
}
}
void
SSProcessTimeout(unsigned long arg)
{
SSProcess_t *sspc = (SSProcess_t *) arg;
Application_t *appl;
__u8 tmp[10], *p;
appl = getApplication4Id(sspc->contr, sspc->ApplId);
if (!appl) {
SSProcessDestr(sspc);
return;
}
p = &tmp[1];
p += capiEncodeWord(p, sspc->Function);
p += capiEncodeFacIndCFact(p, CapiTimeOut, sspc->Handle);
tmp[0] = p - &tmp[1];
SendSSFacilityInd(appl, sspc->addr, tmp);
SSProcessDestr(sspc);
}
void SSProcessAddTimer(SSProcess_t *sspc, int msec)
{
sspc->tl.function = SSProcessTimeout;
sspc->tl.data = (unsigned long) sspc;
init_timer(&sspc->tl);
sspc->tl.expires = jiffies + (msec * HZ) / 1000;
add_timer(&sspc->tl);
}
#if 0
void printPublicPartyNumber(struct PublicPartyNumber *publicPartyNumber)
{
@ -570,16 +540,15 @@ void printAddress(struct Address *address)
}
#endif
void contrDummyFacility(Contr_t *contr, Q931_info_t *qi)
static void
SSProcessFacility(Controller_t *contr, Q931_info_t *qi)
{
Appl_t *appl;
Application_t *appl;
int ie_len;
struct asn1_parm parm;
DummyProcess_t *dummy_pc;
_cmsg cmsg;
__u8 tmp[255];
SSProcess_t *sspc;
__u8 tmp[256];
__u8 *p, *end;
__u16 ApplId;
if (!qi || !qi->facility) {
int_error();
@ -601,136 +570,104 @@ void contrDummyFacility(Contr_t *contr, Q931_info_t *qi)
}
ParseComponent(&parm, p, end);
switch (parm.comp) {
case invoke:
case invoke:
#if 0
printk("invokeId %d\n", parm.u.inv.invokeId);
printk("operationValue %d\n", parm.u.inv.operationValue);
printk("invokeId %d\n", parm.u.inv.invokeId);
printk("operationValue %d\n", parm.u.inv.operationValue);
#endif
switch (parm.u.inv.operationValue) {
case 0x0009:
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);
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);
p = &tmp[1];
p += capiEncodeWord(p, 0x8006);
p += capiEncodeFacIndCFNotAct(p, &parm.u.inv.o.actNot);
tmp[0] = p - &tmp[1];
SendSSFacilityInd2All(contr, SuppServiceCF, tmp);
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
p = &tmp[1];
p += capiEncodeWord(p, 0x8007);
p += capiEncodeFacIndCFNotDeact(p, &parm.u.inv.o.deactNot);
tmp[0] = p - &tmp[1];
SendSSFacilityInd2All(contr, SuppServiceCF, tmp);
break;
default:
int_error();
}
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);
case returnResult:
sspc = getSSProcess4Id(contr, parm.u.retResult.invokeId);
if (!sspc)
return;
appl = getApplication4Id(contr, sspc->ApplId);
if (!appl)
return;
p = &tmp[1];
p += capiEncodeWord(p, sspc->Function);
switch (sspc->Function) {
case 0x0009:
p += capiEncodeFacIndCFact(p, 0, sspc->Handle);
break;
case 0x000a:
p += capiEncodeFacIndCFdeact(p, 0, sspc->Handle);
break;
case 0x000b:
p += capiEncodeFacIndCFinterParameters(p, 0, sspc->Handle,
&parm.u.retResult.o.resultList);
break;
case 0x000c:
p += capiEncodeFacIndCFinterNumbers(p, 0, sspc->Handle,
&parm.u.retResult.o.list);
break;
default:
int_error();
break;
}
tmp[0] = p - &tmp[1];
SendSSFacilityInd(appl, sspc->addr, tmp);
SSProcessDestr(sspc);
break;
case returnError:
sspc = getSSProcess4Id(contr, parm.u.retResult.invokeId);
if (!sspc)
return;
appl = getApplication4Id(contr, sspc->ApplId);
if (!appl)
return;
p = &tmp[1];
p += capiEncodeWord(p, sspc->Function);
p += capiEncodeFacIndCFact(p, 0x3600 | (parm.u.retError.errorValue & 0xff),
sspc->Handle);
tmp[0] = p - &tmp[1];
SendSSFacilityInd(appl, sspc->addr, tmp);
SSProcessDestr(sspc);
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();
}
}
int contrDummyInd(Contr_t *contr, __u32 prim, struct sk_buff *skb)
int
Supplementary_l3l4(Controller_t *contr, __u32 prim, struct sk_buff *skb)
{
int ret = -EINVAL;
if (!skb)
return(ret);
switch (prim) {
case CC_FACILITY | INDICATION:
if (skb && skb->len)
contrDummyFacility(contr, (Q931_info_t *)skb->data);
if (skb->len)
SSProcessFacility(contr, (Q931_info_t *)skb->data);
dev_kfree_skb(skb);
ret = 0;
break;