From c8293a69c2aa8c544ecf74e5ec0a6d9bcb373a51 Mon Sep 17 00:00:00 2001 From: calle Date: Thu, 18 May 2000 14:58:35 +0000 Subject: [PATCH] Plugin for pppd to support PPP over CAPI2.0. --- pppdcapiplugin/Makefile | 34 + pppdcapiplugin/README | 23 + pppdcapiplugin/capiconn.c | 1761 +++++++++++++++++++++++++++++++++ pppdcapiplugin/capiconn.h | 418 ++++++++ pppdcapiplugin/capiplugin.c | 284 ++++++ pppdcapiplugin/install-sh | 251 +++++ pppdcapiplugin/mkinstalldirs | 40 + pppdcapiplugin/peers/arcor | 13 + pppdcapiplugin/peers/avm | 18 + pppdcapiplugin/peers/avm-ml | 20 + pppdcapiplugin/peers/otelo | 13 + pppdcapiplugin/peers/talkline | 13 + pppdcapiplugin/pppd.h | 708 +++++++++++++ pppdcapiplugin/userpass.c | 49 + 14 files changed, 3645 insertions(+) create mode 100644 pppdcapiplugin/Makefile create mode 100644 pppdcapiplugin/README create mode 100644 pppdcapiplugin/capiconn.c create mode 100644 pppdcapiplugin/capiconn.h create mode 100644 pppdcapiplugin/capiplugin.c create mode 100755 pppdcapiplugin/install-sh create mode 100755 pppdcapiplugin/mkinstalldirs create mode 100755 pppdcapiplugin/peers/arcor create mode 100755 pppdcapiplugin/peers/avm create mode 100755 pppdcapiplugin/peers/avm-ml create mode 100644 pppdcapiplugin/peers/otelo create mode 100644 pppdcapiplugin/peers/talkline create mode 100644 pppdcapiplugin/pppd.h create mode 100644 pppdcapiplugin/userpass.c diff --git a/pppdcapiplugin/Makefile b/pppdcapiplugin/Makefile new file mode 100644 index 00000000..fe2cf8c5 --- /dev/null +++ b/pppdcapiplugin/Makefile @@ -0,0 +1,34 @@ +CC = gcc +CFLAGS = -O2 -Wall -fPIC -L../capi20 +LDFLAGS = -shared + +PLUGINDIR=/etc/ppp/plugins +PEERDIR=/etc/ppp/peers/isdn +PEERS= arcor otelo talkline avm avm-ml +INSTALL=./install-sh -c + +ALL = capiplugin.so userpass.so + +all: $(ALL) + +capiplugin.so: capiplugin.o capiconn.o + $(CC) -o $@ $(LDFLAGS) capiplugin.o capiconn.o -lcapi20dyn + +userpass.so: userpass.c + $(CC) -o $@ $(LDFLAGS) $(CFLAGS) -nostdlib userpass.c + +clean: + $(RM) *.so *.o comperr + +install: $(ALL) + ./mkinstalldirs $(PLUGINDIR) + @for i in $(ALL); do \ + echo $(INSTALL) $$i $(PLUGINDIR); \ + $(INSTALL) $$i $(PLUGINDIR); \ + done + ./mkinstalldirs $(PEERDIR) + @for i in $(PEERS); do \ + echo $(INSTALL) peers/$$i $(PEERDIR); \ + $(INSTALL) peers/$$i $(PEERDIR); \ + done + diff --git a/pppdcapiplugin/README b/pppdcapiplugin/README new file mode 100644 index 00000000..e6d82dd1 --- /dev/null +++ b/pppdcapiplugin/README @@ -0,0 +1,23 @@ + +You need a pppd with plugin support: + kernel 2.2.X - ppp-2.3.11 + kernel 2.3.99 - ppp-2.4.0b2 + +usage example: + +Make a single call to arcor: + pppd call isdn/arcor + +Make a call on demand to arcor: + pppd demand connect "" idletime 30 holdoff 1 call isdn/arcor + +Make a multilink call with to channels to AVM test server: +(Only working with 2.3.99-pre8 with ppp_synctty patch) + pppd call isdn/avm-ml + pppd call isdn/avm-ml + +Make a single call to arcor with outside dialing prefix "0" + pppd call isdn/arcor numberprefix 0 + +Make a single call to arcor using controller 2: + pppd call isdn/arcor controller 2 diff --git a/pppdcapiplugin/capiconn.c b/pppdcapiplugin/capiconn.c new file mode 100644 index 00000000..1ccdcd8f --- /dev/null +++ b/pppdcapiplugin/capiconn.c @@ -0,0 +1,1761 @@ +/* + * $Id: capiconn.c,v 1.1 2000/05/18 14:58:35 calle Exp $ + * + * $Log: capiconn.c,v $ + * Revision 1.1 2000/05/18 14:58:35 calle + * Plugin for pppd to support PPP over CAPI2.0. + * + */ + +#include +#include +#include "capiconn.h" + +static char *revision = "$Revision: 1.1 $"; + +/* xxxxxxxxxxxxxxxxxx */ +static _cmsg cmdcmsg; +static _cmsg cmsg; + +/* -------- defines -------------------------------------------------- */ + +#ifndef CAPI_MAXDATAWINDOW +#define CAPI_MAXDATAWINDOW 8 +#endif + +/* -------- type definitions ----------------------------------------- */ + +struct capiconn_context { + struct capiconn_context *next; + + unsigned appid; + struct capiconn_callbacks *cb; + + int ncontr; + struct capi_contr *contr_list; + + /* statistic */ + unsigned long nrecvctlpkt; + unsigned long nrecvdatapkt; + unsigned long nsentctlpkt; + unsigned long nsentdatapkt; +}; + +struct capi_contr { + + struct capi_contr *next; + struct capiconn_context *ctx; + + unsigned contrnr; + struct capi_contrinfo cinfo; + unsigned ddilen; + + /* + * LISTEN state + */ + int state; + _cdword cipmask; + _cdword cipmask2; + + /* + * ID of capi message sent + */ + _cword msgid; + + /* + * B-Channels + */ + int nbchan; + struct capi_connection { + struct capi_connection *next; + struct capi_contr *contr; + struct capiconn_context *ctx; + + struct capi_conninfo conninfo; + + unsigned incoming:1, + disconnecting:1, + localdisconnect:1; + + _cword disconnectreason; + _cword disconnectreason_b3; + + _cdword plci; + _cdword ncci; /* ncci for CONNECT_ACTIVE_IND */ + _cword msgid; /* to identfy CONNECT_CONF */ + int state; + struct capi_ncci { + struct capi_connection *plcip; + struct capiconn_context *ctx; + _cdword ncci; + _cword msgid; /* to identfy CONNECT_B3_CONF */ + int state; + int oldstate; + /* */ + _cword datahandle; + struct ncci_datahandle_queue { + struct ncci_datahandle_queue *next; + _cword datahandle; + unsigned char *data; + } *ackqueue; + int ackqueuelen; + } *nccip; + } *connections; +}; + +typedef struct capi_ncci capi_ncci; +typedef struct capi_contr capi_contr; +typedef struct ncci_datahandle_queue ncci_datahandle_queue; + +/* -------- data definitions ----------------------------------------- */ + +capiconn_context *context_list = 0; + +/* -------- context handling ----------------------------------------- */ + +capiconn_context * +capiconn_getcontext(unsigned appid, capiconn_callbacks *cb) +{ + capiconn_context *ctx; + + if ((ctx = ((*cb->malloc)(sizeof(capiconn_context)))) == 0) + return 0; + memset(ctx, 0, sizeof(capiconn_context)); + + ctx->appid = appid; + ctx->cb = cb; + ctx->next = context_list; + context_list = ctx; + return ctx; +}; + +static void free_all_cards(capiconn_context *ctx) +{ +} + +int +capiconn_freecontext(capiconn_context *ctx) +{ + capiconn_context **pp; + for (pp = &context_list; *pp; pp = &(*pp)->next) { + if (*pp == ctx) { + *pp = (*pp)->next; + free_all_cards(ctx); + (*ctx->cb->free)(ctx); + return 0; + } + } + return -1; +} + +static inline capiconn_context *find_context(unsigned appid) +{ + capiconn_context *p; + for (p = context_list; p; p = p->next) + if (p->appid == appid) + return p; + return 0; +} + +int +capiconn_addcontr(capiconn_context *ctx, unsigned contr, capi_contrinfo *cinfo) +{ + capiconn_callbacks *cb = ctx->cb; + capi_contr *card; + + if (!(card = (capi_contr *) (*cb->malloc)(sizeof(capi_contr)))) + return CAPICONN_NO_MEMORY; + memset(card, 0, sizeof(capi_contr)); + card->contrnr = contr; + card->cinfo = *cinfo; + card->ctx = ctx; + if (card->cinfo.ddi) + card->ddilen = strlen(card->cinfo.ddi); + card->next = ctx->contr_list; + ctx->contr_list = card; + ctx->ncontr++; + return CAPICONN_OK; +} + +/* ------------------------------------------------------------------- */ + +static capi_contr *findcontrbynumber(capiconn_context *ctx, unsigned contr) +{ + capi_contr *p; + + for (p = ctx->contr_list; p; p = p->next) + if (p->contrnr == contr) + break; + return p; +} + +/* -------- plci management ------------------------------------------ */ + +static capi_connection *new_plci(capi_contr * card, int incoming) +{ + capiconn_context *ctx = card->ctx; + capiconn_callbacks *cb = ctx->cb; + capi_connection *plcip; + + plcip = (capi_connection *) (*cb->malloc)(sizeof(capi_connection)); + + if (plcip == 0) + return 0; + + memset(plcip, 0, sizeof(capi_connection)); + plcip->contr = card; + plcip->ctx = ctx; + plcip->incoming = incoming; + plcip->state = ST_PLCI_NONE; + plcip->plci = 0; + plcip->msgid = 0; + plcip->next = card->connections; + card->connections = plcip; + + return plcip; +} + +static capi_connection *find_plci_by_plci(capi_contr * card, _cdword plci) +{ + capi_connection *p; + for (p = card->connections; p; p = p->next) + if (p->plci == plci) + return p; + return 0; +} + +static capi_connection *find_plci_by_msgid(capi_contr * card, _cword msgid) +{ + capi_connection *p; + for (p = card->connections; p; p = p->next) + if (p->msgid == msgid) + return p; + return 0; +} + +static capi_connection *find_plci_by_ncci(capi_contr * card, _cdword ncci) +{ + capi_connection *p; + for (p = card->connections; p; p = p->next) + if (p->plci == (ncci & 0xffff)) + return p; + return 0; +} + +static void free_plci(capi_contr * card, capi_connection * plcip) +{ + capiconn_context *ctx = card->ctx; + capiconn_callbacks *cb = ctx->cb; + capi_connection **pp; + + for (pp = &card->connections; *pp; pp = &(*pp)->next) { + if (*pp == plcip) { + *pp = (*pp)->next; + (*cb->free)(plcip); + return; + } + } + (*cb->errmsg)("free_plci %p (0x%x) not found, Huh?", + plcip, plcip->plci); +} + +/* -------- ncci management ------------------------------------------ */ + +static inline capi_ncci *new_ncci(capi_contr * card, + capi_connection * plcip, + _cdword ncci) +{ + capiconn_context *ctx = card->ctx; + capiconn_callbacks *cb = ctx->cb; + capi_ncci *nccip; + + nccip = (capi_ncci *) (*cb->malloc)(sizeof(capi_ncci)); + + if (nccip == 0) + return 0; + + memset(nccip, 0, sizeof(capi_ncci)); + nccip->ctx = ctx; + nccip->ncci = ncci; + nccip->state = ST_NCCI_NONE; + nccip->plcip = plcip; + nccip->datahandle = 0; + plcip->nccip = nccip; + plcip->ncci = ncci; + + return nccip; +} + +static inline capi_ncci *find_ncci(capi_contr * card, _cdword ncci) +{ + capi_connection *plcip; + + if ((plcip = find_plci_by_ncci(card, ncci)) == 0) + return 0; + + return plcip->nccip; +} + +static inline capi_ncci *find_ncci_by_msgid(capi_contr * card, + _cdword ncci, _cword msgid) +{ + capi_connection *plcip; + + if ((plcip = find_plci_by_ncci(card, ncci)) == 0) + return 0; + + return plcip->nccip; +} + +static void free_ncci(capi_contr * card, capi_ncci *nccip) +{ + capiconn_callbacks *cb = card->ctx->cb; + + nccip->plcip->nccip = 0; + (*cb->free)(nccip); +} + +/* ------------------------------------------------------------------- */ + +static void clr_conninfo1(capiconn_context *ctx, capi_conninfo *p) +{ + capiconn_callbacks *cb = ctx->cb; + + if (p->callednumber) { + (*cb->free)(p->callednumber); + p->callednumber = 0; + } + if (p->callingnumber) { + (*cb->free)(p->callingnumber); + p->callingnumber = 0; + } +} + +static void clr_conninfo2(capiconn_context *ctx, capi_conninfo *p) +{ + capiconn_callbacks *cb = ctx->cb; + + if (p->b1config) { + (*cb->free)(p->b1config); + p->b1config = 0; + } + if (p->b2config) { + (*cb->free)(p->b2config); + p->b2config = 0; + } + if (p->b3config) { + (*cb->free)(p->b3config); + p->b3config = 0; + } + if (p->bchaninfo) { + (*cb->free)(p->bchaninfo); + p->bchaninfo = 0; + } + if (p->ncpi) { + (*cb->free)(p->ncpi); + p->ncpi = 0; + } +} + +static void clr_conninfo(capiconn_context *ctx, capi_conninfo *p) +{ + clr_conninfo1(ctx, p); + clr_conninfo2(ctx, p); +} + +static int set_conninfo1a(capiconn_context *ctx, + capi_conninfo *p, + _cword cipvalue, + char *callednumber, + char *callingnumber) +{ + capiconn_callbacks *cb = ctx->cb; + _cbyte len; + + p->cipvalue = cipvalue; + if ((p->callednumber = (*cb->malloc)(128)) == 0) + goto fail; + if (callednumber) { + len = (_cbyte)strlen(callednumber); + if (callednumber[0] & 0x80) { + memcpy(p->callednumber+1, callednumber, len); + p->callednumber[0] = len; + } else { + memcpy(p->callednumber+2, callednumber, len); + p->callednumber[0] = len+1; + p->callednumber[1] = 0x81; + } + } else { + p->callednumber[0] = 0; + } + if ((p->callingnumber = (*cb->malloc)(128)) == 0) + goto fail; + if (callingnumber) { + len = (_cbyte)strlen(callingnumber); + memcpy(p->callingnumber+3, callingnumber, len); + p->callingnumber[0] = len+2; + p->callingnumber[1] = 0x00; + } else { + p->callingnumber[0] = 0; + } + p->callingnumber[2] = 0x80; + return 0; +fail: + clr_conninfo1(ctx, p); + return -1; +} + +static int set_conninfo1b(capiconn_context *ctx, + capi_conninfo *p, + _cword cipvalue, + _cstruct callednumber, + _cstruct callingnumber) +{ + capiconn_callbacks *cb = ctx->cb; + _cbyte len; + + p->cipvalue = cipvalue; + + if ((p->callednumber = (*cb->malloc)(128)) == 0) + goto fail; + len = callednumber[0]; + memcpy(p->callednumber, callednumber, len); + p->callednumber[len+1] = 0; + + if ((p->callingnumber = (*cb->malloc)(128)) == 0) + goto fail; + len = callingnumber[0]; + memcpy(p->callingnumber, callingnumber, len); + p->callingnumber[len+1] = 0; + return 0; +fail: + clr_conninfo1(ctx, p); + return -1; +} + +static void extend_callednumber(capiconn_context *ctx, capi_conninfo *p, + char *number, _cbyte len) +{ + capiconn_callbacks *cb = ctx->cb; + _cbyte *curnumber = p->callednumber+2; + _cbyte clen = p->callednumber[0]-2; + + (*cb->debugmsg)("extend number %*.*s (len=%d)", + (int)len, (int)len, number, len); + + if (len >= clen && memcmp(curnumber, number, clen) == 0) { + memcpy(p->callednumber + 2, number, len); + p->callednumber[0] = 2 + len; + } else { + memcpy(p->callednumber + p->callednumber[0], number, len); + p->callednumber[0] += len; + } + p->callednumber[p->callednumber[0]+1] = 0; + (*cb->debugmsg)("capiconn: extended to %s", p->callednumber+2); +} + +static int set_conninfo2(capiconn_context *ctx, + capi_conninfo *p, + _cword b1proto, _cword b2proto, _cword b3proto, + _cstruct b1config, _cstruct b2config, _cstruct b3config, + _cstruct bchaninfo, _cstruct ncpi) +{ + capiconn_callbacks *cb = ctx->cb; + + p->b1proto = b1proto; + p->b2proto = b2proto; + p->b3proto = b3proto; + if (b1config) { + if ((p->b1config = (*cb->malloc)(b1config[0]+1)) == 0) + goto fail; + memcpy(p->b1config, b1config, b1config[0]+1); + } + if (b2config) { + if ((p->b2config = (*cb->malloc)(b2config[0]+1)) == 0) + goto fail; + memcpy(p->b2config, b2config, b2config[0]+1); + } + if (b3config) { + if ((p->b3config = (*cb->malloc)(b3config[0]+1)) == 0) + goto fail; + memcpy(p->b3config, b3config, b3config[0]+1); + } + if (bchaninfo) { + if ((p->bchaninfo = (*cb->malloc)(bchaninfo[0]+1)) == 0) + goto fail; + memcpy(p->bchaninfo, bchaninfo, bchaninfo[0]+1); + } + if (ncpi) { + if ((p->ncpi = (*cb->malloc)(ncpi[0]+1)) == 0) + goto fail; + memcpy(p->ncpi, ncpi, ncpi[0]+1); + } + return 0; +fail: + clr_conninfo2(ctx, p); + return -1; +} + +capi_conninfo *capiconn_getinfo(capi_connection *p) +{ + p->conninfo.appid = p->ctx->appid; + p->conninfo.plci = p->plci; + p->conninfo.plci_state = p->state; + p->conninfo.ncci = p->ncci; + p->conninfo.ncci_state = p->nccip ? p->nccip->state : ST_NCCI_NONE; + p->conninfo.isincoming = p->incoming ? 1 : 0; + p->conninfo.disconnect_was_local = p->localdisconnect ? 1 : 0; + p->conninfo.disconnectreason = p->disconnectreason; + p->conninfo.disconnectreason_b3 = p->disconnectreason_b3; + return &p->conninfo; +} + +/* ------------------------------------------------------------------- */ + +static int capi_add_ack(capi_ncci *nccip, + _cword datahandle, + unsigned char *data) +{ + capiconn_context *ctx = nccip->ctx; + capiconn_callbacks *cb = ctx->cb; + ncci_datahandle_queue *n, **pp; + + if (nccip->ackqueuelen >= CAPI_MAXDATAWINDOW) + return 0; + n = (ncci_datahandle_queue *) + (*cb->malloc)(sizeof(ncci_datahandle_queue)); + if (!n) { + (cb->errmsg)("capiconn: cb->malloc ncci_datahandle failed"); + return -1; + } + n->next = 0; + n->datahandle = datahandle; + n->data = data; + for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next) ; + *pp = n; + nccip->ackqueuelen++; + return 0; +} + +static unsigned char *capi_del_ack(capi_ncci *nccip, _cword datahandle) +{ + capiconn_context *ctx = nccip->ctx; + capiconn_callbacks *cb = ctx->cb; + ncci_datahandle_queue **pp, *p; + unsigned char *data; + + for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next) { + if ((*pp)->datahandle == datahandle) { + p = *pp; + data = p->data; + *pp = (*pp)->next; + (*cb->free)(p); + nccip->ackqueuelen--; + return data; + } + } + return 0; +} + +/* -------- convert and send capi message ---------------------------- */ + +static void send_message(capi_contr * card, _cmsg * cmsg) +{ + capiconn_context *ctx = card->ctx; + capiconn_callbacks *cb = ctx->cb; + + capi_cmsg2message(cmsg, cmsg->buf); + (*cb->capi_put_message) (ctx->appid, cmsg->buf); + ctx->nsentctlpkt++; +} + +/* -------- state machine -------------------------------------------- */ + +struct listenstatechange { + int actstate; + int nextstate; + int event; +}; + +static struct listenstatechange listentable[] = +{ + {ST_LISTEN_NONE, ST_LISTEN_WAIT_CONF, EV_LISTEN_REQ}, + {ST_LISTEN_ACTIVE, ST_LISTEN_ACTIVE_WAIT_CONF, EV_LISTEN_REQ}, + {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_ERROR}, + {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_ERROR}, + {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY}, + {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY}, + {ST_LISTEN_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK}, + {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK}, + { 0, 0, 0 }, +}; + +static void listen_change_state(capi_contr * card, int event) +{ + capiconn_context *ctx = card->ctx; + capiconn_callbacks *cb = ctx->cb; + struct listenstatechange *p = listentable; + + while (p->event) { + if (card->state == p->actstate && p->event == event) { + (*cb->debugmsg)("controller %d: listen_change_state %d -> %d", + card->contrnr, card->state, p->nextstate); + card->state = p->nextstate; + return; + } + p++; + } + (*cb->errmsg)("controller %d: listen_change_state state=%d event=%d ????", + card->contrnr, card->state, event); +} + +/* ------------------------------------------------------------------ */ + +static void p0(capi_contr * card, capi_connection * plcip) +{ + capiconn_context *ctx = card->ctx; + capiconn_callbacks *cb = ctx->cb; + if (*cb->disconnected) + (*cb->disconnected)(plcip, + plcip->localdisconnect, + plcip->disconnectreason, + plcip->disconnectreason_b3); + clr_conninfo(ctx, &plcip->conninfo); + free_plci(card, plcip); +} + +/* ------------------------------------------------------------------ */ + +struct plcistatechange { + int actstate; + int nextstate; + int event; + void (*changefunc) (capi_contr * card, capi_connection * plci); +}; + +static struct plcistatechange plcitable[] = +{ + /* P-0 */ + {ST_PLCI_NONE, ST_PLCI_OUTGOING, EV_PLCI_CONNECT_REQ, 0}, + {ST_PLCI_NONE, ST_PLCI_ALLOCATED, EV_PLCI_FACILITY_IND_UP, 0}, + {ST_PLCI_NONE, ST_PLCI_INCOMING, EV_PLCI_CONNECT_IND, 0}, + {ST_PLCI_NONE, ST_PLCI_RESUMEING, EV_PLCI_RESUME_REQ, 0}, + /* P-0.1 */ + {ST_PLCI_OUTGOING, ST_PLCI_NONE, EV_PLCI_CONNECT_CONF_ERROR, p0}, + {ST_PLCI_OUTGOING, ST_PLCI_ALLOCATED, EV_PLCI_CONNECT_CONF_OK, 0}, + /* P-1 */ + {ST_PLCI_ALLOCATED, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, 0}, + {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, + {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, + {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, + /* P-ACT */ + {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, + {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, + {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, + {ST_PLCI_ACTIVE, ST_PLCI_HELD, EV_PLCI_HOLD_IND, 0}, + {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_SUSPEND_IND, 0}, + /* P-2 */ + {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, 0}, + {ST_PLCI_INCOMING, ST_PLCI_FACILITY_IND, EV_PLCI_FACILITY_IND_UP, 0}, + {ST_PLCI_INCOMING, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_RESP, 0}, + {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, + {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, + {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, + {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CD_IND, 0}, + /* P-3 */ + {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, 0}, + {ST_PLCI_FACILITY_IND, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_ACTIVE_IND, 0}, + {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, + {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, + {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, + /* P-4 */ + {ST_PLCI_ACCEPTING, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, 0}, + {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, + {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, + {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, + /* P-5 */ + {ST_PLCI_DISCONNECTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, + /* P-6 */ + {ST_PLCI_DISCONNECTED, ST_PLCI_NONE, EV_PLCI_DISCONNECT_RESP, p0}, + /* P-0.Res */ + {ST_PLCI_RESUMEING, ST_PLCI_NONE, EV_PLCI_RESUME_CONF_ERROR, p0}, + {ST_PLCI_RESUMEING, ST_PLCI_RESUME, EV_PLCI_RESUME_CONF_OK, 0}, + /* P-RES */ + {ST_PLCI_RESUME, ST_PLCI_ACTIVE, EV_PLCI_RESUME_IND, 0}, + /* P-HELD */ + {ST_PLCI_HELD, ST_PLCI_ACTIVE, EV_PLCI_RETRIEVE_IND, 0}, + { 0, 0, 0, 0 }, +}; + +static void plci_change_state(capi_contr * card, capi_connection * plci, int event) +{ + capiconn_callbacks *cb = card->ctx->cb; + struct plcistatechange *p = plcitable; + while (p->event) { + if (plci->state == p->actstate && p->event == event) { + (cb->debugmsg)("plci_change_state:0x%x %d -> %d", + plci->plci, plci->state, p->nextstate); + plci->state = p->nextstate; + if (p->changefunc) + p->changefunc(card, plci); + return; + } + p++; + } + (*cb->errmsg)("plci_change_state:0x%x state=%d event=%d ????", + card->contrnr, plci->plci, plci->state, event); +} + +/* ------------------------------------------------------------------ */ + + +static void n0(capi_contr * card, capi_ncci * ncci) +{ + capiconn_context *ctx = card->ctx; + + capi_fill_DISCONNECT_REQ(&cmsg, + ctx->appid, + card->msgid++, + ncci->plcip->plci, + 0, /* BChannelinformation */ + 0, /* Keypadfacility */ + 0, /* Useruserdata */ /* $$$$ */ + 0 /* Facilitydataarray */ + ); + send_message(card, &cmsg); + plci_change_state(card, ncci->plcip, EV_PLCI_DISCONNECT_REQ); + free_ncci(card, ncci); +} + +/* ------------------------------------------------------------------ */ + +struct nccistatechange { + int actstate; + int nextstate; + int event; + void (*changefunc) (capi_contr * card, capi_ncci * ncci); +}; + +static struct nccistatechange nccitable[] = +{ + /* N-0 */ + {ST_NCCI_NONE, ST_NCCI_OUTGOING, EV_NCCI_CONNECT_B3_REQ, 0}, + {ST_NCCI_NONE, ST_NCCI_INCOMING, EV_NCCI_CONNECT_B3_IND, 0}, + /* N-0.1 */ + {ST_NCCI_OUTGOING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_CONF_OK, 0}, + {ST_NCCI_OUTGOING, ST_NCCI_NONE, EV_NCCI_CONNECT_B3_CONF_ERROR, n0}, + /* N-1 */ + {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_CONNECT_B3_REJECT, 0}, + {ST_NCCI_INCOMING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_RESP, 0}, + {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0}, + {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0}, + /* N-2 */ + {ST_NCCI_ALLOCATED, ST_NCCI_ACTIVE, EV_NCCI_CONNECT_B3_ACTIVE_IND, 0}, + {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0}, + {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0}, + /* N-ACT */ + {ST_NCCI_ACTIVE, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, 0}, + {ST_NCCI_ACTIVE, ST_NCCI_RESETING, EV_NCCI_RESET_B3_REQ, 0}, + {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0}, + {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0}, + /* N-3 */ + {ST_NCCI_RESETING, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, 0}, + {ST_NCCI_RESETING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0}, + {ST_NCCI_RESETING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0}, + /* N-4 */ + {ST_NCCI_DISCONNECTING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0}, + {ST_NCCI_DISCONNECTING, ST_NCCI_PREVIOUS, EV_NCCI_DISCONNECT_B3_CONF_ERROR,0}, + /* N-5 */ + {ST_NCCI_DISCONNECTED, ST_NCCI_NONE, EV_NCCI_DISCONNECT_B3_RESP, n0}, + { 0, 0, 0, 0 }, +}; + +static void ncci_change_state(capi_contr * card, capi_ncci * ncci, int event) +{ + capiconn_callbacks *cb = card->ctx->cb; + struct nccistatechange *p = nccitable; + while (p->event) { + if (ncci->state == p->actstate && p->event == event) { + (*cb->debugmsg)("ncci_change_state:0x%x %d -> %d", + ncci->ncci, ncci->state, p->nextstate); + if (p->nextstate == ST_NCCI_PREVIOUS) { + ncci->state = ncci->oldstate; + ncci->oldstate = p->actstate; + } else { + ncci->oldstate = p->actstate; + ncci->state = p->nextstate; + } + if (p->changefunc) + p->changefunc(card, ncci); + return; + } + p++; + } + (*cb->errmsg)("ncci_change_state:0x%x state=%d event=%d ????", + ncci->ncci, ncci->state, event); +} + +/* ------------------------------------------------------------------- */ + +static void handle_controller(capiconn_context *ctx, _cmsg * cmsg) +{ + capi_contr *card = findcontrbynumber(ctx, cmsg->adr.adrController&0x7f); + capiconn_callbacks *cb = ctx->cb; + + if (!card) { + (*cb->errmsg)("capiconn: %s from unknown controller 0x%x", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->adr.adrController & 0x7f); + return; + } + switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) { + + case CAPI_LISTEN_CONF: /* Controller */ + (*cb->debugmsg)("contr %d: listenconf Info=0x%04x (%s) cipmask=0x%x", + card->contrnr, cmsg->Info, capi_info2str(cmsg->Info), card->cipmask); + if (cmsg->Info) { + listen_change_state(card, EV_LISTEN_CONF_ERROR); + } else if (card->cipmask == 0) { + listen_change_state(card, EV_LISTEN_CONF_EMPTY); + } else { + listen_change_state(card, EV_LISTEN_CONF_OK); + } + break; + + case CAPI_MANUFACTURER_IND: /* Controller */ +#if 0 + if ( cmsg->ManuID == 0x214D5641 + && cmsg->Class == 0 + && cmsg->Function == 1) { + _cbyte *data = cmsg->ManuData+3; + _cword len = cmsg->ManuData[0]; + _cword layer; + int direction; + if (len == 255) { + len = (cmsg->ManuData[1] | (cmsg->ManuData[2] << 8)); + data += 2; + } + len -= 2; + layer = ((*(data-1)) << 8) | *(data-2); + if (layer & 0x300) + direction = (layer & 0x200) ? 0 : 1; + else direction = (layer & 0x800) ? 0 : 1; + if (layer & 0x0C00) { + if ((layer & 0xff) == 0x80) { + handle_dtrace_data(card, direction, 1, data, len); + break; + } + } else if ((layer & 0xff) < 0x80) { + handle_dtrace_data(card, direction, 0, data, len); + break; + } + (*cb->infomsg)("%s from controller %d layer 0x%x, ignored", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->adr.adrController, layer); + break; + } +#endif + goto ignored; + case CAPI_MANUFACTURER_CONF: /* Controller */ + if (cmsg->ManuID == 0x214D5641) { + char *s = 0; + switch (cmsg->Class) { + case 0: break; + case 1: s = "unknown class"; break; + case 2: s = "unknown function"; break; + default: s = "unkown error"; break; + } + if (s) + (*cb->infomsg)("%s from controller 0x%x function %d: %s", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->adr.adrController, + cmsg->Function, s); + break; + } + goto ignored; + case CAPI_FACILITY_IND: /* Controller/plci/ncci */ + goto ignored; + case CAPI_FACILITY_CONF: /* Controller/plci/ncci */ + goto ignored; + case CAPI_INFO_IND: /* Controller/plci */ + goto ignored; + case CAPI_INFO_CONF: /* Controller/plci */ + goto ignored; + + default: + (*cb->errmsg)("got %s from controller 0x%x ???", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->adr.adrController); + } + return; + + ignored: + (*cb->infomsg)("%s from controller 0x%x ignored", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->adr.adrController); +} + +static void check_incoming_complete(capi_connection *plcip) +{ + capi_contr *card = plcip->contr; + capiconn_context *ctx = card->ctx; + capiconn_callbacks *cb = ctx->cb; + capi_contrinfo *cip = &card->cinfo; + unsigned ddilen = plcip->contr->ddilen; + + if (ddilen) { + unsigned len = plcip->conninfo.callednumber[0]-2; + char *num = plcip->conninfo.callednumber+2; + char *start; + int ndigits; + + if ((start = strstr(num, cip->ddi)) != 0) + len = strlen(start); + ndigits = len - ddilen; + if (ndigits < cip->ndigits) { + (*cb->debugmsg)("%d digits missing (%s)", + cip->ndigits-ndigits, num); + return; + } + } + if (*cb->incoming) + (*cb->incoming)(plcip, + plcip->contr->contrnr, + plcip->conninfo.cipvalue, + plcip->conninfo.callednumber+2, + plcip->conninfo.callingnumber+3); + + if (plcip->state == ST_PLCI_INCOMING) { + /* call not accepted, rejected or ignored */ + capi_fill_ALERT_REQ(&cmsg, + ctx->appid, + card->msgid++, + plcip->plci, /* adr */ + 0, /* BChannelinformation */ + 0, /* Keypadfacility */ + 0, /* Useruserdata */ + 0 /* Facilitydataarray */ + ); + plcip->msgid = cmsg.Messagenumber; + send_message(card, &cmsg); + } +} + +static void handle_incoming_call(capi_contr * card, _cmsg * cmsg) +{ + capiconn_context *ctx = card->ctx; + capiconn_callbacks *cb = ctx->cb; + capi_connection *plcip; + + if ((plcip = new_plci(card, 1)) == 0) { + (*cb->errmsg)("incoming call on contr %d: no memory, sorry.", card->contrnr); + goto ignore; + } + plcip->plci = cmsg->adr.adrPLCI; + if (set_conninfo1b(ctx, &plcip->conninfo, + cmsg->CIPValue, + cmsg->CalledPartyNumber, + cmsg->CallingPartyNumber) < 0) { + free_plci(card, plcip); + goto ignore; + } + plci_change_state(card, plcip, EV_PLCI_CONNECT_IND); + + (*cb->infomsg)("incoming call contr=%d cip=%d %s -> %s", + card->contrnr, + cmsg->CIPValue, + plcip->conninfo.callingnumber + 3, + plcip->conninfo.callednumber + 2); + + if (cb->incoming == 0) + goto ignore; + + check_incoming_complete(plcip); + + return; + +ignore: + capi_fill_CONNECT_RESP(&cmdcmsg, + ctx->appid, + card->msgid++, + cmsg->adr.adrPLCI, + 1, /* ignore call */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, /* ConnectedNumber */ + 0, /* ConnectedSubaddress */ + 0, /* LLC */ + 0, /* BChannelinformation */ + 0, /* Keypadfacility */ + 0, /* Useruserdata */ + 0 /* Facilitydataarray */ + ); + capi_cmsg2message(&cmdcmsg, cmdcmsg.buf); + send_message(card, &cmdcmsg); +} + +static int handle_charge_info(capi_connection *plcip, _cmsg *cmsg) +{ + capiconn_context *ctx = plcip->ctx; + capiconn_callbacks *cb = ctx->cb; + unsigned char *p = cmsg->InfoElement; + unsigned long charge = 0; + + if ((cmsg->InfoNumber & 0x4000) && p[0] == 4) { + unsigned char *p = &cmsg->InfoElement[1]; + charge |= ((unsigned)p[1]); + charge |= ((unsigned)p[2]) << 8; + charge |= ((unsigned)p[3]) << 16; + charge |= ((unsigned)p[4]) << 24; + if (cb->chargeinfo) { + if (cmsg->InfoNumber & 0x1) + (*cb->chargeinfo)(plcip, charge, 0); + else (*cb->chargeinfo)(plcip, charge, 1); + } + return 1; + } else if (p[0] > 10 && memcmp("*AOC2*12*", p+1, 9) == 0) { + int i, len = p[0]-10; + if (len > 8) len = 8; + for (i=0; i < len; i++) + charge = charge * 10 + (p[10+i] - '0'); + if (cb->chargeinfo) + (*cb->chargeinfo)(plcip, charge, 0); + return 1; + } else if (p[0] > 7 && memcmp("FR.", p+1, 3) == 0) { + int i, len = p[0]-3; + for (i=0; p[3+i] != '.' && i < len; i++) + charge = charge * 10 + (p[3+i] - '0'); + charge = charge * 10; + if (p[3+i] == '.' && i+1 < len) + charge += (p[3+i+1] - '0'); + if (cb->chargeinfo) + (*cb->chargeinfo)(plcip, charge, 0); + return 1; + } + return 0; +} + +static int handle_callednumber_info(capi_connection *plcip, _cmsg *cmsg) +{ + unsigned char *p = cmsg->InfoElement; + if (cmsg->InfoNumber == 0x0070) { + extend_callednumber(plcip->ctx, &plcip->conninfo, p+2, p[0]-1); + check_incoming_complete(plcip); + return 1; + } + return 0; +} + +static void handle_plci(capiconn_context *ctx, _cmsg * cmsg) +{ + capi_contr *card = findcontrbynumber(ctx, cmsg->adr.adrController&0x7f); + capiconn_callbacks *cb = ctx->cb; + capi_connection *plcip; + + if (!card) { + (*cb->errmsg)("capiconn: %s from unknown controller 0x%x", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->adr.adrController & 0x7f); + return; + } + switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) { + + case CAPI_DISCONNECT_IND: /* plci */ + if (cmsg->Reason) { + (*cb->debugmsg)("%s reason 0x%x (%s) for plci 0x%x", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->Reason, capi_info2str(cmsg->Reason), cmsg->adr.adrPLCI); + } + if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI))) { + capi_cmsg_answer(cmsg); + send_message(card, cmsg); + goto notfound; + } + plcip->disconnectreason = cmsg->Reason; + plcip->disconnecting = 1; + plci_change_state(card, plcip, EV_PLCI_DISCONNECT_IND); + capi_cmsg_answer(cmsg); + send_message(card, cmsg); + plci_change_state(card, plcip, EV_PLCI_DISCONNECT_RESP); + break; + + case CAPI_DISCONNECT_CONF: /* plci */ + if (cmsg->Info) { + (*cb->infomsg)("%s info 0x%x (%s) for plci 0x%x", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->Info, capi_info2str(cmsg->Info), + cmsg->adr.adrPLCI); + } + if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI))) + goto notfound; + + plcip->disconnecting = 1; + break; + + case CAPI_ALERT_CONF: /* plci */ + if (cmsg->Info) { + (*cb->infomsg)("%s info 0x%x (%s) for plci 0x%x", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->Info, capi_info2str(cmsg->Info), + cmsg->adr.adrPLCI); + } + break; + + case CAPI_CONNECT_IND: /* plci */ + handle_incoming_call(card, cmsg); + break; + + case CAPI_CONNECT_CONF: /* plci */ + if (cmsg->Info) { + (*cb->infomsg)("%s info 0x%x (%s) for plci 0x%x", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->Info, capi_info2str(cmsg->Info), + cmsg->adr.adrPLCI); + } + if (!(plcip = find_plci_by_msgid(card, cmsg->Messagenumber))) + goto notfound; + + plcip->plci = cmsg->adr.adrPLCI; + if (cmsg->Info) { + plci_change_state(card, plcip, EV_PLCI_CONNECT_CONF_ERROR); + } else { + plci_change_state(card, plcip, EV_PLCI_CONNECT_CONF_OK); + } + break; + + case CAPI_CONNECT_ACTIVE_IND: /* plci */ + + if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI))) + goto notfound; + + if (plcip->incoming) { + capi_cmsg_answer(cmsg); + send_message(card, cmsg); + plci_change_state(card, plcip, EV_PLCI_CONNECT_ACTIVE_IND); + } else { + capi_ncci *nccip; + capi_cmsg_answer(cmsg); + send_message(card, cmsg); + + nccip = new_ncci(card, plcip, cmsg->adr.adrPLCI); + + if (!nccip) { + (*cb->errmsg)("no mem for ncci on contr %d, sorry", card->contrnr); + break; /* $$$$ */ + } + capi_fill_CONNECT_B3_REQ(cmsg, + ctx->appid, + card->msgid++, + plcip->plci, /* adr */ + plcip->conninfo.ncpi); + nccip->msgid = cmsg->Messagenumber; + send_message(card, cmsg); + plci_change_state(card, plcip, EV_PLCI_CONNECT_ACTIVE_IND); + ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_REQ); + } + break; + + case CAPI_INFO_IND: /* Controller/plci */ + + if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI))) + goto notfound; + + if (handle_charge_info(plcip, cmsg)) { + capi_cmsg_answer(cmsg); + send_message(card, cmsg); + } else if (handle_callednumber_info(plcip, cmsg)) { + capi_cmsg_answer(cmsg); + send_message(card, cmsg); + } else { + capi_cmsg_answer(cmsg); + send_message(card, cmsg); + } + break; + + case CAPI_CONNECT_ACTIVE_CONF: /* plci */ + goto ignored; + case CAPI_SELECT_B_PROTOCOL_CONF: /* plci */ + goto ignored; + case CAPI_FACILITY_IND: /* Controller/plci/ncci */ + goto ignored; + case CAPI_FACILITY_CONF: /* Controller/plci/ncci */ + goto ignored; + case CAPI_INFO_CONF: /* Controller/plci */ + goto ignored; + + default: + (*cb->errmsg)("got %s for plci 0x%x ???", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->adr.adrPLCI); + } + return; + +ignored: + (*cb->infomsg)("%s for plci 0x%x ignored", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->adr.adrPLCI); + return; + +notfound: + (*cb->errmsg)("%s: plci 0x%x not found", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->adr.adrPLCI); + return; +} + +static void handle_ncci(capiconn_context *ctx, _cmsg * cmsg) +{ + capi_contr *card = findcontrbynumber(ctx, cmsg->adr.adrController&0x7f); + capiconn_callbacks *cb = ctx->cb; + capi_connection *plcip; + capi_ncci *nccip; + unsigned char *data; + + if (!card) { + (*cb->errmsg)("capidrv: %s from unknown controller 0x%x", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->adr.adrController & 0x7f); + return; + } + switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) { + + case CAPI_CONNECT_B3_ACTIVE_IND: /* ncci */ + if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) + goto notfound; + + capi_cmsg_answer(cmsg); + send_message(card, cmsg); + ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_ACTIVE_IND); + + + (*cb->infomsg)("ncci 0x%x up", nccip->ncci); + + (*cb->connected)(nccip->plcip, cmsg->NCPI); + break; + + case CAPI_CONNECT_B3_ACTIVE_CONF: /* ncci */ + goto ignored; + + case CAPI_CONNECT_B3_IND: /* ncci */ + + plcip = find_plci_by_ncci(card, cmsg->adr.adrNCCI); + if (plcip) { + nccip = new_ncci(card, plcip, cmsg->adr.adrNCCI); + if (nccip) { + ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_IND); + capi_fill_CONNECT_B3_RESP(cmsg, + ctx->appid, + card->msgid++, + nccip->ncci, /* adr */ + 0, /* Reject */ + 0 /* NCPI */ + ); + send_message(card, cmsg); + ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_RESP); + break; + } + (*cb->errmsg)("capidrv-%d: no mem for ncci, sorry", card->contrnr); + } else { + (*cb->errmsg)("capidrv-%d: %s: plci for ncci 0x%x not found", + card->contrnr, + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->adr.adrNCCI); + } + capi_fill_CONNECT_B3_RESP(cmsg, + ctx->appid, + card->msgid++, + cmsg->adr.adrNCCI, + 2, /* Reject */ + plcip->conninfo.ncpi); + send_message(card, cmsg); + break; + + case CAPI_CONNECT_B3_CONF: /* ncci */ + + if (!(nccip = find_ncci_by_msgid(card, + cmsg->adr.adrNCCI, + cmsg->Messagenumber))) + goto notfound; + + nccip->ncci = cmsg->adr.adrNCCI; + nccip->plcip->ncci = cmsg->adr.adrNCCI; + if (cmsg->Info) { + (*cb->infomsg)("%s info 0x%x (%s) for ncci 0x%x", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->Info, capi_info2str(cmsg->Info), + cmsg->adr.adrNCCI); + } + + if (cmsg->Info) + ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_CONF_ERROR); + else + ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_CONF_OK); + break; + + case CAPI_CONNECT_B3_T90_ACTIVE_IND: /* ncci */ + capi_cmsg_answer(cmsg); + send_message(card, cmsg); + break; + + case CAPI_DATA_B3_IND: /* ncci */ + /* handled in handle_data() */ + goto ignored; + + case CAPI_DATA_B3_CONF: /* ncci */ + if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) + goto notfound; + + data = capi_del_ack(nccip, cmsg->DataHandle); + if (data == 0) + break; + if (cb->datasent) + (*cb->datasent)(nccip->plcip, data); + break; + + case CAPI_DISCONNECT_B3_IND: /* ncci */ + if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) + goto notfound; + + nccip->plcip->disconnectreason_b3 = cmsg->Reason_B3; + nccip->plcip->disconnecting = 1; + ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_IND); + capi_cmsg_answer(cmsg); + send_message(card, cmsg); + ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_RESP); + break; + + case CAPI_DISCONNECT_B3_CONF: /* ncci */ + if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) + goto notfound; + if (cmsg->Info) { + (*cb->infomsg)("%s info 0x%x (%s) for ncci 0x%x", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->Info, capi_info2str(cmsg->Info), + cmsg->adr.adrNCCI); + ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_CONF_ERROR); + } + break; + + case CAPI_RESET_B3_IND: /* ncci */ + if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) + goto notfound; + ncci_change_state(card, nccip, EV_NCCI_RESET_B3_IND); + capi_cmsg_answer(cmsg); + send_message(card, cmsg); + break; + + case CAPI_RESET_B3_CONF: /* ncci */ + goto ignored; /* $$$$ */ + + case CAPI_FACILITY_IND: /* Controller/plci/ncci */ + goto ignored; + case CAPI_FACILITY_CONF: /* Controller/plci/ncci */ + goto ignored; + + default: + (*cb->errmsg)("capidrv-%d: got %s for ncci 0x%x ???", + card->contrnr, + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->adr.adrNCCI); + } + return; +ignored: + (*cb->infomsg)("%s for ncci 0x%x ignored", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->adr.adrNCCI); + return; +notfound: + (*cb->errmsg)("%s: ncci 0x%x not found", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->adr.adrNCCI); +} + + +static void handle_data(capiconn_context *ctx, _cmsg * cmsg) +{ + capi_contr *card = findcontrbynumber(ctx,cmsg->adr.adrController&0x7f); + capiconn_callbacks *cb = ctx->cb; + capi_ncci *nccip; + unsigned char *data; + + if (!card) { + (*cb->errmsg)("capiconn: %s from unknown controller 0x%x", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->adr.adrController & 0x7f); + return; + } + if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) { + (*cb->errmsg)("%s: ncci 0x%x not found", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->adr.adrNCCI); + return; + } + data = (unsigned char *)cmsg->Data; + if (cb->received) + (*cb->received)(nccip->plcip, data, cmsg->DataLength); + capi_cmsg_answer(cmsg); + send_message(card, cmsg); +} + +static _cmsg s_cmsg; + +void capiconn_inject(unsigned applid, unsigned char *msg) +{ + capiconn_context *ctx = find_context(applid); + + if (!ctx) + return; + + capi_message2cmsg(&s_cmsg, msg); + if (s_cmsg.Command == CAPI_DATA_B3 && s_cmsg.Subcommand == CAPI_IND) { + handle_data(ctx, &s_cmsg); + ctx->nrecvdatapkt++; + return; + } + if ((s_cmsg.adr.adrController & 0xffffff00) == 0) + handle_controller(ctx, &s_cmsg); + else if ((s_cmsg.adr.adrPLCI & 0xffff0000) == 0) + handle_plci(ctx, &s_cmsg); + else + handle_ncci(ctx, &s_cmsg); + ctx->nrecvctlpkt++; +} + +/* ------------------------------------------------------------------- */ + +capi_connection *capiconn_connect( + capiconn_context *ctx, + unsigned contr, + _cword cipvalue, + char *callednumber, /* remote number */ + char *callingnumber, /* own number */ + _cword b1proto, + _cword b2proto, + _cword b3proto, + _cstruct b1config, + _cstruct b2config, + _cstruct b3config, + _cstruct bchaninfo, + _cstruct ncpi) +{ + capi_contr *card = findcontrbynumber(ctx, contr); + capiconn_callbacks *cb = ctx->cb; + capi_connection *plcip; + + if (!card) { + (*cb->errmsg)("controller %d not found", contr); + return 0; + } + + if ((plcip = new_plci(card, 0)) == 0) { + (*cb->errmsg)("no mem for plci"); + return 0; + } + + if (set_conninfo1a(ctx, &plcip->conninfo, + cipvalue, + callednumber, + callingnumber) < 0) { + clr_conninfo1(ctx, &plcip->conninfo); + free_plci(card, plcip); + (*cb->errmsg)("no mem for connection info (1a)"); + return 0; + } + + if (set_conninfo2(ctx, &plcip->conninfo, + b1proto, b2proto, b3proto, + b1config, b2config, b3config, + bchaninfo, ncpi) < 0) { + clr_conninfo1(ctx, &plcip->conninfo); + clr_conninfo2(ctx, &plcip->conninfo); + free_plci(card, plcip); + (*cb->errmsg)("no mem for connection info (2)"); + return 0; + } + + capi_fill_CONNECT_REQ(&cmdcmsg, + ctx->appid, + card->msgid++, + card->contrnr, /* adr */ + plcip->conninfo.cipvalue, + plcip->conninfo.callednumber, + plcip->conninfo.callingnumber, + 0, /* CalledPartySubaddress */ + 0, /* CallingPartySubaddress */ + plcip->conninfo.b1proto, + plcip->conninfo.b2proto, + plcip->conninfo.b3proto, + plcip->conninfo.b1config, + plcip->conninfo.b2config, + plcip->conninfo.b3config, + 0, /* BC */ + 0, /* LLC */ + 0, /* HLC */ + plcip->conninfo.bchaninfo, /* BChannelinformation */ + 0, /* Keypadfacility */ + 0, /* Useruserdata */ + 0 /* Facilitydataarray */ + ); + + plcip->msgid = cmdcmsg.Messagenumber; + plci_change_state(card, plcip, EV_PLCI_CONNECT_REQ); + send_message(card, &cmdcmsg); + return plcip; +} + +int capiconn_accept( + capi_connection *plcip, + _cword b1proto, + _cword b2proto, + _cword b3proto, + _cstruct b1config, + _cstruct b2config, + _cstruct b3config, + _cstruct ncpi) +{ + capi_contr *card = plcip->contr; + capiconn_context *ctx = card->ctx; + capiconn_callbacks *cb = ctx->cb; + + if (plcip->state != ST_PLCI_INCOMING) + return CAPICONN_WRONG_STATE; + + if (set_conninfo2(ctx, &plcip->conninfo, + b1proto, b2proto, b3proto, + b1config, b2config, b3config, + 0, ncpi) < 0) { + clr_conninfo2(ctx, &plcip->conninfo); + (*cb->errmsg)("no mem for connection info (2)"); + return CAPICONN_NO_MEMORY; + } + + (*cb->debugmsg)("accept plci 0x%04x %u,%u,%u", + plcip->plci, + plcip->conninfo.b1proto, + plcip->conninfo.b2proto, + plcip->conninfo.b3proto); + + capi_fill_CONNECT_RESP(&cmdcmsg, + ctx->appid, + card->msgid++, + plcip->plci, /* adr */ + 0, /* Reject */ + plcip->conninfo.b1proto, + plcip->conninfo.b2proto, + plcip->conninfo.b3proto, + plcip->conninfo.b1config, + plcip->conninfo.b2config, + plcip->conninfo.b3config, + 0, /* ConnectedNumber */ + 0, /* ConnectedSubaddress */ + 0, /* LLC */ + 0, /* BChannelinformation */ + 0, /* Keypadfacility */ + 0, /* Useruserdata */ + 0 /* Facilitydataarray */ + ); + capi_cmsg2message(&cmdcmsg, cmdcmsg.buf); + plci_change_state(card, plcip, EV_PLCI_CONNECT_RESP); + send_message(card, &cmdcmsg); + return CAPICONN_OK; +} + +int capiconn_ignore(capi_connection *plcip) +{ + capi_contr *card = plcip->contr; + capiconn_context *ctx = card->ctx; + + if (plcip->state != ST_PLCI_INCOMING) + return CAPICONN_WRONG_STATE; + + capi_fill_CONNECT_RESP(&cmdcmsg, + ctx->appid, + card->msgid++, + plcip->plci, /* adr */ + 1, /* ignore call */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, /* ConnectedNumber */ + 0, /* ConnectedSubaddress */ + 0, /* LLC */ + 0, /* BChannelinformation */ + 0, /* Keypadfacility */ + 0, /* Useruserdata */ + 0 /* Facilitydataarray */ + ); + capi_cmsg2message(&cmdcmsg, cmdcmsg.buf); + plci_change_state(card, plcip, EV_PLCI_CONNECT_RESP); + send_message(card, &cmdcmsg); + return CAPICONN_OK; +} + +int capiconn_reject(capi_connection *plcip) +{ + capi_contr *card = plcip->contr; + capiconn_context *ctx = card->ctx; + + if (plcip->state != ST_PLCI_INCOMING) + return CAPICONN_WRONG_STATE; + + capi_fill_CONNECT_RESP(&cmdcmsg, + ctx->appid, + card->msgid++, + plcip->plci, /* adr */ + 2, /* Reject, normal call clearing */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, /* ConnectedNumber */ + 0, /* ConnectedSubaddress */ + 0, /* LLC */ + 0, /* BChannelinformation */ + 0, /* Keypadfacility */ + 0, /* Useruserdata */ + 0 /* Facilitydataarray */ + ); + capi_cmsg2message(&cmdcmsg, cmdcmsg.buf); + plci_change_state(card, plcip, EV_PLCI_CONNECT_RESP); + send_message(card, &cmdcmsg); + return CAPICONN_OK; +} + +int capiconn_disconnect(capi_connection *plcip, _cstruct ncpi) +{ + capi_contr *card = plcip->contr; + capiconn_context *ctx = card->ctx; + + if (plcip->disconnecting) + return CAPICONN_ALREADY_DISCONNECTING; + + if (plcip->nccip) { + plcip->disconnecting = 1; + plcip->localdisconnect = 1; + capi_fill_DISCONNECT_B3_REQ(&cmdcmsg, + ctx->appid, + card->msgid++, + plcip->ncci, + ncpi); + ncci_change_state(card, plcip->nccip, EV_NCCI_DISCONNECT_B3_REQ); + send_message(card, &cmdcmsg); + return CAPICONN_OK; + } + if (plcip->state == ST_PLCI_INCOMING) { + plcip->disconnecting = 1; + plcip->localdisconnect = 1; + return capiconn_reject(plcip); + } + if (plcip->plci) { + plcip->disconnecting = 1; + plcip->localdisconnect = 1; + capi_fill_DISCONNECT_REQ(&cmdcmsg, + ctx->appid, + card->msgid++, + plcip->plci, + 0, /* BChannelinformation */ + 0, /* Keypadfacility */ + 0, /* Useruserdata */ + 0 /* Facilitydataarray */ + ); + plci_change_state(card, plcip, EV_PLCI_DISCONNECT_REQ); + send_message(card, &cmdcmsg); + return CAPICONN_OK; + } + return CAPICONN_WRONG_STATE; +} + +static _cmsg sendcmsg; + +int capiconn_send(capi_connection *plcip, + unsigned char *data, + unsigned len) +{ + capi_contr *card = plcip->contr; + capiconn_context *ctx = card->ctx; + capiconn_callbacks *cb = ctx->cb; + + capi_ncci *nccip; + _cword datahandle; + + nccip = plcip->nccip; + if (!nccip || nccip->state != ST_NCCI_ACTIVE) + return CAPICONN_WRONG_STATE; + + datahandle = nccip->datahandle; + capi_fill_DATA_B3_REQ(&sendcmsg, ctx->appid, card->msgid++, + nccip->ncci, /* adr */ + data, /* Data */ + len, /* DataLength */ + datahandle, /* DataHandle */ + 0 /* Flags */ + ); + + if (capi_add_ack(nccip, datahandle, data) < 0) + return CAPICONN_NOT_SENT; + + capi_cmsg2message(&sendcmsg, sendcmsg.buf); + (*cb->capi_put_message) (ctx->appid, sendcmsg.buf); + nccip->datahandle++; + ctx->nsentdatapkt++; + return CAPICONN_OK; +} + + +/* -------- listen handling ------------------------------------------ */ + +static void send_listen(capi_contr *card) +{ + capiconn_context *ctx = card->ctx; + _cdword infomask = 0; + infomask |= (1<<2); /* Display */ + infomask |= (1<<6); /* Charge Info */ + if (card->ddilen) + infomask |= (1<<7); /* Called Party Number */ + capi_fill_LISTEN_REQ(&cmdcmsg, ctx->appid, + card->msgid++, + card->contrnr, + infomask, + card->cipmask, + card->cipmask2, + 0, 0); + send_message(card, &cmdcmsg); + listen_change_state(card, EV_LISTEN_REQ); +} + +int +capiconn_listen(capiconn_context *ctx, + unsigned contr, unsigned cipmask, unsigned cipmask2) +{ + capi_contr *card = findcontrbynumber(ctx, contr & 0x7f); + + if (card == 0) + return CAPICONN_NO_CONTROLLER; + + card->cipmask = cipmask; /* 0x1FFF03FF */ + card->cipmask2 = cipmask2; /* 0 */ + + send_listen(card); + return CAPICONN_OK; +} + +int +capiconn_listenstate(capiconn_context *ctx, unsigned contr) +{ + capi_contr *card = findcontrbynumber(ctx, contr & 0x7f); + + if (card == 0) + return CAPICONN_NO_CONTROLLER; + if (card->state != ST_LISTEN_NONE && card->state != ST_LISTEN_ACTIVE) + return CAPICONN_WRONG_STATE; + return CAPICONN_OK; +} diff --git a/pppdcapiplugin/capiconn.h b/pppdcapiplugin/capiconn.h new file mode 100644 index 00000000..3c999dbe --- /dev/null +++ b/pppdcapiplugin/capiconn.h @@ -0,0 +1,418 @@ +/* + * $Id: capiconn.h,v 1.1 2000/05/18 14:58:35 calle Exp $ + * + * $Log: capiconn.h,v $ + * Revision 1.1 2000/05/18 14:58:35 calle + * Plugin for pppd to support PPP over CAPI2.0. + * + */ + +#ifndef __CAPICONN_H__ +#define __CAPICONN_H__ + +#include +#include + +/* + * CAPI_MESSAGES: + * capiconn_inject(): + * inject capi message into state machine + * + * capiconn_context: + * capiconn_getcontext(): + * get a context and supply callback functions + * capiconn_freecontext(): + * free a context allocated with "capiconn_getcontext" + * capiconn_addcontr(): + * add a controller to the context + * capi_connection: + * capiconn_connect(): + * connection setup, return a capi_connection. + * capiconn_accept(): + * accept an incoming connection + * capiconn_ignore(): + * ignore an incoming connection + * capiconn_reject(): + * reject an incoming connection + * capiconn_send(): + * send data to the connection + * capiconn_disconnect(): + * disconnect a connection + * capiconn_getinfo() + * get infos about the connection + * capiconn_listen(): + * setup listen + */ + +/* -------- returncodes -------------------------------------------------- */ + +#define CAPICONN_OK 0 +#define CAPICONN_NO_CONTROLLER -1 +#define CAPICONN_NO_MEMORY -2 +#define CAPICONN_WRONG_STATE 1 +#define CAPICONN_NOT_SENT 2 +#define CAPICONN_ALREADY_DISCONNECTING 3 + +/* -------- states for CAPI2.0 machine ----------------------------------- */ + +/* + * LISTEN state machine + */ +#define ST_LISTEN_NONE 0 /* L-0 */ +#define ST_LISTEN_WAIT_CONF 1 /* L-0.1 */ +#define ST_LISTEN_ACTIVE 2 /* L-1 */ +#define ST_LISTEN_ACTIVE_WAIT_CONF 3 /* L-1.1 */ + + +#define EV_LISTEN_REQ 1 /* L-0 -> L-0.1 + L-1 -> L-1.1 */ +#define EV_LISTEN_CONF_ERROR 2 /* L-0.1 -> L-0 + L-1.1 -> L-1 */ +#define EV_LISTEN_CONF_EMPTY 3 /* L-0.1 -> L-0 + L-1.1 -> L-0 */ +#define EV_LISTEN_CONF_OK 4 /* L-0.1 -> L-1 + L-1.1 -> L.1 */ + +/* + * per plci state machine + */ +#define ST_PLCI_NONE 0 /* P-0 */ +#define ST_PLCI_OUTGOING 1 /* P-0.1 */ +#define ST_PLCI_ALLOCATED 2 /* P-1 */ +#define ST_PLCI_ACTIVE 3 /* P-ACT */ +#define ST_PLCI_INCOMING 4 /* P-2 */ +#define ST_PLCI_FACILITY_IND 5 /* P-3 */ +#define ST_PLCI_ACCEPTING 6 /* P-4 */ +#define ST_PLCI_DISCONNECTING 7 /* P-5 */ +#define ST_PLCI_DISCONNECTED 8 /* P-6 */ +#define ST_PLCI_RESUMEING 9 /* P-0.Res */ +#define ST_PLCI_RESUME 10 /* P-Res */ +#define ST_PLCI_HELD 11 /* P-HELD */ + +#define EV_PLCI_CONNECT_REQ 1 /* P-0 -> P-0.1 + */ +#define EV_PLCI_CONNECT_CONF_ERROR 2 /* P-0.1 -> P-0 + */ +#define EV_PLCI_CONNECT_CONF_OK 3 /* P-0.1 -> P-1 + */ +#define EV_PLCI_FACILITY_IND_UP 4 /* P-0 -> P-1 + */ +#define EV_PLCI_CONNECT_IND 5 /* P-0 -> P-2 + */ +#define EV_PLCI_CONNECT_ACTIVE_IND 6 /* P-1 -> P-ACT + */ +#define EV_PLCI_CONNECT_REJECT 7 /* P-2 -> P-5 + P-3 -> P-5 + */ +#define EV_PLCI_DISCONNECT_REQ 8 /* P-1 -> P-5 + P-2 -> P-5 + P-3 -> P-5 + P-4 -> P-5 + P-ACT -> P-5 + P-Res -> P-5 (*) + P-HELD -> P-5 (*) + */ +#define EV_PLCI_DISCONNECT_IND 9 /* P-1 -> P-6 + P-2 -> P-6 + P-3 -> P-6 + P-4 -> P-6 + P-5 -> P-6 + P-ACT -> P-6 + P-Res -> P-6 (*) + P-HELD -> P-6 (*) + */ +#define EV_PLCI_FACILITY_IND_DOWN 10 /* P-0.1 -> P-5 + P-1 -> P-5 + P-ACT -> P-5 + P-2 -> P-5 + P-3 -> P-5 + P-4 -> P-5 + */ +#define EV_PLCI_DISCONNECT_RESP 11 /* P-6 -> P-0 + */ +#define EV_PLCI_CONNECT_RESP 12 /* P-6 -> P-0 + */ + +#define EV_PLCI_RESUME_REQ 13 /* P-0 -> P-0.Res + */ +#define EV_PLCI_RESUME_CONF_OK 14 /* P-0.Res -> P-Res + */ +#define EV_PLCI_RESUME_CONF_ERROR 15 /* P-0.Res -> P-0 + */ +#define EV_PLCI_RESUME_IND 16 /* P-Res -> P-ACT + */ +#define EV_PLCI_HOLD_IND 17 /* P-ACT -> P-HELD + */ +#define EV_PLCI_RETRIEVE_IND 18 /* P-HELD -> P-ACT + */ +#define EV_PLCI_SUSPEND_IND 19 /* P-ACT -> P-5 + */ +#define EV_PLCI_CD_IND 20 /* P-2 -> P-5 + */ + +/* + * per ncci state machine + */ +#define ST_NCCI_PREVIOUS -1 +#define ST_NCCI_NONE 0 /* N-0 */ +#define ST_NCCI_OUTGOING 1 /* N-0.1 */ +#define ST_NCCI_INCOMING 2 /* N-1 */ +#define ST_NCCI_ALLOCATED 3 /* N-2 */ +#define ST_NCCI_ACTIVE 4 /* N-ACT */ +#define ST_NCCI_RESETING 5 /* N-3 */ +#define ST_NCCI_DISCONNECTING 6 /* N-4 */ +#define ST_NCCI_DISCONNECTED 7 /* N-5 */ + +#define EV_NCCI_CONNECT_B3_REQ 1 /* N-0 -> N-0.1 */ +#define EV_NCCI_CONNECT_B3_IND 2 /* N-0 -> N.1 */ +#define EV_NCCI_CONNECT_B3_CONF_OK 3 /* N-0.1 -> N.2 */ +#define EV_NCCI_CONNECT_B3_CONF_ERROR 4 /* N-0.1 -> N.0 */ +#define EV_NCCI_CONNECT_B3_REJECT 5 /* N-1 -> N-4 */ +#define EV_NCCI_CONNECT_B3_RESP 6 /* N-1 -> N-2 */ +#define EV_NCCI_CONNECT_B3_ACTIVE_IND 7 /* N-2 -> N-ACT */ +#define EV_NCCI_RESET_B3_REQ 8 /* N-ACT -> N-3 */ +#define EV_NCCI_RESET_B3_IND 9 /* N-3 -> N-ACT */ +#define EV_NCCI_DISCONNECT_B3_IND 10 /* N-4 -> N.5 */ +#define EV_NCCI_DISCONNECT_B3_CONF_ERROR 11 /* N-4 -> previous */ +#define EV_NCCI_DISCONNECT_B3_REQ 12 /* N-1 -> N-4 + N-2 -> N-4 + N-3 -> N-4 + N-ACT -> N-4 */ +#define EV_NCCI_DISCONNECT_B3_RESP 13 /* N-5 -> N-0 */ + +/* ----------------------------------------------------------------------- */ + + +/* -------- context ------------------------------------------------------ */ + +struct capi_connection; typedef struct capi_connection capi_connection; +struct capiconn_context; typedef struct capiconn_context capiconn_context; + +struct capiconn_callbacks +{ + /* ---------- memory functions ----------------- */ + + void *(*malloc)(size_t size); + void (*free)(void *buf); + + /* ---------- connection callbacks ------------- */ + + /* + * the capi_connection will be destoried after + * calling this function + */ + void (*disconnected)(capi_connection *, + int localdisconnect, + unsigned reason, + unsigned reason_b3); + /* + * The application should call capiconn_accept() + * capiconn_ignore() or capiconn_reject() inside + * of the function. If not called an ALERT_REQ will + * be sent, to let the application time to decide ... + */ + void (*incoming)(capi_connection *, + unsigned contr, + unsigned chipvalue, + char *callednumber, + char *callingnumber); + + /* + * Channel is ready to send and receive data + */ + void (*connected)(capi_connection *, _cstruct); + + /* + * Data received on channel, the data pointer + * can not be used, after this function is called. + */ + void (*received)(capi_connection *, + unsigned char *data, + unsigned datalen); + + /* + * called for every call to capiconn_send(). + */ + void (*datasent)(capi_connection *, unsigned char *); + + /* + * charge info received + */ + void (*chargeinfo)(capi_connection *, + unsigned long charge, + int inunits); + /* + * capi functions + */ + void (*capi_put_message) (unsigned appid, unsigned char *msg); + + /* + * message functions + */ + void (*debugmsg)(const char *fmt, ...); + void (*infomsg)(const char *fmt, ...); + void (*errmsg)(const char *fmt, ...); +}; +typedef struct capiconn_callbacks capiconn_callbacks; + +/* -------- context functions -------------------------------------------- */ + +capiconn_context *capiconn_getcontext(unsigned appid, capiconn_callbacks *env); + +int capiconn_freecontext(capiconn_context *ctx); + +/* -------- inject capi message into state machine ----------------------- */ + +void capiconn_inject(unsigned appid, unsigned char *msg); + +/* -------- add controller to context ------------------------------------ */ + +struct capi_contrinfo { + int bchannels; + char *ddi; + int ndigits; /* Durchwahllaenge */ +}; +typedef struct capi_contrinfo capi_contrinfo; + +/* + * returncodes: + * CAPICONN_OK - controller added to the context + * CAPICONN_NO_MEMORY - callback "malloc" returns no memory. + */ +int capiconn_addcontr(capiconn_context *ctx, + unsigned contr, capi_contrinfo *cinfo); + +/* -------- initiate a connection & disconnect a connection -------------- */ + +/* + * returncodes: + * a capi connection or 0 if + * - controller not found + * - memory problems + */ + +capi_connection * +capiconn_connect( + capiconn_context *ctx, + unsigned contr, + _cword cipvalue, + char *callednumber, /* remote number */ + char *callingnumber, /* own number */ + _cword b1proto, + _cword b2proto, + _cword b3proto, + _cstruct b1config, + _cstruct b2config, + _cstruct b3config, + _cstruct bchaninfo, + _cstruct ncpi); + +/* + * returncodes: + * CAPICONN_OK - disconnect initiated + * CAPICONN_ALREADY_DISCONNECTING - disconnect already initiated + * CAPICONN_WRONG_STATE - should not happen + */ +int capiconn_disconnect(capi_connection *connection, _cstruct ncpi); + +/* -------- reaction on incoming calls ----------------------------------- */ + +/* + * returncodes: + * CAPICONN_OK - Accept initiated + * CAPICONN_WRONG_STATE - "conn" ist not in state "incoming" + * CAPICONN_NO_MEMORY - callback "malloc" returns no memory. + */ +int capiconn_accept( + capi_connection *conn, + _cword b1proto, + _cword b2proto, + _cword b3proto, + _cstruct b1config, + _cstruct b2config, + _cstruct b3config, + _cstruct ncpi); + +/* + * returncodes: + * CAPICONN_OK - call will be ignored + * CAPICONN_WRONG_STATE - "conn" ist not in state "incoming" + */ +int capiconn_ignore(capi_connection *conn); + +/* + * returncodes: + * CAPICONN_OK - call will be rejected + * CAPICONN_WRONG_STATE - "conn" ist not in state "incoming" + */ +int capiconn_reject(capi_connection *conn); + +/* + * returncode: + * CAPICONN_OK - Data sent to CAPI + * CAPICONN_NOT_SENT - Data not sent (8 messages not acked) + * CAPICONN_WRONG_STATE - Connection is not connected + */ +int capiconn_send(capi_connection *plcip, + unsigned char *data, + unsigned len); + +/* + * get info about connection + */ + +struct capi_conninfo { + unsigned appid; + + unsigned plci; + int plci_state; + unsigned ncci; + int ncci_state; + unsigned isincoming:1, + disconnect_was_local; + unsigned disconnectreason; + unsigned disconnectreason_b3; + + /* user supplied */ + _cword cipvalue; + _cstruct callednumber; + _cstruct callingnumber; + _cword b1proto; + _cword b2proto; + _cword b3proto; + _cstruct b1config; + _cstruct b2config; + _cstruct b3config; + _cstruct bchaninfo; + _cstruct ncpi; +}; +typedef struct capi_conninfo capi_conninfo; + +/* + * returncode: + * always a pointer to the conninfo. + * the conninfo will not be update automaticly, + * you always have to call this function to get + * the actual informations. + */ +capi_conninfo *capiconn_getinfo(capi_connection *p); + +/* + * returncodes: + * CAPICONN_OK - Listen request sent + * CAPICONN_NO_CONTROLLER - Controller "contr" not added with + * capiconn_addcontr() + */ +int capiconn_listen(capiconn_context *ctx, + unsigned contr, unsigned cipmask, unsigned cipmask2); + +/* + * returncodes: + * CAPICONN_OK - got ack for listen request + * CAPICONN_NO_CONTROLLER - Controller "contr" not added with + * capiconn_addcontr() + * CAPICONN_WRONG_STATE - got no ack for listen request + */ +int capiconn_listenstate(capiconn_context *ctx, unsigned contr); + +#endif /* __CAPICONN_H__ */ diff --git a/pppdcapiplugin/capiplugin.c b/pppdcapiplugin/capiplugin.c new file mode 100644 index 00000000..e5a6d2df --- /dev/null +++ b/pppdcapiplugin/capiplugin.c @@ -0,0 +1,284 @@ +/* + * capiconnect.c - pppd plugin to implement a `minconnect' option. + * + * Copyright 2000 Carsten Paeth (calle@calle.de) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include "pppd.h" +#include "capiconn.h" +#include +#include +#include + +static capiconn_context *ctx; +static capi_connection *conn = 0; +static int isconnected = 0; +static unsigned applid; + +static int opt_contr = 1; +static char *opt_numberprefix = 0; +static char *opt_number = 0; +static char *opt_msn = 0; +static char *opt_proto = 0; + +static option_t my_options[] = { + { + "controller", o_int, &opt_contr, + "capi controller" + }, + { + "number", o_string, &opt_number, + "number to call" + }, + { + "numberprefix", o_string, &opt_numberprefix, + "prefix for number" + }, + { + "msn", o_string, &opt_msn, + "number to call from" + }, + { + "protocol", o_string, &opt_proto, + "protocol x75 or hdlc" + }, + { NULL } +}; + +/* -------------------------------------------------------------------- */ + +static void dodisconnect(void) +{ + if (!conn) + return; + (void)capiconn_disconnect(conn, 0); + while (conn) { + unsigned char *msg = 0; + struct timeval tv; + tv.tv_sec = 1; + tv.tv_usec = 0; + if (capi20_waitformessage(applid, &tv) == 0) { + if (capi20_get_message (applid, &msg) == 0) + capiconn_inject(applid, msg); + } + } +} + +static void makeconnection(void) +{ + char number[256]; + + if (opt_number == 0) { + fatal("capiplugin: no number"); + return; + } + + snprintf(number, sizeof(number), "%s%s", + opt_numberprefix ? opt_numberprefix : "", + opt_number); + if (opt_proto == 0 || strcasecmp(opt_proto, "hdlc") == 0) { + conn = capiconn_connect(ctx, + opt_contr, /* contr */ + 2, /* cipvalue */ + number, + opt_msn, + 0, 1, 0, + 0, 0, 0, 0, 0); + } else if (strcasecmp(opt_proto, "x75") == 0) { + conn = capiconn_connect(ctx, + opt_contr, /* contr */ + 2, /* cipvalue */ + number, + opt_msn, + 0, 0, 0, + 0, 0, 0, 0, 0); + } else if (strcasecmp(opt_proto, "modem") == 0) { + conn = capiconn_connect(ctx, + opt_contr, /* contr */ + 1, /* cipvalue */ + number, + opt_msn, + 8, 1, 0, + 0, 0, 0, 0, 0); + } else { + fatal("capiplugin: unknown protocol \"%s\"", opt_proto); + return; + } + while (!isconnected && conn) { + unsigned char *msg = 0; + struct timeval tv; + tv.tv_sec = 1; + tv.tv_usec = 0; + if (capi20_waitformessage(applid, &tv) == 0) { + if (capi20_get_message (applid, &msg) == 0) + capiconn_inject(applid, msg); + } + } + if (!conn) + fatal("capiplugin: couldn't make connection"); +} + +static void init_capiconn(void) +{ + static capi_contrinfo cinfo = { 0 , 0, 0 }; + static int init = 0; + + if (init) + return; + init = 1; + + if (capiconn_addcontr(ctx, opt_contr, &cinfo) != CAPICONN_OK) { + (void)capiconn_freecontext(ctx); + (void)capi20_release(applid); + fatal("capiplugin: add controller %d failed", opt_contr); + return; + } +} + +static int capi_new_phase_hook(int phase) +{ + switch (phase) { + case PHASE_DEAD: + info("capiplugin: phase dead"); + dodisconnect(); + break; + case PHASE_INITIALIZE: + info("capiplugin: phase initialize"); + break; + case PHASE_SERIALCONN: + info("capiplugin: phase serialconn"); + init_capiconn(); + makeconnection(); + break; + case PHASE_DORMANT: + info("capiplugin: phase dormant"); + break; + case PHASE_ESTABLISH: + info("capiplugin: phase establish"); + break; + case PHASE_AUTHENTICATE: + info("capiplugin: phase authenticate"); + break; + case PHASE_CALLBACK: + info("capiplugin: phase callback"); + break; + case PHASE_NETWORK: + info("capiplugin: phase network"); + break; + case PHASE_RUNNING: + info("capiplugin: phase running"); + break; + case PHASE_TERMINATE: + info("capiplugin: phase terminate"); + break; + case PHASE_DISCONNECT: + info("capiplugin: phase disconnect"); + break; + case PHASE_HOLDOFF: + info("capiplugin: phase holdoff"); + break; + } + return 0; +} + +/* -------------------------------------------------------------------- */ + +static char *conninfo(capi_connection *p) +{ + static char buf[1024]; + capi_conninfo *cp = capiconn_getinfo(p); + + snprintf(buf, sizeof(buf), + "plci=0x%x ncci=0x%x %s", + cp->plci, + cp->ncci, + cp->isincoming ? "incoming" : "outgoing" + ); + return buf; +} + +static void disconnected(capi_connection *cp, + int localdisconnect, + unsigned reason, + unsigned reason_b3) +{ + info("capiplugin: disconnected(%s): %s: 0x%04x (0x%04x) - %s", + conninfo(cp), + localdisconnect ? "local" : "remote", + reason, reason_b3, capi_info2str(reason)); + conn = 0; + isconnected = 0; +} + +static void connected(capi_connection *cp, _cstruct NCPI) +{ + capi_conninfo *p = capiconn_getinfo(cp); + char buf[PATH_MAX]; + char *tty; + + tty = capi20ext_get_tty_devname(p->appid, p->ncci, buf, sizeof(buf)); + info("capiplugin: connected(%s) %s", conninfo(cp), tty); + strcpy(devnam, tty); + isconnected = 1; +} + +void put_message(unsigned appid, unsigned char *msg) +{ + unsigned err; + err = capi20_put_message (appid, msg); + if (err) + fatal("capiplugin: putmessage(appid=%u) = 0x%x", appid, err); +} + +/* -------------------------------------------------------------------- */ + +capiconn_callbacks callbacks = { + malloc: malloc, + free: free, + + disconnected: disconnected, + incoming: 0, + connected: connected, + received: 0, + datasent: 0, + chargeinfo: 0, + + capi_put_message: put_message, + + debugmsg: dbglog, + infomsg: info, + errmsg: error +}; + +void plugin_init(void) +{ + int err; + + info("plugin_init: capiconnect"); + + add_options(my_options); + + if ((err = capi20_register (30, 8, 2048, &applid)) != 0) { + fatal("capiplugin: CAPI_REGISTER failed - 0x%04x", err); + return; + } + if (capi20ext_set_flags(applid, 1) < 0) { + (void)capi20_release(applid); + fatal("capiplugin: failed to set highjacking mode"); + return; + } + + if ((ctx = capiconn_getcontext(applid, &callbacks)) == 0) { + (void)capi20_release(applid); + fatal("capiplugin: get_context failed"); + return; + } + + new_phase_hook = capi_new_phase_hook; +} diff --git a/pppdcapiplugin/install-sh b/pppdcapiplugin/install-sh new file mode 100755 index 00000000..e9de2384 --- /dev/null +++ b/pppdcapiplugin/install-sh @@ -0,0 +1,251 @@ +#!/bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5 (mit/util/scripts/install.sh). +# +# Copyright 1991 by the Massachusetts Institute of Technology +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, provided that +# the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation, and that the name of M.I.T. not be used in advertising or +# publicity pertaining to distribution of the software without specific, +# written prior permission. M.I.T. makes no representations about the +# suitability of this software for any purpose. It is provided "as is" +# without express or implied warranty. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +transformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + chmodcmd="" + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/pppdcapiplugin/mkinstalldirs b/pppdcapiplugin/mkinstalldirs new file mode 100755 index 00000000..4cd044a9 --- /dev/null +++ b/pppdcapiplugin/mkinstalldirs @@ -0,0 +1,40 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy +# Author: Noah Friedman +# Created: 1993-05-16 +# Public domain + +# $Id: mkinstalldirs,v 1.1 2000/05/18 14:58:35 calle Exp $ + +errstatus=0 + +for file +do + set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` + shift + + pathcomp= + for d + do + pathcomp="$pathcomp$d" + case "$pathcomp" in + -* ) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" + + mkdir "$pathcomp" || lasterr=$? + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + fi + fi + + pathcomp="$pathcomp/" + done +done + +exit $errstatus + +# mkinstalldirs ends here diff --git a/pppdcapiplugin/peers/arcor b/pppdcapiplugin/peers/arcor new file mode 100755 index 00000000..296f35f6 --- /dev/null +++ b/pppdcapiplugin/peers/arcor @@ -0,0 +1,13 @@ +debug +sync +noauth +plugin /etc/ppp/plugins/userpass.so +username arcor +password internet +defaultroute +plugin /etc/ppp/plugins/capiplugin.so +#controller 1 +#numberprefix 0 +number 010700192070 +protocol hdlc +/dev/null diff --git a/pppdcapiplugin/peers/avm b/pppdcapiplugin/peers/avm new file mode 100755 index 00000000..f506f28e --- /dev/null +++ b/pppdcapiplugin/peers/avm @@ -0,0 +1,18 @@ +# +# AVM GmbH - Fast Internet Test Server +# +debug +sync +noauth +plugin /etc/ppp/plugins/userpass.so +username netways +password netways +defaultroute +plugin /etc/ppp/plugins/capiplugin.so +#controller 1 +#numberprefix 0 +number 03039984330 +protocol hdlc +ipcp-accept-local +ipcp-accept-remote +/dev/null diff --git a/pppdcapiplugin/peers/avm-ml b/pppdcapiplugin/peers/avm-ml new file mode 100755 index 00000000..797b2f98 --- /dev/null +++ b/pppdcapiplugin/peers/avm-ml @@ -0,0 +1,20 @@ +# +# AVM GmbH - Fast Internet Test Server with Multilink +# +debug +sync +noauth +plugin /etc/ppp/plugins/userpass.so +username netways +password netways +defaultroute +plugin /etc/ppp/plugins/capiplugin.so +number 03039984330 +protocol hdlc +ipcp-accept-local +ipcp-accept-remote +multilink +mrru 1500 +# endpoint need to be changed +endpoint magic:4711 +/dev/null diff --git a/pppdcapiplugin/peers/otelo b/pppdcapiplugin/peers/otelo new file mode 100644 index 00000000..54c390a1 --- /dev/null +++ b/pppdcapiplugin/peers/otelo @@ -0,0 +1,13 @@ +debug +sync +noauth +plugin /etc/ppp/plugins/userpass.so +username otelo +password online +defaultroute +plugin /etc/ppp/plugins/capiplugin.so +#controller 1 +#numberprefix 0 +number 010110191501 +protocol hdlc +/dev/null diff --git a/pppdcapiplugin/peers/talkline b/pppdcapiplugin/peers/talkline new file mode 100644 index 00000000..cd5b4dfc --- /dev/null +++ b/pppdcapiplugin/peers/talkline @@ -0,0 +1,13 @@ +debug +sync +noauth +plugin /etc/ppp/plugins/userpass.so +username talknet +password talknet +defaultroute +plugin /etc/ppp/plugins/capiplugin.so +#controller 1 +#numberprefix 0 +number 01050019251 +protocol hdlc +/dev/null diff --git a/pppdcapiplugin/pppd.h b/pppdcapiplugin/pppd.h new file mode 100644 index 00000000..3cc24d86 --- /dev/null +++ b/pppdcapiplugin/pppd.h @@ -0,0 +1,708 @@ +/* + * pppd.h - PPP daemon global declarations. + * + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Carnegie Mellon University. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: pppd.h,v 1.1 2000/05/18 14:58:35 calle Exp $ + */ + +/* + * TODO: + */ + +#ifndef __PPPD_H__ +#define __PPPD_H__ + +#include /* for FILE */ +#include /* for NGROUPS_MAX */ +#include /* for MAXPATHLEN and BSD4_4, if defined */ +#include /* for u_int32_t, if defined */ +#include /* for struct timeval */ +#include + +#if defined(__STDC__) +#include +#define __V(x) x +#else +#include +#define __V(x) (va_alist) va_dcl +#define const +#define volatile +#endif + +#ifdef INET6 +#include "eui64.h" +#endif + +/* + * Limits. + */ + +#define NUM_PPP 1 /* One PPP interface supported (per process) */ +#define MAXWORDLEN 1024 /* max length of word in file (incl null) */ +#define MAXARGS 1 /* max # args to a command */ +#define MAXNAMELEN 256 /* max length of hostname or name for auth */ +#define MAXSECRETLEN 256 /* max length of password or secret */ + +/* + * Option descriptor structure. + */ + +typedef unsigned char bool; + +enum opt_type { + o_special_noarg = 0, + o_special = 1, + o_bool, + o_int, + o_uint32, + o_string, +}; + +typedef struct { + char *name; /* name of the option */ + enum opt_type type; + void *addr; + char *description; + int flags; + void *addr2; + int upper_limit; + int lower_limit; +} option_t; + +/* Values for flags */ +#define OPT_VALUE 0xff /* mask for presupplied value */ +#define OPT_HEX 0x100 /* int option is in hex */ +#define OPT_NOARG 0x200 /* option doesn't take argument */ +#define OPT_OR 0x400 /* OR in argument to value */ +#define OPT_INC 0x800 /* increment value */ +#define OPT_PRIV 0x1000 /* privileged option */ +#define OPT_STATIC 0x2000 /* string option goes into static array */ +#define OPT_LLIMIT 0x4000 /* check value against lower limit */ +#define OPT_ULIMIT 0x8000 /* check value against upper limit */ +#define OPT_LIMITS (OPT_LLIMIT|OPT_ULIMIT) +#define OPT_ZEROOK 0x10000 /* 0 value is OK even if not within limits */ +#define OPT_NOINCR 0x20000 /* value mustn't be increased */ +#define OPT_ZEROINF 0x40000 /* with OPT_NOINCR, 0 == infinity */ +#define OPT_A2INFO 0x100000 /* addr2 -> option_info to update */ +#define OPT_A2COPY 0x200000 /* addr2 -> second location to rcv value */ +#define OPT_ENABLE 0x400000 /* use *addr2 as enable for option */ +#define OPT_PRIVFIX 0x800000 /* can't be overridden if noauth */ +#define OPT_PREPASS 0x1000000 /* do this opt in pre-pass to find device */ +#define OPT_INITONLY 0x2000000 /* option can only be set in init phase */ +#define OPT_DEVEQUIV 0x4000000 /* equiv to device name */ +#define OPT_DEVNAM (OPT_PREPASS | OPT_INITONLY | OPT_DEVEQUIV) + +#define OPT_VAL(x) ((x) & OPT_VALUE) + +#ifndef GIDSET_TYPE +#define GIDSET_TYPE gid_t +#endif + +/* Structure representing a list of permitted IP addresses. */ +struct permitted_ip { + int permit; /* 1 = permit, 0 = forbid */ + u_int32_t base; /* match if (addr & mask) == base */ + u_int32_t mask; /* base and mask are in network byte order */ +}; + +/* + * Unfortunately, the linux kernel driver uses a different structure + * for statistics from the rest of the ports. + * This structure serves as a common representation for the bits + * pppd needs. + */ +struct pppd_stats { + unsigned int bytes_in; + unsigned int bytes_out; +}; + +/* Used for storing a sequence of words. Usually malloced. */ +struct wordlist { + struct wordlist *next; + char *word; +}; + +/* An endpoint discriminator, used with multilink. */ +#define MAX_ENDP_LEN 20 /* maximum length of discriminator value */ +struct epdisc { + unsigned char class; + unsigned char length; + unsigned char value[MAX_ENDP_LEN]; +}; + +/* values for epdisc.class */ +#define EPD_NULL 0 /* null discriminator, no data */ +#define EPD_LOCAL 1 +#define EPD_IP 2 +#define EPD_MAC 3 +#define EPD_MAGIC 4 +#define EPD_PHONENUM 5 + +/* + * Global variables. + */ + +extern int hungup; /* Physical layer has disconnected */ +extern int ifunit; /* Interface unit number */ +extern char ifname[]; /* Interface name */ +extern int ttyfd; /* Serial device file descriptor */ +extern char hostname[]; /* Our hostname */ +extern u_char outpacket_buf[]; /* Buffer for outgoing packets */ +extern int phase; /* Current state of link - see values below */ +extern int baud_rate; /* Current link speed in bits/sec */ +extern char *progname; /* Name of this program */ +extern int redirect_stderr;/* Connector's stderr should go to file */ +extern char peer_authname[];/* Authenticated name of peer */ +extern int privileged; /* We were run by real-uid root */ +extern int need_holdoff; /* Need holdoff period after link terminates */ +extern char **script_env; /* Environment variables for scripts */ +extern int detached; /* Have detached from controlling tty */ +extern GIDSET_TYPE groups[NGROUPS_MAX]; /* groups the user is in */ +extern int ngroups; /* How many groups valid in groups */ +extern struct pppd_stats link_stats; /* byte/packet counts etc. for link */ +extern int link_stats_valid; /* set if link_stats is valid */ +extern int link_connect_time; /* time the link was up for */ +extern int using_pty; /* using pty as device (notty or pty opt.) */ +extern int log_to_fd; /* logging to this fd as well as syslog */ +extern bool log_to_file; /* log_to_fd is a file */ +extern bool log_to_specific_fd; /* log_to_fd was specified by user */ +extern char *no_ppp_msg; /* message to print if ppp not in kernel */ +extern volatile int status; /* exit status for pppd */ +extern int devnam_fixed; /* can no longer change devnam */ +extern int unsuccess; /* # unsuccessful connection attempts */ +extern int do_callback; /* set if we want to do callback next */ +extern int doing_callback; /* set if this is a callback */ + +/* Values for do_callback and doing_callback */ +#define CALLBACK_DIALIN 1 /* we are expecting the call back */ +#define CALLBACK_DIALOUT 2 /* we are dialling out to call back */ + +/* + * Variables set by command-line options. + */ + +extern int debug; /* Debug flag */ +extern int kdebugflag; /* Tell kernel to print debug messages */ +extern int default_device; /* Using /dev/tty or equivalent */ +extern char devnam[MAXPATHLEN]; /* Device name */ +extern int crtscts; /* Use hardware flow control */ +extern bool modem; /* Use modem control lines */ +extern int inspeed; /* Input/Output speed requested */ +extern u_int32_t netmask; /* IP netmask to set on interface */ +extern bool lockflag; /* Create lock file to lock the serial dev */ +extern bool nodetach; /* Don't detach from controlling tty */ +extern bool updetach; /* Detach from controlling tty when link up */ +extern char *initializer; /* Script to initialize physical link */ +extern char *connect_script; /* Script to establish physical link */ +extern char *disconnect_script; /* Script to disestablish physical link */ +extern char *welcomer; /* Script to welcome client after connection */ +extern char *ptycommand; /* Command to run on other side of pty */ +extern int maxconnect; /* Maximum connect time (seconds) */ +extern char user[MAXNAMELEN];/* Our name for authenticating ourselves */ +extern char passwd[MAXSECRETLEN]; /* Password for PAP or CHAP */ +extern bool auth_required; /* Peer is required to authenticate */ +extern bool persist; /* Reopen link after it goes down */ +extern bool uselogin; /* Use /etc/passwd for checking PAP */ +extern char our_name[MAXNAMELEN];/* Our name for authentication purposes */ +extern char remote_name[MAXNAMELEN]; /* Peer's name for authentication */ +extern bool explicit_remote;/* remote_name specified with remotename opt */ +extern bool demand; /* Do dial-on-demand */ +extern char *ipparam; /* Extra parameter for ip up/down scripts */ +extern bool cryptpap; /* Others' PAP passwords are encrypted */ +extern int idle_time_limit;/* Shut down link if idle for this long */ +extern int holdoff; /* Dead time before restarting */ +extern bool holdoff_specified; /* true if user gave a holdoff value */ +extern bool notty; /* Stdin/out is not a tty */ +extern char *pty_socket; /* Socket to connect to pty */ +extern char *record_file; /* File to record chars sent/received */ +extern bool sync_serial; /* Device is synchronous serial device */ +extern int maxfail; /* Max # of unsuccessful connection attempts */ +extern char linkname[MAXPATHLEN]; /* logical name for link */ +extern bool tune_kernel; /* May alter kernel settings as necessary */ +extern int connect_delay; /* Time to delay after connect script */ +extern int max_data_rate; /* max bytes/sec through charshunt */ +extern int req_unit; /* interface unit number to use */ +extern bool multilink; /* enable multilink operation */ +extern bool noendpoint; /* don't send or accept endpt. discrim. */ +extern char *bundle_name; /* bundle name for multilink */ + +#ifdef PPP_FILTER +extern struct bpf_program pass_filter; /* Filter for pkts to pass */ +extern struct bpf_program active_filter; /* Filter for link-active pkts */ +#endif + +#ifdef MSLANMAN +extern bool ms_lanman; /* Use LanMan password instead of NT */ + /* Has meaning only with MS-CHAP challenges */ +#endif + +extern char *current_option; /* the name of the option being parsed */ +extern int privileged_option; /* set iff the current option came from root */ +extern char *option_source; /* string saying where the option came from */ + +/* + * Values for phase. + */ +#define PHASE_DEAD 0 +#define PHASE_INITIALIZE 1 +#define PHASE_SERIALCONN 2 +#define PHASE_DORMANT 3 +#define PHASE_ESTABLISH 4 +#define PHASE_AUTHENTICATE 5 +#define PHASE_CALLBACK 6 +#define PHASE_NETWORK 7 +#define PHASE_RUNNING 8 +#define PHASE_TERMINATE 9 +#define PHASE_DISCONNECT 10 +#define PHASE_HOLDOFF 11 + +/* + * The following struct gives the addresses of procedures to call + * for a particular protocol. + */ +struct protent { + u_short protocol; /* PPP protocol number */ + /* Initialization procedure */ + void (*init) __P((int unit)); + /* Process a received packet */ + void (*input) __P((int unit, u_char *pkt, int len)); + /* Process a received protocol-reject */ + void (*protrej) __P((int unit)); + /* Lower layer has come up */ + void (*lowerup) __P((int unit)); + /* Lower layer has gone down */ + void (*lowerdown) __P((int unit)); + /* Open the protocol */ + void (*open) __P((int unit)); + /* Close the protocol */ + void (*close) __P((int unit, char *reason)); + /* Print a packet in readable form */ + int (*printpkt) __P((u_char *pkt, int len, + void (*printer) __P((void *, char *, ...)), + void *arg)); + /* Process a received data packet */ + void (*datainput) __P((int unit, u_char *pkt, int len)); + bool enabled_flag; /* 0 iff protocol is disabled */ + char *name; /* Text name of protocol */ + char *data_name; /* Text name of corresponding data protocol */ + option_t *options; /* List of command-line options */ + /* Check requested options, assign defaults */ + void (*check_options) __P((void)); + /* Configure interface for demand-dial */ + int (*demand_conf) __P((int unit)); + /* Say whether to bring up link for this pkt */ + int (*active_pkt) __P((u_char *pkt, int len)); +}; + +/* Table of pointers to supported protocols */ +extern struct protent *protocols[]; + +/* + * Prototypes. + */ + +/* Procedures exported from main.c. */ +void set_ifunit __P((int)); /* set stuff that depends on ifunit */ +void detach __P((void)); /* Detach from controlling tty */ +void die __P((int)); /* Cleanup and exit */ +void quit __P((void)); /* like die(1) */ +void novm __P((char *)); /* Say we ran out of memory, and die */ +void timeout __P((void (*func)(void *), void *arg, int t)); + /* Call func(arg) after t seconds */ +void untimeout __P((void (*func)(void *), void *arg)); + /* Cancel call to func(arg) */ +pid_t run_program __P((char *prog, char **args, int must_exist, + void (*done)(void *), void *arg)); + /* Run program prog with args in child */ +void reopen_log __P((void)); /* (re)open the connection to syslog */ +void update_link_stats __P((int)); /* Get stats at link termination */ +void script_setenv __P((char *, char *, int)); /* set script env var */ +void script_unsetenv __P((char *)); /* unset script env var */ +void new_phase __P((int)); /* signal start of new phase */ + +/* Procedures exported from utils.c. */ +void log_packet __P((u_char *, int, char *, int)); + /* Format a packet and log it with syslog */ +void print_string __P((char *, int, void (*) (void *, char *, ...), + void *)); /* Format a string for output */ +int slprintf __P((char *, int, char *, ...)); /* sprintf++ */ +int vslprintf __P((char *, int, char *, va_list)); /* vsprintf++ */ +size_t strlcpy __P((char *, const char *, size_t)); /* safe strcpy */ +size_t strlcat __P((char *, const char *, size_t)); /* safe strncpy */ +void dbglog __P((char *, ...)); /* log a debug message */ +void info __P((char *, ...)); /* log an informational message */ +void notice __P((char *, ...)); /* log a notice-level message */ +void warn __P((char *, ...)); /* log a warning message */ +void error __P((char *, ...)); /* log an error message */ +void fatal __P((char *, ...)); /* log an error message and die(1) */ + +/* Procedures exported from auth.c */ +void link_required __P((int)); /* we are starting to use the link */ +void link_terminated __P((int)); /* we are finished with the link */ +void link_down __P((int)); /* the LCP layer has left the Opened state */ +void link_established __P((int)); /* the link is up; authenticate now */ +void start_networks __P((void)); /* start all the network control protos */ +void np_up __P((int, int)); /* a network protocol has come up */ +void np_down __P((int, int)); /* a network protocol has gone down */ +void np_finished __P((int, int)); /* a network protocol no longer needs link */ +void auth_peer_fail __P((int, int)); + /* peer failed to authenticate itself */ +void auth_peer_success __P((int, int, char *, int)); + /* peer successfully authenticated itself */ +void auth_withpeer_fail __P((int, int)); + /* we failed to authenticate ourselves */ +void auth_withpeer_success __P((int, int)); + /* we successfully authenticated ourselves */ +void auth_check_options __P((void)); + /* check authentication options supplied */ +void auth_reset __P((int)); /* check what secrets we have */ +int check_passwd __P((int, char *, int, char *, int, char **)); + /* Check peer-supplied username/password */ +int get_secret __P((int, char *, char *, char *, int *, int)); + /* get "secret" for chap */ +int auth_ip_addr __P((int, u_int32_t)); + /* check if IP address is authorized */ +int bad_ip_adrs __P((u_int32_t)); + /* check if IP address is unreasonable */ + +/* Procedures exported from demand.c */ +void demand_conf __P((void)); /* config interface(s) for demand-dial */ +void demand_block __P((void)); /* set all NPs to queue up packets */ +void demand_unblock __P((void)); /* set all NPs to pass packets */ +void demand_discard __P((void)); /* set all NPs to discard packets */ +void demand_rexmit __P((int)); /* retransmit saved frames for an NP */ +int loop_chars __P((unsigned char *, int)); /* process chars from loopback */ +int loop_frame __P((unsigned char *, int)); /* should we bring link up? */ + +/* Procedures exported from multilink.c */ +void mp_check_options __P((void)); /* Check multilink-related options */ +int mp_join_bundle __P((void)); /* join our link to an appropriate bundle */ +char *epdisc_to_str __P((struct epdisc *)); /* string from endpoint discrim. */ +int str_to_epdisc __P((struct epdisc *, char *)); /* endpt disc. from str */ + +/* Procedures exported from sys-*.c */ +void sys_init __P((void)); /* Do system-dependent initialization */ +void sys_cleanup __P((void)); /* Restore system state before exiting */ +int sys_check_options __P((void)); /* Check options specified */ +void sys_close __P((void)); /* Clean up in a child before execing */ +int ppp_available __P((void)); /* Test whether ppp kernel support exists */ +int get_pty __P((int *, int *, char *, int)); /* Get pty master/slave */ +int open_ppp_loopback __P((void)); /* Open loopback for demand-dialling */ +int establish_ppp __P((int)); /* Turn serial port into a ppp interface */ +void restore_loop __P((void)); /* Transfer ppp unit back to loopback */ +void disestablish_ppp __P((int)); /* Restore port to normal operation */ +void make_new_bundle __P((int, int, int, int)); /* Create new bundle */ +int bundle_attach __P((int)); /* Attach link to existing bundle */ +void cfg_bundle __P((int, int, int, int)); /* Configure existing bundle */ +void clean_check __P((void)); /* Check if line was 8-bit clean */ +void set_up_tty __P((int, int)); /* Set up port's speed, parameters, etc. */ +void restore_tty __P((int)); /* Restore port's original parameters */ +void setdtr __P((int, int)); /* Raise or lower port's DTR line */ +void output __P((int, u_char *, int)); /* Output a PPP packet */ +void wait_input __P((struct timeval *)); + /* Wait for input, with timeout */ +void add_fd __P((int)); /* Add fd to set to wait for */ +void remove_fd __P((int)); /* Remove fd from set to wait for */ +int read_packet __P((u_char *)); /* Read PPP packet */ +int get_loop_output __P((void)); /* Read pkts from loopback */ +void ppp_send_config __P((int, int, u_int32_t, int, int)); + /* Configure i/f transmit parameters */ +void ppp_set_xaccm __P((int, ext_accm)); + /* Set extended transmit ACCM */ +void ppp_recv_config __P((int, int, u_int32_t, int, int)); + /* Configure i/f receive parameters */ +int ccp_test __P((int, u_char *, int, int)); + /* Test support for compression scheme */ +void ccp_flags_set __P((int, int, int)); + /* Set kernel CCP state */ +int ccp_fatal_error __P((int)); /* Test for fatal decomp error in kernel */ +int get_idle_time __P((int, struct ppp_idle *)); + /* Find out how long link has been idle */ +int get_ppp_stats __P((int, struct pppd_stats *)); + /* Return link statistics */ +int sifvjcomp __P((int, int, int, int)); + /* Configure VJ TCP header compression */ +int sifup __P((int)); /* Configure i/f up for one protocol */ +int sifnpmode __P((int u, int proto, enum NPmode mode)); + /* Set mode for handling packets for proto */ +int sifdown __P((int)); /* Configure i/f down for one protocol */ +int sifaddr __P((int, u_int32_t, u_int32_t, u_int32_t)); + /* Configure IPv4 addresses for i/f */ +int cifaddr __P((int, u_int32_t, u_int32_t)); + /* Reset i/f IP addresses */ +#ifdef INET6 +int sif6addr __P((int, eui64_t, eui64_t)); + /* Configure IPv6 addresses for i/f */ +int cif6addr __P((int, eui64_t, eui64_t)); + /* Remove an IPv6 address from i/f */ +#endif +int sifdefaultroute __P((int, u_int32_t, u_int32_t)); + /* Create default route through i/f */ +int cifdefaultroute __P((int, u_int32_t, u_int32_t)); + /* Delete default route through i/f */ +int sifproxyarp __P((int, u_int32_t)); + /* Add proxy ARP entry for peer */ +int cifproxyarp __P((int, u_int32_t)); + /* Delete proxy ARP entry for peer */ +u_int32_t GetMask __P((u_int32_t)); /* Get appropriate netmask for address */ +int lock __P((char *)); /* Create lock file for device */ +int relock __P((int)); /* Rewrite lock file with new pid */ +void unlock __P((void)); /* Delete previously-created lock file */ +void logwtmp __P((const char *, const char *, const char *)); + /* Write entry to wtmp file */ +int get_host_seed __P((void)); /* Get host-dependent random number seed */ +int have_route_to __P((u_int32_t)); /* Check if route to addr exists */ +#ifdef PPP_FILTER +int set_filters __P((struct bpf_program *pass, struct bpf_program *active)); + /* Set filter programs in kernel */ +#endif +#ifdef IPX_CHANGE +int sipxfaddr __P((int, unsigned long, unsigned char *)); +int cipxfaddr __P((int)); +#endif +int get_if_hwaddr __P((u_char *addr, char *name)); +char *get_first_ethernet __P((void)); + +/* Procedures exported from options.c */ +int parse_args __P((int argc, char **argv)); + /* Parse options from arguments given */ +int options_from_file __P((char *filename, int must_exist, int check_prot, + int privileged)); + /* Parse options from an options file */ +int options_from_user __P((void)); /* Parse options from user's .ppprc */ +int options_for_tty __P((void)); /* Parse options from /etc/ppp/options.tty */ +int options_from_list __P((struct wordlist *, int privileged)); + /* Parse options from a wordlist */ +int getword __P((FILE *f, char *word, int *newlinep, char *filename)); + /* Read a word from a file */ +void option_error __P((char *fmt, ...)); + /* Print an error message about an option */ +int int_option __P((char *, int *)); + /* Simplified number_option for decimal ints */ +void add_options __P((option_t *)); /* Add extra options */ +int parse_dotted_ip __P((char *, u_int32_t *)); + +/* + * This structure is used to store information about certain + * options, such as where the option value came from (/etc/ppp/options, + * command line, etc.) and whether it came from a privileged source. + */ + +struct option_info { + int priv; /* was value set by sysadmin? */ + char *source; /* where option came from */ +}; + +extern struct option_info devnam_info; +extern struct option_info initializer_info; +extern struct option_info connect_script_info; +extern struct option_info disconnect_script_info; +extern struct option_info welcomer_info; +extern struct option_info ptycommand_info; + +/* + * Hooks to enable plugins to change various things. + */ +extern int (*new_phase_hook) __P((int)); +extern int (*idle_time_hook) __P((struct ppp_idle *)); +extern int (*holdoff_hook) __P((void)); +extern int (*pap_check_hook) __P((void)); +extern int (*pap_auth_hook) __P((char *user, char *passwd, char **msgp, + struct wordlist **paddrs, + struct wordlist **popts)); +extern void (*pap_logout_hook) __P((void)); +extern int (*pap_passwd_hook) __P((char *user, char *passwd)); +extern void (*ip_up_hook) __P((void)); +extern void (*ip_down_hook) __P((void)); + +/* + * Inline versions of get/put char/short/long. + * Pointer is advanced; we assume that both arguments + * are lvalues and will already be in registers. + * cp MUST be u_char *. + */ +#define GETCHAR(c, cp) { \ + (c) = *(cp)++; \ +} +#define PUTCHAR(c, cp) { \ + *(cp)++ = (u_char) (c); \ +} + + +#define GETSHORT(s, cp) { \ + (s) = *(cp)++ << 8; \ + (s) |= *(cp)++; \ +} +#define PUTSHORT(s, cp) { \ + *(cp)++ = (u_char) ((s) >> 8); \ + *(cp)++ = (u_char) (s); \ +} + +#define GETLONG(l, cp) { \ + (l) = *(cp)++ << 8; \ + (l) |= *(cp)++; (l) <<= 8; \ + (l) |= *(cp)++; (l) <<= 8; \ + (l) |= *(cp)++; \ +} +#define PUTLONG(l, cp) { \ + *(cp)++ = (u_char) ((l) >> 24); \ + *(cp)++ = (u_char) ((l) >> 16); \ + *(cp)++ = (u_char) ((l) >> 8); \ + *(cp)++ = (u_char) (l); \ +} + +#define INCPTR(n, cp) ((cp) += (n)) +#define DECPTR(n, cp) ((cp) -= (n)) + +/* + * System dependent definitions for user-level 4.3BSD UNIX implementation. + */ + +#define TIMEOUT(r, f, t) timeout((r), (f), (t)) +#define UNTIMEOUT(r, f) untimeout((r), (f)) + +#define BCOPY(s, d, l) memcpy(d, s, l) +#define BZERO(s, n) memset(s, 0, n) + +#define PRINTMSG(m, l) { info("Remote message: %0.*v", l, m); } + +/* + * MAKEHEADER - Add Header fields to a packet. + */ +#define MAKEHEADER(p, t) { \ + PUTCHAR(PPP_ALLSTATIONS, p); \ + PUTCHAR(PPP_UI, p); \ + PUTSHORT(t, p); } + +/* + * Exit status values. + */ +#define EXIT_OK 0 +#define EXIT_FATAL_ERROR 1 +#define EXIT_OPTION_ERROR 2 +#define EXIT_NOT_ROOT 3 +#define EXIT_NO_KERNEL_SUPPORT 4 +#define EXIT_USER_REQUEST 5 +#define EXIT_LOCK_FAILED 6 +#define EXIT_OPEN_FAILED 7 +#define EXIT_CONNECT_FAILED 8 +#define EXIT_PTYCMD_FAILED 9 +#define EXIT_NEGOTIATION_FAILED 10 +#define EXIT_PEER_AUTH_FAILED 11 +#define EXIT_IDLE_TIMEOUT 12 +#define EXIT_CONNECT_TIME 13 +#define EXIT_CALLBACK 14 +#define EXIT_PEER_DEAD 15 +#define EXIT_HANGUP 16 +#define EXIT_LOOPBACK 17 +#define EXIT_INIT_FAILED 18 +#define EXIT_AUTH_TOPEER_FAILED 19 + +/* + * Debug macros. Slightly useful for finding bugs in pppd, not particularly + * useful for finding out why your connection isn't being established. + */ +#ifdef DEBUGALL +#define DEBUGMAIN 1 +#define DEBUGFSM 1 +#define DEBUGLCP 1 +#define DEBUGIPCP 1 +#define DEBUGIPV6CP 1 +#define DEBUGUPAP 1 +#define DEBUGCHAP 1 +#endif + +#ifndef LOG_PPP /* we use LOG_LOCAL2 for syslog by default */ +#if defined(DEBUGMAIN) || defined(DEBUGFSM) || defined(DEBUGSYS) \ + || defined(DEBUGLCP) || defined(DEBUGIPCP) || defined(DEBUGUPAP) \ + || defined(DEBUGCHAP) || defined(DEBUG) || defined(DEBUGIPV6CP) +#define LOG_PPP LOG_LOCAL2 +#else +#define LOG_PPP LOG_DAEMON +#endif +#endif /* LOG_PPP */ + +#ifdef DEBUGMAIN +#define MAINDEBUG(x) if (debug) dbglog x +#else +#define MAINDEBUG(x) +#endif + +#ifdef DEBUGSYS +#define SYSDEBUG(x) if (debug) dbglog x +#else +#define SYSDEBUG(x) +#endif + +#ifdef DEBUGFSM +#define FSMDEBUG(x) if (debug) dbglog x +#else +#define FSMDEBUG(x) +#endif + +#ifdef DEBUGLCP +#define LCPDEBUG(x) if (debug) dbglog x +#else +#define LCPDEBUG(x) +#endif + +#ifdef DEBUGIPCP +#define IPCPDEBUG(x) if (debug) dbglog x +#else +#define IPCPDEBUG(x) +#endif + +#ifdef DEBUGIPV6CP +#define IPV6CPDEBUG(x) if (debug) dbglog x +#else +#define IPV6CPDEBUG(x) +#endif + +#ifdef DEBUGUPAP +#define UPAPDEBUG(x) if (debug) dbglog x +#else +#define UPAPDEBUG(x) +#endif + +#ifdef DEBUGCHAP +#define CHAPDEBUG(x) if (debug) dbglog x +#else +#define CHAPDEBUG(x) +#endif + +#ifdef DEBUGIPXCP +#define IPXCPDEBUG(x) if (debug) dbglog x +#else +#define IPXCPDEBUG(x) +#endif + +#ifndef SIGTYPE +#if defined(sun) || defined(SYSV) || defined(POSIX_SOURCE) +#define SIGTYPE void +#else +#define SIGTYPE int +#endif /* defined(sun) || defined(SYSV) || defined(POSIX_SOURCE) */ +#endif /* SIGTYPE */ + +#ifndef MIN +#define MIN(a, b) ((a) < (b)? (a): (b)) +#endif +#ifndef MAX +#define MAX(a, b) ((a) > (b)? (a): (b)) +#endif + +#endif /* __PPP_H__ */ diff --git a/pppdcapiplugin/userpass.c b/pppdcapiplugin/userpass.c new file mode 100644 index 00000000..9224b46d --- /dev/null +++ b/pppdcapiplugin/userpass.c @@ -0,0 +1,49 @@ +/* + * + * $Id: userpass.c,v 1.1 2000/05/18 14:58:35 calle Exp $ + * + * userpass.c - pppd plugin to provide username password + * + * Copyright 2000 Carsten Paeth + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * $Log: userpass.c,v $ + * Revision 1.1 2000/05/18 14:58:35 calle + * Plugin for pppd to support PPP over CAPI2.0. + * + * + */ +#include "pppd.h" + +static char username[MAXNAMELEN+1]; +static char password[MAXSECRETLEN+1]; + +static option_t options[] = { +{ "username", o_string, username, "username", OPT_STATIC, 0, MAXNAMELEN }, +{ "password", o_string, password, "password", OPT_STATIC, 0, MAXSECRETLEN }, +{ 0 } +}; + +static void copystr(char *to, char *from) +{ + while (*from) + *to++ = *from++; + *to = 0; +} + +static int userpass(char *user, char *passwd) +{ + if (username) copystr(user, username); + if (passwd) copystr(passwd, password); + return 1; +} + +void plugin_init(void) +{ + add_options(options); + pap_passwd_hook = userpass; +}