diff --git a/drivers/isdn/hardware/mISDN/Makefile b/drivers/isdn/hardware/mISDN/Makefile index 346d7b6..46fa1bd 100644 --- a/drivers/isdn/hardware/mISDN/Makefile +++ b/drivers/isdn/hardware/mISDN/Makefile @@ -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 diff --git a/drivers/isdn/hardware/mISDN/Makefile.v2.6 b/drivers/isdn/hardware/mISDN/Makefile.v2.6 index 1c63b43..3d98082 100644 --- a/drivers/isdn/hardware/mISDN/Makefile.v2.6 +++ b/drivers/isdn/hardware/mISDN/Makefile.v2.6 @@ -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 diff --git a/drivers/isdn/hardware/mISDN/app_plci.c b/drivers/isdn/hardware/mISDN/app_plci.c new file mode 100644 index 0000000..e28307c --- /dev/null +++ b/drivers/isdn/hardware/mISDN/app_plci.c @@ -0,0 +1,1512 @@ +/* $Id$ + * + */ + +#include "m_capi.h" +#include "helper.h" +#include "debug.h" +#include "dss1.h" + +#define AppPlciDebug(aplci, lev, fmt, args...) \ + capidebug(lev, fmt, ## args) + +static void AppPlciClearOtherApps(AppPlci_t *); +static void AppPlciInfoIndMsg(AppPlci_t *, __u32, unsigned char); +static void AppPlciInfoIndIE(AppPlci_t *, unsigned char, __u32, Q931_info_t *); +static void AppPlciLinkUp(AppPlci_t *); +static void AppPlciLinkDown(AppPlci_t *); + +static u_char BEARER_SPEECH_64K_ALAW[] = {4, 3, 0x80, 0x90, 0xA3}; +static u_char BEARER_SPEECH_64K_ULAW[] = {4, 3, 0x80, 0x90, 0xA2}; +static u_char BEARER_UNRES_DIGITAL_64K[] = {4, 2, 0x88, 0x90}; +static u_char BEARER_RES_DIGITAL_64K[] = {4, 2, 0x89, 0x90}; +static u_char BEARER_31AUDIO_64K_ALAW[] = {4, 3, 0x90, 0x90, 0xA3}; +static u_char BEARER_31AUDIO_64K_ULAW[] = {4, 3, 0x90, 0x90, 0xA2}; +static u_char HLC_TELEPHONY[] = {0x7d, 2, 0x91, 0x81}; +static u_char HLC_FACSIMILE[] = {0x7d, 2, 0x91, 0x84}; + +__u16 q931CIPValue(Q931_info_t *qi) +{ + __u16 CIPValue = 0; + u_char *p; + + if (!qi) + return 0; + if (!qi->bearer_capability) + return 0; + p = (u_char *)qi; + p += L3_EXTRA_SIZE + qi->bearer_capability; + if (memcmp(p, BEARER_SPEECH_64K_ALAW, 5) == 0 + || memcmp(p, BEARER_SPEECH_64K_ULAW, 5) == 0) { + CIPValue = 1; + } else if (memcmp(p, BEARER_UNRES_DIGITAL_64K, 4) == 0) { + CIPValue = 2; + } else if (memcmp(p, BEARER_RES_DIGITAL_64K, 4) == 0) { + CIPValue = 3; + } else if (memcmp(p, BEARER_31AUDIO_64K_ALAW, 5) == 0 + || memcmp(p, BEARER_31AUDIO_64K_ULAW, 5) == 0) { + CIPValue = 4; + } else { + CIPValue = 0; + } + + if (!qi->hlc) + return CIPValue; + + p = (u_char *)qi; + p += L3_EXTRA_SIZE + qi->hlc; + if ((CIPValue == 1) || (CIPValue == 4)) { + if (memcmp(p, HLC_TELEPHONY, 4) == 0) { + CIPValue = 16; + } else if (memcmp(p, HLC_FACSIMILE, 4) == 0) { + CIPValue = 17; + } + } + return CIPValue; +} + +u_int plci_parse_channel_id(u_char *p) +{ + u_int cid = -1; + int l; + + if (p) { + p++; + capidebug(CAPI_DBG_PLCI_INFO, "%s: l(%d) %x", __FUNCTION__, p[0], p[1]); + l = *p++; + if (l == 1) { + cid = *p; + } else if (l == 3) { + cid = *p++ << 16; + cid |= *p++ << 8; + cid |= *p; + } + } + return(cid); +} + +__u16 CIPValue2setup(__u16 CIPValue, struct sk_buff *skb) +{ + switch (CIPValue) { + case 16: + AddvarIE(skb, BEARER_31AUDIO_64K_ALAW); + AddvarIE(skb, HLC_TELEPHONY); + break; + case 17: + AddvarIE(skb, BEARER_31AUDIO_64K_ALAW); + AddvarIE(skb, HLC_FACSIMILE); + break; + case 1: + AddvarIE(skb, BEARER_SPEECH_64K_ALAW); + break; + case 2: + AddvarIE(skb, BEARER_UNRES_DIGITAL_64K); + break; + case 3: + AddvarIE(skb, BEARER_RES_DIGITAL_64K); + break; + case 4: + AddvarIE(skb, BEARER_31AUDIO_64K_ALAW); + break; + default: + return CapiIllMessageParmCoding; + } + return 0; +} + +__u16 cmsg2setup_req(_cmsg *cmsg, struct sk_buff *skb) +{ + if (CIPValue2setup(cmsg->CIPValue, skb)) + goto err; + AddIE(skb, IE_CALLING_PN, cmsg->CallingPartyNumber); + AddIE(skb, IE_CALLING_SUB, cmsg->CallingPartySubaddress); + AddIE(skb, IE_CALLED_PN, cmsg->CalledPartyNumber); + AddIE(skb, IE_CALLED_SUB, cmsg->CalledPartySubaddress); + AddIE(skb, IE_BEARER, cmsg->BC); + AddIE(skb, IE_LLC, cmsg->LLC); + AddIE(skb, IE_HLC, cmsg->HLC); + return 0; + err: + return CapiIllMessageParmCoding; +} + +__u16 cmsg2info_req(_cmsg *cmsg, struct sk_buff *skb) +{ + AddIE(skb, IE_KEYPAD, cmsg->Keypadfacility); + AddIE(skb, IE_CALLED_PN, cmsg->CalledPartyNumber); + return 0; +} + +__u16 cmsg2alerting_req(_cmsg *cmsg, struct sk_buff *skb) +{ + AddIE(skb, IE_USER_USER, cmsg->Useruserdata); + return 0; +} + +__u16 AppPlciCheckBprotocol(AppPlci_t *aplci, _cmsg *cmsg) +{ + struct capi_ctr *ctrl = aplci->contr->ctrl; + u_long sprot; + + sprot = ctrl->profile.support1; + if (!test_bit(cmsg->B1protocol, &sprot)) + return CapiB1ProtocolNotSupported; + sprot = ctrl->profile.support2; + if (!test_bit(cmsg->B2protocol, &sprot)) + return CapiB2ProtocolNotSupported; + sprot = ctrl->profile.support3; + if (!test_bit(cmsg->B3protocol, &sprot)) + return CapiB3ProtocolNotSupported; + + aplci->Bprotocol.B1 = cmsg->B1protocol; + aplci->Bprotocol.B2 = cmsg->B2protocol; + aplci->Bprotocol.B3 = cmsg->B3protocol; + return 0; +} + +// -------------------------------------------------------------------- +// PLCI state machine +// +// Some rules: +// * EV_AP_* events come from CAPI Application +// * EV_L3_* events come from the ISDN stack +// * EV_PI_* events generated in PLCI handling +// * messages are send in the routine that handle the event +// +// -------------------------------------------------------------------- + +enum { + ST_PLCI_P_0, + ST_PLCI_P_0_1, + ST_PLCI_P_1, + ST_PLCI_P_2, + ST_PLCI_P_3, + ST_PLCI_P_4, + ST_PLCI_P_ACT, + ST_PLCI_P_5, + ST_PLCI_P_6, + ST_PLCI_P_RES, +} + +const ST_PLCI_COUNT = ST_PLCI_P_RES + 1; + +static char *str_st_plci[] = { + "ST_PLCI_P_0", + "ST_PLCI_P_0_1", + "ST_PLCI_P_1", + "ST_PLCI_P_2", + "ST_PLCI_P_3", + "ST_PLCI_P_4", + "ST_PLCI_P_ACT", + "ST_PLCI_P_5", + "ST_PLCI_P_6", + "ST_PLCI_P_RES", +}; + +enum { + EV_AP_CONNECT_REQ, + EV_PI_CONNECT_CONF, + EV_PI_CONNECT_IND, + EV_AP_CONNECT_RESP, + EV_PI_CONNECT_ACTIVE_IND, + EV_AP_CONNECT_ACTIVE_RESP, + EV_AP_ALERT_REQ, + EV_AP_INFO_REQ, + EV_PI_INFO_IND, + EV_PI_FACILITY_IND, + EV_AP_SELECT_B_PROTOCOL_REQ, + EV_AP_DISCONNECT_REQ, + EV_PI_DISCONNECT_IND, + EV_AP_DISCONNECT_RESP, + EV_AP_SUSPEND_REQ, + EV_PI_SUSPEND_CONF, + EV_AP_RESUME_REQ, + EV_PI_RESUME_CONF, + EV_PI_CHANNEL_ERR, + EV_L3_SETUP_IND, + EV_L3_SETUP_CONF_ERR, + EV_L3_SETUP_CONF, + EV_L3_SETUP_COMPL_IND, + EV_L3_DISCONNECT_IND, + EV_L3_RELEASE_IND, + EV_L3_RELEASE_PROC_IND, + EV_L3_NOTIFY_IND, + EV_L3_SUSPEND_ERR, + EV_L3_SUSPEND_CONF, + EV_L3_RESUME_ERR, + EV_L3_RESUME_CONF, + EV_L3_REJECT_IND, + EV_PH_CONTROL_IND, + EV_AP_RELEASE, +} + +const EV_PLCI_COUNT = EV_AP_RELEASE + 1; + +static char* str_ev_plci[] = { + "EV_AP_CONNECT_REQ", + "EV_PI_CONNECT_CONF", + "EV_PI_CONNECT_IND", + "EV_AP_CONNECT_RESP", + "EV_PI_CONNECT_ACTIVE_IND", + "EV_AP_CONNECT_ACTIVE_RESP", + "EV_AP_ALERT_REQ", + "EV_AP_INFO_REQ", + "EV_PI_INFO_IND", + "EV_PI_FACILITY_IND", + "EV_AP_SELECT_B_PROTOCOL_REQ", + "EV_AP_DISCONNECT_REQ", + "EV_PI_DISCONNECT_IND", + "EV_AP_DISCONNECT_RESP", + "EV_AP_SUSPEND_REQ", + "EV_PI_SUSPEND_CONF", + "EV_AP_RESUME_REQ", + "EV_PI_RESUME_CONF", + "EV_PI_CHANNEL_ERR", + "EV_L3_SETUP_IND", + "EV_L3_SETUP_CONF_ERR", + "EV_L3_SETUP_CONF", + "EV_L3_SETUP_COMPL_IND", + "EV_L3_DISCONNECT_IND", + "EV_L3_RELEASE_IND", + "EV_L3_RELEASE_PROC_IND", + "EV_L3_NOTIFY_IND", + "EV_L3_SUSPEND_ERR", + "EV_L3_SUSPEND_CONF", + "EV_L3_RESUME_ERR", + "EV_L3_RESUME_CONF", + "EV_L3_REJECT_IND", + "EV_PH_CONTROL_IND", + "EV_AP_RELEASE", +}; + +static struct Fsm plci_fsm = +{ 0, 0, 0, 0, 0 }; + +static void +AppPlci_debug(struct FsmInst *fi, char *fmt, ...) +{ + char tmp[128]; + char *p = tmp; + va_list args; + AppPlci_t *aplci = fi->userdata; + + va_start(args, fmt); + p += sprintf(p, "APLCI 0x%x: ", aplci->addr); + p += vsprintf(p, fmt, args); + *p = 0; + AppPlciDebug(aplci, CAPI_DBG_PLCI_STATE, tmp); + va_end(args); +} + +static inline void +Send2Application(AppPlci_t *aplci, _cmsg *cmsg) +{ + SendCmsg2Application(aplci->appl, cmsg); +} + +static inline void +AppPlciCmsgHeader(AppPlci_t *aplci, _cmsg *cmsg, __u8 cmd, __u8 subcmd) +{ + capi_cmsg_header(cmsg, aplci->appl->ApplId, cmd, subcmd, + aplci->appl->MsgId++, aplci->addr); +} + +static void +plci_connect_req(struct FsmInst *fi, int event, void *arg) +{ + AppPlci_t *aplci = fi->userdata; + Plci_t *plci = aplci->plci; + struct sk_buff *skb; + _cmsg *cmsg = arg; + __u16 Info = 0; + + FsmChangeState(fi, ST_PLCI_P_0_1); + test_and_set_bit(PLCI_STATE_OUTGOING, &plci->state); + + skb = alloc_l3msg(260, MT_SETUP); + + if (!skb) { + Info = CapiNoPlciAvailable; + goto answer; + } + if ((Info = cmsg2setup_req(cmsg, skb))) { + goto answer; + } + if ((Info = AppPlciCheckBprotocol(aplci, cmsg))) { + goto answer; + } + + plciNewCrReq(plci); + plciL4L3(plci, CC_SETUP | REQUEST, skb); +answer: + capi_cmsg_answer(cmsg); + cmsg->Info = Info; + if (cmsg->Info == 0) + cmsg->adr.adrPLCI = aplci->addr; + Send2Application(aplci, cmsg); + FsmEvent(fi, EV_PI_CONNECT_CONF, cmsg); +} + +static void +plci_connect_conf(struct FsmInst *fi, int event, void *arg) +{ + AppPlci_t *aplci = fi->userdata; + _cmsg *cmsg = arg; + + if (cmsg->Info == 0) { + FsmChangeState(fi, ST_PLCI_P_1); + } else { + FsmChangeState(fi, ST_PLCI_P_0); + AppPlciDestr(aplci); + } +} + +static void +plci_connect_ind(struct FsmInst *fi, int event, void *arg) +{ + FsmChangeState(fi, ST_PLCI_P_2); + Send2Application(fi->userdata, arg); +} + +static void plci_suspend_req(struct FsmInst *fi, int event, void *arg) +{ + AppPlci_t *aplci = fi->userdata; + Plci_t *plci = aplci->plci; + + plciL4L3(plci, CC_SUSPEND | REQUEST, arg); +} + +static void plci_resume_req(struct FsmInst *fi, int event, void *arg) +{ + AppPlci_t *aplci = fi->userdata; + Plci_t *plci = aplci->plci; + + // we already sent CONF with Info = SuppInfo = 0 + FsmChangeState(fi, ST_PLCI_P_RES); + plciNewCrReq(plci); + plciL4L3(plci, CC_RESUME | REQUEST, arg); +} + +static void +plci_alert_req(struct FsmInst *fi, int event, void *arg) +{ + AppPlci_t *aplci = fi->userdata; + Plci_t *plci = aplci->plci; + _cmsg *cmsg = arg; + __u16 Info = 0; + + if (test_and_set_bit(PLCI_STATE_ALERTING, &plci->state)) { + Info = 0x0003; // other app is already alerting + } else { + struct sk_buff *skb = alloc_l3msg(10, MT_ALERTING); + if (!skb) { + int_error(); + goto answer; + } + Info = cmsg2alerting_req(cmsg, skb); + if (Info == 0) { + plciL4L3(plci, CC_ALERTING | REQUEST, skb); + } + } +answer: + capi_cmsg_answer(cmsg); + cmsg->Info = Info; + Send2Application(aplci, cmsg); +} + +static void +plci_connect_resp(struct FsmInst *fi, int event, void *arg) +{ + AppPlci_t *aplci = fi->userdata; + Plci_t *plci = aplci->plci; + unsigned char cause[4]; + _cmsg *cmsg = arg; + struct sk_buff *skb; + + if (cmsg->Reject == 0) { // accept + if (AppPlciCheckBprotocol(aplci, cmsg)) { + int_error(); + } + AppPlciClearOtherApps(aplci); + plciL4L3(plci, CC_CONNECT | REQUEST, NULL); + FsmChangeState(fi, ST_PLCI_P_4); + cmsg_free(cmsg); + return; + } + // ignore, reject + memcpy(cause, "\x02\x80", 2); // IE CAUSE, location = local + switch (cmsg->Reject) { + case 2: cause[2] = 0x90; break; // normal call clearing + case 3: cause[2] = 0x91; break; // user busy + case 4: cause[2] = 0xac; break; // req circuit/channel not avail + case 5: cause[2] = 0x9d; break; // fac rejected + case 6: cause[2] = 0x86; break; // channel unacceptable + case 7: cause[2] = 0xd8; break; // incompatible dest + case 8: cause[2] = 0x9b; break; // dest out of order + default: + if ((cmsg->Reject & 0xff00) == 0x3400) { + cause[2] = cmsg->Reject & 0xff; + } else { + cause[2] = 0x90; break; // normal call clearing + } + } + // FIXME + // WHY ??? + // if (cmsg->Reject != 1) { + // ignore + // AppPlciClearOtherApps(aplci); + // } + // plciDetachAppPlci(plci, aplci); + if (plci->nAppl == 1) { + int prim; + if (test_bit(PLCI_STATE_ALERTING, &plci->state)) + prim = CC_DISCONNECT | REQUEST; + else + // if we already answered, we can't just ignore but must clear actively + prim = CC_RELEASE_COMPLETE | REQUEST; + skb = alloc_l3msg(10, MT_DISCONNECT); + if (!skb) { + plciL4L3(plci, prim, NULL); + } else { + AddIE(skb, IE_CAUSE, cause); + plciL4L3(plci, prim, skb); + } + } + cmsg->Command = CAPI_DISCONNECT; + cmsg->Subcommand = CAPI_IND; + cmsg->Messagenumber = aplci->appl->MsgId++; + cmsg->Reject = 0x3400 | cause[2]; + if (FsmEvent(&aplci->plci_m, EV_PI_DISCONNECT_IND, cmsg)) + cmsg_free(cmsg); +} + +static void +plci_connect_active_ind(struct FsmInst *fi, int event, void *arg) +{ + AppPlci_t *aplci = fi->userdata; + + FsmChangeState(fi, ST_PLCI_P_ACT); + AppPlciLinkUp(aplci); + Send2Application(aplci, arg); +} + +static void plci_connect_active_resp(struct FsmInst *fi, int event, void *arg) +{ + cmsg_free(arg); +} + +static void plci_disconnect_req(struct FsmInst *fi, int event, void *arg) +{ + AppPlci_t *aplci = fi->userdata; + Plci_t *plci = aplci->plci; + u_char cause[4]; + _cmsg *cmsg = arg; + + FsmChangeState(fi, ST_PLCI_P_5); + + if (!plci) { + int_error(); + return; + } + // FIXME handle additional Inf + capi_cmsg_answer(cmsg); + cmsg->Reason = 0; // disconnect initiated + Send2Application(aplci, cmsg); + + AppPlciLinkDown(aplci); + + if (!aplci->cause[0]) { // FIXME handle additional Info + struct sk_buff *skb; + + skb = alloc_l3msg(10, MT_DISCONNECT); + if (!skb) { + plciL4L3(plci, CC_DISCONNECT | REQUEST, NULL); + } else { + memcpy(cause, "\x02\x80\x90", 3); // normal call clearing + AddIE(skb, IE_CAUSE, cause); + plciL4L3(plci, CC_DISCONNECT | REQUEST, skb); + } + } else { + /* release physical link */ + // FIXME + plciL4L3(plci, CC_RELEASE | REQUEST, NULL); + } +} + +static void plci_suspend_conf(struct FsmInst *fi, int event, void *arg) +{ + FsmChangeState(fi, ST_PLCI_P_5); +} + +static void plci_resume_conf(struct FsmInst *fi, int event, void *arg) +{ + // facility_ind Resume: Reason = 0 + AppPlci_t *aplci = fi->userdata; + + FsmChangeState(fi, ST_PLCI_P_ACT); + AppPlciLinkUp(aplci); + Send2Application(aplci, arg); +} + +static void +plci_disconnect_ind(struct FsmInst *fi, int event, void *arg) +{ + FsmChangeState(fi, ST_PLCI_P_6); + Send2Application(fi->userdata, arg); +} + +static void +plci_disconnect_resp(struct FsmInst *fi, int event, void *arg) +{ + if (arg) + cmsg_free(arg); + FsmChangeState(fi, ST_PLCI_P_0); + AppPlciDestr(fi->userdata); +} + +static void +plci_appl_release(struct FsmInst *fi, int event, void *arg) +{ + AppPlciDestr(fi->userdata); +} + +static void +plci_appl_release_disc(struct FsmInst *fi, int event, void *arg) +{ + AppPlci_t *aplci = fi->userdata; + Plci_t *plci = aplci->plci; + + FsmChangeState(fi, ST_PLCI_P_5); + + if (!plci) { + int_error(); + return; + } + + AppPlciLinkDown(aplci); + + if (!aplci->cause[0]) { + struct sk_buff *skb; + + skb = alloc_l3msg(10, MT_DISCONNECT); + if (!skb) { + plciL4L3(plci, CC_DISCONNECT | REQUEST, NULL); + } else { + u_char *cause = "\x02\x80\x9f"; + + AddIE(skb, IE_CAUSE, cause); + plciL4L3(plci, CC_DISCONNECT | REQUEST, skb); + } + } else { + /* release physical link */ + // FIXME + plciL4L3(plci, CC_RELEASE | REQUEST, NULL); + } +} + +static void +plci_cc_setup_conf(struct FsmInst *fi, int event, void *arg) +{ + AppPlci_t *aplci = fi->userdata; + _cmsg *cmsg; + Q931_info_t *qi = arg; + u_char *p; + + if (aplci->channel == -1) {/* no valid channel set */ + FsmEvent(fi, EV_PI_CHANNEL_ERR, NULL); + return; + } + CMSG_ALLOC(cmsg); + AppPlciCmsgHeader(aplci, cmsg, CAPI_CONNECT_ACTIVE, CAPI_IND); + if (qi) { + p = (u_char *)qi; + p += L3_EXTRA_SIZE; + if (qi->connected_nr) + cmsg->ConnectedNumber = &p[qi->connected_nr + 1]; + if (qi->connected_sub) + cmsg->ConnectedSubaddress = &p[qi->connected_sub + 1]; + if (qi->llc) + cmsg->LLC = &p[qi->llc + 1]; + } + if (FsmEvent(fi, EV_PI_CONNECT_ACTIVE_IND, cmsg)) + cmsg_free(cmsg); +} + +static void +plci_cc_setup_conf_err(struct FsmInst *fi, int event, void *arg) +{ + AppPlci_t *aplci = fi->userdata; + _cmsg *cmsg; + + CMSG_ALLOC(cmsg); + AppPlciCmsgHeader(aplci, cmsg, CAPI_DISCONNECT, CAPI_IND); + cmsg->Reason = CapiProtocolErrorLayer3; + if (FsmEvent(&aplci->plci_m, EV_PI_DISCONNECT_IND, cmsg)) + cmsg_free(cmsg); +} + +static void +plci_channel_err(struct FsmInst *fi, int event, void *arg) +{ + AppPlci_t *aplci = fi->userdata; + _cmsg *cmsg; + u_char cause[4]; + struct sk_buff *skb; + + skb = alloc_l3msg(10, MT_RELEASE_COMPLETE); + if (skb) { + cause[0] = 2; + cause[1] = 0x80; + cause[2] = 0x86; /* channel unacceptable */ + AddIE(skb, IE_CAUSE, cause); + plciL4L3(aplci->plci, CC_RELEASE_COMPLETE | REQUEST, skb); + } else + int_error(); + CMSG_ALLOC(cmsg); + AppPlciCmsgHeader(aplci, cmsg, CAPI_DISCONNECT, CAPI_IND); + cmsg->Reason = CapiProtocolErrorLayer3; + if (FsmEvent(&aplci->plci_m, EV_PI_DISCONNECT_IND, cmsg)) + cmsg_free(cmsg); +} + +static void +plci_cc_setup_ind(struct FsmInst *fi, int event, void *arg) +{ + AppPlci_t *aplci = fi->userdata; + Q931_info_t *qi = arg; + _cmsg *cmsg; + u_char *p; + + CMSG_ALLOC(cmsg); + AppPlciCmsgHeader(aplci, cmsg, CAPI_CONNECT, CAPI_IND); + + // FIXME: CW + if (qi) { + p = (u_char *)qi; + p += L3_EXTRA_SIZE; + cmsg->CIPValue = q931CIPValue(qi); + if (qi->called_nr) + cmsg->CalledPartyNumber = &p[qi->called_nr + 1]; + if (qi->called_sub) + cmsg->CalledPartySubaddress = &p[qi->called_sub + 1]; + if (qi->calling_nr) + cmsg->CallingPartyNumber = &p[qi->calling_nr + 1]; + if (qi->calling_sub) + cmsg->CallingPartySubaddress = &p[qi->calling_sub + 1]; + if (qi->bearer_capability) + cmsg->BC = &p[qi->bearer_capability + 1]; + if (qi->llc) + cmsg->LLC = &p[qi->llc + 1]; + if (qi->hlc) + cmsg->HLC = &p[qi->hlc + 1]; + // all else set to default + } + if (FsmEvent(&aplci->plci_m, EV_PI_CONNECT_IND, cmsg)) + cmsg_free(cmsg); +} + +static void +plci_cc_setup_compl_ind(struct FsmInst *fi, int event, void *arg) +{ + AppPlci_t *aplci = fi->userdata; + _cmsg *cmsg; + + CMSG_ALLOC(cmsg); + AppPlciCmsgHeader(aplci, cmsg, CAPI_CONNECT_ACTIVE, CAPI_IND); + if (FsmEvent(&aplci->plci_m, EV_PI_CONNECT_ACTIVE_IND, cmsg)) + cmsg_free(cmsg); +} + +static void +plci_cc_disconnect_ind(struct FsmInst *fi, int event, void *arg) +{ + AppPlci_t *aplci = fi->userdata; + Q931_info_t *qi = arg; + u_char *p; + + if (qi) { + p = (u_char *)qi; + p += L3_EXTRA_SIZE; + if (qi->cause) + memcpy(aplci->cause, &p[qi->cause + 1], 3); + } + if (aplci->appl->InfoMask & CAPI_INFOMASK_EARLYB3) + return; + + AppPlciLinkDown(aplci); + plciL4L3(aplci->plci, CC_RELEASE | REQUEST, NULL); +} + +static void +plci_cc_release_ind(struct FsmInst *fi, int event, void *arg) +{ + AppPlci_t *aplci = fi->userdata; + Q931_info_t *qi = arg; + u_char *p; + _cmsg *cmsg; + + AppPlciLinkDown(aplci); + CMSG_ALLOC(cmsg); + AppPlciCmsgHeader(aplci, cmsg, CAPI_DISCONNECT, CAPI_IND); + if (qi) { + p = (u_char *)qi; + p += L3_EXTRA_SIZE; + if (qi->cause) + cmsg->Reason = 0x3400 | p[qi->cause + 3]; + else if (aplci->cause[0]) // cause from CC_DISCONNECT IND + cmsg->Reason = 0x3400 | aplci->cause[2]; + else + cmsg->Reason = 0; + } else { + cmsg->Reason = CapiProtocolErrorLayer1; + } + if (FsmEvent(&aplci->plci_m, EV_PI_DISCONNECT_IND, cmsg)) + cmsg_free(cmsg); +} + +static void +plci_cc_notify_ind(struct FsmInst *fi, int event, void *arg) +{ + AppPlci_t *aplci = fi->userdata; + Q931_info_t *qi = arg; + _cmsg *cmsg; + __u8 tmp[10], *p, *nf; + + if (!qi || !qi->notify) + return; + nf = (u_char *)qi; + nf += L3_EXTRA_SIZE + qi->notify + 1; + if (nf[0] != 1) // len != 1 + return; + switch (nf[1]) { + case 0x80: // user suspended + case 0x81: // user resumed + if (!aplci->appl) + break; + if (!(aplci->appl->NotificationMask & SuppServiceTP)) + break; + CMSG_ALLOC(cmsg); + AppPlciCmsgHeader(aplci, cmsg, CAPI_FACILITY, CAPI_IND); + p = &tmp[1]; + p += capiEncodeWord(p, 0x8002 + (nf[1] & 1)); // Suspend/Resume Notification + *p++ = 0; // empty struct + tmp[0] = p - &tmp[1]; + cmsg->FacilitySelector = 0x0003; + cmsg->FacilityIndicationParameter = tmp; + Send2Application(aplci, cmsg); + break; + } +} + +static void +AppPlci_suspend_reply(AppPlci_t *aplci, __u16 SuppServiceReason) +{ + _cmsg *cmsg; + __u8 tmp[10], *p; + + if (aplci->appl) { + CMSG_ALLOC(cmsg); + AppPlciCmsgHeader(aplci, cmsg, CAPI_FACILITY, CAPI_IND); + p = &tmp[1]; + p += capiEncodeWord(p, 0x0004); // Suspend + p += capiEncodeFacIndSuspend(p, SuppServiceReason); + tmp[0] = p - &tmp[1]; + cmsg->FacilitySelector = 0x0003; + cmsg->FacilityIndicationParameter = tmp; + Send2Application(aplci, cmsg); + } + if (SuppServiceReason == CapiSuccess) + FsmEvent(&aplci->plci_m, EV_PI_SUSPEND_CONF, NULL); +} + +static void +plci_cc_suspend_err(struct FsmInst *fi, int event, void *arg) +{ + AppPlci_t *aplci = fi->userdata; + Q931_info_t *qi = arg; + u_char *p; + __u16 SuppServiceReason; + + if (qi) { // reject from network + if (qi->cause) { + p = (u_char *)qi; + p += L3_EXTRA_SIZE + qi->cause; + SuppServiceReason = 0x3400 | p[3]; + } else + SuppServiceReason = CapiProtocolErrorLayer3; + } else { // timeout + SuppServiceReason = CapiTimeOut; + } + AppPlci_suspend_reply(aplci, SuppServiceReason); +} + +static void +plci_cc_suspend_conf(struct FsmInst *fi, int event, void *arg) +{ + AppPlci_t *aplci = fi->userdata; + _cmsg *cmsg; + + AppPlciLinkDown(aplci); + + AppPlci_suspend_reply(aplci, CapiSuccess); + + CMSG_ALLOC(cmsg); + AppPlciCmsgHeader(aplci, cmsg, CAPI_DISCONNECT, CAPI_IND); + if (FsmEvent(&aplci->plci_m, EV_PI_DISCONNECT_IND, cmsg)) + cmsg_free(cmsg); +} + +static void +plci_cc_resume_err(struct FsmInst *fi, int event, void *arg) +{ + AppPlci_t *aplci = fi->userdata; + Q931_info_t *qi = arg; + u_char *p; + _cmsg *cmsg; + + CMSG_ALLOC(cmsg); + AppPlciCmsgHeader(aplci, cmsg, CAPI_DISCONNECT, CAPI_IND); + if (qi) { // reject from network + if (qi->cause) { + p = (u_char *)qi; + p += L3_EXTRA_SIZE + qi->cause; + cmsg->Reason = 0x3400 | p[3]; + } else + cmsg->Reason = 0; + } else { // timeout + cmsg->Reason = CapiProtocolErrorLayer1; + } + if (FsmEvent(&aplci->plci_m, EV_PI_DISCONNECT_IND, cmsg)) + cmsg_free(cmsg); +} + +static void +plci_cc_resume_conf(struct FsmInst *fi, int event, void *arg) +{ + AppPlci_t *aplci = fi->userdata; + Q931_info_t *qi = arg; + _cmsg *cmsg; + __u8 tmp[10], *p; + + if (!qi || !qi->channel_id) { + int_error(); + return; + } + p = (u_char *)qi; + p += L3_EXTRA_SIZE + qi->channel_id; + aplci->channel = plci_parse_channel_id(p); + CMSG_ALLOC(cmsg); + AppPlciCmsgHeader(aplci, cmsg, CAPI_FACILITY, CAPI_IND); + p = &tmp[1]; + p += capiEncodeWord(p, 0x0005); // Suspend + p += capiEncodeFacIndSuspend(p, CapiSuccess); + tmp[0] = p - &tmp[1]; + cmsg->FacilitySelector = 0x0003; + cmsg->FacilityIndicationParameter = tmp; + if (FsmEvent(&aplci->plci_m, EV_PI_RESUME_CONF, cmsg)) + cmsg_free(cmsg); +} + +static void +plci_select_b_protocol_req(struct FsmInst *fi, int event, void *arg) +{ + AppPlci_t *aplci = fi->userdata; + _cmsg *cmsg = arg; + __u16 Info; + + Info = AppPlciCheckBprotocol(aplci, cmsg); + if (Info) + goto answer; + + if (!aplci->ncci) { + int_error(); + cmsg_free(cmsg); + return; + } + + Info = ncciSelectBprotocol(aplci->ncci); +answer: + capi_cmsg_answer(cmsg); + cmsg->Info = Info; + Send2Application(aplci, cmsg); +} + +static void +plci_info_req_overlap(struct FsmInst *fi, int event, void *arg) +{ + AppPlci_t *aplci = fi->userdata; + Plci_t *plci = aplci->plci; + _cmsg *cmsg = arg; + __u16 Info = 0; + struct sk_buff *skb; + + skb = alloc_l3msg(100, MT_INFORMATION); + if (skb) { + Info = cmsg2info_req(cmsg, skb); + if (Info == CapiSuccess) + plciL4L3(plci, CC_INFORMATION | REQUEST, skb); + else + kfree_skb(skb); + } + capi_cmsg_answer(cmsg); + cmsg->Info = Info; + Send2Application(aplci, cmsg); +} + +static void +plci_cc_ph_control_ind(struct FsmInst *fi, int event, void *arg) +{ + AppPlci_t *aplci = fi->userdata; + int *tt = arg; + _cmsg *cmsg; + __u8 tmp[2]; + + if (!arg) + return; + AppPlciDebug(aplci, CAPI_DBG_PLCI_INFO, "%s: tt(%x)", __FUNCTION__, *tt); + if ((*tt & ~DTMF_TONE_MASK) != DTMF_TONE_VAL) + return; + + CMSG_ALLOC(cmsg); + AppPlciCmsgHeader(aplci, cmsg, CAPI_FACILITY, CAPI_IND); + tmp[0] = 1; + tmp[1] = *tt & DTMF_TONE_MASK; + cmsg->FacilitySelector = 0x0001; + cmsg->FacilityIndicationParameter = tmp; + Send2Application(aplci, cmsg); +} + +static void +plci_info_req(struct FsmInst *fi, int event, void *arg) +{ + // FIXME handle INFO CONF + if (arg) + cmsg_free(arg); +} + +static struct FsmNode fn_plci_list[] = +{ + {ST_PLCI_P_0, EV_AP_CONNECT_REQ, plci_connect_req}, + {ST_PLCI_P_0, EV_PI_CONNECT_IND, plci_connect_ind}, + {ST_PLCI_P_0, EV_AP_RESUME_REQ, plci_resume_req}, + {ST_PLCI_P_0, EV_L3_SETUP_IND, plci_cc_setup_ind}, + {ST_PLCI_P_0, EV_AP_RELEASE, plci_appl_release}, + + {ST_PLCI_P_0_1, EV_PI_CONNECT_CONF, plci_connect_conf}, + {ST_PLCI_P_0_1, EV_AP_RELEASE, plci_appl_release}, + + {ST_PLCI_P_1, EV_PI_CONNECT_ACTIVE_IND, plci_connect_active_ind}, + {ST_PLCI_P_1, EV_AP_DISCONNECT_REQ, plci_disconnect_req}, + {ST_PLCI_P_1, EV_PI_DISCONNECT_IND, plci_disconnect_ind}, + {ST_PLCI_P_1, EV_AP_INFO_REQ, plci_info_req_overlap}, + {ST_PLCI_P_1, EV_L3_SETUP_CONF, plci_cc_setup_conf}, + {ST_PLCI_P_1, EV_L3_SETUP_CONF_ERR, plci_cc_setup_conf_err}, + {ST_PLCI_P_1, EV_L3_DISCONNECT_IND, plci_cc_disconnect_ind}, + {ST_PLCI_P_1, EV_L3_RELEASE_PROC_IND, plci_cc_setup_conf_err}, + {ST_PLCI_P_1, EV_L3_RELEASE_IND, plci_cc_release_ind}, + {ST_PLCI_P_1, EV_L3_REJECT_IND, plci_cc_release_ind}, + {ST_PLCI_P_1, EV_PI_CHANNEL_ERR, plci_channel_err}, + {ST_PLCI_P_1, EV_AP_RELEASE, plci_appl_release_disc}, + + {ST_PLCI_P_2, EV_AP_ALERT_REQ, plci_alert_req}, + {ST_PLCI_P_2, EV_AP_CONNECT_RESP, plci_connect_resp}, + {ST_PLCI_P_2, EV_AP_DISCONNECT_REQ, plci_disconnect_req}, + {ST_PLCI_P_2, EV_PI_DISCONNECT_IND, plci_disconnect_ind}, + {ST_PLCI_P_2, EV_AP_INFO_REQ, plci_info_req}, + {ST_PLCI_P_2, EV_L3_RELEASE_IND, plci_cc_release_ind}, + {ST_PLCI_P_2, EV_AP_RELEASE, plci_appl_release_disc}, + + {ST_PLCI_P_4, EV_PI_CONNECT_ACTIVE_IND, plci_connect_active_ind}, + {ST_PLCI_P_4, EV_AP_DISCONNECT_REQ, plci_disconnect_req}, + {ST_PLCI_P_4, EV_PI_DISCONNECT_IND, plci_disconnect_ind}, + {ST_PLCI_P_4, EV_AP_INFO_REQ, plci_info_req}, + {ST_PLCI_P_4, EV_L3_SETUP_COMPL_IND, plci_cc_setup_compl_ind}, + {ST_PLCI_P_4, EV_L3_RELEASE_IND, plci_cc_release_ind}, + {ST_PLCI_P_4, EV_PI_CHANNEL_ERR, plci_channel_err}, + {ST_PLCI_P_4, EV_AP_RELEASE, plci_appl_release_disc}, + + {ST_PLCI_P_ACT, EV_AP_CONNECT_ACTIVE_RESP, plci_connect_active_resp}, + {ST_PLCI_P_ACT, EV_AP_DISCONNECT_REQ, plci_disconnect_req}, + {ST_PLCI_P_ACT, EV_PI_DISCONNECT_IND, plci_disconnect_ind}, + {ST_PLCI_P_ACT, EV_AP_INFO_REQ, plci_info_req}, + {ST_PLCI_P_ACT, EV_AP_SELECT_B_PROTOCOL_REQ, plci_select_b_protocol_req}, + {ST_PLCI_P_ACT, EV_AP_SUSPEND_REQ, plci_suspend_req}, + {ST_PLCI_P_ACT, EV_PI_SUSPEND_CONF, plci_suspend_conf}, + {ST_PLCI_P_ACT, EV_L3_DISCONNECT_IND, plci_cc_disconnect_ind}, + {ST_PLCI_P_ACT, EV_L3_RELEASE_IND, plci_cc_release_ind}, + {ST_PLCI_P_ACT, EV_L3_NOTIFY_IND, plci_cc_notify_ind}, + {ST_PLCI_P_ACT, EV_L3_SUSPEND_ERR, plci_cc_suspend_err}, + {ST_PLCI_P_ACT, EV_L3_SUSPEND_CONF, plci_cc_suspend_conf}, + {ST_PLCI_P_ACT, EV_PH_CONTROL_IND, plci_cc_ph_control_ind}, + {ST_PLCI_P_ACT, EV_AP_RELEASE, plci_appl_release_disc}, + + {ST_PLCI_P_5, EV_PI_DISCONNECT_IND, plci_disconnect_ind}, + {ST_PLCI_P_5, EV_L3_RELEASE_IND, plci_cc_release_ind}, + + {ST_PLCI_P_6, EV_AP_DISCONNECT_RESP, plci_disconnect_resp}, + {ST_PLCI_P_6, EV_AP_RELEASE, plci_disconnect_resp}, + + {ST_PLCI_P_RES, EV_PI_RESUME_CONF, plci_resume_conf}, + {ST_PLCI_P_RES, EV_PI_DISCONNECT_IND, plci_disconnect_ind}, + {ST_PLCI_P_RES, EV_L3_RESUME_ERR, plci_cc_resume_err}, + {ST_PLCI_P_RES, EV_L3_RESUME_CONF, plci_cc_resume_conf}, + {ST_PLCI_P_RES, EV_AP_RELEASE, plci_appl_release_disc}, +}; + +const int FN_PLCI_COUNT = sizeof(fn_plci_list)/sizeof(struct FsmNode); + +int +AppPlciConstr(AppPlci_t **aplci, Application_t *appl, Plci_t *plci) +{ + AppPlci_t *apl = AppPlci_alloc(); + + if (!apl) + return(-ENOMEM); + memset(apl, 0, sizeof(AppPlci_t)); + INIT_LIST_HEAD(&apl->head); + apl->addr = plci->addr; + apl->appl = appl; + apl->plci = plci; + apl->contr = plci->contr; + apl->plci_m.fsm = &plci_fsm; + apl->plci_m.state = ST_PLCI_P_0; + apl->plci_m.debug = plci->contr->debug & CAPI_DBG_PLCI_STATE; + apl->plci_m.userdata = apl; + apl->plci_m.printdebug = AppPlci_debug; + apl->channel = -1; + *aplci = apl; + return(0); +} + +void AppPlciDestr(AppPlci_t *aplci) +{ + if (aplci->plci) { + AppPlciDebug(aplci, CAPI_DBG_PLCI, "%s plci state %s", __FUNCTION__, + str_st_plci[aplci->plci_m.state]); + if (aplci->plci_m.state != ST_PLCI_P_0) { + struct sk_buff *skb = alloc_l3msg(10, MT_RELEASE_COMPLETE); + unsigned char cause[] = {2,0x80,0x80| CAUSE_RESOURCES_UNAVAIL}; + + if (skb) { + AddIE(skb, IE_CAUSE, cause); + plciL4L3(aplci->plci, CC_RELEASE_COMPLETE | REQUEST, skb); + } + } + plciDetachAppPlci(aplci->plci, aplci); + } + if (aplci->ncci) { + ncciDelAppPlci(aplci->ncci); + aplci->ncci = NULL; + } + if (aplci->appl) + ApplicationDelAppPlci(aplci->appl, aplci); + AppPlci_free(aplci); +} + +void +AppPlciRelease(AppPlci_t *aplci) +{ + if (aplci->ncci) + ncciApplRelease(aplci->ncci); + FsmEvent(&aplci->plci_m, EV_AP_RELEASE, NULL); +} + +void AppPlciDelNCCI(AppPlci_t *aplci) { + aplci->ncci = NULL; +} + +void AppPlci_l3l4(AppPlci_t *aplci, int pr, void *arg) +{ + Q931_info_t *qi = arg; + u_char *ie; + + AppPlciDebug(aplci, CAPI_DBG_PLCI_L3, "%s: aplci(%x) pr(%x) arg(%p)", + __FUNCTION__, aplci->addr, pr, arg); + switch (pr) { + case CC_SETUP | INDICATION: + if (!qi) + return; + AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi); + AppPlciInfoIndIE(aplci, IE_USER_USER, CAPI_INFOMASK_USERUSER, qi); + AppPlciInfoIndIE(aplci, IE_PROGRESS, CAPI_INFOMASK_PROGRESS, qi); + AppPlciInfoIndIE(aplci, IE_FACILITY, CAPI_INFOMASK_FACILITY, qi); + AppPlciInfoIndIE(aplci, IE_CHANNEL_ID, CAPI_INFOMASK_CHANNELID, qi); + if (qi->channel_id) { + ie = (u_char *)qi; + ie += L3_EXTRA_SIZE + qi->channel_id; + aplci->channel = plci_parse_channel_id(ie); + } + FsmEvent(&aplci->plci_m, EV_L3_SETUP_IND, arg); + break; + case CC_TIMEOUT | INDICATION: + FsmEvent(&aplci->plci_m, EV_L3_SETUP_CONF_ERR, arg); + break; + case CC_CONNECT | INDICATION: + if (qi) { + AppPlciInfoIndIE(aplci, IE_DATE, CAPI_INFOMASK_DISPLAY, qi); + AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi); + AppPlciInfoIndIE(aplci, IE_USER_USER, CAPI_INFOMASK_USERUSER, qi); + AppPlciInfoIndIE(aplci, IE_PROGRESS, CAPI_INFOMASK_PROGRESS, qi); + AppPlciInfoIndIE(aplci, IE_FACILITY, CAPI_INFOMASK_FACILITY, qi); + AppPlciInfoIndIE(aplci, IE_CHANNEL_ID, CAPI_INFOMASK_CHANNELID, qi); + if (qi->channel_id) { + ie = (u_char *)qi; + ie += L3_EXTRA_SIZE + qi->channel_id; + aplci->channel = plci_parse_channel_id(ie); + } + } + FsmEvent(&aplci->plci_m, EV_L3_SETUP_CONF, arg); + break; + case CC_CONNECT_ACKNOWLEDGE | INDICATION: + if (qi) { + AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi); + AppPlciInfoIndIE(aplci, IE_CHANNEL_ID, CAPI_INFOMASK_CHANNELID, qi); + if (qi->channel_id) { + ie = (u_char *)qi; + ie += L3_EXTRA_SIZE + qi->channel_id; + aplci->channel = plci_parse_channel_id(ie); + } + } + FsmEvent(&aplci->plci_m, EV_L3_SETUP_COMPL_IND, arg); + break; + case CC_DISCONNECT | INDICATION: + if (qi) { + AppPlciInfoIndMsg(aplci, CAPI_INFOMASK_EARLYB3, MT_DISCONNECT); + AppPlciInfoIndIE(aplci, IE_CAUSE, CAPI_INFOMASK_CAUSE, qi); + AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi); + AppPlciInfoIndIE(aplci, IE_USER_USER, CAPI_INFOMASK_USERUSER, qi); + AppPlciInfoIndIE(aplci, IE_PROGRESS, CAPI_INFOMASK_PROGRESS, qi); + AppPlciInfoIndIE(aplci, IE_FACILITY, CAPI_INFOMASK_FACILITY, qi); + } + FsmEvent(&aplci->plci_m, EV_L3_DISCONNECT_IND, arg); + break; + case CC_RELEASE | INDICATION: + if (qi) { + AppPlciInfoIndIE(aplci, IE_CAUSE, CAPI_INFOMASK_CAUSE, qi); + AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi); + AppPlciInfoIndIE(aplci, IE_USER_USER, CAPI_INFOMASK_USERUSER, qi); + AppPlciInfoIndIE(aplci, IE_FACILITY, CAPI_INFOMASK_FACILITY, qi); + } + FsmEvent(&aplci->plci_m, EV_L3_RELEASE_IND, arg); + break; + case CC_RELEASE_COMPLETE | INDICATION: + if (qi) { + AppPlciInfoIndIE(aplci, IE_CAUSE, CAPI_INFOMASK_CAUSE, qi); + AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi); + AppPlciInfoIndIE(aplci, IE_USER_USER, CAPI_INFOMASK_USERUSER, qi); + AppPlciInfoIndIE(aplci, IE_FACILITY, CAPI_INFOMASK_FACILITY, qi); + } + FsmEvent(&aplci->plci_m, EV_L3_RELEASE_IND, arg); + break; + case CC_RELEASE_CR | INDICATION: + FsmEvent(&aplci->plci_m, EV_L3_RELEASE_PROC_IND, arg); + break; + case CC_SETUP_ACKNOWLEDGE | INDICATION: + if (qi) { + AppPlciInfoIndMsg(aplci, CAPI_INFOMASK_PROGRESS, MT_SETUP_ACKNOWLEDGE); + AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi); + AppPlciInfoIndIE(aplci, IE_PROGRESS, + CAPI_INFOMASK_PROGRESS | CAPI_INFOMASK_EARLYB3, qi); + AppPlciInfoIndIE(aplci, IE_CHANNEL_ID, CAPI_INFOMASK_CHANNELID, qi); + if (qi->channel_id) { + ie = (u_char *)qi; + ie += L3_EXTRA_SIZE + qi->channel_id; + aplci->channel = plci_parse_channel_id(ie); + } + } + break; + case CC_PROCEEDING | INDICATION: + if (qi) { + AppPlciInfoIndMsg(aplci, CAPI_INFOMASK_PROGRESS, MT_CALL_PROCEEDING); + AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi); + AppPlciInfoIndIE(aplci, IE_PROGRESS, + CAPI_INFOMASK_PROGRESS | CAPI_INFOMASK_EARLYB3, qi); + AppPlciInfoIndIE(aplci, IE_CHANNEL_ID, CAPI_INFOMASK_CHANNELID, qi); + if (qi->channel_id) { + ie = (u_char *)qi; + ie += L3_EXTRA_SIZE + qi->channel_id; + aplci->channel = plci_parse_channel_id(ie); + } + } + break; + case CC_ALERTING | INDICATION: + if (qi) { + AppPlciInfoIndMsg(aplci, CAPI_INFOMASK_PROGRESS, MT_ALERTING); + AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi); + AppPlciInfoIndIE(aplci, IE_USER_USER, CAPI_INFOMASK_USERUSER, qi); + AppPlciInfoIndIE(aplci, IE_PROGRESS, + CAPI_INFOMASK_PROGRESS | CAPI_INFOMASK_EARLYB3, qi); + AppPlciInfoIndIE(aplci, IE_FACILITY, CAPI_INFOMASK_FACILITY, qi); + AppPlciInfoIndIE(aplci, IE_CHANNEL_ID, CAPI_INFOMASK_CHANNELID, qi); + if (qi->channel_id) { + ie = (u_char *)qi; + ie += L3_EXTRA_SIZE + qi->channel_id; + aplci->channel = plci_parse_channel_id(ie); + } + } + break; + case CC_PROGRESS | INDICATION: + if (qi) { + AppPlciInfoIndMsg(aplci, CAPI_INFOMASK_PROGRESS, MT_PROGRESS); + AppPlciInfoIndIE(aplci, IE_CAUSE, CAPI_INFOMASK_CAUSE, qi); + AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi); + AppPlciInfoIndIE(aplci, IE_USER_USER, CAPI_INFOMASK_USERUSER, qi); + AppPlciInfoIndIE(aplci, IE_PROGRESS, + CAPI_INFOMASK_PROGRESS | CAPI_INFOMASK_EARLYB3, qi); + } + break; + case CC_SUSPEND_ACKNOWLEDGE | INDICATION: + FsmEvent(&aplci->plci_m, EV_L3_SUSPEND_CONF, arg); + break; + case CC_SUSPEND_REJECT | INDICATION: + FsmEvent(&aplci->plci_m, EV_L3_SUSPEND_ERR, arg); + break; + case CC_RESUME_ACKNOWLEDGE | INDICATION: + FsmEvent(&aplci->plci_m, EV_L3_RESUME_CONF, arg); + break; + case CC_RESUME_REJECT | INDICATION: + FsmEvent(&aplci->plci_m, EV_L3_RESUME_ERR, arg); + break; + case CC_NOTIFY | INDICATION: + FsmEvent(&aplci->plci_m, EV_L3_NOTIFY_IND, arg); + break; + case PH_CONTROL | INDICATION: + /* TOUCH TONE */ + FsmEvent(&aplci->plci_m, EV_PH_CONTROL_IND, arg); + break; + default: + AppPlciDebug(aplci, CAPI_DBG_WARN, + "%s: pr 0x%x not handled", __FUNCTION__, pr); + break; + } +} + +void +AppPlciGetCmsg(AppPlci_t *aplci, _cmsg *cmsg) +{ + int retval = 0; + + switch (CMSGCMD(cmsg)) { + case CAPI_INFO_REQ: + retval = FsmEvent(&aplci->plci_m, EV_AP_INFO_REQ, cmsg); + break; + case CAPI_ALERT_REQ: + retval = FsmEvent(&aplci->plci_m, EV_AP_ALERT_REQ, cmsg); + break; + case CAPI_CONNECT_REQ: + retval = FsmEvent(&aplci->plci_m, EV_AP_CONNECT_REQ, cmsg); + break; + case CAPI_CONNECT_RESP: + retval = FsmEvent(&aplci->plci_m, EV_AP_CONNECT_RESP, cmsg); + break; + case CAPI_DISCONNECT_REQ: + retval = FsmEvent(&aplci->plci_m, EV_AP_DISCONNECT_REQ, cmsg); + break; + case CAPI_DISCONNECT_RESP: + retval = FsmEvent(&aplci->plci_m, EV_AP_DISCONNECT_RESP, cmsg); + break; + case CAPI_CONNECT_ACTIVE_RESP: + retval = FsmEvent(&aplci->plci_m, EV_AP_CONNECT_ACTIVE_RESP, cmsg); + break; + case CAPI_SELECT_B_PROTOCOL_REQ: + retval = FsmEvent(&aplci->plci_m, EV_AP_SELECT_B_PROTOCOL_REQ, cmsg); + break; + default: + int_error(); + retval = -1; + } + if (retval) { + if (cmsg->Command == CAPI_REQ) { + capi_cmsg_answer(cmsg); + cmsg->Info = CapiMessageNotSupportedInCurrentState; + Send2Application(aplci, cmsg); + } else + cmsg_free(cmsg); + } +} + +void +AppPlciSendMessage(AppPlci_t *aplci, struct sk_buff *skb) +{ + _cmsg *cmsg; + + cmsg = cmsg_alloc(); + if (!cmsg) { + int_error(); + dev_kfree_skb(skb); + return; + } + capi_message2cmsg(cmsg, skb->data); + AppPlciGetCmsg(aplci, cmsg); + dev_kfree_skb(skb); +} + +static void +AppPlciLinkUp(AppPlci_t *aplci) +{ + if (aplci->ncci) + return; + if (aplci->channel == -1) {/* no valid channel set */ + int_error(); + return; + } + + aplci->ncci = ncciConstr(aplci); + if (!aplci->ncci) { + int_error(); + return; + } + ncciLinkUp(aplci->ncci); +} + +static void +AppPlciLinkDown(AppPlci_t *aplci) +{ + if (!aplci->ncci) { + return; + } + ncciLinkDown(aplci->ncci); +} + +int +AppPlciFacSuspendReq(AppPlci_t *aplci, FacReqParm_t *facReqParm, FacConfParm_t *facConfParm) +{ + __u8 *CallIdentity; + struct sk_buff *skb; + + CallIdentity = facReqParm->u.Suspend.CallIdentity; + if (CallIdentity && CallIdentity[0] > 8) + return CapiIllMessageParmCoding; + skb = alloc_l3msg(20, MT_SUSPEND); + if (!skb) { + int_error(); + return CapiIllMessageParmCoding; + } + if (CallIdentity && CallIdentity[0]) + AddIE(skb, IE_CALL_ID, CallIdentity); + + if (FsmEvent(&aplci->plci_m, EV_AP_SUSPEND_REQ, skb)) { + // no routine + facConfParm->u.Info.SupplementaryServiceInfo = + CapiRequestNotAllowedInThisState; + kfree(skb); + } else { + facConfParm->u.Info.SupplementaryServiceInfo = CapiSuccess; + } + return CapiSuccess; +} + +int +AppPlciFacResumeReq(AppPlci_t *aplci, FacReqParm_t *facReqParm, FacConfParm_t *facConfParm) +{ + __u8 *CallIdentity; + struct sk_buff *skb; + + CallIdentity = facReqParm->u.Resume.CallIdentity; + if (CallIdentity && CallIdentity[0] > 8) { + AppPlciDestr(aplci); + return CapiIllMessageParmCoding; + } + skb = alloc_l3msg(20, MT_RESUME); + if (!skb) { + int_error(); + AppPlciDestr(aplci); + return CapiIllMessageParmCoding; + } + if (CallIdentity && CallIdentity[0]) + AddIE(skb, IE_CALL_ID, CallIdentity); + if (FsmEvent(&aplci->plci_m, EV_AP_RESUME_REQ, skb)) + kfree(skb); + + facConfParm->u.Info.SupplementaryServiceInfo = CapiSuccess; + return CapiSuccess; +} + +static void +AppPlciClearOtherApps(AppPlci_t *aplci) +{ + AppPlci_t *o_aplci; + _cmsg *cm; + struct list_head *item, *next; + + if (aplci->plci) + return; + if (aplci->plci->nAppl <= 1) + return; + list_for_each_safe(item, next, &aplci->plci->AppPlcis) { + o_aplci = (AppPlci_t *)item; + if (o_aplci != aplci) { + CMSG_ALLOC(cm); + AppPlciCmsgHeader(o_aplci, cm, CAPI_DISCONNECT, CAPI_IND); + cm->Reason = 0x3304; // other application got the call + FsmEvent(&o_aplci->plci_m, EV_PI_DISCONNECT_IND, cm); + } + } +} + +static void +AppPlciInfoIndMsg(AppPlci_t *aplci, __u32 mask, unsigned char mt) +{ + _cmsg *cmsg; + + if ((!aplci->appl) || (!(aplci->appl->InfoMask & mask))) + return; + CMSG_ALLOC(cmsg); + AppPlciCmsgHeader(aplci, cmsg, CAPI_INFO, CAPI_IND); + cmsg->InfoNumber = 0x8000 | mt; + cmsg->InfoElement = 0; + Send2Application(aplci, cmsg); +} + +static void +AppPlciInfoIndIE(AppPlci_t *aplci, unsigned char ie, __u32 mask, Q931_info_t *qi) +{ + _cmsg *cmsg; + u_char *iep = NULL; + u16 *ies; + + + if ((!aplci->appl) || (!(aplci->appl->InfoMask & mask))) + return; + if (!qi) + return; + ies = &qi->bearer_capability; + if (ie & 0x80) { /* single octett */ + int_error(); + return; + } else { + if (l3_ie2pos(ie) < 0) + return; + ies += l3_ie2pos(ie); + if (!*ies) + return; + iep = (u_char *)qi; + iep += L3_EXTRA_SIZE + *ies +1; + } + if (ie == IE_PROGRESS && aplci->appl->InfoMask & CAPI_INFOMASK_EARLYB3) { + if (iep[0] == 0x02 && iep[2] == 0x88) { // in-band information available + AppPlciLinkUp(aplci); + } + } + CMSG_ALLOC(cmsg); + AppPlciCmsgHeader(aplci, cmsg, CAPI_INFO, CAPI_IND); + cmsg->InfoNumber = ie; + cmsg->InfoElement = iep; + Send2Application(aplci, cmsg); +} + +void init_AppPlci(void) +{ + plci_fsm.state_count = ST_PLCI_COUNT; + plci_fsm.event_count = EV_PLCI_COUNT; + plci_fsm.strEvent = str_ev_plci; + plci_fsm.strState = str_st_plci; + + FsmNew(&plci_fsm, fn_plci_list, FN_PLCI_COUNT); +} + + +void free_AppPlci(void) +{ + FsmFree(&plci_fsm); +} diff --git a/drivers/isdn/hardware/mISDN/appl.c b/drivers/isdn/hardware/mISDN/appl.c index 5626461..4f62382 100644 --- a/drivers/isdn/hardware/mISDN/appl.c +++ b/drivers/isdn/hardware/mISDN/appl.c @@ -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); } diff --git a/drivers/isdn/hardware/mISDN/asn1_enc.c b/drivers/isdn/hardware/mISDN/asn1_enc.c index 216f421..8346577 100644 --- a/drivers/isdn/hardware/mISDN/asn1_enc.c +++ b/drivers/isdn/hardware/mISDN/asn1_enc.c @@ -2,7 +2,7 @@ * */ -#include "capi.h" +#include "m_capi.h" #include "helper.h" #include "asn1_enc.h" diff --git a/drivers/isdn/hardware/mISDN/capi.c b/drivers/isdn/hardware/mISDN/capi.c index 3ee46d7..d891d65 100644 --- a/drivers/isdn/hardware/mISDN/capi.c +++ b/drivers/isdn/hardware/mISDN/capi.c @@ -3,7 +3,7 @@ */ #include -#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(); } diff --git a/drivers/isdn/hardware/mISDN/capi.h b/drivers/isdn/hardware/mISDN/capi.h deleted file mode 100644 index eb6bee2..0000000 --- a/drivers/isdn/hardware/mISDN/capi.h +++ /dev/null @@ -1,393 +0,0 @@ -/* $Id$ - * - */ - -#ifndef __mISDN_CAPI_H__ -#define __mISDN_CAPI_H__ - -#include -#include -#include -#include -#include -#ifdef OLDCAPI_DRIVER_INTERFACE -#include "../avmb1/capiutil.h" -#include "../avmb1/capicmd.h" -#include "../avmb1/capilli.h" -#else -#include -#include -#include -#include -#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 diff --git a/drivers/isdn/hardware/mISDN/capi_enc.c b/drivers/isdn/hardware/mISDN/capi_enc.c index 5dd56db..15a9838 100644 --- a/drivers/isdn/hardware/mISDN/capi_enc.c +++ b/drivers/isdn/hardware/mISDN/capi_enc.c @@ -2,7 +2,7 @@ * */ -#include "capi.h" +#include "m_capi.h" #include "asn1.h" int capiEncodeWord(__u8 *p, __u16 i) diff --git a/drivers/isdn/hardware/mISDN/contr.c b/drivers/isdn/hardware/mISDN/contr.c index 0893098..6b2a73b 100644 --- a/drivers/isdn/hardware/mISDN/contr.c +++ b/drivers/isdn/hardware/mISDN/contr.c @@ -4,7 +4,7 @@ #include #include -#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 diff --git a/drivers/isdn/hardware/mISDN/cplci.c b/drivers/isdn/hardware/mISDN/cplci.c deleted file mode 100644 index d5549dd..0000000 --- a/drivers/isdn/hardware/mISDN/cplci.c +++ /dev/null @@ -1,1383 +0,0 @@ -/* $Id$ - * - */ - -#include "capi.h" -#include "helper.h" -#include "debug.h" -#include "dss1.h" - -#define cplciDebug(cplci, lev, fmt, args...) \ - capidebug(lev, fmt, ## args) - -static u_char BEARER_SPEECH_64K_ALAW[] = {4, 3, 0x80, 0x90, 0xA3}; -static u_char BEARER_SPEECH_64K_ULAW[] = {4, 3, 0x80, 0x90, 0xA2}; -static u_char BEARER_UNRES_DIGITAL_64K[] = {4, 2, 0x88, 0x90}; -static u_char BEARER_RES_DIGITAL_64K[] = {4, 2, 0x89, 0x90}; -static u_char BEARER_31AUDIO_64K_ALAW[] = {4, 3, 0x90, 0x90, 0xA3}; -static u_char BEARER_31AUDIO_64K_ULAW[] = {4, 3, 0x90, 0x90, 0xA2}; -static u_char HLC_TELEPHONY[] = {0x7d, 2, 0x91, 0x81}; -static u_char HLC_FACSIMILE[] = {0x7d, 2, 0x91, 0x84}; - -__u16 q931CIPValue(Q931_info_t *qi) -{ - __u16 CIPValue = 0; - u_char *p; - - if (!qi) - return 0; - if (!qi->bearer_capability) - return 0; - p = (u_char *)qi; - p += L3_EXTRA_SIZE + qi->bearer_capability; - if (memcmp(p, BEARER_SPEECH_64K_ALAW, 5) == 0 - || memcmp(p, BEARER_SPEECH_64K_ULAW, 5) == 0) { - CIPValue = 1; - } else if (memcmp(p, BEARER_UNRES_DIGITAL_64K, 4) == 0) { - CIPValue = 2; - } else if (memcmp(p, BEARER_RES_DIGITAL_64K, 4) == 0) { - CIPValue = 3; - } else if (memcmp(p, BEARER_31AUDIO_64K_ALAW, 5) == 0 - || memcmp(p, BEARER_31AUDIO_64K_ULAW, 5) == 0) { - CIPValue = 4; - } else { - CIPValue = 0; - } - - if (!qi->hlc) - return CIPValue; - - p = (u_char *)qi; - p += L3_EXTRA_SIZE + qi->hlc; - if ((CIPValue == 1) || (CIPValue == 4)) { - if (memcmp(p, HLC_TELEPHONY, 4) == 0) { - CIPValue = 16; - } else if (memcmp(p, HLC_FACSIMILE, 4) == 0) { - CIPValue = 17; - } - } - return CIPValue; -} - -u_int plci_parse_channel_id(u_char *p) -{ - u_int cid = -1; - int l; - - if (p) { - p++; - capidebug(CAPI_DBG_PLCI_INFO, "%s: l(%d) %x", __FUNCTION__, p[0], p[1]); - l = *p++; - if (l == 1) { - cid = *p; - } else if (l == 3) { - cid = *p++ << 16; - cid |= *p++ << 8; - cid |= *p; - } - } - return(cid); -} - -__u16 CIPValue2setup(__u16 CIPValue, struct sk_buff *skb) -{ - switch (CIPValue) { - case 16: - AddvarIE(skb, BEARER_31AUDIO_64K_ALAW); - AddvarIE(skb, HLC_TELEPHONY); - break; - case 17: - AddvarIE(skb, BEARER_31AUDIO_64K_ALAW); - AddvarIE(skb, HLC_FACSIMILE); - break; - case 1: - AddvarIE(skb, BEARER_SPEECH_64K_ALAW); - break; - case 2: - AddvarIE(skb, BEARER_UNRES_DIGITAL_64K); - break; - case 3: - AddvarIE(skb, BEARER_RES_DIGITAL_64K); - break; - case 4: - AddvarIE(skb, BEARER_31AUDIO_64K_ALAW); - break; - default: - return CapiIllMessageParmCoding; - } - return 0; -} - -__u16 cmsg2setup_req(_cmsg *cmsg, struct sk_buff *skb) -{ - if (CIPValue2setup(cmsg->CIPValue, skb)) - goto err; - AddIE(skb, IE_CALLING_PN, cmsg->CallingPartyNumber); - AddIE(skb, IE_CALLING_SUB, cmsg->CallingPartySubaddress); - AddIE(skb, IE_CALLED_PN, cmsg->CalledPartyNumber); - AddIE(skb, IE_CALLED_SUB, cmsg->CalledPartySubaddress); - AddIE(skb, IE_BEARER, cmsg->BC); - AddIE(skb, IE_LLC, cmsg->LLC); - AddIE(skb, IE_HLC, cmsg->HLC); - return 0; - err: - return CapiIllMessageParmCoding; -} - -__u16 cmsg2info_req(_cmsg *cmsg, struct sk_buff *skb) -{ - AddIE(skb, IE_KEYPAD, cmsg->Keypadfacility); - AddIE(skb, IE_CALLED_PN, cmsg->CalledPartyNumber); - return 0; -} - -__u16 cmsg2alerting_req(_cmsg *cmsg, struct sk_buff *skb) -{ - AddIE(skb, IE_USER_USER, cmsg->Useruserdata); - return 0; -} - -__u16 cplciCheckBprotocol(Cplci_t *cplci, _cmsg *cmsg) -{ - struct capi_ctr *ctrl = cplci->contr->ctrl; - u_long sprot; - - sprot = ctrl->profile.support1; - if (!test_bit(cmsg->B1protocol, &sprot)) - return CapiB1ProtocolNotSupported; - sprot = ctrl->profile.support2; - if (!test_bit(cmsg->B2protocol, &sprot)) - return CapiB2ProtocolNotSupported; - sprot = ctrl->profile.support3; - if (!test_bit(cmsg->B3protocol, &sprot)) - return CapiB3ProtocolNotSupported; - - cplci->Bprotocol.B1protocol = cmsg->B1protocol; - cplci->Bprotocol.B2protocol = cmsg->B2protocol; - cplci->Bprotocol.B3protocol = cmsg->B3protocol; - return 0; -} - -// =============================================================== plci === - -// -------------------------------------------------------------------- -// PLCI state machine - -enum { - ST_PLCI_P_0, - ST_PLCI_P_0_1, - ST_PLCI_P_1, - ST_PLCI_P_2, - ST_PLCI_P_3, - ST_PLCI_P_4, - ST_PLCI_P_ACT, - ST_PLCI_P_5, - ST_PLCI_P_6, - ST_PLCI_P_RES, -} - -const ST_PLCI_COUNT = ST_PLCI_P_RES + 1; - -static char *str_st_plci[] = { - "ST_PLCI_P_0", - "ST_PLCI_P_0_1", - "ST_PLCI_P_1", - "ST_PLCI_P_2", - "ST_PLCI_P_3", - "ST_PLCI_P_4", - "ST_PLCI_P_ACT", - "ST_PLCI_P_5", - "ST_PLCI_P_6", - "ST_PLCI_P_RES", -}; - -enum { - EV_PLCI_CONNECT_REQ, - EV_PLCI_CONNECT_CONF, - EV_PLCI_CONNECT_IND, - EV_PLCI_CONNECT_RESP, - EV_PLCI_CONNECT_ACTIVE_IND, - EV_PLCI_CONNECT_ACTIVE_RESP, - EV_PLCI_ALERT_REQ, - EV_PLCI_INFO_REQ, - EV_PLCI_INFO_IND, - EV_PLCI_FACILITY_IND, - EV_PLCI_SELECT_B_PROTOCOL_REQ, - EV_PLCI_DISCONNECT_REQ, - EV_PLCI_DISCONNECT_IND, - EV_PLCI_DISCONNECT_RESP, - EV_PLCI_SUSPEND_REQ, - EV_PLCI_SUSPEND_CONF, - EV_PLCI_RESUME_REQ, - EV_PLCI_RESUME_CONF, - EV_PLCI_CHANNEL_ERR, - EV_PLCI_CC_SETUP_IND, - EV_PLCI_CC_SETUP_CONF_ERR, - EV_PLCI_CC_SETUP_CONF, - EV_PLCI_CC_SETUP_COMPL_IND, - EV_PLCI_CC_DISCONNECT_IND, - EV_PLCI_CC_RELEASE_IND, - EV_PLCI_CC_RELEASE_PROC_IND, - EV_PLCI_CC_NOTIFY_IND, - EV_PLCI_CC_SUSPEND_ERR, - EV_PLCI_CC_SUSPEND_CONF, - EV_PLCI_CC_RESUME_ERR, - EV_PLCI_CC_RESUME_CONF, - EV_PLCI_CC_REJECT_IND, - EV_PLCI_CC_PH_CONTROL_IND, -} - -const EV_PLCI_COUNT = EV_PLCI_CC_PH_CONTROL_IND + 1; - -static char* str_ev_plci[] = { - "EV_PLCI_CONNECT_REQ", - "EV_PLCI_CONNECT_CONF", - "EV_PLCI_CONNECT_IND", - "EV_PLCI_CONNECT_RESP", - "EV_PLCI_CONNECT_ACTIVE_IND", - "EV_PLCI_CONNECT_ACTIVE_RESP", - "EV_PLCI_ALERT_REQ", - "EV_PLCI_INFO_REQ", - "EV_PLCI_INFO_IND", - "EV_PLCI_FACILITY_IND", - "EV_PLCI_SELECT_B_PROTOCOL_REQ", - "EV_PLCI_DISCONNECT_REQ", - "EV_PLCI_DISCONNECT_IND", - "EV_PLCI_DISCONNECT_RESP", - "EV_PLCI_SUSPEND_REQ", - "EV_PLCI_SUSPEND_CONF", - "EV_PLCI_RESUME_REQ", - "EV_PLCI_RESUME_CONF", - "EV_PLCI_CHANNEL_ERR", - "EV_PLCI_CC_SETUP_IND", - "EV_PLCI_CC_SETUP_CONF_ERR", - "EV_PLCI_CC_SETUP_CONF", - "EV_PLCI_CC_SETUP_COMPL_IND", - "EV_PLCI_CC_DISCONNECT_IND", - "EV_PLCI_CC_RELEASE_IND", - "EV_PLCI_CC_RELEASE_PROC_IND", - "EV_PLCI_CC_NOTIFY_IND", - "EV_PLCI_CC_SUSPEND_ERR", - "EV_PLCI_CC_SUSPEND_CONF", - "EV_PLCI_CC_RESUME_ERR", - "EV_PLCI_CC_RESUME_CONF", - "EV_PLCI_CC_REJECT_IND", - "EV_PLCI_CC_PH_CONTROL_IND", -}; - -static struct Fsm plci_fsm = -{ 0, 0, 0, 0, 0 }; - -static void cplci_debug(struct FsmInst *fi, char *fmt, ...) -{ - char tmp[128]; - char *p = tmp; - va_list args; - Cplci_t *cplci = fi->userdata; - - va_start(args, fmt); - p += sprintf(p, "PLCI 0x%x: ", cplci->adrPLCI); - p += vsprintf(p, fmt, args); - *p = 0; - cplciDebug(cplci, CAPI_DBG_PLCI_STATE, tmp); - va_end(args); -} - -inline void cplciRecvCmsg(Cplci_t *cplci, _cmsg *cmsg) -{ - contrRecvCmsg(cplci->contr, cmsg); -} - -inline void cplciCmsgHeader(Cplci_t *cplci, _cmsg *cmsg, __u8 cmd, __u8 subcmd) -{ - capi_cmsg_header(cmsg, cplci->appl->ApplId, cmd, subcmd, - cplci->appl->MsgId++, cplci->adrPLCI); -} - -static void plci_connect_req(struct FsmInst *fi, int event, void *arg) -{ - Cplci_t *cplci = fi->userdata; - Plci_t *plci = cplci->plci; - struct sk_buff *skb; - _cmsg *cmsg = arg; - __u16 Info = 0; - - FsmChangeState(fi, ST_PLCI_P_0_1); - test_and_set_bit(PLCI_FLAG_OUTGOING, &plci->flags); - - skb = alloc_l3msg(260, MT_SETUP); - - if (!skb) { - Info = CapiNoPlciAvailable; - goto answer; - } - if ((Info = cmsg2setup_req(cmsg, skb))) { - goto answer; - } - if ((Info = cplciCheckBprotocol(cplci, cmsg))) { - goto answer; - } - - plciNewCrReq(plci); - plciL4L3(plci, CC_SETUP | REQUEST, skb); -answer: - capi_cmsg_answer(cmsg); - cmsg->Info = Info; - if (cmsg->Info == 0) - cmsg->adr.adrPLCI = cplci->adrPLCI; - cplciRecvCmsg(cplci, cmsg); - FsmEvent(fi, EV_PLCI_CONNECT_CONF, cmsg); -} - -static void plci_connect_conf(struct FsmInst *fi, int event, void *arg) -{ - Cplci_t *cplci = fi->userdata; - _cmsg *cmsg = arg; - - if (cmsg->Info == 0) { - FsmChangeState(fi, ST_PLCI_P_1); - } else { - FsmChangeState(fi, ST_PLCI_P_0); - applDelCplci(cplci->appl, cplci); - } -} - -static void plci_connect_ind(struct FsmInst *fi, int event, void *arg) -{ - FsmChangeState(fi, ST_PLCI_P_2); -} - -static void plci_suspend_req(struct FsmInst *fi, int event, void *arg) -{ - Cplci_t *cplci = fi->userdata; - Plci_t *plci = cplci->plci; - - plciL4L3(plci, CC_SUSPEND | REQUEST, arg); -} - -static void plci_resume_req(struct FsmInst *fi, int event, void *arg) -{ - Cplci_t *cplci = fi->userdata; - Plci_t *plci = cplci->plci; - - // we already sent CONF with Info = SuppInfo = 0 - FsmChangeState(fi, ST_PLCI_P_RES); - plciNewCrReq(plci); - plciL4L3(plci, CC_RESUME | REQUEST, arg); -} - -static void plci_alert_req(struct FsmInst *fi, int event, void *arg) -{ - Cplci_t *cplci = fi->userdata; - Plci_t *plci = cplci->plci; - _cmsg *cmsg = arg; - __u16 Info = 0; - - if (test_and_set_bit(PLCI_FLAG_ALERTING, &plci->flags)) { - Info = 0x0003; // other app is already alerting - } else { - struct sk_buff *skb = alloc_l3msg(10, MT_ALERTING); - if (!skb) { - int_error(); - goto answer; - } - Info = cmsg2alerting_req(cmsg, skb); - if (Info == 0) { - plciL4L3(plci, CC_ALERTING | REQUEST, skb); - } - } -answer: - capi_cmsg_answer(cmsg); - cmsg->Info = Info; - cplciRecvCmsg(cplci, cmsg); -} - -static void plci_connect_resp(struct FsmInst *fi, int event, void *arg) -{ - Cplci_t *cplci = fi->userdata; - Plci_t *plci = cplci->plci; - unsigned char cause[4]; - _cmsg *cmsg = arg; - struct sk_buff *skb; - - switch (cmsg->Reject) { - case 0 : // accept - if (cplciCheckBprotocol(cplci, cmsg)) { - int_error(); - } - cplciClearOtherApps(cplci); - plciL4L3(plci, CC_CONNECT | REQUEST, NULL); - FsmChangeState(fi, ST_PLCI_P_4); - break; - default : // ignore, reject - memcpy(cause, "\x02\x80", 2); // IE CAUSE, location = local - switch (cmsg->Reject) { - case 2: cause[2] = 0x90; break; // normal call clearing - case 3: cause[2] = 0x91; break; // user busy - case 4: cause[2] = 0xac; break; // req circuit/channel not avail - case 5: cause[2] = 0x9d; break; // fac rejected - case 6: cause[2] = 0x86; break; // channel unacceptable - case 7: cause[2] = 0xd8; break; // incompatible dest - case 8: cause[2] = 0x9b; break; // dest out of order - default: - if ((cmsg->Reject & 0xff00) == 0x3400) { - cause[2] = cmsg->Reject & 0xff; - } else { - cause[2] = 0x90; break; // normal call clearing - } - } - if (cmsg->Reject != 1) { // ignore - cplciClearOtherApps(cplci); - } - plciDetachCplci(plci, cplci); - if (plci->nAppl == 0) { - if (test_bit(PLCI_FLAG_ALERTING, &plci->flags)) { - // if we already answered, we can't just ignore but must clear actively - skb = alloc_l3msg(10, MT_DISCONNECT); - if (!skb) { - plciL4L3(plci, CC_DISCONNECT | REQUEST, NULL); - } else { - AddIE(skb, IE_CAUSE, cause); - plciL4L3(plci, CC_DISCONNECT | REQUEST, skb); - } - } else { - plciL4L3(plci, CC_RELEASE_COMPLETE | REQUEST, NULL); - } - } - - capi_cmsg_answer(cmsg); - cmsg->Command = CAPI_DISCONNECT; - cmsg->Subcommand = CAPI_IND; - cmsg->Messagenumber = cplci->appl->MsgId++; - FsmEvent(&cplci->plci_m, EV_PLCI_DISCONNECT_IND, cmsg); - cplciRecvCmsg(cplci, cmsg); - } -} - -static void plci_connect_active_ind(struct FsmInst *fi, int event, void *arg) -{ - Cplci_t *cplci = fi->userdata; - - FsmChangeState(fi, ST_PLCI_P_ACT); - cplciLinkUp(cplci); -} - -static void plci_connect_active_resp(struct FsmInst *fi, int event, void *arg) -{ -} - -static void plci_disconnect_req(struct FsmInst *fi, int event, void *arg) -{ - Cplci_t *cplci = fi->userdata; - Plci_t *plci = cplci->plci; - u_char cause[4]; - _cmsg *cmsg = arg; - - FsmChangeState(fi, ST_PLCI_P_5); - - if (!plci) { - int_error(); - return; - } - capi_cmsg_answer(cmsg); - cmsg->Reason = 0; // disconnect initiated - cplciRecvCmsg(cplci, cmsg); - - cplciLinkDown(cplci); - - if (!cplci->cause[0]) { // FIXME - struct sk_buff *skb; - -// plciL4L3(cplci->plci, CC_STATUS_ENQUIRY | REQUEST, NULL); - skb = alloc_l3msg(10, MT_DISCONNECT); - if (!skb) { - plciL4L3(plci, CC_DISCONNECT | REQUEST, NULL); - } else { - memcpy(cause, "\x02\x80\x90", 3); // normal call clearing - AddIE(skb, IE_CAUSE, cause); - plciL4L3(plci, CC_DISCONNECT | REQUEST, skb); - } - } else { - /* release physical link */ - // FIXME - plciL4L3(plci, CC_RELEASE | REQUEST, NULL); - } -// plciL4L3(cplci->plci, CC_STATUS_ENQUIRY | REQUEST, NULL); -} - -static void plci_suspend_conf(struct FsmInst *fi, int event, void *arg) -{ - FsmChangeState(fi, ST_PLCI_P_5); -} - -static void plci_resume_conf(struct FsmInst *fi, int event, void *arg) -{ - // facility_ind Resume: Reason = 0 - Cplci_t *cplci = fi->userdata; - - FsmChangeState(fi, ST_PLCI_P_ACT); - cplciLinkUp(cplci); -} - -static void plci_disconnect_ind(struct FsmInst *fi, int event, void *arg) -{ - FsmChangeState(fi, ST_PLCI_P_6); -} - -static void plci_disconnect_resp(struct FsmInst *fi, int event, void *arg) -{ - Cplci_t *cplci = fi->userdata; - - FsmChangeState(fi, ST_PLCI_P_0); - applDelCplci(cplci->appl, cplci); -} - -static void plci_cc_setup_conf(struct FsmInst *fi, int event, void *arg) -{ - Cplci_t *cplci = fi->userdata; - _cmsg cmsg; - Q931_info_t *qi = arg; - u_char *p; - - if (cplci->bchannel == -1) {/* no valid channel set */ - FsmEvent(fi, EV_PLCI_CHANNEL_ERR, NULL); - return; - } - cplciCmsgHeader(cplci, &cmsg, CAPI_CONNECT_ACTIVE, CAPI_IND); - if (qi) { - p = (u_char *)qi; - p += L3_EXTRA_SIZE; - if (qi->connected_nr) - cmsg.ConnectedNumber = &p[qi->connected_nr + 1]; - if (qi->connected_sub) - cmsg.ConnectedSubaddress = &p[qi->connected_sub + 1]; - if (qi->llc) - cmsg.LLC = &p[qi->llc + 1]; - } - FsmEvent(fi, EV_PLCI_CONNECT_ACTIVE_IND, &cmsg); - cplciRecvCmsg(cplci, &cmsg); -} - -static void plci_cc_setup_conf_err(struct FsmInst *fi, int event, void *arg) -{ - Cplci_t *cplci = fi->userdata; - _cmsg cmsg; - - cplciCmsgHeader(cplci, &cmsg, CAPI_DISCONNECT, CAPI_IND); - cmsg.Reason = CapiProtocolErrorLayer3; - FsmEvent(&cplci->plci_m, EV_PLCI_DISCONNECT_IND, &cmsg); - cplciRecvCmsg(cplci, &cmsg); -} - -static void plci_channel_err(struct FsmInst *fi, int event, void *arg) -{ - Cplci_t *cplci = fi->userdata; - Plci_t *plci = cplci->plci; - _cmsg cmsg; - unsigned char cause[4]; - struct sk_buff *skb; - - if (!plci) { - int_error(); - return; - } - skb = alloc_l3msg(10, MT_RELEASE_COMPLETE); - if (skb) { - cause[0] = 2; - cause[1] = 0x80; - cause[2] = 0x86; /* channel unacceptable */ - AddIE(skb, IE_CAUSE, cause); - plciL4L3(plci, CC_RELEASE_COMPLETE | REQUEST, skb); - } else - int_error(); - cplciCmsgHeader(cplci, &cmsg, CAPI_DISCONNECT, CAPI_IND); - cmsg.Reason = CapiProtocolErrorLayer3; - FsmEvent(&cplci->plci_m, EV_PLCI_DISCONNECT_IND, &cmsg); - cplciRecvCmsg(cplci, &cmsg); -} - -static void plci_cc_setup_ind(struct FsmInst *fi, int event, void *arg) -{ - Cplci_t *cplci = fi->userdata; - Q931_info_t *qi = arg; - _cmsg cmsg; - u_char *p; - - cplciCmsgHeader(cplci, &cmsg, CAPI_CONNECT, CAPI_IND); - - // FIXME: CW - if (qi) { - p = (u_char *)qi; - p += L3_EXTRA_SIZE; - cmsg.CIPValue = q931CIPValue(qi); - if (qi->called_nr) - cmsg.CalledPartyNumber = &p[qi->called_nr + 1]; - if (qi->called_sub) - cmsg.CalledPartySubaddress = &p[qi->called_sub + 1]; - if (qi->calling_nr) - cmsg.CallingPartyNumber = &p[qi->calling_nr + 1]; - if (qi->calling_sub) - cmsg.CallingPartySubaddress = &p[qi->calling_sub + 1]; - if (qi->bearer_capability) - cmsg.BC = &p[qi->bearer_capability + 1]; - if (qi->llc) - cmsg.LLC = &p[qi->llc + 1]; - if (qi->hlc) - cmsg.HLC = &p[qi->hlc + 1]; - // all else set to default - } - FsmEvent(&cplci->plci_m, EV_PLCI_CONNECT_IND, &cmsg); - cplciRecvCmsg(cplci, &cmsg); -} - -static void plci_cc_setup_compl_ind(struct FsmInst *fi, int event, void *arg) -{ - Cplci_t *cplci = fi->userdata; - _cmsg cmsg; - - cplciCmsgHeader(cplci, &cmsg, CAPI_CONNECT_ACTIVE, CAPI_IND); - FsmEvent(&cplci->plci_m, EV_PLCI_CONNECT_ACTIVE_IND, &cmsg); - cplciRecvCmsg(cplci, &cmsg); -} - -static void plci_cc_disconnect_ind(struct FsmInst *fi, int event, void *arg) -{ - Cplci_t *cplci = fi->userdata; - Q931_info_t *qi = arg; - u_char *p; - - if (qi) { - p = (u_char *)qi; - p += L3_EXTRA_SIZE; - if (qi->cause) - memcpy(cplci->cause, &p[qi->cause + 1], 3); - } - if (!(cplci->appl->listen.InfoMask & CAPI_INFOMASK_EARLYB3)) { - cplciLinkDown(cplci); - plciL4L3(cplci->plci, CC_RELEASE | REQUEST, NULL); - } -} - -static void plci_cc_release_ind(struct FsmInst *fi, int event, void *arg) -{ - Cplci_t *cplci = fi->userdata; - Q931_info_t *qi = arg; - u_char *p; - _cmsg cmsg; - - plciDetachCplci(cplci->plci, cplci); - - cplciLinkDown(cplci); - cplciCmsgHeader(cplci, &cmsg, CAPI_DISCONNECT, CAPI_IND); - if (qi) { - p = (u_char *)qi; - p += L3_EXTRA_SIZE; - if (qi->cause) - cmsg.Reason = 0x3400 | p[qi->cause + 3]; - else if (cplci->cause[0]) // cause from CC_DISCONNECT IND - cmsg.Reason = 0x3400 | cplci->cause[2]; - else - cmsg.Reason = 0; - } else { - cmsg.Reason = CapiProtocolErrorLayer1; - } - FsmEvent(&cplci->plci_m, EV_PLCI_DISCONNECT_IND, &cmsg); - cplciRecvCmsg(cplci, &cmsg); -} - -static void plci_cc_notify_ind(struct FsmInst *fi, int event, void *arg) -{ - Cplci_t *cplci = fi->userdata; - Q931_info_t *qi = arg; - _cmsg cmsg; - __u8 tmp[10], *p, *nf; - - if (!qi || !qi->notify) - return; - nf = (u_char *)qi; - nf += L3_EXTRA_SIZE + qi->notify + 1; - if (nf[0] != 1) // len != 1 - return; - - switch (nf[1]) { - case 0x80: // user suspended - case 0x81: // user resumed - if (!(cplci->appl->NotificationMask & SuppServiceTP)) - break; - cplciCmsgHeader(cplci, &cmsg, CAPI_FACILITY, CAPI_IND); - p = &tmp[1]; - p += capiEncodeWord(p, 0x8002 + (nf[1] & 1)); // Suspend/Resume Notification - *p++ = 0; // empty struct - tmp[0] = p - &tmp[1]; - cmsg.FacilitySelector = 0x0003; - cmsg.FacilityIndicationParameter = tmp; - cplciRecvCmsg(cplci, &cmsg); - break; - } -} - -static void plci_suspend_reply(Cplci_t *cplci, __u16 SuppServiceReason) -{ - _cmsg cmsg; - __u8 tmp[10], *p; - - cplciCmsgHeader(cplci, &cmsg, CAPI_FACILITY, CAPI_IND); - p = &tmp[1]; - p += capiEncodeWord(p, 0x0004); // Suspend - p += capiEncodeFacIndSuspend(p, SuppServiceReason); - tmp[0] = p - &tmp[1]; - cmsg.FacilitySelector = 0x0003; - cmsg.FacilityIndicationParameter = tmp; - cplciRecvCmsg(cplci, &cmsg); - - if (SuppServiceReason == CapiSuccess) - FsmEvent(&cplci->plci_m, EV_PLCI_SUSPEND_CONF, &cmsg); -} - -static void plci_cc_suspend_err(struct FsmInst *fi, int event, void *arg) -{ - Cplci_t *cplci = fi->userdata; - Q931_info_t *qi = arg; - u_char *p; - __u16 SuppServiceReason; - - if (qi) { // reject from network - if (qi->cause) { - p = (u_char *)qi; - p += L3_EXTRA_SIZE + qi->cause; - SuppServiceReason = 0x3400 | p[3]; - } else - SuppServiceReason = CapiProtocolErrorLayer3; - } else { // timeout - SuppServiceReason = CapiTimeOut; - } - plci_suspend_reply(cplci, SuppServiceReason); -} - -static void plci_cc_suspend_conf(struct FsmInst *fi, int event, void *arg) -{ - Cplci_t *cplci = fi->userdata; - _cmsg cmsg; - - cplciLinkDown(cplci); - - plci_suspend_reply(cplci, CapiSuccess); - - plciDetachCplci(cplci->plci, cplci); - cplciCmsgHeader(cplci, &cmsg, CAPI_DISCONNECT, CAPI_IND); - FsmEvent(&cplci->plci_m, EV_PLCI_DISCONNECT_IND, &cmsg); - cplciRecvCmsg(cplci, &cmsg); -} - -static void plci_cc_resume_err(struct FsmInst *fi, int event, void *arg) -{ - Cplci_t *cplci = fi->userdata; - Q931_info_t *qi = arg; - u_char *p; - _cmsg cmsg; - - cplciCmsgHeader(cplci, &cmsg, CAPI_DISCONNECT, CAPI_IND); - if (qi) { // reject from network - plciDetachCplci(cplci->plci, cplci); - if (qi->cause) { - p = (u_char *)qi; - p += L3_EXTRA_SIZE + qi->cause; - cmsg.Reason = 0x3400 | p[3]; - } else - cmsg.Reason = 0; - } else { // timeout - cmsg.Reason = CapiProtocolErrorLayer1; - } - FsmEvent(&cplci->plci_m, EV_PLCI_DISCONNECT_IND, &cmsg); - cplciRecvCmsg(cplci, &cmsg); -} - -static void plci_cc_resume_conf(struct FsmInst *fi, int event, void *arg) -{ - Cplci_t *cplci = fi->userdata; - Q931_info_t *qi = arg; - _cmsg cmsg; - __u8 tmp[10], *p; - - if (!qi || !qi->channel_id) { - int_error(); - return; - } - p = (u_char *)qi; - p += L3_EXTRA_SIZE + qi->channel_id; - cplci->bchannel = plci_parse_channel_id(p); - cplciCmsgHeader(cplci, &cmsg, CAPI_FACILITY, CAPI_IND); - p = &tmp[1]; - p += capiEncodeWord(p, 0x0005); // Suspend - p += capiEncodeFacIndSuspend(p, CapiSuccess); - tmp[0] = p - &tmp[1]; - cmsg.FacilitySelector = 0x0003; - cmsg.FacilityIndicationParameter = tmp; - contrRecvCmsg(cplci->contr, &cmsg); - - FsmEvent(&cplci->plci_m, EV_PLCI_RESUME_CONF, &cmsg); -} - -static void plci_select_b_protocol_req(struct FsmInst *fi, int event, void *arg) -{ - Cplci_t *cplci = fi->userdata; - Ncci_t *ncci = cplci->ncci; - _cmsg *cmsg = arg; - __u16 Info; - - Info = cplciCheckBprotocol(cplci, cmsg); - - if (!ncci) { - int_error(); - return; - } - - Info = ncciSelectBprotocol(ncci); - - capi_cmsg_answer(cmsg); - cmsg->Info = Info; - cplciRecvCmsg(cplci, cmsg); -} - -static void plci_info_req_overlap(struct FsmInst *fi, int event, void *arg) -{ - Cplci_t *cplci = fi->userdata; - Plci_t *plci = cplci->plci; - _cmsg *cmsg = arg; - __u16 Info = 0; - struct sk_buff *skb; - - skb = alloc_l3msg(100, MT_INFORMATION); - if (skb) { - Info = cmsg2info_req(cmsg, skb); - if (Info == CapiSuccess) - plciL4L3(plci, CC_INFORMATION | REQUEST, skb); - else - kfree_skb(skb); - } - - capi_cmsg_answer(cmsg); - cmsg->Info = Info; - cplciRecvCmsg(cplci, cmsg); -} - -static void plci_cc_ph_control_ind(struct FsmInst *fi, int event, void *arg) -{ - Cplci_t *cplci = fi->userdata; - int *tt = arg; - _cmsg cmsg; - __u8 tmp[2]; - - if (!arg) - return; - - cplciDebug(cplci, CAPI_DBG_PLCI_INFO, "%s: tt(%x)", __FUNCTION__, *tt); - if ((*tt & ~DTMF_TONE_MASK) != DTMF_TONE_VAL) - return; - - cplciCmsgHeader(cplci, &cmsg, CAPI_FACILITY, CAPI_IND); - tmp[0] = 1; - tmp[1] = *tt & DTMF_TONE_MASK; - cmsg.FacilitySelector = 0x0001; - cmsg.FacilityIndicationParameter = tmp; - cplciRecvCmsg(cplci, &cmsg); -} - -static void plci_info_req(struct FsmInst *fi, int event, void *arg) -{ -} - -static struct FsmNode fn_plci_list[] = -{ - {ST_PLCI_P_0, EV_PLCI_CONNECT_REQ, plci_connect_req}, - {ST_PLCI_P_0, EV_PLCI_CONNECT_IND, plci_connect_ind}, - {ST_PLCI_P_0, EV_PLCI_RESUME_REQ, plci_resume_req}, - {ST_PLCI_P_0, EV_PLCI_CC_SETUP_IND, plci_cc_setup_ind}, - - {ST_PLCI_P_0_1, EV_PLCI_CONNECT_CONF, plci_connect_conf}, - - {ST_PLCI_P_1, EV_PLCI_CONNECT_ACTIVE_IND, plci_connect_active_ind}, - {ST_PLCI_P_1, EV_PLCI_DISCONNECT_REQ, plci_disconnect_req}, - {ST_PLCI_P_1, EV_PLCI_DISCONNECT_IND, plci_disconnect_ind}, - {ST_PLCI_P_1, EV_PLCI_INFO_REQ, plci_info_req_overlap}, - {ST_PLCI_P_1, EV_PLCI_CC_SETUP_CONF, plci_cc_setup_conf}, - {ST_PLCI_P_1, EV_PLCI_CC_SETUP_CONF_ERR, plci_cc_setup_conf_err}, - {ST_PLCI_P_1, EV_PLCI_CC_DISCONNECT_IND, plci_cc_disconnect_ind}, - {ST_PLCI_P_1, EV_PLCI_CC_RELEASE_PROC_IND, plci_cc_setup_conf_err}, - {ST_PLCI_P_1, EV_PLCI_CC_RELEASE_IND, plci_cc_release_ind}, - {ST_PLCI_P_1, EV_PLCI_CC_REJECT_IND, plci_cc_release_ind}, - {ST_PLCI_P_1, EV_PLCI_CHANNEL_ERR, plci_channel_err}, - - {ST_PLCI_P_2, EV_PLCI_ALERT_REQ, plci_alert_req}, - {ST_PLCI_P_2, EV_PLCI_CONNECT_RESP, plci_connect_resp}, - {ST_PLCI_P_2, EV_PLCI_DISCONNECT_REQ, plci_disconnect_req}, - {ST_PLCI_P_2, EV_PLCI_DISCONNECT_IND, plci_disconnect_ind}, - {ST_PLCI_P_2, EV_PLCI_INFO_REQ, plci_info_req}, - {ST_PLCI_P_2, EV_PLCI_CC_RELEASE_IND, plci_cc_release_ind}, - - {ST_PLCI_P_4, EV_PLCI_CONNECT_ACTIVE_IND, plci_connect_active_ind}, - {ST_PLCI_P_4, EV_PLCI_DISCONNECT_REQ, plci_disconnect_req}, - {ST_PLCI_P_4, EV_PLCI_DISCONNECT_IND, plci_disconnect_ind}, - {ST_PLCI_P_4, EV_PLCI_INFO_REQ, plci_info_req}, - {ST_PLCI_P_4, EV_PLCI_CC_SETUP_COMPL_IND, plci_cc_setup_compl_ind}, - {ST_PLCI_P_4, EV_PLCI_CC_RELEASE_IND, plci_cc_release_ind}, - {ST_PLCI_P_4, EV_PLCI_CHANNEL_ERR, plci_channel_err}, - - {ST_PLCI_P_ACT, EV_PLCI_CONNECT_ACTIVE_RESP, plci_connect_active_resp}, - {ST_PLCI_P_ACT, EV_PLCI_DISCONNECT_REQ, plci_disconnect_req}, - {ST_PLCI_P_ACT, EV_PLCI_DISCONNECT_IND, plci_disconnect_ind}, - {ST_PLCI_P_ACT, EV_PLCI_INFO_REQ, plci_info_req}, - {ST_PLCI_P_ACT, EV_PLCI_SELECT_B_PROTOCOL_REQ, plci_select_b_protocol_req}, - {ST_PLCI_P_ACT, EV_PLCI_SUSPEND_REQ, plci_suspend_req}, - {ST_PLCI_P_ACT, EV_PLCI_SUSPEND_CONF, plci_suspend_conf}, - {ST_PLCI_P_ACT, EV_PLCI_CC_DISCONNECT_IND, plci_cc_disconnect_ind}, - {ST_PLCI_P_ACT, EV_PLCI_CC_RELEASE_IND, plci_cc_release_ind}, - {ST_PLCI_P_ACT, EV_PLCI_CC_NOTIFY_IND, plci_cc_notify_ind}, - {ST_PLCI_P_ACT, EV_PLCI_CC_SUSPEND_ERR, plci_cc_suspend_err}, - {ST_PLCI_P_ACT, EV_PLCI_CC_SUSPEND_CONF, plci_cc_suspend_conf}, - {ST_PLCI_P_ACT, EV_PLCI_CC_PH_CONTROL_IND, plci_cc_ph_control_ind}, - - {ST_PLCI_P_5, EV_PLCI_DISCONNECT_IND, plci_disconnect_ind}, - {ST_PLCI_P_5, EV_PLCI_CC_RELEASE_IND, plci_cc_release_ind}, - - {ST_PLCI_P_6, EV_PLCI_DISCONNECT_RESP, plci_disconnect_resp}, - - {ST_PLCI_P_RES, EV_PLCI_RESUME_CONF, plci_resume_conf}, - {ST_PLCI_P_RES, EV_PLCI_DISCONNECT_IND, plci_disconnect_ind}, - {ST_PLCI_P_RES, EV_PLCI_CC_RESUME_ERR, plci_cc_resume_err}, - {ST_PLCI_P_RES, EV_PLCI_CC_RESUME_CONF, plci_cc_resume_conf}, - -#if 0 - {ST_PLCI_P_0, EV_PLCI_FACILITY_IND, plci_facility_ind_p_0_off_hook}, - - {ST_PLCI_P_0_1, EV_PLCI_FACILITY_IND, plci_facility_ind_on_hook}, - - {ST_PLCI_P_1, EV_PLCI_FACILITY_IND, plci_facility_ind_on_hook}, - - {ST_PLCI_P_2, EV_PLCI_FACILITY_IND, plci_facility_ind_p_2_off_hook}, - - {ST_PLCI_P_3, EV_PLCI_CONNECT_RESP, plci_connect_resp}, - {ST_PLCI_P_3, EV_PLCI_INFO_REQ, plci_info_req}, - {ST_PLCI_P_3, EV_PLCI_DISCONNECT_REQ, plci_disconnect_req}, - {ST_PLCI_P_3, EV_PLCI_DISCONNECT_IND, plci_disconnect_ind}, - {ST_PLCI_P_3, EV_PLCI_FACILITY_IND, plci_facility_ind_on_hook}, - {ST_PLCI_P_3, EV_PLCI_CC_RELEASE_IND, plci_cc_release_ind}, - - {ST_PLCI_P_4, EV_PLCI_FACILITY_IND, plci_facility_ind_on_hook}, - - {ST_PLCI_P_ACT, EV_PLCI_FACILITY_IND, plci_facility_ind_on_hook}, - - {ST_PLCI_P_5, EV_PLCI_FACILITY_IND, plci_facility_ind_on_hook}, -#endif -}; - -const int FN_PLCI_COUNT = sizeof(fn_plci_list)/sizeof(struct FsmNode); - -void cplciConstr(Cplci_t *cplci, Appl_t *appl, Plci_t *plci) -{ - memset(cplci, 0, sizeof(Cplci_t)); - cplci->adrPLCI = plci->adrPLCI; - cplci->appl = appl; - cplci->plci = plci; - cplci->contr = plci->contr; - cplci->plci_m.fsm = &plci_fsm; - cplci->plci_m.state = ST_PLCI_P_0; - cplci->plci_m.debug = plci->contr->debug & CAPI_DBG_PLCI_STATE; - cplci->plci_m.userdata = cplci; - cplci->plci_m.printdebug = cplci_debug; - cplci->bchannel = -1; -} - -void cplciDestr(Cplci_t *cplci) -{ - if (cplci->plci) { - cplciDebug(cplci, CAPI_DBG_PLCI, "%s plci state %s", __FUNCTION__, - str_st_plci[cplci->plci_m.state]); - if (cplci->plci_m.state != ST_PLCI_P_0) { - struct sk_buff *skb = alloc_l3msg(10, MT_RELEASE_COMPLETE); - unsigned char cause[] = {2,0x80,0x80| CAUSE_RESOURCES_UNAVAIL}; - - if (skb) { - AddIE(skb, IE_CAUSE, cause); - plciL4L3(cplci->plci, CC_RELEASE_COMPLETE | REQUEST, skb); - } - } - plciDetachCplci(cplci->plci, cplci); - } - if (cplci->ncci) { - ncciDestr(cplci->ncci); - kfree(cplci->ncci); - cplci->ncci = NULL; - } -} - -void cplci_l3l4(Cplci_t *cplci, int pr, void *arg) -{ - Q931_info_t *qi = arg; - u_char *ie; - - cplciDebug(cplci, CAPI_DBG_PLCI_L3, "%s: cplci(%x) plci(%x) pr(%x) arg(%p)", - __FUNCTION__, cplci->adrPLCI, cplci->plci->adrPLCI, pr, arg); - switch (pr) { - case CC_SETUP | INDICATION: - if (!qi) - return; - cplciInfoIndIE(cplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi); - cplciInfoIndIE(cplci, IE_USER_USER, CAPI_INFOMASK_USERUSER, qi); - cplciInfoIndIE(cplci, IE_PROGRESS, CAPI_INFOMASK_PROGRESS, qi); - cplciInfoIndIE(cplci, IE_FACILITY, CAPI_INFOMASK_FACILITY, qi); - cplciInfoIndIE(cplci, IE_CHANNEL_ID, CAPI_INFOMASK_CHANNELID, qi); - if (qi->channel_id) { - ie = (u_char *)qi; - ie += L3_EXTRA_SIZE + qi->channel_id; - cplci->bchannel = plci_parse_channel_id(ie); - } - FsmEvent(&cplci->plci_m, EV_PLCI_CC_SETUP_IND, arg); - break; - case CC_TIMEOUT | INDICATION: - FsmEvent(&cplci->plci_m, EV_PLCI_CC_SETUP_CONF_ERR, arg); - break; - case CC_CONNECT | INDICATION: - if (qi) { - cplciInfoIndIE(cplci, IE_DATE, CAPI_INFOMASK_DISPLAY, qi); - cplciInfoIndIE(cplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi); - cplciInfoIndIE(cplci, IE_USER_USER, CAPI_INFOMASK_USERUSER, qi); - cplciInfoIndIE(cplci, IE_PROGRESS, CAPI_INFOMASK_PROGRESS, qi); - cplciInfoIndIE(cplci, IE_FACILITY, CAPI_INFOMASK_FACILITY, qi); - cplciInfoIndIE(cplci, IE_CHANNEL_ID, CAPI_INFOMASK_CHANNELID, qi); - if (qi->channel_id) { - ie = (u_char *)qi; - ie += L3_EXTRA_SIZE + qi->channel_id; - cplci->bchannel = plci_parse_channel_id(ie); - } - } - FsmEvent(&cplci->plci_m, EV_PLCI_CC_SETUP_CONF, arg); - break; - case CC_CONNECT_ACKNOWLEDGE | INDICATION: - if (qi) { - cplciInfoIndIE(cplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi); - cplciInfoIndIE(cplci, IE_CHANNEL_ID, CAPI_INFOMASK_CHANNELID, qi); - if (qi->channel_id) { - ie = (u_char *)qi; - ie += L3_EXTRA_SIZE + qi->channel_id; - cplci->bchannel = plci_parse_channel_id(ie); - } - } - FsmEvent(&cplci->plci_m, EV_PLCI_CC_SETUP_COMPL_IND, arg); - break; - case CC_DISCONNECT | INDICATION: - if (qi) { - cplciInfoIndMsg(cplci, CAPI_INFOMASK_EARLYB3, MT_DISCONNECT); - cplciInfoIndIE(cplci, IE_CAUSE, CAPI_INFOMASK_CAUSE, qi); - cplciInfoIndIE(cplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi); - cplciInfoIndIE(cplci, IE_USER_USER, CAPI_INFOMASK_USERUSER, qi); - cplciInfoIndIE(cplci, IE_PROGRESS, CAPI_INFOMASK_PROGRESS, qi); - cplciInfoIndIE(cplci, IE_FACILITY, CAPI_INFOMASK_FACILITY, qi); - } - FsmEvent(&cplci->plci_m, EV_PLCI_CC_DISCONNECT_IND, arg); - break; - case CC_RELEASE | INDICATION: - if (qi) { - cplciInfoIndIE(cplci, IE_CAUSE, CAPI_INFOMASK_CAUSE, qi); - cplciInfoIndIE(cplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi); - cplciInfoIndIE(cplci, IE_USER_USER, CAPI_INFOMASK_USERUSER, qi); - cplciInfoIndIE(cplci, IE_FACILITY, CAPI_INFOMASK_FACILITY, qi); - } - FsmEvent(&cplci->plci_m, EV_PLCI_CC_RELEASE_IND, arg); - break; - case CC_RELEASE_COMPLETE | INDICATION: - if (qi) { - cplciInfoIndIE(cplci, IE_CAUSE, CAPI_INFOMASK_CAUSE, qi); - cplciInfoIndIE(cplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi); - cplciInfoIndIE(cplci, IE_USER_USER, CAPI_INFOMASK_USERUSER, qi); - cplciInfoIndIE(cplci, IE_FACILITY, CAPI_INFOMASK_FACILITY, qi); - } - FsmEvent(&cplci->plci_m, EV_PLCI_CC_RELEASE_IND, arg); - break; - case CC_RELEASE_CR | INDICATION: - FsmEvent(&cplci->plci_m, EV_PLCI_CC_RELEASE_PROC_IND, arg); - break; - case CC_SETUP_ACKNOWLEDGE | INDICATION: - if (qi) { - cplciInfoIndMsg(cplci, CAPI_INFOMASK_PROGRESS, MT_SETUP_ACKNOWLEDGE); - cplciInfoIndIE(cplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi); - cplciInfoIndIE(cplci, IE_PROGRESS, - CAPI_INFOMASK_PROGRESS | CAPI_INFOMASK_EARLYB3, qi); - cplciInfoIndIE(cplci, IE_CHANNEL_ID, CAPI_INFOMASK_CHANNELID, qi); - if (qi->channel_id) { - ie = (u_char *)qi; - ie += L3_EXTRA_SIZE + qi->channel_id; - cplci->bchannel = plci_parse_channel_id(ie); - } - } - break; - case CC_PROCEEDING | INDICATION: - if (qi) { - cplciInfoIndMsg(cplci, CAPI_INFOMASK_PROGRESS, MT_CALL_PROCEEDING); - cplciInfoIndIE(cplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi); - cplciInfoIndIE(cplci, IE_PROGRESS, - CAPI_INFOMASK_PROGRESS | CAPI_INFOMASK_EARLYB3, qi); - cplciInfoIndIE(cplci, IE_CHANNEL_ID, CAPI_INFOMASK_CHANNELID, qi); - if (qi->channel_id) { - ie = (u_char *)qi; - ie += L3_EXTRA_SIZE + qi->channel_id; - cplci->bchannel = plci_parse_channel_id(ie); - } - } - break; - case CC_ALERTING | INDICATION: - if (qi) { - cplciInfoIndMsg(cplci, CAPI_INFOMASK_PROGRESS, MT_ALERTING); - cplciInfoIndIE(cplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi); - cplciInfoIndIE(cplci, IE_USER_USER, CAPI_INFOMASK_USERUSER, qi); - cplciInfoIndIE(cplci, IE_PROGRESS, - CAPI_INFOMASK_PROGRESS | CAPI_INFOMASK_EARLYB3, qi); - cplciInfoIndIE(cplci, IE_FACILITY, CAPI_INFOMASK_FACILITY, qi); - cplciInfoIndIE(cplci, IE_CHANNEL_ID, CAPI_INFOMASK_CHANNELID, qi); - if (qi->channel_id) { - ie = (u_char *)qi; - ie += L3_EXTRA_SIZE + qi->channel_id; - cplci->bchannel = plci_parse_channel_id(ie); - } - } - break; - case CC_PROGRESS | INDICATION: - if (qi) { - cplciInfoIndMsg(cplci, CAPI_INFOMASK_PROGRESS, MT_PROGRESS); - cplciInfoIndIE(cplci, IE_CAUSE, CAPI_INFOMASK_CAUSE, qi); - cplciInfoIndIE(cplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi); - cplciInfoIndIE(cplci, IE_USER_USER, CAPI_INFOMASK_USERUSER, qi); - cplciInfoIndIE(cplci, IE_PROGRESS, - CAPI_INFOMASK_PROGRESS | CAPI_INFOMASK_EARLYB3, qi); - } - break; - case CC_SUSPEND_ACKNOWLEDGE | INDICATION: - FsmEvent(&cplci->plci_m, EV_PLCI_CC_SUSPEND_CONF, arg); - break; - case CC_SUSPEND_REJECT | INDICATION: - FsmEvent(&cplci->plci_m, EV_PLCI_CC_SUSPEND_ERR, arg); - break; - case CC_RESUME_ACKNOWLEDGE | INDICATION: - FsmEvent(&cplci->plci_m, EV_PLCI_CC_RESUME_CONF, arg); - break; - case CC_RESUME_REJECT | INDICATION: - FsmEvent(&cplci->plci_m, EV_PLCI_CC_RESUME_ERR, arg); - break; - case CC_NOTIFY | INDICATION: - FsmEvent(&cplci->plci_m, EV_PLCI_CC_NOTIFY_IND, arg); - break; - case PH_CONTROL | INDICATION: - /* TOUCH TONE */ - FsmEvent(&cplci->plci_m, EV_PLCI_CC_PH_CONTROL_IND, arg); - break; - default: - cplciDebug(cplci, CAPI_DBG_WARN, - "%s: pr 0x%x not handled", __FUNCTION__, pr); - break; - } -} - -void cplciSendMessage(Cplci_t *cplci, struct sk_buff *skb) -{ - int retval = 0; - _cmsg cmsg; - capi_message2cmsg(&cmsg, skb->data); - - switch (CMSGCMD(&cmsg)) { - case CAPI_INFO_REQ: - retval = FsmEvent(&cplci->plci_m, EV_PLCI_INFO_REQ, &cmsg); - break; - case CAPI_ALERT_REQ: - retval = FsmEvent(&cplci->plci_m, EV_PLCI_ALERT_REQ, &cmsg); - break; - case CAPI_CONNECT_REQ: - retval = FsmEvent(&cplci->plci_m, EV_PLCI_CONNECT_REQ, &cmsg); - break; - case CAPI_CONNECT_RESP: - retval = FsmEvent(&cplci->plci_m, EV_PLCI_CONNECT_RESP, &cmsg); - break; - case CAPI_DISCONNECT_REQ: - retval = FsmEvent(&cplci->plci_m, EV_PLCI_DISCONNECT_REQ, &cmsg); - break; - case CAPI_DISCONNECT_RESP: - retval = FsmEvent(&cplci->plci_m, EV_PLCI_DISCONNECT_RESP, &cmsg); - break; - case CAPI_CONNECT_ACTIVE_RESP: - retval = FsmEvent(&cplci->plci_m, EV_PLCI_CONNECT_ACTIVE_RESP, &cmsg); - break; - case CAPI_SELECT_B_PROTOCOL_REQ: - retval = FsmEvent(&cplci->plci_m, EV_PLCI_SELECT_B_PROTOCOL_REQ, &cmsg); - break; - default: - int_error(); - retval = -1; - } - if (retval) { - if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_REQ) { - contrAnswerMessage(cplci->contr, skb, - CapiMessageNotSupportedInCurrentState); - } - } - dev_kfree_skb(skb); -} - -void cplciLinkUp(Cplci_t *cplci) -{ - if (cplci->ncci) - return; - if (cplci->bchannel == -1) {/* no valid channel set */ - int_error(); - return; - } - - cplci->ncci = kmalloc(sizeof(Ncci_t), GFP_ATOMIC); - if (!cplci->ncci) { - int_error(); - return; - } - ncciConstr(cplci->ncci, cplci); - ncciLinkUp(cplci->ncci); -} - -void cplciLinkDown(Cplci_t *cplci) -{ - if (!cplci->ncci) { - return; - } - ncciLinkDown(cplci->ncci); -} - -int cplciFacSuspendReq(Cplci_t *cplci, struct FacReqParm *facReqParm, - struct FacConfParm *facConfParm) -{ - __u8 *CallIdentity; - struct sk_buff *skb; - - CallIdentity = facReqParm->u.Suspend.CallIdentity; - if (CallIdentity && CallIdentity[0] > 8) - return CapiIllMessageParmCoding; - skb = alloc_l3msg(20, MT_SUSPEND); - if (!skb) { - int_error(); - return CapiIllMessageParmCoding; - } - if (CallIdentity && CallIdentity[0]) - AddIE(skb, IE_CALL_ID, CallIdentity); - - if (FsmEvent(&cplci->plci_m, EV_PLCI_SUSPEND_REQ, skb)) { - // no routine - facConfParm->u.Info.SupplementaryServiceInfo = - CapiRequestNotAllowedInThisState; - kfree(skb); - } else { - facConfParm->u.Info.SupplementaryServiceInfo = CapiSuccess; - } - return CapiSuccess; -} - -int cplciFacResumeReq(Cplci_t *cplci, struct FacReqParm *facReqParm, - struct FacConfParm *facConfParm) -{ - __u8 *CallIdentity; - struct sk_buff *skb; - - CallIdentity = facReqParm->u.Resume.CallIdentity; - if (CallIdentity && CallIdentity[0] > 8) { - applDelCplci(cplci->appl, cplci); - return CapiIllMessageParmCoding; - } - skb = alloc_l3msg(20, MT_RESUME); - if (!skb) { - int_error(); - return CapiIllMessageParmCoding; - } - if (CallIdentity && CallIdentity[0]) - AddIE(skb, IE_CALL_ID, CallIdentity); - if (FsmEvent(&cplci->plci_m, EV_PLCI_RESUME_REQ, skb)) - kfree(skb); - - facConfParm->u.Info.SupplementaryServiceInfo = CapiSuccess; - return CapiSuccess; -} - -void cplciClearOtherApps(Cplci_t *cplci) -{ - Plci_t *plci = cplci->plci; - Cplci_t *cp; - __u16 applId; - _cmsg cm; - - for (applId = 1; applId <= CAPI_MAXAPPL; applId++) { - cp = plci->cplcis[applId - 1]; - if (cp && (cp != cplci)) { - plciDetachCplci(plci, cp); - cplciCmsgHeader(cp, &cm, CAPI_DISCONNECT, CAPI_IND); - cm.Reason = 0x3304; // other application got the call - FsmEvent(&cp->plci_m, EV_PLCI_DISCONNECT_IND, &cm); - cplciRecvCmsg(cp, &cm); - } - } -} - -void cplciInfoIndMsg(Cplci_t *cplci, __u32 mask, unsigned char mt) -{ - _cmsg cmsg; - - if (!(cplci->appl->listen.InfoMask & mask)) - return; - cplciCmsgHeader(cplci, &cmsg, CAPI_INFO, CAPI_IND); - cmsg.InfoNumber = 0x8000 | mt; - cmsg.InfoElement = 0; - cplciRecvCmsg(cplci, &cmsg); -} - -void cplciInfoIndIE(Cplci_t *cplci, unsigned char ie, __u32 mask, Q931_info_t *qi) -{ - _cmsg cmsg; - u_char *iep = NULL; - u16 *ies; - - - if (!(cplci->appl->listen.InfoMask & mask)) - return; - if (!qi) - return; - ies = &qi->bearer_capability; - if (ie & 0x80) { /* single octett */ - int_error(); - return; - } else { - if (l3_ie2pos(ie) < 0) - return; - ies += l3_ie2pos(ie); - if (!*ies) - return; - iep = (u_char *)qi; - iep += L3_EXTRA_SIZE + *ies +1; - } - if (ie == IE_PROGRESS && cplci->appl->listen.InfoMask & CAPI_INFOMASK_EARLYB3) { - if (iep[0] == 0x02 && iep[2] == 0x88) { // in-band information available - cplciLinkUp(cplci); - } - } - cplciCmsgHeader(cplci, &cmsg, CAPI_INFO, CAPI_IND); - cmsg.InfoNumber = ie; - cmsg.InfoElement = iep; - cplciRecvCmsg(cplci, &cmsg); -} - -void init_cplci(void) -{ - plci_fsm.state_count = ST_PLCI_COUNT; - plci_fsm.event_count = EV_PLCI_COUNT; - plci_fsm.strEvent = str_ev_plci; - plci_fsm.strState = str_st_plci; - - FsmNew(&plci_fsm, fn_plci_list, FN_PLCI_COUNT); -} - - -void free_cplci(void) -{ - FsmFree(&plci_fsm); -} diff --git a/drivers/isdn/hardware/mISDN/listen.c b/drivers/isdn/hardware/mISDN/listen.c index c986f96..23b4285 100644 --- a/drivers/isdn/hardware/mISDN/listen.c +++ b/drivers/isdn/hardware/mISDN/listen.c @@ -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; diff --git a/drivers/isdn/hardware/mISDN/m_capi.h b/drivers/isdn/hardware/mISDN/m_capi.h new file mode 100755 index 0000000..d3d5c30 --- /dev/null +++ b/drivers/isdn/hardware/mISDN/m_capi.h @@ -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 +#include +#include +#include +#include +#ifdef OLDCAPI_DRIVER_INTERFACE +#include "../avmb1/capiutil.h" +#include "../avmb1/capicmd.h" +#include "../avmb1/capilli.h" +#else +#include +#include +#include +#include +#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 diff --git a/drivers/isdn/hardware/mISDN/ncci.c b/drivers/isdn/hardware/mISDN/ncci.c index 7759ddf..ca92897 100644 --- a/drivers/isdn/hardware/mISDN/ncci.c +++ b/drivers/isdn/hardware/mISDN/ncci.c @@ -2,17 +2,26 @@ * */ -#include "capi.h" +#include "m_capi.h" #include "helper.h" #include "debug.h" #include "dss1.h" #include "mISDNManufacturer.h" -static int ncciL4L3(Ncci_t *, u_int, int, int, void *, struct sk_buff *); +static int ncciL4L3(Ncci_t *, u_int, int, int, void *, struct sk_buff *); +static void ncciInitSt(Ncci_t *); +static void ncciReleaseSt(Ncci_t *); // -------------------------------------------------------------------- // NCCI state machine - +// +// Some rules: +// * EV_AP_* events come from CAPI Application +// * EV_DL_* events come from the ISDN stack +// * EV_NC_* events generated in NCCI handling +// * messages are send in the routine that handle the event +// +// -------------------------------------------------------------------- enum { ST_NCCI_N_0, ST_NCCI_N_0_1, @@ -38,59 +47,62 @@ static char *str_st_ncci[] = { }; enum { - EV_NCCI_CONNECT_B3_REQ, - EV_NCCI_CONNECT_B3_CONF, - EV_NCCI_CONNECT_B3_IND, - EV_NCCI_CONNECT_B3_RESP, - EV_NCCI_CONNECT_B3_ACTIVE_IND, - EV_NCCI_CONNECT_B3_ACTIVE_RESP, - EV_NCCI_RESET_B3_REQ, - EV_NCCI_RESET_B3_IND, - EV_NCCI_CONNECT_B3_T90_ACTIVE_IND, - EV_NCCI_DISCONNECT_B3_REQ, - EV_NCCI_DISCONNECT_B3_IND, - EV_NCCI_DISCONNECT_B3_CONF, - EV_NCCI_DISCONNECT_B3_RESP, - EV_NCCI_FACILITY_REQ, - EV_NCCI_MANUFACTURER_REQ, - EV_NCCI_SELECT_B_PROTOCOL, - EV_NCCI_DL_ESTABLISH_IND, - EV_NCCI_DL_ESTABLISH_CONF, - EV_NCCI_DL_RELEASE_IND, - EV_NCCI_DL_RELEASE_CONF, - EV_NCCI_DL_DOWN_IND, + EV_AP_CONNECT_B3_REQ, + EV_NC_CONNECT_B3_CONF, + EV_NC_CONNECT_B3_IND, + EV_AP_CONNECT_B3_RESP, + EV_NC_CONNECT_B3_ACTIVE_IND, + EV_AP_CONNECT_B3_ACTIVE_RESP, + EV_AP_RESET_B3_REQ, + EV_NC_RESET_B3_IND, + EV_NC_CONNECT_B3_T90_ACTIVE_IND, + EV_AP_DISCONNECT_B3_REQ, + EV_NC_DISCONNECT_B3_IND, + EV_NC_DISCONNECT_B3_CONF, + EV_AP_DISCONNECT_B3_RESP, + EV_AP_FACILITY_REQ, + EV_AP_MANUFACTURER_REQ, + EV_AP_SELECT_B_PROTOCOL, + EV_DL_ESTABLISH_IND, + EV_DL_ESTABLISH_CONF, + EV_DL_RELEASE_IND, + EV_DL_RELEASE_CONF, + EV_DL_DOWN_IND, + EV_AP_RELEASE, } -const EV_NCCI_COUNT = EV_NCCI_DL_DOWN_IND + 1; +const EV_NCCI_COUNT = EV_AP_RELEASE + 1; static char* str_ev_ncci[] = { - "EV_NCCI_CONNECT_B3_REQ", - "EV_NCCI_CONNECT_B3_CONF", - "EV_NCCI_CONNECT_B3_IND", - "EV_NCCI_CONNECT_B3_RESP", - "EV_NCCI_CONNECT_B3_ACTIVE_IND", - "EV_NCCI_CONNECT_B3_ACTIVE_RESP", - "EV_NCCI_RESET_B3_REQ", - "EV_NCCI_RESET_B3_IND", - "EV_NCCI_CONNECT_B3_T90_ACTIVE_IND", - "EV_NCCI_DISCONNECT_B3_REQ", - "EV_NCCI_DISCONNECT_B3_IND", - "EV_NCCI_DISCONNECT_B3_CONF", - "EV_NCCI_DISCONNECT_B3_RESP", - "EV_NCCI_FACILITY_REQ", - "EV_NCCI_MANUFACTURER_REQ", - "EV_NCCI_SELECT_B_PROTOCOL", - "EV_NCCI_DL_ESTABLISH_IND", - "EV_NCCI_DL_ESTABLISH_CONF", - "EV_NCCI_DL_RELEASE_IND", - "EV_NCCI_DL_RELEASE_CONF", - "EV_NCCI_DL_DOWN_IND", + "EV_AP_CONNECT_B3_REQ", + "EV_NC_CONNECT_B3_CONF", + "EV_NC_CONNECT_B3_IND", + "EV_AP_CONNECT_B3_RESP", + "EV_NC_CONNECT_B3_ACTIVE_IND", + "EV_AP_CONNECT_B3_ACTIVE_RESP", + "EV_AP_RESET_B3_REQ", + "EV_NC_RESET_B3_IND", + "EV_NC_CONNECT_B3_T90_ACTIVE_IND", + "EV_AP_DISCONNECT_B3_REQ", + "EV_NC_DISCONNECT_B3_IND", + "EV_NC_DISCONNECT_B3_CONF", + "EV_AP_DISCONNECT_B3_RESP", + "EV_AP_FACILITY_REQ", + "EV_AP_MANUFACTURER_REQ", + "EV_AP_SELECT_B_PROTOCOL", + "EV_DL_ESTABLISH_IND", + "EV_DL_ESTABLISH_CONF", + "EV_DL_RELEASE_IND", + "EV_DL_RELEASE_CONF", + "EV_DL_DOWN_IND", + "EV_AP_RELEASE", }; static struct Fsm ncci_fsm = { 0, 0, 0, 0, 0 }; -static void ncci_debug(struct FsmInst *fi, char *fmt, ...) +static void +ncci_debug(struct FsmInst *fi, char *fmt, ...) { char tmp[128]; char *p = tmp; @@ -100,7 +112,7 @@ static void ncci_debug(struct FsmInst *fi, char *fmt, ...) if (!ncci->ncci_m.debug) return; va_start(args, fmt); - p += sprintf(p, "NCCI 0x%x: ", ncci->adrNCCI); + p += sprintf(p, "NCCI 0x%x: ", ncci->addr); p += vsprintf(p, fmt, args); *p++ = '\n'; *p = 0; @@ -108,87 +120,147 @@ static void ncci_debug(struct FsmInst *fi, char *fmt, ...) va_end(args); } -inline void ncciRecvCmsg(Ncci_t *ncci, _cmsg *cmsg) +static inline void +Send2Application(Ncci_t *ncci, _cmsg *cmsg) { - contrRecvCmsg(ncci->contr, cmsg); + SendCmsg2Application(ncci->appl, cmsg); } -inline void ncciCmsgHeader(Ncci_t *ncci, _cmsg *cmsg, __u8 cmd, __u8 subcmd) +static inline void +ncciCmsgHeader(Ncci_t *ncci, _cmsg *cmsg, __u8 cmd, __u8 subcmd) { capi_cmsg_header(cmsg, ncci->appl->ApplId, cmd, subcmd, - ncci->appl->MsgId++, ncci->adrNCCI); + ncci->appl->MsgId++, ncci->addr); } -static void ncci_connect_b3_req(struct FsmInst *fi, int event, void *arg) +static void +ncci_connect_b3_req(struct FsmInst *fi, int event, void *arg) { Ncci_t *ncci = fi->userdata; _cmsg *cmsg = arg; + // FIXME + if (!ncci->appl) { + cmsg_free(cmsg); + return; + } FsmChangeState(fi, ST_NCCI_N_0_1); capi_cmsg_answer(cmsg); - cmsg->adr.adrNCCI = ncci->adrNCCI; + cmsg->adr.adrNCCI = ncci->addr; + + // TODO: NCPI handling + cmsg->Info = 0; - FsmEvent(fi, EV_NCCI_CONNECT_B3_CONF, cmsg); - ncciRecvCmsg(ncci, cmsg); ncci_debug(fi, "ncci_connect_b3_req NCCI %x cmsg->Info(%x)", - ncci->adrNCCI, cmsg->Info); - if (cmsg->Info < 0x1000) - ncciL4L3(ncci, DL_ESTABLISH | REQUEST, 0, 0, NULL, NULL); + ncci->addr, cmsg->Info); + if (FsmEvent(fi, EV_NC_CONNECT_B3_CONF, cmsg)) + cmsg_free(cmsg); } -static void ncci_connect_b3_ind(struct FsmInst *fi, int event, void *arg) +static void +ncci_connect_b3_ind(struct FsmInst *fi, int event, void *arg) { + // from DL_ESTABLISH FsmChangeState(fi, ST_NCCI_N_1); + Send2Application(fi->userdata, arg); } -static void ncci_connect_b3_resp(struct FsmInst *fi, int event, void *arg) +static void +ncci_connect_b3_resp(struct FsmInst *fi, int event, void *arg) { Ncci_t *ncci = fi->userdata; _cmsg *cmsg = arg; + // FIXME + if (!ncci->appl) { + cmsg_free(cmsg); + return; + } if (cmsg->Info == 0) { FsmChangeState(fi, ST_NCCI_N_2); ncciCmsgHeader(ncci, cmsg, CAPI_CONNECT_B3_ACTIVE, CAPI_IND); - FsmEvent(&ncci->ncci_m, EV_NCCI_CONNECT_B3_ACTIVE_IND, cmsg); - ncciRecvCmsg(ncci, cmsg); + event = EV_NC_CONNECT_B3_ACTIVE_IND; } else { FsmChangeState(fi, ST_NCCI_N_4); + cmsg->Info = 0; ncciCmsgHeader(ncci, cmsg, CAPI_DISCONNECT_B3, CAPI_IND); - FsmEvent(&ncci->ncci_m, EV_NCCI_DISCONNECT_B3_IND, cmsg); - ncciRecvCmsg(ncci, cmsg); + event = EV_NC_DISCONNECT_B3_IND; } + if (FsmEvent(&ncci->ncci_m, event, cmsg)) + cmsg_free(cmsg); } -static void ncci_connect_b3_conf(struct FsmInst *fi, int event, void *arg) +static void +ncci_connect_b3_conf(struct FsmInst *fi, int event, void *arg) { - _cmsg *cmsg = arg; + _cmsg *cmsg = arg; if (cmsg->Info == 0) { FsmChangeState(fi, ST_NCCI_N_2); + Send2Application(fi->userdata, cmsg); + ncciL4L3(fi->userdata, DL_ESTABLISH | REQUEST, 0, 0, NULL, NULL); } else { FsmChangeState(fi, ST_NCCI_N_0); + Send2Application(fi->userdata, cmsg); + ncciDestr(fi->userdata); } } -static void ncci_disconnect_b3_req(struct FsmInst *fi, int event, void *arg) +static void +ncci_disconnect_b3_req(struct FsmInst *fi, int event, void *arg) { - Ncci_t *ncci = fi->userdata; - _cmsg *cmsg = arg; - __u16 Info = 0; - int saved_state = fi->state; - - FsmChangeState(fi, ST_NCCI_N_4); + Ncci_t *ncci = fi->userdata; + _cmsg *cmsg = arg; + __u16 Info = 0; - capi_cmsg_answer(cmsg); - cmsg->Info = Info; - FsmEvent(fi, EV_NCCI_DISCONNECT_B3_CONF, cmsg); - if (cmsg->Info != 0) { - FsmChangeState(fi, saved_state); - ncciRecvCmsg(ncci, cmsg); + if (ncci->appl) { //FIXME + /* TODO: handle NCPI and wait for all DATA_B3_REQ confirmed on + * related protocols (voice, T30) + */ + capi_cmsg_answer(cmsg); + cmsg->Info = Info; + if (FsmEvent(fi, EV_NC_DISCONNECT_B3_CONF, cmsg)) + cmsg_free(cmsg); } else { - ncciRecvCmsg(ncci, cmsg); - ncciL4L3(ncci, DL_RELEASE | REQUEST, 0, 0, NULL, NULL); + cmsg_free(cmsg); + FsmChangeState(fi, ST_NCCI_N_4); } + ncciL4L3(ncci, DL_RELEASE | REQUEST, 0, 0, NULL, NULL); +} + +static void +ncci_disconnect_b3_conf(struct FsmInst *fi, int event, void *arg) +{ + _cmsg *cmsg = arg; + + if (cmsg->Info == 0) { + FsmChangeState(fi, ST_NCCI_N_4); + } + Send2Application(fi->userdata, cmsg); +} + +static void +ncci_disconnect_b3_ind(struct FsmInst *fi, int event, void *arg) +{ + Ncci_t *ncci = fi->userdata; + + FsmChangeState(fi, ST_NCCI_N_5); + if (ncci->appl) { // FIXME + Send2Application(ncci, arg); + } else { + cmsg_free(arg); + FsmChangeState(fi, ST_NCCI_N_0); + ncciDestr(ncci); + } +} + +static void +ncci_disconnect_b3_resp(struct FsmInst *fi, int event, void *arg) +{ + if (arg) + cmsg_free(arg); + FsmChangeState(fi, ST_NCCI_N_0); + ncciDestr(fi->userdata); } static void @@ -200,6 +272,8 @@ ncci_facility_req(struct FsmInst *fi, int event, void *arg) u16 func; int op; + if (!ncci->appl) + return; capi_cmsg_answer(cmsg); cmsg->Info = CAPI_NOERROR; if (cmsg->FacilitySelector == 0) { // Handset @@ -228,7 +302,7 @@ ncci_facility_req(struct FsmInst *fi, int event, void *arg) } else cmsg->Info = CapiIllMessageParmCoding; - ncciRecvCmsg(ncci, cmsg); + Send2Application(ncci, cmsg); } static void @@ -247,6 +321,8 @@ ncci_manufacturer_req(struct FsmInst *fi, int event, void *arg) u16 vol __attribute__((packed)); } *mrp; + if (!ncci->appl) + return; mrp = (struct _manu_req_para *)cmsg->ManuData; capi_cmsg_answer(cmsg); if (cmsg->Class == mISDN_MF_CLASS_HANDSET) { // Handset @@ -286,10 +362,11 @@ ncci_manufacturer_req(struct FsmInst *fi, int event, void *arg) mcp.Info = CapiIllMessageParmCoding; cmsg->ManuData = (_cstruct)&mcp; - ncciRecvCmsg(ncci, cmsg); + Send2Application(ncci, cmsg); } -static void ncci_connect_b3_active_ind(struct FsmInst *fi, int event, void *arg) +static void +ncci_connect_b3_active_ind(struct FsmInst *fi, int event, void *arg) { Ncci_t *ncci = fi->userdata; int i; @@ -299,64 +376,70 @@ static void ncci_connect_b3_active_ind(struct FsmInst *fi, int event, void *arg) ncci->xmit_skb_handles[i].skb = 0; ncci->recv_skb_handles[i] = 0; } + Send2Application(ncci, arg); } -static void ncci_connect_b3_active_resp(struct FsmInst *fi, int event, void *arg) +static void +ncci_connect_b3_active_resp(struct FsmInst *fi, int event, void *arg) { + cmsg_free(arg); } -static void ncci_disconnect_b3_conf(struct FsmInst *fi, int event, void *arg) +static void +ncci_n0_dl_establish_ind_conf(struct FsmInst *fi, int event, void *arg) { + _cmsg *cmsg; + Ncci_t *ncci = fi->userdata; + + if (!ncci->appl) + return; + CMSG_ALLOC(cmsg); + ncciCmsgHeader(ncci, cmsg, CAPI_CONNECT_B3, CAPI_IND); + if (FsmEvent(&ncci->ncci_m, EV_NC_CONNECT_B3_IND, cmsg)) + cmsg_free(cmsg); } -static void ncci_disconnect_b3_ind(struct FsmInst *fi, int event, void *arg) +static void +ncci_dl_establish_conf(struct FsmInst *fi, int event, void *arg) { - FsmChangeState(fi, ST_NCCI_N_5); + Ncci_t *ncci = fi->userdata; + _cmsg *cmsg; + + if (!ncci->appl) + return; + CMSG_ALLOC(cmsg); + ncciCmsgHeader(ncci, cmsg, CAPI_CONNECT_B3_ACTIVE, CAPI_IND); + if (FsmEvent(&ncci->ncci_m, EV_NC_CONNECT_B3_ACTIVE_IND, cmsg)) + cmsg_free(cmsg); } -static void ncci_disconnect_b3_resp(struct FsmInst *fi, int event, void *arg) +static void +ncci_dl_release_ind_conf(struct FsmInst *fi, int event, void *arg) { - FsmChangeState(fi, ST_NCCI_N_0); + Ncci_t *ncci = fi->userdata; + _cmsg *cmsg; + + CMSG_ALLOC(cmsg); + ncciCmsgHeader(ncci, cmsg, CAPI_DISCONNECT_B3, CAPI_IND); + if (FsmEvent(&ncci->ncci_m, EV_NC_DISCONNECT_B3_IND, cmsg)) + cmsg_free(cmsg); } -static void ncci_n0_dl_establish_ind_conf(struct FsmInst *fi, int event, void *arg) +static void +ncci_dl_down_ind(struct FsmInst *fi, int event, void *arg) { - Ncci_t *ncci = fi->userdata; + Ncci_t *ncci = fi->userdata; + _cmsg *cmsg; - ncciCmsgHeader(ncci, &ncci->tmpmsg, CAPI_CONNECT_B3, CAPI_IND); - FsmEvent(&ncci->ncci_m, EV_NCCI_CONNECT_B3_IND, &ncci->tmpmsg); - ncciRecvCmsg(ncci, &ncci->tmpmsg); + CMSG_ALLOC(cmsg); + ncciCmsgHeader(ncci, cmsg, CAPI_DISCONNECT_B3, CAPI_IND); + cmsg->Reason_B3 = CapiProtocolErrorLayer1; + if (FsmEvent(&ncci->ncci_m, EV_NC_DISCONNECT_B3_IND, cmsg)) + cmsg_free(cmsg); } -static void ncci_dl_establish_conf(struct FsmInst *fi, int event, void *arg) -{ - Ncci_t *ncci = fi->userdata; - - ncciCmsgHeader(ncci, &ncci->tmpmsg, CAPI_CONNECT_B3_ACTIVE, CAPI_IND); - FsmEvent(&ncci->ncci_m, EV_NCCI_CONNECT_B3_ACTIVE_IND, &ncci->tmpmsg); - ncciRecvCmsg(ncci, &ncci->tmpmsg); -} - -static void ncci_dl_release_ind_conf(struct FsmInst *fi, int event, void *arg) -{ - Ncci_t *ncci = fi->userdata; - - ncciCmsgHeader(ncci, &ncci->tmpmsg, CAPI_DISCONNECT_B3, CAPI_IND); - FsmEvent(&ncci->ncci_m, EV_NCCI_DISCONNECT_B3_IND, &ncci->tmpmsg); - ncciRecvCmsg(ncci, &ncci->tmpmsg); -} - -static void ncci_dl_down_ind(struct FsmInst *fi, int event, void *arg) -{ - Ncci_t *ncci = fi->userdata; - - ncciCmsgHeader(ncci, &ncci->tmpmsg, CAPI_DISCONNECT_B3, CAPI_IND); - ncci->tmpmsg.Reason_B3 = CapiProtocolErrorLayer1; - FsmEvent(&ncci->ncci_m, EV_NCCI_DISCONNECT_B3_IND, &ncci->tmpmsg); - ncciRecvCmsg(ncci, &ncci->tmpmsg); -} - -static void ncci_select_b_protocol(struct FsmInst *fi, int event, void *arg) +static void +ncci_select_b_protocol(struct FsmInst *fi, int event, void *arg) { Ncci_t *ncci = fi->userdata; @@ -364,126 +447,157 @@ static void ncci_select_b_protocol(struct FsmInst *fi, int event, void *arg) ncciInitSt(ncci); } + +static void +ncci_appl_release(struct FsmInst *fi, int event, void *arg) +{ + ncciDestr(fi->userdata); +} + +static void +ncci_appl_release_disc(struct FsmInst *fi, int event, void *arg) +{ + ncciL4L3(fi->userdata, DL_RELEASE | REQUEST, 0, 0, NULL, NULL); +} + static struct FsmNode fn_ncci_list[] = { - {ST_NCCI_N_0, EV_NCCI_CONNECT_B3_REQ, ncci_connect_b3_req}, - {ST_NCCI_N_0, EV_NCCI_CONNECT_B3_IND, ncci_connect_b3_ind}, - {ST_NCCI_N_0, EV_NCCI_SELECT_B_PROTOCOL, ncci_select_b_protocol}, - {ST_NCCI_N_0, EV_NCCI_DL_ESTABLISH_CONF, ncci_n0_dl_establish_ind_conf}, - {ST_NCCI_N_0, EV_NCCI_DL_ESTABLISH_IND, ncci_n0_dl_establish_ind_conf}, + {ST_NCCI_N_0, EV_AP_CONNECT_B3_REQ, ncci_connect_b3_req}, + {ST_NCCI_N_0, EV_NC_CONNECT_B3_IND, ncci_connect_b3_ind}, + {ST_NCCI_N_0, EV_AP_SELECT_B_PROTOCOL, ncci_select_b_protocol}, + {ST_NCCI_N_0, EV_DL_ESTABLISH_CONF, ncci_n0_dl_establish_ind_conf}, + {ST_NCCI_N_0, EV_DL_ESTABLISH_IND, ncci_n0_dl_establish_ind_conf}, + {ST_NCCI_N_0, EV_AP_RELEASE, ncci_appl_release}, - {ST_NCCI_N_0_1, EV_NCCI_CONNECT_B3_CONF, ncci_connect_b3_conf}, - {ST_NCCI_N_0_1, EV_NCCI_MANUFACTURER_REQ, ncci_manufacturer_req}, + {ST_NCCI_N_0_1, EV_NC_CONNECT_B3_CONF, ncci_connect_b3_conf}, + {ST_NCCI_N_0_1, EV_AP_MANUFACTURER_REQ, ncci_manufacturer_req}, + {ST_NCCI_N_0_1, EV_AP_RELEASE, ncci_appl_release}, - {ST_NCCI_N_1, EV_NCCI_CONNECT_B3_RESP, ncci_connect_b3_resp}, - {ST_NCCI_N_1, EV_NCCI_DISCONNECT_B3_REQ, ncci_disconnect_b3_req}, - {ST_NCCI_N_1, EV_NCCI_DISCONNECT_B3_IND, ncci_disconnect_b3_ind}, - {ST_NCCI_N_1, EV_NCCI_MANUFACTURER_REQ, ncci_manufacturer_req}, + {ST_NCCI_N_1, EV_AP_CONNECT_B3_RESP, ncci_connect_b3_resp}, + {ST_NCCI_N_1, EV_AP_DISCONNECT_B3_REQ, ncci_disconnect_b3_req}, + {ST_NCCI_N_1, EV_NC_DISCONNECT_B3_IND, ncci_disconnect_b3_ind}, + {ST_NCCI_N_1, EV_AP_MANUFACTURER_REQ, ncci_manufacturer_req}, + {ST_NCCI_N_1, EV_AP_RELEASE, ncci_appl_release_disc}, - {ST_NCCI_N_2, EV_NCCI_CONNECT_B3_ACTIVE_IND, ncci_connect_b3_active_ind}, - {ST_NCCI_N_2, EV_NCCI_DISCONNECT_B3_REQ, ncci_disconnect_b3_req}, - {ST_NCCI_N_2, EV_NCCI_DISCONNECT_B3_IND, ncci_disconnect_b3_ind}, - {ST_NCCI_N_2, EV_NCCI_DL_ESTABLISH_CONF, ncci_dl_establish_conf}, - {ST_NCCI_N_2, EV_NCCI_DL_RELEASE_IND, ncci_dl_release_ind_conf}, - {ST_NCCI_N_2, EV_NCCI_MANUFACTURER_REQ, ncci_manufacturer_req}, + {ST_NCCI_N_2, EV_NC_CONNECT_B3_ACTIVE_IND, ncci_connect_b3_active_ind}, + {ST_NCCI_N_2, EV_AP_DISCONNECT_B3_REQ, ncci_disconnect_b3_req}, + {ST_NCCI_N_2, EV_NC_DISCONNECT_B3_IND, ncci_disconnect_b3_ind}, + {ST_NCCI_N_2, EV_DL_ESTABLISH_CONF, ncci_dl_establish_conf}, + {ST_NCCI_N_2, EV_DL_RELEASE_IND, ncci_dl_release_ind_conf}, + {ST_NCCI_N_2, EV_AP_MANUFACTURER_REQ, ncci_manufacturer_req}, + {ST_NCCI_N_2, EV_AP_RELEASE, ncci_appl_release_disc}, - {ST_NCCI_N_ACT, EV_NCCI_CONNECT_B3_ACTIVE_RESP, ncci_connect_b3_active_resp}, - {ST_NCCI_N_ACT, EV_NCCI_DISCONNECT_B3_REQ, ncci_disconnect_b3_req}, - {ST_NCCI_N_ACT, EV_NCCI_DISCONNECT_B3_IND, ncci_disconnect_b3_ind}, - {ST_NCCI_N_ACT, EV_NCCI_DL_RELEASE_IND, ncci_dl_release_ind_conf}, - {ST_NCCI_N_ACT, EV_NCCI_DL_DOWN_IND, ncci_dl_down_ind}, - {ST_NCCI_N_ACT, EV_NCCI_FACILITY_REQ, ncci_facility_req}, - {ST_NCCI_N_ACT, EV_NCCI_MANUFACTURER_REQ, ncci_manufacturer_req}, - - {ST_NCCI_N_4, EV_NCCI_DISCONNECT_B3_CONF, ncci_disconnect_b3_conf}, - {ST_NCCI_N_4, EV_NCCI_DISCONNECT_B3_IND, ncci_disconnect_b3_ind}, - {ST_NCCI_N_4, EV_NCCI_DL_RELEASE_CONF, ncci_dl_release_ind_conf}, - {ST_NCCI_N_4, EV_NCCI_DL_DOWN_IND, ncci_dl_down_ind}, - {ST_NCCI_N_4, EV_NCCI_MANUFACTURER_REQ, ncci_manufacturer_req}, - - {ST_NCCI_N_5, EV_NCCI_DISCONNECT_B3_RESP, ncci_disconnect_b3_resp}, - #if 0 - {ST_NCCI_N_ACT, EV_NCCI_RESET_B3_REQ, ncci_reset_b3_req}, - {ST_NCCI_N_ACT, EV_NCCI_RESET_B3_IND, ncci_reset_b3_ind}, - {ST_NCCI_N_ACT, EV_NCCI_CONNECT_B3_T90_ACTIVE_IND, ncci_connect_b3_t90_active_ind}, - - {ST_NCCI_N_3, EV_NCCI_RESET_B3_IND, ncci_reset_b3_ind}, - {ST_NCCI_N_3, EV_NCCI_DISCONNECT_B3_REQ, ncci_disconnect_b3_req}, - {ST_NCCI_N_3, EV_NCCI_DISCONNECT_B3_IND, ncci_disconnect_b3_ind}, + {ST_NCCI_N_3, EV_NC_RESET_B3_IND, ncci_reset_b3_ind}, + {ST_NCCI_N_3, EV_AP_DISCONNECT_B3_REQ, ncci_disconnect_b3_req}, + {ST_NCCI_N_3, EV_NC_DISCONNECT_B3_IND, ncci_disconnect_b3_ind}, + {ST_NCCI_N_3, EV_AP_RELEASE, ncci_appl_release_disc}, #endif + + {ST_NCCI_N_ACT, EV_AP_CONNECT_B3_ACTIVE_RESP, ncci_connect_b3_active_resp}, + {ST_NCCI_N_ACT, EV_AP_DISCONNECT_B3_REQ, ncci_disconnect_b3_req}, + {ST_NCCI_N_ACT, EV_NC_DISCONNECT_B3_IND, ncci_disconnect_b3_ind}, + {ST_NCCI_N_ACT, EV_DL_RELEASE_IND, ncci_dl_release_ind_conf}, + {ST_NCCI_N_ACT, EV_DL_RELEASE_CONF, ncci_dl_release_ind_conf}, + {ST_NCCI_N_ACT, EV_DL_DOWN_IND, ncci_dl_down_ind}, + {ST_NCCI_N_ACT, EV_AP_FACILITY_REQ, ncci_facility_req}, + {ST_NCCI_N_ACT, EV_AP_MANUFACTURER_REQ, ncci_manufacturer_req}, + {ST_NCCI_N_ACT, EV_AP_RELEASE, ncci_appl_release_disc}, +#if 0 + {ST_NCCI_N_ACT, EV_AP_RESET_B3_REQ, ncci_reset_b3_req}, + {ST_NCCI_N_ACT, EV_NC_RESET_B3_IND, ncci_reset_b3_ind}, + {ST_NCCI_N_ACT, EV_NC_CONNECT_B3_T90_ACTIVE_IND,ncci_connect_b3_t90_active_ind}, +#endif + + {ST_NCCI_N_4, EV_NC_DISCONNECT_B3_CONF, ncci_disconnect_b3_conf}, + {ST_NCCI_N_4, EV_NC_DISCONNECT_B3_IND, ncci_disconnect_b3_ind}, + {ST_NCCI_N_4, EV_DL_RELEASE_CONF, ncci_dl_release_ind_conf}, + {ST_NCCI_N_4, EV_DL_DOWN_IND, ncci_dl_down_ind}, + {ST_NCCI_N_4, EV_AP_MANUFACTURER_REQ, ncci_manufacturer_req}, + + {ST_NCCI_N_5, EV_AP_DISCONNECT_B3_RESP, ncci_disconnect_b3_resp}, + {ST_NCCI_N_5, EV_AP_RELEASE, ncci_disconnect_b3_resp}, }; const int FN_NCCI_COUNT = sizeof(fn_ncci_list)/sizeof(struct FsmNode); -void ncciConstr(Ncci_t *ncci, Cplci_t *cplci) +Ncci_t * +ncciConstr(AppPlci_t *aplci) { - memset(ncci, 0, sizeof(Ncci_t)); + Ncci_t *ncci = ncci_alloc(); + if (!ncci) + return(NULL); + + memset(ncci, 0, sizeof(Ncci_t)); ncci->ncci_m.fsm = &ncci_fsm; ncci->ncci_m.state = ST_NCCI_N_0; - ncci->ncci_m.debug = cplci->plci->contr->debug & CAPI_DBG_NCCI_STATE; + ncci->ncci_m.debug = aplci->plci->contr->debug & CAPI_DBG_NCCI_STATE; ncci->ncci_m.userdata = ncci; ncci->ncci_m.printdebug = ncci_debug; - - ncci->adrNCCI = 0x10000 | cplci->adrPLCI; - ncci->cplci = cplci; - ncci->contr = cplci->contr; - ncci->appl = cplci->appl; - ncci->window = cplci->appl->rp.datablkcnt; + /* we only support one NCCI per AppPlci at the moment */ + ncci->addr = 0x10000 | aplci->addr; + ncci->AppPlci = aplci; + ncci->contr = aplci->contr; + ncci->appl = aplci->appl; + ncci->window = aplci->appl->reg_params.datablkcnt; skb_queue_head_init(&ncci->squeue); if (ncci->window > CAPI_MAXDATAWINDOW) { ncci->window = CAPI_MAXDATAWINDOW; } + printk(KERN_DEBUG "%s: ncci(%p) NCCI(%x) debug (%x/%x)\n", + __FUNCTION__, ncci, ncci->addr, aplci->plci->contr->debug, CAPI_DBG_NCCI_STATE); + return(ncci); } -void ncciInitSt(Ncci_t *ncci) +static void +ncciInitSt(Ncci_t *ncci) { mISDN_pid_t pid; mISDN_stPara_t stpara; int retval; - Cplci_t *cplci = ncci->cplci; + AppPlci_t *aplci = ncci->AppPlci; memset(&pid, 0, sizeof(mISDN_pid_t)); pid.layermask = ISDN_LAYER(1) | ISDN_LAYER(2) | ISDN_LAYER(3) | ISDN_LAYER(4); - if (test_bit(PLCI_FLAG_OUTGOING, &cplci->plci->flags)) + if (test_bit(PLCI_STATE_OUTGOING, &aplci->plci->state)) pid.global = 1; // DTE, orginate else pid.global = 2; // DCE, answer - if (cplci->Bprotocol.B1protocol > 23) { - int_errtxt("wrong B1 prot %x", cplci->Bprotocol.B1protocol); + if (aplci->Bprotocol.B1 > 23) { + int_errtxt("wrong B1 prot %x", aplci->Bprotocol.B1); return; } - pid.protocol[1] = (1 << cplci->Bprotocol.B1protocol) | + pid.protocol[1] = (1 << aplci->Bprotocol.B1) | ISDN_PID_LAYER(1) | ISDN_PID_BCHANNEL_BIT; - if (cplci->Bprotocol.B2protocol > 23) { - int_errtxt("wrong B2 prot %x", cplci->Bprotocol.B2protocol); + if (aplci->Bprotocol.B2 > 23) { + int_errtxt("wrong B2 prot %x", aplci->Bprotocol.B2); return; } - if (cplci->Bprotocol.B2protocol == 0) /* X.75 has own flowctrl */ - ncci->Flags = 0; + if (aplci->Bprotocol.B2 == 0) /* X.75 has own flowctrl */ + ncci->state = 0; else - ncci->Flags = NCCI_FLG_FCTRL; - pid.protocol[2] = (1 << cplci->Bprotocol.B2protocol) | + ncci->state = NCCI_STATE_FCTRL; + pid.protocol[2] = (1 << aplci->Bprotocol.B2) | ISDN_PID_LAYER(2) | ISDN_PID_BCHANNEL_BIT; /* handle DTMF TODO */ if ((pid.protocol[2] == ISDN_PID_L2_B_TRANS) && (pid.protocol[1] == ISDN_PID_L1_B_64TRANS)) pid.protocol[2] = ISDN_PID_L2_B_TRANSDTMF; - if (cplci->Bprotocol.B3protocol > 23) { - int_errtxt("wrong B3 prot %x", cplci->Bprotocol.B3protocol); + if (aplci->Bprotocol.B3 > 23) { + int_errtxt("wrong B3 prot %x", aplci->Bprotocol.B3); return; } - pid.protocol[3] = (1 << cplci->Bprotocol.B3protocol) | + pid.protocol[3] = (1 << aplci->Bprotocol.B3) | ISDN_PID_LAYER(3) | ISDN_PID_BCHANNEL_BIT; capidebug(CAPI_DBG_NCCI, "ncciInitSt B1(%x) B2(%x) B3(%x) global(%d) ch(%x)", pid.protocol[1], pid.protocol[2], pid.protocol[3], pid.global, - cplci->bchannel); - capidebug(CAPI_DBG_NCCI, "ncciInitSt ch(%d) cplci->contr->binst(%p)", - cplci->bchannel & 3, cplci->contr->binst); + aplci->channel); + capidebug(CAPI_DBG_NCCI, "ncciInitSt ch(%d) aplci->contr->binst(%p)", + aplci->channel & 3, aplci->contr->binst); pid.protocol[4] = ISDN_PID_L4_B_CAPI20; - ncci->binst = contrSelChannel(cplci->contr, cplci->bchannel); + ncci->binst = ControllerSelChannel(aplci->contr, aplci->channel); if (!ncci->binst) { int_error(); return; @@ -504,7 +618,7 @@ void ncciInitSt(Ncci_t *ncci) __FUNCTION__, retval); return; } - stpara.maxdatalen = ncci->appl->rp.datablklen; + stpara.maxdatalen = ncci->appl->reg_params.datablklen; stpara.up_headerlen = CAPI_B3_DATA_IND_HEADER_SIZE; stpara.down_headerlen = 0; @@ -523,7 +637,8 @@ void ncciInitSt(Ncci_t *ncci) } } -void ncciReleaseSt(Ncci_t *ncci) +static void +ncciReleaseSt(Ncci_t *ncci) { int retval; @@ -538,40 +653,47 @@ void ncciReleaseSt(Ncci_t *ncci) } } -void ncciLinkUp(Ncci_t *ncci) +void +ncciLinkUp(Ncci_t *ncci) { #ifdef OLDCAPI_DRIVER_INTERFACE - ncci->contr->ctrl->new_ncci(ncci->contr->ctrl, ncci->appl->ApplId, ncci->adrNCCI, ncci->window); + ncci->contr->ctrl->new_ncci(ncci->contr->ctrl, ncci->appl->ApplId, ncci->addr, ncci->window); #endif ncciInitSt(ncci); } -void ncciLinkDown(Ncci_t *ncci) +void +ncciLinkDown(Ncci_t *ncci) { if (ncci->binst) ncciReleaseSt(ncci); - FsmEvent(&ncci->ncci_m, EV_NCCI_DL_DOWN_IND, 0); + FsmEvent(&ncci->ncci_m, EV_DL_DOWN_IND, 0); } -__u16 ncciSelectBprotocol(Ncci_t *ncci) +__u16 +ncciSelectBprotocol(Ncci_t *ncci) { int retval; - retval = FsmEvent(&ncci->ncci_m, EV_NCCI_SELECT_B_PROTOCOL, 0); + retval = FsmEvent(&ncci->ncci_m, EV_AP_SELECT_B_PROTOCOL, 0); if (retval) return CapiMessageNotSupportedInCurrentState; return CapiSuccess; } -void ncciDestr(Ncci_t *ncci) +void +ncciDestr(Ncci_t *ncci) { int i; - capidebug(CAPI_DBG_NCCI, "ncciDestr NCCI %x", ncci->adrNCCI); + printk(KERN_DEBUG "%s: ncci(%p) NCCI(%x)\n", + __FUNCTION__, ncci, ncci->addr); + capidebug(CAPI_DBG_NCCI, "ncciDestr NCCI %x", ncci->addr); if (ncci->binst) ncciReleaseSt(ncci); - if (ncci->appl) + #ifdef OLDCAPI_DRIVER_INTERFACE - ncci->contr->ctrl->free_ncci(ncci->contr->ctrl, ncci->appl->ApplId, ncci->adrNCCI); + if (!test_bit(NCCI_STATE_APPLRELEASED, &ncci->state)) + ncci->contr->ctrl->free_ncci(ncci->contr->ctrl, ncci->appl->ApplId, ncci->addr); #endif /* cleanup data queues */ discard_queue(&ncci->squeue); @@ -579,9 +701,29 @@ void ncciDestr(Ncci_t *ncci) if (ncci->xmit_skb_handles[i].skb) ncci->xmit_skb_handles[i].skb = NULL; } + if (ncci->AppPlci) + AppPlciDelNCCI(ncci->AppPlci); + ncci_free(ncci); } -void ncciDataInd(Ncci_t *ncci, int pr, struct sk_buff *skb) +void +ncciApplRelease(Ncci_t *ncci) +{ + test_and_set_bit(NCCI_STATE_APPLRELEASED, &ncci->state); + FsmEvent(&ncci->ncci_m, EV_AP_RELEASE, NULL); +} + +void +ncciDelAppPlci(Ncci_t *ncci) +{ + printk(KERN_DEBUG "%s: ncci(%p) NCCI(%x)\n", + __FUNCTION__, ncci, ncci->addr); + ncci->AppPlci = NULL; + /* maybe we should release the NCCI here */ +} + +void +ncciDataInd(Ncci_t *ncci, int pr, struct sk_buff *skb) { struct sk_buff *nskb; int i; @@ -618,7 +760,7 @@ void ncciDataInd(Ncci_t *ncci, int pr, struct sk_buff *skb) *((__u8*) (nskb->data+4)) = CAPI_DATA_B3; *((__u8*) (nskb->data+5)) = CAPI_IND; *((__u16*)(nskb->data+6)) = ncci->appl->MsgId++; - *((__u32*)(nskb->data+8)) = ncci->adrNCCI; + *((__u32*)(nskb->data+8)) = ncci->addr; if (sizeof(nskb) == 4) { *((__u32*)(nskb->data+12)) = (__u32)(nskb->data + CAPI_B3_DATA_IND_HEADER_SIZE); *((__u64*)(nskb->data+22)) = 0; @@ -637,10 +779,12 @@ void ncciDataInd(Ncci_t *ncci, int pr, struct sk_buff *skb) #endif } -void ncciDataReq(Ncci_t *ncci, struct sk_buff *skb) +void +ncciDataReq(Ncci_t *ncci, struct sk_buff *skb) { int i, err; __u16 len, capierr = 0; + _cmsg *cmsg; len = CAPIMSG_LEN(skb->data); if (len != 22 && len != 30) { @@ -665,8 +809,8 @@ void ncciDataReq(Ncci_t *ncci, struct sk_buff *skb) /* the data begins behind the header, we don't use Data32/Data64 here */ skb_pull(skb, len); - if (ncci->Flags & NCCI_FLG_FCTRL) { - if (test_and_set_bit(NCCI_FLG_BUSY, &ncci->Flags)) { + if (ncci->state & NCCI_STATE_FCTRL) { + if (test_and_set_bit(NCCI_STATE_BUSY, &ncci->state)) { skb_queue_tail(&ncci->squeue, skb); return; } @@ -695,18 +839,26 @@ void ncciDataReq(Ncci_t *ncci, struct sk_buff *skb) ncci->xmit_skb_handles[i].skb = NULL; } fail: - capi_cmsg_header(&ncci->tmpmsg, ncci->cplci->appl->ApplId, CAPI_DATA_B3, CAPI_CONF, - CAPIMSG_MSGID(skb->data), ncci->adrNCCI); + cmsg = cmsg_alloc(); + if (!cmsg) { + int_error(); + dev_kfree_skb(skb); + return; + } + capi_cmsg_header(cmsg, ncci->AppPlci->appl->ApplId, CAPI_DATA_B3, CAPI_CONF, + CAPIMSG_MSGID(skb->data), ncci->addr); /* illegal len (too short) ??? */ - ncci->tmpmsg.DataHandle = CAPIMSG_REQ_DATAHANDLE(skb->data); - ncci->tmpmsg.Info = capierr; - ncciRecvCmsg(ncci, &ncci->tmpmsg); + cmsg->DataHandle = CAPIMSG_REQ_DATAHANDLE(skb->data); + cmsg->Info = capierr; + Send2Application(ncci, cmsg); dev_kfree_skb(skb); } -int ncciDataConf(Ncci_t *ncci, int pr, struct sk_buff *skb) +int +ncciDataConf(Ncci_t *ncci, int pr, struct sk_buff *skb) { - int i; + int i; + _cmsg *cmsg; for (i = 0; i < ncci->window; i++) { if (ncci->xmit_skb_handles[i].skb == skb) @@ -719,13 +871,19 @@ int ncciDataConf(Ncci_t *ncci, int pr, struct sk_buff *skb) ncci->xmit_skb_handles[i].skb = NULL; capidebug(CAPI_DBG_NCCI_L3, "%s: entry %d/%d handle (%x)", __FUNCTION__, i, ncci->window, ncci->xmit_skb_handles[i].DataHandle); + + cmsg = cmsg_alloc(); + if (!cmsg) { + int_error(); + return(-ENOMEM); + } dev_kfree_skb(skb); - capi_cmsg_header(&ncci->tmpmsg, ncci->cplci->appl->ApplId, CAPI_DATA_B3, CAPI_CONF, - ncci->xmit_skb_handles[i].MsgId, ncci->adrNCCI); - ncci->tmpmsg.DataHandle = ncci->xmit_skb_handles[i].DataHandle; - ncci->tmpmsg.Info = 0; - ncciRecvCmsg(ncci, &ncci->tmpmsg); - if (ncci->Flags & NCCI_FLG_FCTRL) { + capi_cmsg_header(cmsg, ncci->AppPlci->appl->ApplId, CAPI_DATA_B3, CAPI_CONF, + ncci->xmit_skb_handles[i].MsgId, ncci->addr); + cmsg->DataHandle = ncci->xmit_skb_handles[i].DataHandle; + cmsg->Info = 0; + Send2Application(ncci, cmsg); + if (ncci->state & NCCI_STATE_FCTRL) { if (skb_queue_len(&ncci->squeue)) { skb = skb_dequeue(&ncci->squeue); if (ncciL4L3(ncci, DL_DATA | REQUEST, DINFO_SKB, @@ -734,12 +892,13 @@ int ncciDataConf(Ncci_t *ncci, int pr, struct sk_buff *skb) dev_kfree_skb(skb); } } else - test_and_clear_bit(NCCI_FLG_BUSY, &ncci->Flags); + test_and_clear_bit(NCCI_STATE_BUSY, &ncci->state); } return(0); } -void ncciDataResp(Ncci_t *ncci, struct sk_buff *skb) +void +ncciDataResp(Ncci_t *ncci, struct sk_buff *skb) { // FIXME: incoming flow control doesn't work yet @@ -759,17 +918,59 @@ void ncciDataResp(Ncci_t *ncci, struct sk_buff *skb) dev_kfree_skb(skb); } -void ncciSendMessage(Ncci_t *ncci, struct sk_buff *skb) +void +ncciGetCmsg(Ncci_t *ncci, _cmsg *cmsg) { - int retval = 0; + int retval = 0; - // we're not using the cmesg for DATA_B3 for performance reasons + switch (CMSGCMD(cmsg)) { + case CAPI_CONNECT_B3_REQ: + retval = FsmEvent(&ncci->ncci_m, EV_AP_CONNECT_B3_REQ, cmsg); + break; + case CAPI_CONNECT_B3_RESP: + retval = FsmEvent(&ncci->ncci_m, EV_AP_CONNECT_B3_RESP, cmsg); + break; + case CAPI_CONNECT_B3_ACTIVE_RESP: + retval = FsmEvent(&ncci->ncci_m, EV_AP_CONNECT_B3_ACTIVE_RESP, cmsg); + break; + case CAPI_DISCONNECT_B3_REQ: + retval = FsmEvent(&ncci->ncci_m, EV_AP_DISCONNECT_B3_REQ, cmsg); + break; + case CAPI_DISCONNECT_B3_RESP: + retval = FsmEvent(&ncci->ncci_m, EV_AP_DISCONNECT_B3_RESP, cmsg); + break; + case CAPI_FACILITY_REQ: + retval = FsmEvent(&ncci->ncci_m, EV_AP_FACILITY_REQ, cmsg); + break; + case CAPI_MANUFACTURER_REQ: + retval = FsmEvent(&ncci->ncci_m, EV_AP_MANUFACTURER_REQ, cmsg); + break; + default: + int_error(); + retval = -1; + } + if (retval) { + if (cmsg->Command == CAPI_REQ) { + capi_cmsg_answer(cmsg); + cmsg->Info = CapiMessageNotSupportedInCurrentState; + Send2Application(ncci, cmsg); + } else + cmsg_free(cmsg); + } +} + +void +ncciSendMessage(Ncci_t *ncci, struct sk_buff *skb) +{ + _cmsg *cmsg; + + // we're not using the cmsg for DATA_B3 for performance reasons switch (CAPICMD(CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data))) { case CAPI_DATA_B3_REQ: if (ncci->ncci_m.state == ST_NCCI_N_ACT) { ncciDataReq(ncci, skb); } else { - contrAnswerMessage(ncci->cplci->contr, skb, + AnswerMessage2Application(ncci->appl, skb, CapiMessageNotSupportedInCurrentState); dev_kfree_skb(skb); } @@ -778,54 +979,22 @@ void ncciSendMessage(Ncci_t *ncci, struct sk_buff *skb) ncciDataResp(ncci, skb); return; } - - capi_message2cmsg(&ncci->tmpmsg, skb->data); - switch (CMSGCMD(&ncci->tmpmsg)) { - case CAPI_CONNECT_B3_REQ: - retval = FsmEvent(&ncci->ncci_m, EV_NCCI_CONNECT_B3_REQ, - &ncci->tmpmsg); - break; - case CAPI_CONNECT_B3_RESP: - retval = FsmEvent(&ncci->ncci_m, EV_NCCI_CONNECT_B3_RESP, - &ncci->tmpmsg); - break; - case CAPI_CONNECT_B3_ACTIVE_RESP: - retval = FsmEvent(&ncci->ncci_m, EV_NCCI_CONNECT_B3_ACTIVE_RESP, - &ncci->tmpmsg); - break; - case CAPI_DISCONNECT_B3_REQ: - retval = FsmEvent(&ncci->ncci_m, EV_NCCI_DISCONNECT_B3_REQ, - &ncci->tmpmsg); - break; - case CAPI_DISCONNECT_B3_RESP: - retval = FsmEvent(&ncci->ncci_m, EV_NCCI_DISCONNECT_B3_RESP, - &ncci->tmpmsg); - break; - case CAPI_FACILITY_REQ: - retval = FsmEvent(&ncci->ncci_m, EV_NCCI_FACILITY_REQ, - &ncci->tmpmsg); - break; - case CAPI_MANUFACTURER_REQ: - retval = FsmEvent(&ncci->ncci_m, EV_NCCI_MANUFACTURER_REQ, - &ncci->tmpmsg); - break; - default: - int_error(); - retval = -1; - } - if (retval) { - if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_REQ) { - contrAnswerMessage(ncci->cplci->contr, skb, - CapiMessageNotSupportedInCurrentState); - } + cmsg = cmsg_alloc(); + if (!cmsg) { + int_error(); + dev_kfree_skb(skb); + return; } + capi_message2cmsg(cmsg, skb->data); + ncciGetCmsg(ncci, cmsg); dev_kfree_skb(skb); } -int ncci_l3l4(mISDNif_t *hif, struct sk_buff *skb) +int +ncci_l3l4(mISDNif_t *hif, struct sk_buff *skb) { - Ncci_t *ncci; + Ncci_t *ncci; int ret = -EINVAL; mISDN_head_t *hh; @@ -834,7 +1003,7 @@ int ncci_l3l4(mISDNif_t *hif, struct sk_buff *skb) hh = mISDN_HEAD_P(skb); ncci = hif->fdata; capidebug(CAPI_DBG_NCCI_L3, "%s: NCCI %x prim(%x) dinfo (%x) skb(%p)", - __FUNCTION__, ncci->adrNCCI, hh->prim, hh->dinfo, skb); + __FUNCTION__, ncci->addr, hh->prim, hh->dinfo, skb); switch (hh->prim) { // we're not using the Fsm for DL_DATA for performance reasons case DL_DATA | INDICATION: @@ -849,20 +1018,20 @@ int ncci_l3l4(mISDNif_t *hif, struct sk_buff *skb) } break; case DL_ESTABLISH | INDICATION: - FsmEvent(&ncci->ncci_m, EV_NCCI_DL_ESTABLISH_IND, skb); + FsmEvent(&ncci->ncci_m, EV_DL_ESTABLISH_IND, skb); break; case DL_ESTABLISH | CONFIRM: - FsmEvent(&ncci->ncci_m, EV_NCCI_DL_ESTABLISH_CONF, skb); + FsmEvent(&ncci->ncci_m, EV_DL_ESTABLISH_CONF, skb); break; case DL_RELEASE | INDICATION: - FsmEvent(&ncci->ncci_m, EV_NCCI_DL_RELEASE_IND, skb); + FsmEvent(&ncci->ncci_m, EV_DL_RELEASE_IND, skb); break; case DL_RELEASE | CONFIRM: - FsmEvent(&ncci->ncci_m, EV_NCCI_DL_RELEASE_CONF, skb); + FsmEvent(&ncci->ncci_m, EV_DL_RELEASE_CONF, skb); break; case PH_CONTROL | INDICATION: /* e.g touch tones */ - /* handled by cplci */ - cplci_l3l4(ncci->cplci, hh->prim, skb->data); + /* handled by AppPlci */ + AppPlci_l3l4(ncci->AppPlci, hh->prim, skb->data); break; default: capidebug(CAPI_DBG_WARN, "%s: unknown prim(%x) dinfo(%x) len(%d) skb(%p)", @@ -878,7 +1047,7 @@ static int ncciL4L3(Ncci_t *ncci, u_int prim, int dtyp, int len, void *arg, struct sk_buff *skb) { capidebug(CAPI_DBG_NCCI_L3, "%s: NCCI %x prim(%x) dtyp(%x) skb(%p)", - __FUNCTION__, ncci->adrNCCI, prim, dtyp, skb); + __FUNCTION__, ncci->addr, prim, dtyp, skb); if (skb) return(if_newhead(&ncci->binst->inst.down, prim, dtyp, skb)); else @@ -886,7 +1055,8 @@ ncciL4L3(Ncci_t *ncci, u_int prim, int dtyp, int len, void *arg, struct sk_buff len, arg, 8)); } -void init_ncci(void) +void +init_ncci(void) { ncci_fsm.state_count = ST_NCCI_COUNT; ncci_fsm.event_count = EV_NCCI_COUNT; @@ -896,7 +1066,8 @@ void init_ncci(void) FsmNew(&ncci_fsm, fn_ncci_list, FN_NCCI_COUNT); } -void free_ncci(void) +void +free_ncci(void) { FsmFree(&ncci_fsm); } diff --git a/drivers/isdn/hardware/mISDN/plci.c b/drivers/isdn/hardware/mISDN/plci.c index 2036b77..f48fc11 100644 --- a/drivers/isdn/hardware/mISDN/plci.c +++ b/drivers/isdn/hardware/mISDN/plci.c @@ -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); diff --git a/drivers/isdn/hardware/mISDN/supp_serv.c b/drivers/isdn/hardware/mISDN/supp_serv.c index 6828c8f..617d3ad 100644 --- a/drivers/isdn/hardware/mISDN/supp_serv.c +++ b/drivers/isdn/hardware/mISDN/supp_serv.c @@ -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;