/* * 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; }