mISDN/drivers/isdn/hardware/mISDN/plci.c

158 lines
3.1 KiB
C

/* $Id$
*
*/
#include "m_capi.h"
#include "dss1.h"
#include "helper.h"
#include "debug.h"
#define plciDebug(plci, lev, fmt, args...) \
capidebug(lev, fmt, ## args)
void plciInit(Controller_t *contr)
{
Plci_t *plci = contr->plcis;
int i;
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;
if (contr->debug & CAPI_DBG_PLCI)
printk(KERN_DEBUG "%s: %p PLCI(%x) l3id(%x)\n",
__FUNCTION__, plci, plci->addr, plci->l3id);
plci++;
}
}
void plciHandleSetupInd(Plci_t *plci, int pr, Q931_info_t *qi)
{
__u16 CIPValue;
Application_t *appl;
AppPlci_t *aplci;
struct list_head *item, *next;
if (!qi || !plci->contr) {
int_error();
return;
}
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) {
struct sk_buff *skb = mISDN_alloc_l3msg(10, MT_RELEASE_COMPLETE);
u_char cause[4] = {IE_CAUSE,2,0x80,0xd8}; /* incompatible destination */
if (skb) {
mISDN_AddvarIE(skb,cause);
plciL4L3(plci, CC_RELEASE_COMPLETE | REQUEST, skb);
}
ControllerReleasePlci(plci);
}
}
int plci_l3l4(Plci_t *plci, int pr, struct sk_buff *skb)
{
AppPlci_t *aplci;
Q931_info_t *qi;
struct list_head *item, *next;
if (skb->len)
qi = (Q931_info_t *)skb->data;
else
qi = NULL;
switch (pr) {
case CC_SETUP | INDICATION:
plciHandleSetupInd(plci, pr, qi);
break;
/*
// no extra treatment for CC_RELEASE_CR | INDICATION !
case CC_RELEASE_CR | INDICATION:
break;
*/
default:
list_for_each_safe(item, next, &plci->AppPlcis) {
aplci = (AppPlci_t *)item;
AppPlci_l3l4(aplci, pr, qi);
}
break;
}
dev_kfree_skb(skb);
return(0);
}
AppPlci_t *
getAppPlci4Id(Plci_t *plci, __u16 appId) {
struct list_head *item;
AppPlci_t *aplci;
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;
}
list_add(&aplci->head, &plci->AppPlcis);
plci->nAppl++;
}
void
plciDetachAppPlci(Plci_t *plci, AppPlci_t *aplci)
{
aplci->plci = NULL;
list_del_init(&aplci->head);
plci->nAppl--;
if (!plci->nAppl)
ControllerReleasePlci(plci);
}
void plciNewCrReq(Plci_t *plci)
{
plciL4L3(plci, CC_NEW_CR | REQUEST, NULL);
}
int
plciL4L3(Plci_t *plci, __u32 prim, struct sk_buff *skb)
{
#define MY_RESERVE 8
int err;
if (!skb) {
if (!(skb = alloc_skb(MY_RESERVE, GFP_ATOMIC))) {
printk(KERN_WARNING "%s: no skb size %d\n",
__FUNCTION__, MY_RESERVE);
return(-ENOMEM);
} else
skb_reserve(skb, MY_RESERVE);
}
err = ControllerL4L3(plci->contr, prim, plci->l3id, skb);
if (err)
dev_kfree_skb(skb);
return(err);
}