diff --git a/capi20/application.c b/capi20/application.c index a5e8e81..b54af4a 100644 --- a/capi20/application.c +++ b/capi20/application.c @@ -175,6 +175,18 @@ void SendCmsgAnswer2Application(struct mApplication *appl, struct mc_buf *mc, __ SendCmsg2Application(appl, mc); } +struct lPLCI *get_lPLCI4plci(struct mApplication *appl, uint32_t id) +{ + struct lController *lc; + struct mPLCI *plci; + + lc = get_lController(appl, id & 0x7f); + if (!lc) + return NULL; + plci = getPLCI4Id(lc->Contr, id & 0xFFFF); + return get_lPLCI4Id(plci, appl->AppId); +} + #define CapiFacilityNotSupported 0x300b static int FacilityMessage(struct mApplication *appl, struct pController *pc, struct mc_buf *mc) diff --git a/capi20/daemon.c b/capi20/daemon.c index 3b0f328..59d44ca 100644 --- a/capi20/daemon.c +++ b/capi20/daemon.c @@ -11,15 +11,16 @@ * this package for more details. */ +#include +#include #include #include -#include #include #include -#include #include #include #include +#include #include "m_capi.h" #include "mc_buffer.h" #include "m_capi_sock.h" @@ -30,6 +31,14 @@ /* should be moved to capi_debug.h */ #include +/* for some reasons when _XOPEN_SOURCE 600 was defined lot of other things are not longer + * defined so use this as workaround + */ + +extern int grantpt(int fd); +extern int unlockpt(int fd); +extern int ptsname_r(int fd, char *buf, size_t buflen); + #ifndef DEF_CONFIG_FILE #define DEF_CONFIG_FILE "/etc/capi20.conf" #endif @@ -369,38 +378,126 @@ struct BInstance *ControllerSelChannel(struct pController *pc, int nr, int proto return bi; } + +static int Create_tty(struct BInstance *bi) +{ + int ret, pmod; + + ret = posix_openpt(O_RDWR | O_NOCTTY); + if (ret < 0) { + eprint("Cannot open terminal - %s\n", strerror(errno)); + } else { + bi->tty = ret; + ret = grantpt(bi->tty); + if (ret < 0) { + eprint("Error on grantpt - %s\n", strerror(errno)); + close(bi->tty); + bi->tty = -1; + } else { + ret = unlockpt(bi->tty); + if (ret < 0) { + eprint("Error on unlockpt - %s\n", strerror(errno)); + close(bi->tty); + bi->tty = -1; + } else { + /* packet mode */ + pmod = 1; + ret = ioctl(bi->tty, TIOCPKT, &pmod); + if (ret < 0) { + eprint("Cannot set packet mode - %s\n", strerror(errno)); + close(bi->tty); + bi->tty = -1; + } + } + + } + } + return ret; +} + static int recvBchannel(struct BInstance *); + +static int recv_tty(struct BInstance *bi) +{ + int ret, maxl; + struct mc_buf *mc; + + mc = alloc_mc_buf(); + if (!mc) + return -ENOMEM; + if (!bi) + return -EINVAL; + mc->rp = mc->rb + 8; + maxl = MC_RB_SIZE - 8; + ret = read(bi->tty, mc->rp, maxl); + if (ret < 0) { + wprint("Error on reading from tty %d errno %d - %s\n", bi->tty, errno, strerror(errno)); + ret = -errno; + } else if (ret == 0) { + /* closed */ + wprint("Read 0 bytes from tty %d\n", bi->tty); + ret = -ECONNABORTED; + } else if (ret == maxl) { + eprint("Message too big %d ctrl %02x (%02x%02x%02x%02x%02x%02x%02x%02x)\n", + ret, mc->rp[0], mc->rp[1], mc->rp[2], mc->rp[3], mc->rp[4], mc->rp[5], mc->rp[6], mc->rp[7], mc->rp[8]); + ret = -EMSGSIZE; + } + if (ret > 0) { + mc->len = ret; + /* Fake length of DATA_B3 REQ to pass offset check */ + capimsg_setu16(mc->rb, 0, 22); + mc->cmsg.Command = CAPI_DATA_TTY; + mc->cmsg.Subcommand = CAPI_REQ; + ret = bi->from_up(bi, mc); + } + + if (ret != 0) /* if message is not queued or freed */ + free_mc_buf(mc); + return ret; +} + static void *BCthread(void *arg) { struct BInstance *bi = arg; unsigned char cmd; - int ret; + int ret, i; bi->running = 1; while (bi->running) { - ret = poll(bi->pfd, 2, -1); + ret = poll(bi->pfd, bi->pcnt, -1); if (ret < 0) { wprint("Bchannel%d Error on poll - %s\n", bi->nr, strerror(errno)); continue; } + for (i = 1; i < bi->pcnt; i++) { + if (bi->pfd[i].revents & POLLIN) { + switch(i) { + case 1: + ret = recvBchannel(bi); + break; + case 2: + ret = recv_tty(bi); + break; + default: + wprint("Bchannel%d poll idx %d not handled\n", bi->nr, i); + } + } + } + if (bi->pfd[0].revents & POLLIN) { - ret = recvBchannel(bi); - } else if (bi->pfd[1].revents & POLLIN) { - ret = read(bi->pfd[1].fd, &cmd, 1); + ret = read(bi->pfd[0].fd, &cmd, 1); if (cmd == 42) { bi->running = 0; } - } else { - wprint("Bchannel%d no POLLIN event\n", bi->nr); } } return NULL; } -static int CreateBchannelThread(struct BInstance *bi) +static int CreateBchannelThread(struct BInstance *bi, int pcnt) { - int ret; + int ret, i; ret = pipe(bi->cpipe); if (ret) { @@ -417,10 +514,11 @@ static int CreateBchannelThread(struct BInstance *bi) eprint("error - %s\n", strerror(errno)); return ret; } - bi->pfd[0].fd = bi->fd; + bi->pfd[0].fd = bi->cpipe[0]; bi->pfd[0].events = POLLIN | POLLPRI; - bi->pfd[1].fd = bi->cpipe[0]; + bi->pfd[1].fd = bi->fd; bi->pfd[1].events = POLLIN | POLLPRI; + bi->pcnt = pcnt; ret = pthread_create(&bi->tid, NULL, BCthread, bi); if (ret) { eprint("Cannot create thread error - %s\n", strerror(errno)); @@ -429,7 +527,8 @@ static int CreateBchannelThread(struct BInstance *bi) bi->cpipe[0] = -1; bi->cpipe[1] = -1; bi->pfd[0].fd = -1; - bi->pfd[1].fd = -1; + for (i = 1; i < bi->pcnt; i++) + bi->pfd[i].fd = -1; } else iprint("Created Bchannel tread %d\n", (int)bi->tid); return ret; @@ -437,7 +536,7 @@ static int CreateBchannelThread(struct BInstance *bi) static int StopBchannelThread(struct BInstance *bi) { - int ret; + int ret, i; unsigned char cmd; if (bi->running) { @@ -453,7 +552,9 @@ static int StopBchannelThread(struct BInstance *bi) close(bi->cpipe[0]); close(bi->cpipe[1]); bi->pfd[0].fd = -1; - bi->pfd[1].fd = -1; + for (i = 1; i < bi->pcnt; i++) + bi->pfd[i].fd = -1; + bi->pcnt = 0; bi->cpipe[0] = -1; bi->cpipe[1] = -1; } @@ -496,11 +597,15 @@ int OpenBInstance(struct BInstance *bi, struct lPLCI *lp, enum BType btype) bi->from_up = ncciB3Data; break; #ifdef USE_SOFTFAX - case BType_Fax: + case BType_Fax: bi->from_down = FaxRecvBData; bi->from_up = FaxB3Message; break; #endif + case BType_tty: + bi->from_down = recvBdirect; + bi->from_up = ncciB3Data; + break; default: eprint("Error unnkown BType %d\n", btype); close(sk); @@ -538,10 +643,33 @@ int OpenBInstance(struct BInstance *bi, struct lPLCI *lp, enum BType btype) bi->UpId = 0; bi->DownId = 0; } - } else { - ret = CreateBchannelThread(bi); + } else if (btype == BType_Fax) { + ret = CreateBchannelThread(bi, 2); if (ret < 0) { - eprint("Error while creating B-channel thread)\n"); + eprint("Error while creating B%d-channel thread\n", bi->nr); + close(sk); + bi->fd = -1; + bi->lp = NULL; + } else { + ret = 0; + bi->UpId = 0; + bi->DownId = 0; + } + } else if (btype == BType_tty) { + ret = Create_tty(bi); + if (ret < 0) { + eprint("Error while creating B%d-channel tty\n", bi->nr); + close(sk); + bi->fd = -1; + bi->lp = NULL; + return ret; + } else { + bi->pfd[2].fd = bi->tty; + bi->pfd[2].events = POLLIN | POLLPRI; + ret = CreateBchannelThread(bi, 3); + } + if (ret < 0) { + eprint("Error while creating B%d-channel thread\n", bi->nr); close(sk); bi->fd = -1; bi->lp = NULL; @@ -570,6 +698,11 @@ int CloseBInstance(struct BInstance *bi) StopBchannelThread(bi); break; #endif + case BType_tty: + StopBchannelThread(bi); + if (bi->tty > -1) + close(bi->tty); + bi->tty = -1; default: break; } @@ -915,6 +1048,70 @@ static void misdn_manufacturer_req(int fd, struct mc_buf *mc) eprint("error send %d/%d - %s\n", ret, 10, strerror(errno)); } +static void mIcapi_userflag(int fd, int idx, struct mc_buf *mc) +{ + int ret; + struct mApplication *appl = pollinfo[idx].data; + uint32_t sf, cf, uf = 0xffffffff; + + CAPIMSG_SETSUBCOMMAND(mc->rb, CAPI_CONF); + capimsg_setu16(mc->rb, 0, 12); + if (appl) { + uf = appl->UserFlags; + sf = CAPIMSG_U32(mc->rb, 8); + cf = CAPIMSG_U32(mc->rb, 12); + if (cf) + uf &= ~cf; + if (sf) + uf |= sf; + iprint("UserFlags old=%x new=%x\n", appl->UserFlags, uf); + appl->UserFlags = uf; + } + capimsg_setu32(mc->rb, 8, uf); + ret = send(fd, mc->rb, 12, 0); + if (ret != 12) + eprint("error send %d/%d - %s\n", ret, 12, strerror(errno)); +} + +static void mIcapi_ttyname(int fd, int idx, struct mc_buf *mc) +{ + int ret, ml, l = 0; + struct mApplication *appl = pollinfo[idx].data; + struct lPLCI *lp; + uint32_t ncci = 0; + char name[80]; + + CAPIMSG_SETSUBCOMMAND(mc->rb, CAPI_CONF); + if (appl) { + ncci = CAPIMSG_U32(mc->rb, 8); + ml = CAPIMSG_U32(mc->rb, 12); + if (appl->UserFlags & CAPIFLAG_HIGHJACKING) { + lp = get_lPLCI4plci(appl, ncci); + if (lp->BIlink && lp->BIlink->tty > -1) { + ret = ptsname_r(lp->BIlink->tty, name, 80); + if (ret) + eprint("NCCI %06x: error to get ptsname for %d - %s\n", + ncci, lp->BIlink->tty, strerror(errno)); + else + l = strlen(name); + } else + eprint("NCCI %06x: do not find lPLCI for NCCI\n", ncci); + } + } + if (l >= ml) + l = 0; + if (l) { + iprint("NCCI %06x: ttyname set to %s\n", ncci, name); + memcpy(&mc->rb[8], name, l); + } else + wprint("NCCI %06x: ttyname requested but not available\n", ncci); + mc->rb[8 + l] = 0; + capimsg_setu16(mc->rb, 0, l + 8); + ret = send(fd, mc->rb, l + 8, 0); + if (ret != l + 8) + eprint("error send %d/%d - %s\n", ret, 12, strerror(errno)); +} + static int main_recv(int fd, int idx) { int ret, len, cmd, dl; @@ -980,6 +1177,12 @@ static int main_recv(int fd, int idx) case MIC_MANUFACTURER_REQ: misdn_manufacturer_req(fd, mc); break; + case MIC_USERFLAG_REQ: + mIcapi_userflag(fd, idx, mc); + break; + case MIC_TTYNAME_REQ: + mIcapi_ttyname(fd, idx, mc); + break; default: if (pollinfo[idx].type == PIT_Application) ret = PutMessageApplication(pollinfo[idx].data, mc); @@ -1236,6 +1439,7 @@ int main(int argc, char *argv[]) pc->BInstances[j].nr = j; pc->BInstances[j].pc = pc; pc->BInstances[j].fd = -1; + pc->BInstances[j].tty = -1; sem_init(&pc->BInstances[j].wait, 0, 0); } pc->profile.ncontroller = i + 1; diff --git a/capi20/lplci.c b/capi20/lplci.c index 248fb85..080b057 100644 --- a/capi20/lplci.c +++ b/capi20/lplci.c @@ -1642,6 +1642,7 @@ static int lPLCILinkUp(struct lPLCI *lp) int proto = -1, ret = 0, act_l1; struct mISDNhead mh; enum BType btype = BType_None; + struct mApplication *ap = lp->lc->Appl; mh.id = 1; mh.prim = 0; @@ -1716,6 +1717,9 @@ static int lPLCILinkUp(struct lPLCI *lp) if (ret) return ret; + if (ap->UserFlags & CAPIFLAG_HIGHJACKING) { + btype = BType_tty; + } dprint(MIDEBUG_PLCI, "lPLCILinkUp B1(%x) B2(%x) B3(%x) ch(%d) proto(%x)\n", lp->Bprotocol.B1, lp->Bprotocol.B2, lp->Bprotocol.B3, lp->chid.nr, proto); diff --git a/capi20/m_capi.h b/capi20/m_capi.h index 4bb80d8..7caf79b 100644 --- a/capi20/m_capi.h +++ b/capi20/m_capi.h @@ -61,7 +61,8 @@ typedef int (BDataTrans_t)(struct BInstance *, struct mc_buf *); enum BType { BType_None = 0, BType_Direct = 1, - BType_Fax = 2 + BType_Fax = 2, + BType_tty = 3 }; struct BInstance { @@ -69,6 +70,7 @@ struct BInstance { int usecnt; int proto; int fd; + int tty; enum BType type; uint16_t DownId; /* Ids for send down messages */ uint16_t UpId; /* Ids for send up messages */ @@ -78,7 +80,8 @@ struct BInstance { BDataTrans_t *from_down; BDataTrans_t *from_up; pthread_t tid; - struct pollfd pfd[2]; + struct pollfd pfd[4]; + int pcnt; int cpipe[2]; sem_t wait; unsigned int running:1; @@ -154,6 +157,7 @@ struct mApplication { int MaxB3Con; int MaxB3Blk; int MaxB3Size; + uint32_t UserFlags; }; struct mApplication *RegisterApplication(uint16_t, uint32_t, uint32_t, uint32_t); @@ -217,6 +221,7 @@ struct mNCCI *getNCCI4addr(struct lPLCI *, uint32_t, int); void lPLCIDelNCCI(struct mNCCI *); struct mNCCI *ConnectB3Request(struct lPLCI *, struct mc_buf *); void B3ReleaseLink(struct lPLCI *, struct BInstance *); +struct lPLCI *get_lPLCI4plci(struct mApplication *, uint32_t); #define GET_NCCI_EXACT 1 #define GET_NCCI_ONLY_PLCI 2 @@ -265,6 +270,7 @@ struct mNCCI { unsigned char up_header[30]; unsigned int dtmflisten:1; unsigned int l1direct:1; + unsigned int l1trans:1; unsigned int l2trans:1; unsigned int l3trans:1; unsigned int dlbusy:1; @@ -362,6 +368,11 @@ void mCapi_message2str(struct mc_buf *); #define CAPI_B3_DATA_IND_HEADER_SIZE ((4 == sizeof(void *)) ? 22 : 30) + +#define CAPIFLAG_HIGHJACKING 1 + +#define CAPI_DATA_TTY 0xe0 + /* some helper */ static inline int capiEncodeWord(unsigned char *p, uint16_t i) { diff --git a/capi20/m_capi_sock.h b/capi20/m_capi_sock.h index 9e6fe6a..9c19485 100644 --- a/capi20/m_capi_sock.h +++ b/capi20/m_capi_sock.h @@ -37,6 +37,8 @@ extern "C" { #define MIC_VERSION_REQ CAPICMD(0xf4, 0xff) #define MIC_GET_MANUFACTURER_REQ CAPICMD(0xf5, 0xff) #define MIC_MANUFACTURER_REQ CAPICMD(0xf6, 0xff) +#define MIC_USERFLAG_REQ CAPICMD(0xf7, 0xff) +#define MIC_TTYNAME_REQ CAPICMD(0xf8, 0xff) #ifdef __cplusplus diff --git a/capi20/module/capi_mod_misdn.c b/capi20/module/capi_mod_misdn.c index 3143b11..4d3710b 100644 --- a/capi20/module/capi_mod_misdn.c +++ b/capi20/module/capi_mod_misdn.c @@ -422,6 +422,87 @@ static unsigned misdnGetProfile(int nHandle, unsigned nController, unsigned char return err; } +static int misdnFlagReq(uint16_t ApplId, uint32_t set_f, uint32_t clr_f) +{ + unsigned char anBuf[100]; + int ret, fd; + + fd = capi_applid2fd(ApplId); + if (fd < 0) + return -1; + misdnSetHeader(anBuf, 16, ApplId, MIC_USERFLAG_REQ, 0); + capimsg_setu32(anBuf, 8, set_f); + capimsg_setu32(anBuf, 12, clr_f); + ret = misdnRemoteCommand(fd, anBuf, 16, MIC_USERFLAG_REQ); + if (ret == 12) + ret = CAPIMSG_U32(anBuf, 8); + else + ret = -1; + return ret; +} + +static int misdnGetFlags(unsigned nApplId, unsigned *pnFlagsPtr) +{ + int ret; + + ret = misdnFlagReq(nApplId, 0, 0); + if (ret < 0) + *pnFlagsPtr = 0; + else { + *pnFlagsPtr = ret; + ret = 0; + } + return ret; +} + +static int misdnSetFlags(unsigned nApplId, unsigned nFlags) +{ + int ret; + + ret = misdnFlagReq(nApplId, nFlags, 0); + if (ret >= 0) + ret = 0; + return ret; +} + +static int misdnClearFlags(unsigned nApplId, unsigned nFlags) +{ + int ret; + + ret = misdnFlagReq(nApplId, 0, nFlags); + if (ret >= 0) + ret = 0; + return ret; +} + +static char *misdnGetTtyDeviceName(unsigned nApplId,unsigned nNcci, char *pnBuffer, size_t nSize) +{ + unsigned char *anBuf; + int ret, fd; + + fd = capi_applid2fd(nApplId); + if (fd < 0) + return NULL; + + if (nSize > 64) + nSize = 64; + anBuf = malloc(nSize + 12); + if (!anBuf) + return NULL; + misdnSetHeader(anBuf, 16, nApplId, MIC_TTYNAME_REQ, 0); + capimsg_setu32(anBuf, 8, nNcci); + capimsg_setu32(anBuf, 12, nSize & 0xff); + ret = misdnRemoteCommand(fd, anBuf, 16, MIC_TTYNAME_REQ); + if (ret > 8) { + ret = ret - 8; + memcpy(pnBuffer, &anBuf[8], ret); + pnBuffer[ret] = 0; + } else + return NULL; + free(anBuf); + return pnBuffer; +} + /** Module operations structure */ static struct sModuleOperations sRemoteCapi = { misdnIsInstalled, @@ -434,10 +515,10 @@ static struct sModuleOperations sRemoteCapi = { misdnGetSerialNumber, misdnGetProfile, NULL, - NULL, - NULL, - NULL, - NULL, + misdnGetFlags, + misdnSetFlags, + misdnClearFlags, + misdnGetTtyDeviceName, NULL, NULL }; diff --git a/capi20/ncci.c b/capi20/ncci.c index a420d04..2302de1 100644 --- a/capi20/ncci.c +++ b/capi20/ncci.c @@ -378,7 +378,7 @@ static void ncci_n0_dl_establish_ind_conf(struct FsmInst *fi, int event, void *a FsmEvent(&ncci->ncci_m, EV_NC_CONNECT_B3_IND, arg); } -static void ncci_dl_establish_conf(struct FsmInst *fi, int event, void *arg) +static void ncci_dl_establish_ind_conf(struct FsmInst *fi, int event, void *arg) { struct mNCCI *ncci = fi->userdata; struct mc_buf *mc = arg; @@ -453,7 +453,8 @@ static struct FsmNode fn_ncci_list[] = { {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_NC_DISCONNECT_B3_CONF, ncci_disconnect_b3_conf}, - {ST_NCCI_N_2, EV_DL_ESTABLISH_CONF, ncci_dl_establish_conf}, + {ST_NCCI_N_2, EV_DL_ESTABLISH_CONF, ncci_dl_establish_ind_conf}, + {ST_NCCI_N_2, EV_DL_ESTABLISH_IND, ncci_dl_establish_ind_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}, @@ -551,7 +552,11 @@ struct mNCCI *ncciCreate(struct lPLCI *lp) nc->window = lp->lc->Appl->MaxB3Blk; pthread_mutex_init(&nc->lock, NULL); switch (lp->Bprotocol.B1) { + case 0: + nc->l1trans = 0; + break; case 1: + nc->l1trans = 1; if (!lp->l1dtmf) { nc->flowmode = flmPHDATA; nc->l1direct = 1; @@ -567,12 +572,18 @@ struct mNCCI *ncciCreate(struct lPLCI *lp) break; } - if (lp->Bprotocol.B2 == 0) { /* X.75 has own flowctrl */ + if (lp->Bprotocol.B2 == 1) { /* X.75 has own flowctrl */ nc->l2trans = 1; if (lp->Bprotocol.B1 == 0) { nc->l1direct = 1; nc->flowmode = flmPHDATA; } + } else { + nc->l2trans = 1; + if (lp->Bprotocol.B1 == 0) { // HDLC + nc->l1direct = 1; + nc->flowmode = flmPHDATA; + } } if (lp->Bprotocol.B3 == 0) { nc->l3trans = 1; @@ -788,19 +799,44 @@ static uint16_t ncciDataReq(struct mNCCI *ncci, struct mc_buf *mc) AnswerDataB3Req(ncci, mc, CapiMessageNotSupportedInCurrentState); return 0; } - if (ncci->xmit_handles[ncci->iidx].pkt) { + if (ncci->BIlink->tty > -1) { + /* We have a packet from pseudo tty */ + if (ncci->xmit_handles[ncci->iidx].pkt) { + wprint("NCCI %06x: tty CapiSendQueueFull\n", ncci->ncci); + /* TODO FLOW CONTROL */ + pthread_mutex_unlock(&ncci->lock); + free_mc_buf(mc); + return 0; + } + len = mc->len; + if (*mc->rp == 0) { + len--; + mc->rp++; + dhexprint(MIDEBUG_NCCI_DATA, "Queued Data: ", mc->rp, len); + } else { + /* TODO FLOW CONTROL */ + wprint("NCCI %06x: tty got ctrl %02x\n", ncci->ncci, *mc->rp); + pthread_mutex_unlock(&ncci->lock); + free_mc_buf(mc); + return 0; + } + ncci->xmit_handles[ncci->iidx].DataHandle = 0; + ncci->xmit_handles[ncci->iidx].MsgId = 0; + off = 8; + } else if (ncci->xmit_handles[ncci->iidx].pkt) { wprint("NCCI %06x: CapiSendQueueFull\n", ncci->ncci); pthread_mutex_unlock(&ncci->lock); AnswerDataB3Req(ncci, mc, CapiSendQueueFull); return 0; + } else { + len = CAPIMSG_DATALEN(mc->rb); + ncci->xmit_handles[ncci->iidx].DataHandle = CAPIMSG_REQ_DATAHANDLE(mc->rb); + ncci->xmit_handles[ncci->iidx].MsgId = CAPIMSG_MSGID(mc->rb); + mc->rp = mc->rb + off; } - len = CAPIMSG_DATALEN(mc->rb); ncci->xmit_handles[ncci->iidx].pkt = mc; - ncci->xmit_handles[ncci->iidx].DataHandle = CAPIMSG_REQ_DATAHANDLE(mc->rb); - ncci->xmit_handles[ncci->iidx].MsgId = CAPIMSG_MSGID(mc->rb); ncci->xmit_handles[ncci->iidx].dlen = len; ncci->xmit_handles[ncci->iidx].sent = 0; - mc->rp = mc->rb + off; mc->len = len; ncci->xmit_handles[ncci->iidx].sp = mc->rp; @@ -838,6 +874,23 @@ static int ncciDataInd(struct mNCCI *ncci, int pr, struct mc_buf *mc) wprint("NCCI %06x: : frame with %d bytes dropped BIlink gone\n", ncci->ncci, dlen); return -EINVAL; } + if (ncci->BIlink->tty > -1) { + /* transfer via a pseudo tty */ + pthread_mutex_unlock(&ncci->lock); + hh++; + mc->rp = (unsigned char *)hh; + ret = write(ncci->BIlink->tty, mc->rp, dlen); + if (ret != dlen) + wprint("NCCI %06x: frame with %d bytes only %d bytes were written to tty - %s\n", + ncci->ncci, dlen, ret, strerror(errno)); + else { + dprint(MIDEBUG_NCCI, "NCCI %06x: frame with %d bytes was written to tty\n", + ncci->ncci, dlen); + dhexprint(MIDEBUG_NCCI_DATA, "Data: ", mc->rp, dlen); + } + free_mc_buf(mc); + return 0; + } for (i = 0; i < ncci->window; i++) { if (ncci->recv_handles[i] == 0) break; @@ -871,7 +924,7 @@ static int ncciDataInd(struct mNCCI *ncci, int pr, struct mc_buf *mc) pthread_mutex_unlock(&ncci->lock); if (ret != tot) { - wprint("NCCI %06x: : frame with %d + %d bytes only %d bytes are sent - %s\n", + wprint("NCCI %06x: frame with %d + %d bytes only %d bytes are sent - %s\n", ncci->ncci, dlen, CAPI_B3_DATA_IND_HEADER_SIZE, ret, strerror(errno)); ret = -EINVAL; } else @@ -884,7 +937,7 @@ static int ncciDataInd(struct mNCCI *ncci, int pr, struct mc_buf *mc) static void ncciDataConf(struct mNCCI *ncci, struct mc_buf *mc) { - int i; + int i, do_answer = 1; struct mISDNhead *hh; hh = (struct mISDNhead *)mc->rb; @@ -895,6 +948,14 @@ static void ncciDataConf(struct mNCCI *ncci, struct mc_buf *mc) } pthread_mutex_lock(&ncci->lock); + if (!ncci->BIlink) { + pthread_mutex_unlock(&ncci->lock); + wprint("NCCI %06x: ack dropped BIlink gone\n", ncci->ncci); + free_mc_buf(mc); + return; + } + if (ncci->BIlink->tty > -1) + do_answer = 0; for (i = 0; i < ncci->window; i++) { if (ncci->xmit_handles[i].PktId == hh->id) { if (ncci->xmit_handles[i].pkt) @@ -917,7 +978,8 @@ static void ncciDataConf(struct mNCCI *ncci, struct mc_buf *mc) ncci->xmit_handles[i].PktId = 0; ncci->dlbusy = 0; pthread_mutex_unlock(&ncci->lock); - AnswerDataB3Req(ncci, mc, CapiNoError); + if (do_answer) + AnswerDataB3Req(ncci, mc, CapiNoError); SendDataB3Down(ncci, 0); return; } @@ -1043,8 +1105,15 @@ static int ncciSendMessage(struct mNCCI *ncci, uint8_t cmd, uint8_t subcmd, stru free_mc_buf(mc); ret = CapiNoError; } + } else if (cmd == CAPI_DATA_TTY) { + if (ncci->ncci_m.state == ST_NCCI_N_ACT) { + ret = ncciDataReq(ncci, mc); + } else { + ret = CapiMessageNotSupportedInCurrentState; + wprint("NCCI %06x: DATA_TTY_REQ - but but NCCI state %s\n", ncci->ncci, + str_st_ncci[ncci->ncci_m.state]); + } } else { - // capi_message2cmsg(cmsg, skb->data); ret = ncciGetCmsg(ncci, cmd, subcmd, mc); } return ret; @@ -1052,7 +1121,22 @@ static int ncciSendMessage(struct mNCCI *ncci, uint8_t cmd, uint8_t subcmd, stru int ncciB3Data(struct BInstance *bi, struct mc_buf *mc) { - return ncciSendMessage(bi->b3data, mc->cmsg.Command, mc->cmsg.Subcommand, mc); + struct mNCCI *ncci = bi->b3data; + + if (mc->cmsg.Command == CAPI_CONNECT_B3 && mc->cmsg.Subcommand == CAPI_REQ) { + if (ncci) + wprint("NCCI %06x: already assigned\n", ncci->ncci); + else { + ncci = ConnectB3Request(bi->lp, mc); + bi->b3data = ncci; + } + + } + if (!ncci) { + wprint("No NCCI asigned for PCLI %04x\n", bi->lp->plci); + return -EINVAL; + } + return ncciSendMessage(ncci, mc->cmsg.Command, mc->cmsg.Subcommand, mc); } int ncciB3Message(struct mNCCI *ncci, struct mc_buf *mc) @@ -1197,9 +1281,12 @@ int recvBdirect(struct BInstance *bi, struct mc_buf *mc) bi->b3data = ncci; } FsmEvent(&ncci->ncci_m, EV_DL_ESTABLISH_CONF, mc); - mc->len = 520; - memset(&mc->rb[8], 0x55, 512); - ncciDataInd(ncci, hh->prim, mc); + if (ncci->l1trans) { + /* prefill FIFO 64 ms */ + mc->len = 520; + memset(&mc->rb[8], 0x55, 512); + ncciDataInd(ncci, hh->prim, mc); + } ret = 0; break; case PH_ACTIVATE_IND: @@ -1211,7 +1298,8 @@ int recvBdirect(struct BInstance *bi, struct mc_buf *mc) return -ENOMEM; } else bi->b3data = ncci; - } + } else + dprint(MIDEBUG_NCCI, "NCCI %06x: %s on existing NCCIx\n", ncci->ncci, _mi_msg_type2str(hh->prim)); FsmEvent(&ncci->ncci_m, EV_DL_ESTABLISH_IND, mc); ret = 1; break;