Annotation of embedaddon/mpd/src/modem.c, revision 1.1
1.1 ! misho 1:
! 2: /*
! 3: * modem.c
! 4: *
! 5: * Written by Archie Cobbs <archie@freebsd.org>
! 6: * Copyright (c) 1995-1999 Whistle Communications, Inc. All rights reserved.
! 7: * See ``COPYRIGHT.whistle''
! 8: */
! 9:
! 10: #include "ppp.h"
! 11: #include <termios.h>
! 12: #include "chat.h"
! 13: #include "phys.h"
! 14: #include "modem.h"
! 15: #include "ngfunc.h"
! 16: #include "lcp.h"
! 17: #include "event.h"
! 18: #include "util.h"
! 19: #include "log.h"
! 20:
! 21: #include <netgraph/ng_message.h>
! 22: #include <netgraph/ng_socket.h>
! 23: #include <netgraph/ng_async.h>
! 24: #include <netgraph/ng_tty.h>
! 25: #include <netgraph.h>
! 26:
! 27: /*
! 28: * DEFINITIONS
! 29: */
! 30:
! 31: #ifndef NETGRAPHDISC
! 32: #define NETGRAPHDISC 7 /* XXX */
! 33: #endif
! 34:
! 35: #define MODEM_MTU 1600
! 36: #define MODEM_MRU 1600
! 37:
! 38: #define MODEM_MIN_CLOSE_TIME 3
! 39: #define MODEM_CHECK_INTERVAL 1
! 40: #define MODEM_DEFAULT_SPEED 115200
! 41: #define MODEM_ERR_REPORT_INTERVAL 60
! 42:
! 43: #define MODEM_IDLE_RESULT_ANSWER "answer"
! 44: #define MODEM_IDLE_RESULT_RINGBACK "ringback"
! 45:
! 46: /* Special chat script variables we set/use */
! 47: #define CHAT_VAR_LOGIN "$Login"
! 48: #define CHAT_VAR_PASSWORD "$Password"
! 49: #define CHAT_VAR_DEVICE "$modemDevice"
! 50: #define CHAT_VAR_IDLE_RESULT "$IdleResult"
! 51: #define CHAT_VAR_CONNECT_SPEED "$ConnectionSpeed"
! 52: #define CHAT_VAR_CALLING "$CallingID"
! 53: #define CHAT_VAR_CALLED "$CalledID"
! 54:
! 55: /* Nominal link parameters */
! 56: #define MODEM_DEFAULT_BANDWIDTH 28800 /* ~33.6 modem */
! 57: #define MODEM_DEFAULT_LATENCY 10000 /* 10ms */
! 58:
! 59: /* Modem device state */
! 60: struct modeminfo {
! 61: int fd; /* Device file desc, or -1 */
! 62: int csock; /* netgraph control socket */
! 63: int speed; /* Port speed */
! 64: u_int watch; /* Signals to watch */
! 65: char device[20]; /* Serial device name */
! 66: char ttynode[NG_NODESIZ]; /* TTY node name */
! 67: char connScript[CHAT_MAX_LABEL]; /* Connect script */
! 68: char idleScript[CHAT_MAX_LABEL]; /* Idle script */
! 69: struct pppTimer checkTimer; /* Timer to check pins */
! 70: struct pppTimer reportTimer; /* Timer to report errs */
! 71: struct pppTimer startTimer; /* Timer for ModemStart() */
! 72: struct optinfo options; /* Binary options */
! 73: struct ng_async_cfg acfg; /* ng_async node config */
! 74: ChatInfo chat; /* Chat script state */
! 75: time_t lastClosed; /* Last time device closed */
! 76: u_char opened:1; /* We have been opened */
! 77: u_char originated:1; /* We originated current call */
! 78: u_char answering:1; /* $IdleResult was "answer" */
! 79: };
! 80: typedef struct modeminfo *ModemInfo;
! 81:
! 82: /* Set menu options */
! 83: enum {
! 84: SET_DEVICE,
! 85: SET_SPEED,
! 86: SET_CSCRIPT,
! 87: SET_ISCRIPT,
! 88: SET_SCRIPT_VAR,
! 89: SET_WATCH
! 90: };
! 91:
! 92: /*
! 93: * INTERNAL FUNCTIONS
! 94: */
! 95:
! 96: static int ModemInit(Link l);
! 97: static void ModemOpen(Link l);
! 98: static void ModemClose(Link l);
! 99: static void ModemUpdate(Link l);
! 100: static int ModemSetAccm(Link l, u_int32_t xmit, u_int32_t recv);
! 101: static void ModemStat(Context ctx);
! 102: static int ModemOriginated(Link l);
! 103: static int ModemIsSync(Link l);
! 104: static int ModemSelfAddr(Link l, void *buf, size_t buf_len);
! 105: static int ModemIface(Link l, void *buf, size_t buf_len);
! 106: static int ModemCallingNum(Link l, void *buf, size_t buf_len);
! 107: static int ModemCalledNum(Link l, void *buf, size_t buf_len);
! 108:
! 109: static void ModemStart(void *arg);
! 110: static void ModemDoClose(Link l, int opened);
! 111:
! 112: /* Chat callbacks */
! 113: static int ModemChatSetBaudrate(void *arg, int baud);
! 114: static void ModemChatConnectResult(void *arg,
! 115: int rslt, const char *msg);
! 116: static void ModemChatIdleResult(void *arg, int rslt,
! 117: const char *msg);
! 118:
! 119: static int ModemSetCommand(Context ctx, int ac, char *av[], void *arg);
! 120: static int ModemInstallNodes(Link l);
! 121: static int ModemGetNgStats(Link l, struct ng_async_stat *sp);
! 122:
! 123: static void ModemCheck(void *arg);
! 124: static void ModemErrorCheck(void *arg);
! 125:
! 126: /*
! 127: * GLOBAL VARIABLES
! 128: */
! 129:
! 130: const struct phystype gModemPhysType = {
! 131: .name = "modem",
! 132: .descr = "Serial port modem",
! 133: .mtu = MODEM_MTU,
! 134: .mru = MODEM_MRU,
! 135: .tmpl = 0,
! 136: .init = ModemInit,
! 137: .open = ModemOpen,
! 138: .close = ModemClose,
! 139: .update = ModemUpdate,
! 140: .showstat = ModemStat,
! 141: .originate = ModemOriginated,
! 142: .issync = ModemIsSync,
! 143: .setaccm = ModemSetAccm,
! 144: .selfaddr = ModemSelfAddr,
! 145: .peeraddr = ModemSelfAddr,
! 146: .peeriface = ModemIface,
! 147: .callingnum = ModemCallingNum,
! 148: .callednum = ModemCalledNum,
! 149: };
! 150:
! 151: const struct cmdtab ModemSetCmds[] = {
! 152: { "device {name}", "Set modem device",
! 153: ModemSetCommand, NULL, 2, (void *) SET_DEVICE },
! 154: { "speed {port-speed}", "Set modem speed",
! 155: ModemSetCommand, NULL, 2, (void *) SET_SPEED },
! 156: { "script [{label}]", "Set connect script",
! 157: ModemSetCommand, NULL, 2, (void *) SET_CSCRIPT },
! 158: { "idle-script [{label}]", "Set idle script",
! 159: ModemSetCommand, NULL, 2, (void *) SET_ISCRIPT },
! 160: { "var ${var} {string}", "Set script variable",
! 161: ModemSetCommand, NULL, 2, (void *) SET_SCRIPT_VAR },
! 162: { "watch [+|-cd] [+|-dsr]", "Set signals to monitor",
! 163: ModemSetCommand, NULL, 2, (void *) SET_WATCH },
! 164: { NULL },
! 165: };
! 166:
! 167: /*
! 168: * INTERNAL VARIABLES
! 169: */
! 170:
! 171: static int gSpeedList[] = {
! 172: 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200,
! 173: 38400, 7200, 14400, 28800, 57600, 76800, 115200, 230400, 460800, 614400,
! 174: 921600, 1228800, 1843200, 2000000, 3000000, -1
! 175: };
! 176:
! 177: /*
! 178: * ModemInit()
! 179: *
! 180: * Allocate and initialize device private info
! 181: */
! 182:
! 183: static int
! 184: ModemInit(Link l)
! 185: {
! 186: char defSpeed[32];
! 187: ModemInfo m;
! 188:
! 189: m = (ModemInfo) (l->info = Malloc(MB_PHYS, sizeof(*m)));
! 190: m->watch = TIOCM_CAR;
! 191: m->chat = ChatInit(l, ModemChatSetBaudrate);
! 192: m->fd = -1;
! 193: m->opened = FALSE;
! 194:
! 195: /* Set nominal link speed and bandwith for a modem connection */
! 196: l->latency = MODEM_DEFAULT_LATENCY;
! 197: l->bandwidth = MODEM_DEFAULT_BANDWIDTH;
! 198:
! 199: /* Set default speed */
! 200: m->speed = MODEM_DEFAULT_SPEED;
! 201: snprintf(defSpeed, sizeof(defSpeed), "%d", m->speed);
! 202: ChatPresetVar(m->chat, CHAT_VAR_BAUDRATE, defSpeed);
! 203: return(0);
! 204: }
! 205:
! 206: /*
! 207: * ModemOpen()
! 208: */
! 209:
! 210: static void
! 211: ModemOpen(Link l)
! 212: {
! 213: ModemInfo const m = (ModemInfo) l->info;
! 214:
! 215: assert(!m->opened);
! 216: m->opened = TRUE;
! 217: if (m->fd >= 0) { /* Device is already open.. */
! 218: if (m->answering) { /* We just answered a call */
! 219: m->originated = FALSE;
! 220: m->answering = FALSE;
! 221: ModemChatConnectResult(l, TRUE, NULL);
! 222: } else {
! 223: Log(LG_PHYS2, ("[%s] MODEM: Stop idle script then dial back",
! 224: l->name));
! 225: ModemDoClose(l, TRUE); /* Stop idle script then dial back */
! 226: }
! 227: } else
! 228: ModemStart(l); /* Open device and try to dial */
! 229: }
! 230:
! 231: /*
! 232: * ModemStart()
! 233: */
! 234:
! 235: static void
! 236: ModemStart(void *arg)
! 237: {
! 238: Link const l = (Link) arg;
! 239: ModemInfo const m = (ModemInfo) l->info;
! 240: const time_t now = time(NULL);
! 241: char password[AUTH_MAX_PASSWORD];
! 242: FILE *scriptfp;
! 243:
! 244: /* If we're idle, and there's no idle script, there's nothing to do */
! 245: assert(!m->answering);
! 246: TimerStop(&m->startTimer);
! 247: if (!m->opened &&
! 248: (!*m->idleScript || !Enabled(&l->conf.options, LINK_CONF_INCOMING) ||
! 249: gShutdownInProgress))
! 250: return;
! 251:
! 252: /* Avoid brief hang from kernel enforcing minimum DTR hold time */
! 253: if (now - m->lastClosed < MODEM_MIN_CLOSE_TIME) {
! 254: TimerInit(&m->startTimer, "ModemStart",
! 255: (MODEM_MIN_CLOSE_TIME - (now - m->lastClosed)) * SECONDS, ModemStart, l);
! 256: TimerStart(&m->startTimer);
! 257: return;
! 258: }
! 259:
! 260: /* Open and configure serial port */
! 261: if ((m->fd = OpenSerialDevice(l->name, m->device, m->speed)) < 0) {
! 262: Log(LG_ERR, ("[%s] MODEM: Fail to open serial port %s on speed %d",
! 263: l->name, m->device, m->speed));
! 264: goto fail;
! 265: }
! 266: /* If connecting, but no connect script, then skip chat altogether */
! 267: if (m->opened && !*m->connScript) {
! 268: Log(LG_PHYS2, ("[%s] MODEM: No connect script present", l->name));
! 269: ModemChatConnectResult(l, TRUE, NULL);
! 270: return;
! 271: }
! 272:
! 273: /* Open chat script file */
! 274: if ((scriptfp = OpenConfFile(SCRIPT_FILE, NULL)) == NULL) {
! 275: Log(LG_ERR, ("[%s] MODEM: can't open chat script file", l->name));
! 276: ExclusiveCloseDevice(l->name, m->fd, m->device);
! 277: m->fd = -1;
! 278: fail:
! 279: m->opened = FALSE;
! 280: m->lastClosed = time(NULL);
! 281: l->state = PHYS_STATE_DOWN;
! 282: PhysDown(l, STR_ERROR, STR_DEV_NOT_READY);
! 283: return;
! 284: }
! 285:
! 286: /* Preset some special chat variables */
! 287: ChatPresetVar(m->chat, CHAT_VAR_DEVICE, m->device);
! 288: ChatPresetVar(m->chat, CHAT_VAR_LOGIN, l->lcp.auth.conf.authname);
! 289: if (l->lcp.auth.conf.password[0] != 0) {
! 290: ChatPresetVar(m->chat, CHAT_VAR_PASSWORD, l->lcp.auth.conf.password);
! 291: } else if (AuthGetData(l->lcp.auth.conf.authname,
! 292: password, sizeof(password), NULL, NULL) >= 0) {
! 293: ChatPresetVar(m->chat, CHAT_VAR_PASSWORD, password);
! 294: }
! 295:
! 296: /* Run connect or idle script as appropriate */
! 297: if (!m->opened) {
! 298: ChatPresetVar(m->chat, CHAT_VAR_IDLE_RESULT, "<unknown>");
! 299: ChatStart(m->chat, m->fd, scriptfp, m->idleScript, ModemChatIdleResult);
! 300: } else {
! 301: m->originated = TRUE;
! 302: l->state = PHYS_STATE_CONNECTING;
! 303: ChatStart(m->chat, m->fd, scriptfp, m->connScript, ModemChatConnectResult);
! 304: }
! 305: }
! 306:
! 307: /*
! 308: * ModemClose()
! 309: */
! 310:
! 311: static void
! 312: ModemClose(Link l)
! 313: {
! 314: ModemInfo const m = (ModemInfo) l->info;
! 315:
! 316: if (!m->opened)
! 317: return;
! 318: ModemDoClose(l, FALSE);
! 319: l->state = PHYS_STATE_DOWN;
! 320: PhysDown(l, STR_MANUALLY, NULL);
! 321: }
! 322:
! 323: static void
! 324: ModemUpdate(Link l)
! 325: {
! 326: ModemInfo const m = (ModemInfo) l->info;
! 327:
! 328: if (m->opened || TimerRemain(&m->startTimer) >= 0)
! 329: return; /* nothing needs to be done right now */
! 330: if (m->fd >= 0 &&
! 331: (!*m->idleScript || !Enabled(&l->conf.options, LINK_CONF_INCOMING)))
! 332: ModemDoClose(l, FALSE);
! 333: else if (m->fd < 0 &&
! 334: (*m->idleScript && Enabled(&l->conf.options, LINK_CONF_INCOMING)))
! 335: ModemStart(l);
! 336: }
! 337:
! 338: /*
! 339: * ModemDoClose()
! 340: */
! 341:
! 342: static void
! 343: ModemDoClose(Link l, int opened)
! 344: {
! 345: ModemInfo const m = (ModemInfo) l->info;
! 346: const char ch = ' ';
! 347:
! 348: /* Shutdown everything */
! 349: assert(m->fd >= 0);
! 350: ChatAbort(m->chat);
! 351: TimerStop(&m->checkTimer);
! 352: TimerStop(&m->startTimer);
! 353: TimerStop(&m->reportTimer);
! 354: if (*m->ttynode != '\0') {
! 355: char path[NG_PATHSIZ];
! 356:
! 357: snprintf(path, sizeof(path), "%s:%s", m->ttynode, NG_TTY_HOOK);
! 358: NgFuncShutdownNode(m->csock, l->name, path);
! 359: snprintf(path, sizeof(path), "%s:", m->ttynode);
! 360: NgFuncShutdownNode(m->csock, l->name, path);
! 361: *m->ttynode = '\0';
! 362: }
! 363: (void) write(m->fd, &ch, 1); /* USR kludge to prevent dial lockup */
! 364: if (m->csock > 0) {
! 365: close(m->csock);
! 366: m->csock = -1;
! 367: }
! 368: ExclusiveCloseDevice(l->name, m->fd, m->device);
! 369: m->lastClosed = time(NULL);
! 370: m->answering = FALSE;
! 371: m->fd = -1;
! 372: m->opened = opened;
! 373: ModemStart(l);
! 374: }
! 375:
! 376: /*
! 377: * ModemSetAccm()
! 378: */
! 379:
! 380: static int
! 381: ModemSetAccm(Link l, u_int32_t xmit, u_int32_t recv)
! 382: {
! 383: ModemInfo const m = (ModemInfo) l->info;
! 384: char path[NG_PATHSIZ];
! 385:
! 386: /* Update async config */
! 387: m->acfg.accm = xmit|recv;
! 388: snprintf(path, sizeof(path), "%s:%s", m->ttynode, NG_TTY_HOOK);
! 389: if (NgSendMsg(m->csock, path, NGM_ASYNC_COOKIE,
! 390: NGM_ASYNC_CMD_SET_CONFIG, &m->acfg, sizeof(m->acfg)) < 0) {
! 391: Perror("[%s] MODEM: can't update config for %s", l->name, path);
! 392: return (-1);
! 393: }
! 394: return (0);
! 395: }
! 396:
! 397: /*
! 398: * ModemChatConnectResult()
! 399: *
! 400: * Connect chat script returns here when finished.
! 401: */
! 402:
! 403: static void
! 404: ModemChatConnectResult(void *arg, int result, const char *msg)
! 405: {
! 406: Link const l = (Link) arg;
! 407: ModemInfo const m = (ModemInfo) l->info;
! 408: char *cspeed;
! 409: int bw;
! 410:
! 411: /* Was the connect script successful? */
! 412: Log(LG_PHYS, ("[%s] MODEM: chat script %s",
! 413: l->name, result ? "succeeded" : "failed"));
! 414: if (!result) {
! 415: failed:
! 416: ModemDoClose(l, FALSE);
! 417: l->state = PHYS_STATE_DOWN;
! 418: PhysDown(l, STR_ERROR, msg);
! 419: return;
! 420: }
! 421:
! 422: /* Set modem's reported connection speed (if any) as the link bandwidth */
! 423: if ((cspeed = ChatGetVar(m->chat, CHAT_VAR_CONNECT_SPEED)) != NULL) {
! 424: if ((bw = (int) strtoul(cspeed, NULL, 10)) > 0)
! 425: l->bandwidth = bw;
! 426: Freee(cspeed);
! 427: }
! 428:
! 429: /* Do async <-> sync conversion via netgraph node */
! 430: if (ModemInstallNodes(l) < 0) {
! 431: msg = STR_DEV_NOT_READY;
! 432: goto failed;
! 433: }
! 434:
! 435: /* Start pin check and report timers */
! 436: TimerInit(&m->checkTimer, "ModemCheck",
! 437: MODEM_CHECK_INTERVAL * SECONDS, ModemCheck, l);
! 438: TimerStart(&m->checkTimer);
! 439: TimerStop(&m->reportTimer);
! 440: TimerInit(&m->reportTimer, "ModemReport",
! 441: MODEM_ERR_REPORT_INTERVAL * SECONDS, ModemErrorCheck, l);
! 442: TimerStart(&m->reportTimer);
! 443:
! 444: l->state = PHYS_STATE_UP;
! 445: PhysUp(l);
! 446: }
! 447:
! 448: /*
! 449: * ModemChatIdleResult()
! 450: *
! 451: * Idle chat script returns here when finished. If the script returned
! 452: * successfully, then one of two things happened: either we answered
! 453: * an incoming call, or else we got a ring and want to do ringback.
! 454: * We tell the difference by checking $IdleResult.
! 455: */
! 456:
! 457: static void
! 458: ModemChatIdleResult(void *arg, int result, const char *msg)
! 459: {
! 460: Link const l = (Link) arg;
! 461: ModemInfo const m = (ModemInfo) l->info;
! 462: char *idleResult;
! 463:
! 464: /* If script failed, then do nothing */
! 465: if (!result) {
! 466: ModemDoClose(l, FALSE);
! 467: return;
! 468: }
! 469:
! 470: /* See what script wants us to do now by checking variable $IdleResult */
! 471: if ((idleResult = ChatGetVar(m->chat, CHAT_VAR_IDLE_RESULT)) == NULL) {
! 472: Log(LG_ERR, ("[%s] MODEM: idle script succeeded, but %s not defined",
! 473: l->name, CHAT_VAR_IDLE_RESULT));
! 474: ModemDoClose(l, FALSE);
! 475: return;
! 476: }
! 477:
! 478: /* Do whatever */
! 479: Log(LG_PHYS, ("[%s] MODEM: idle script succeeded, action=%s",
! 480: l->name, idleResult));
! 481:
! 482: if (gShutdownInProgress) {
! 483: Log(LG_PHYS, ("Shutdown sequence in progress, ignoring"));
! 484: ModemDoClose(l, FALSE);
! 485: } else if (strcasecmp(idleResult, MODEM_IDLE_RESULT_ANSWER) == 0) {
! 486: Log(LG_PHYS, ("[%s] MODEM: opening link in %s mode", l->name, "answer"));
! 487: RecordLinkUpDownReason(NULL, l, 1, STR_INCOMING_CALL, msg ? "%s" : NULL, msg);
! 488: m->answering = TRUE;
! 489: l->state = PHYS_STATE_READY;
! 490: PhysIncoming(l);
! 491: } else if (strcasecmp(idleResult, MODEM_IDLE_RESULT_RINGBACK) == 0) {
! 492: Log(LG_PHYS, ("[%s] MODEM: opening link in %s mode", l->name, "ringback"));
! 493: RecordLinkUpDownReason(NULL, l, 1, STR_RINGBACK, msg ? "%s" : NULL, msg);
! 494: m->answering = FALSE;
! 495: PhysIncoming(l);
! 496: } else {
! 497: Log(LG_ERR, ("[%s] MODEM: idle script succeeded, but action \"%s\" unknown",
! 498: l->name, idleResult));
! 499: ModemDoClose(l, FALSE);
! 500: }
! 501: Freee(idleResult);
! 502: }
! 503:
! 504: /*
! 505: * ModemInstallNodes()
! 506: */
! 507:
! 508: static int
! 509: ModemInstallNodes(Link l)
! 510: {
! 511: ModemInfo m = (ModemInfo) l->info;
! 512: struct ngm_mkpeer ngm;
! 513: struct ngm_connect cn;
! 514: char path[NG_PATHSIZ];
! 515: int hotchar = PPP_FLAG;
! 516: #if NGM_TTY_COOKIE < 1226109660
! 517: struct nodeinfo ngtty;
! 518: int ldisc = NETGRAPHDISC;
! 519: #else
! 520: struct ngm_rmhook rm;
! 521: union {
! 522: u_char buf[sizeof(struct ng_mesg) + sizeof(struct nodeinfo)];
! 523: struct ng_mesg reply;
! 524: } repbuf;
! 525: struct ng_mesg *const reply = &repbuf.reply;
! 526: struct nodeinfo *ninfo = (struct nodeinfo *)&reply->data;
! 527: int tty[2];
! 528: #endif
! 529:
! 530: /* Get a temporary netgraph socket node */
! 531: if (NgMkSockNode(NULL, &m->csock, NULL) < 0) {
! 532: Perror("[%s] MODEM: NgMkSockNode failed", l->name);
! 533: return(-1);
! 534: }
! 535:
! 536: #if NGM_TTY_COOKIE < 1226109660
! 537: /* Install ng_tty line discipline */
! 538: if (ioctl(m->fd, TIOCSETD, &ldisc) < 0) {
! 539:
! 540: /* Installation of the tty node type should be automatic, but isn't yet.
! 541: The 'mkpeer' below will fail, because you can only create a ng_tty
! 542: node via TIOCSETD; however, this will force a load of the node type. */
! 543: if (errno == ENODEV) {
! 544: (void)NgSendAsciiMsg(m->csock, ".:",
! 545: "mkpeer { type=\"%s\" ourhook=\"dummy\" peerhook=\"%s\" }",
! 546: NG_TTY_NODE_TYPE, NG_TTY_HOOK);
! 547: }
! 548: if (ioctl(m->fd, TIOCSETD, &ldisc) < 0) {
! 549: Perror("[%s] ioctl(TIOCSETD, %d)", l->name, ldisc);
! 550: close(m->csock);
! 551: return(-1);
! 552: }
! 553: }
! 554:
! 555: /* Get the name of the ng_tty node */
! 556: if (ioctl(m->fd, NGIOCGINFO, &ngtty) < 0) {
! 557: Perror("[%s] MODEM: ioctl(NGIOCGINFO)", l->name);
! 558: close(m->csock);
! 559: return(-1);
! 560: }
! 561: strlcpy(m->ttynode, ngtty.name, sizeof(m->ttynode));
! 562: #else
! 563: /* Attach a TTY node */
! 564: snprintf(ngm.type, sizeof(ngm.type), "%s", NG_TTY_NODE_TYPE);
! 565: snprintf(ngm.ourhook, sizeof(ngm.ourhook), "%s", NG_TTY_HOOK);
! 566: snprintf(ngm.peerhook, sizeof(ngm.peerhook), "%s", NG_TTY_HOOK);
! 567: if (NgSendMsg(m->csock, ".", NGM_GENERIC_COOKIE,
! 568: NGM_MKPEER, &ngm, sizeof(ngm)) < 0) {
! 569: Perror("[%s] MODEM: can't connect %s node on %s", l->name,
! 570: NG_TTY_NODE_TYPE, ".");
! 571: close(m->csock);
! 572: return(-1);
! 573: }
! 574: snprintf(path, sizeof(path), ".:%s", NG_TTY_HOOK);
! 575: if (NgSendMsg(m->csock, path,
! 576: NGM_GENERIC_COOKIE, NGM_NODEINFO, NULL, 0) != -1) {
! 577: if (NgRecvMsg(m->csock, reply, sizeof(repbuf), NULL) < 0) {
! 578: Perror("[%s] MODEM: can't locate %s node on %s (%d)", l->name,
! 579: NG_TTY_NODE_TYPE, path, errno);
! 580: close(m->csock);
! 581: return(-1);
! 582: }
! 583: }
! 584: snprintf(m->ttynode, sizeof(m->ttynode), "[%x]", ninfo->id);
! 585: /* Attach to the TTY */
! 586: tty[0] = gPid;
! 587: tty[1] = m->fd;
! 588: if (NgSendMsg(m->csock, path, NGM_TTY_COOKIE,
! 589: NGM_TTY_SET_TTY, &tty, sizeof(tty)) < 0) {
! 590: Perror("[%s] MODEM: can't hook tty to fd %d", l->name, m->fd);
! 591: close(m->csock);
! 592: return(-1);
! 593: }
! 594: /* Disconnect temporary hook. */
! 595: snprintf(rm.ourhook, sizeof(rm.ourhook), "%s", NG_TTY_HOOK);
! 596: if (NgSendMsg(m->csock, ".",
! 597: NGM_GENERIC_COOKIE, NGM_RMHOOK, &rm, sizeof(rm)) < 0) {
! 598: Perror("[%s] MODEM: can't remove hook %s", l->name, NG_TTY_HOOK);
! 599: close(m->csock);
! 600: return(-1);
! 601: }
! 602: #endif
! 603:
! 604: /* Set the ``hot char'' on the TTY node */
! 605: snprintf(path, sizeof(path), "%s:", m->ttynode);
! 606: if (NgSendMsg(m->csock, path, NGM_TTY_COOKIE,
! 607: NGM_TTY_SET_HOTCHAR, &hotchar, sizeof(hotchar)) < 0) {
! 608: Perror("[%s] MODEM: can't set hotchar", l->name);
! 609: close(m->csock);
! 610: return(-1);
! 611: }
! 612:
! 613: /* Attach an async converter node */
! 614: strcpy(ngm.type, NG_ASYNC_NODE_TYPE);
! 615: strcpy(ngm.ourhook, NG_TTY_HOOK);
! 616: strcpy(ngm.peerhook, NG_ASYNC_HOOK_ASYNC);
! 617: if (NgSendMsg(m->csock, path, NGM_GENERIC_COOKIE,
! 618: NGM_MKPEER, &ngm, sizeof(ngm)) < 0) {
! 619: Perror("[%s] MODEM: can't connect %s node", l->name, NG_ASYNC_NODE_TYPE);
! 620: close(m->csock);
! 621: return(-1);
! 622: }
! 623:
! 624: /* Configure the async converter node */
! 625: snprintf(path, sizeof(path), "%s:%s", m->ttynode, NG_TTY_HOOK);
! 626: memset(&m->acfg, 0, sizeof(m->acfg));
! 627: m->acfg.enabled = TRUE;
! 628: m->acfg.accm = ~0;
! 629: m->acfg.amru = MODEM_MRU;
! 630: m->acfg.smru = MODEM_MTU;
! 631: if (NgSendMsg(m->csock, path, NGM_ASYNC_COOKIE,
! 632: NGM_ASYNC_CMD_SET_CONFIG, &m->acfg, sizeof(m->acfg)) < 0) {
! 633: Perror("[%s] MODEM: can't config %s", l->name, path);
! 634: close(m->csock);
! 635: return(-1);
! 636: }
! 637:
! 638: /* Attach async node to PPP node */
! 639: if (!PhysGetUpperHook(l, cn.path, cn.peerhook)) {
! 640: Log(LG_PHYS, ("[%s] MODEM: can't get upper hook", l->name));
! 641: close(m->csock);
! 642: return (-1);
! 643: }
! 644: snprintf(cn.ourhook, sizeof(cn.ourhook), NG_ASYNC_HOOK_SYNC);
! 645: if (NgSendMsg(m->csock, path, NGM_GENERIC_COOKIE, NGM_CONNECT,
! 646: &cn, sizeof(cn)) < 0) {
! 647: Perror("[%s] MODEM: can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
! 648: l->name, path, cn.ourhook, cn.path, cn.peerhook);
! 649: close(m->csock);
! 650: return (-1);
! 651: }
! 652:
! 653: return(0);
! 654: }
! 655:
! 656: /*
! 657: * ModemChatSetBaudrate()
! 658: *
! 659: * This callback changes the actual baudrate of the serial port.
! 660: * Should only be called once the device is already open.
! 661: * Returns -1 on failure.
! 662: */
! 663:
! 664: static int
! 665: ModemChatSetBaudrate(void *arg, int baud)
! 666: {
! 667: Link const l = (Link) arg;
! 668: ModemInfo const m = (ModemInfo) l->info;
! 669: struct termios attr;
! 670:
! 671: /* Change baud rate */
! 672: if (tcgetattr(m->fd, &attr) < 0) {
! 673: Perror("[%s] MODEM: can't tcgetattr \"%s\"", l->name, m->device);
! 674: return(-1);
! 675: }
! 676: if (cfsetspeed(&attr, (speed_t) baud) < 0) {
! 677: Perror("[%s] MODEM: can't set speed %d", l->name, baud);
! 678: return(-1);
! 679: }
! 680: if (tcsetattr(m->fd, TCSANOW, &attr) < 0) {
! 681: Perror("[%s] MODEM: can't tcsetattr \"%s\"", l->name, m->device);
! 682: return(-1);
! 683: }
! 684: return(0);
! 685: }
! 686:
! 687: /*
! 688: * ModemGetVar()
! 689: */
! 690:
! 691: char *
! 692: ModemGetVar(Link l, const char *name)
! 693: {
! 694: ModemInfo const m = (ModemInfo) l->info;
! 695:
! 696: return ChatGetVar(m->chat, name);
! 697: }
! 698:
! 699: /*
! 700: * ModemCheck()
! 701: */
! 702:
! 703: static void
! 704: ModemCheck(void *arg)
! 705: {
! 706: Link const l = (Link)arg;
! 707: ModemInfo const m = (ModemInfo) l->info;
! 708: int state;
! 709:
! 710: if (ioctl(m->fd, TIOCMGET, &state) < 0) {
! 711: Perror("[%s] MODEM: can't ioctl(TIOCMGET) %s", l->name, m->device);
! 712: l->state = PHYS_STATE_DOWN;
! 713: ModemDoClose(l, FALSE);
! 714: PhysDown(l, STR_ERROR, strerror(errno));
! 715: return;
! 716: }
! 717: if ((m->watch & TIOCM_CAR) && !(state & TIOCM_CAR)) {
! 718: Log(LG_PHYS, ("[%s] MODEM: carrier detect (CD) signal lost", l->name));
! 719: l->state = PHYS_STATE_DOWN;
! 720: ModemDoClose(l, FALSE);
! 721: PhysDown(l, STR_DROPPED, STR_LOST_CD);
! 722: return;
! 723: }
! 724: if ((m->watch & TIOCM_DSR) && !(state & TIOCM_DSR)) {
! 725: Log(LG_PHYS, ("[%s] MODEM: data-set ready (DSR) signal lost", l->name));
! 726: l->state = PHYS_STATE_DOWN;
! 727: ModemDoClose(l, FALSE);
! 728: PhysDown(l, STR_DROPPED, STR_LOST_DSR);
! 729: return;
! 730: }
! 731: TimerStart(&m->checkTimer);
! 732: }
! 733:
! 734: /*
! 735: * ModemErrorCheck()
! 736: *
! 737: * Called every second to record errors to the log
! 738: */
! 739:
! 740: static void
! 741: ModemErrorCheck(void *arg)
! 742: {
! 743: Link const l = (Link) arg;
! 744: ModemInfo const m = (ModemInfo) l->info;
! 745: char path[NG_PATHSIZ];
! 746: struct ng_async_stat stats;
! 747:
! 748: /* Check for errors */
! 749: snprintf(path, sizeof(path), "%s:%s", m->ttynode, NG_TTY_HOOK);
! 750: if (ModemGetNgStats(l, &stats) >= 0
! 751: && (stats.asyncBadCheckSums
! 752: || stats.asyncRunts || stats.asyncOverflows)) {
! 753: Log(LG_PHYS, ("[%s] NEW FRAME ERRS: FCS %u RUNT %u OVFL %u", l->name,
! 754: stats.asyncBadCheckSums, stats.asyncRunts, stats.asyncOverflows));
! 755: (void) NgSendMsg(m->csock, path,
! 756: NGM_ASYNC_COOKIE, NGM_ASYNC_CMD_CLR_STATS, NULL, 0);
! 757: }
! 758:
! 759: /* Restart timer */
! 760: TimerStop(&m->reportTimer);
! 761: TimerStart(&m->reportTimer);
! 762: }
! 763:
! 764: /*
! 765: * ModemGetNgStats()
! 766: */
! 767:
! 768: static int
! 769: ModemGetNgStats(Link l, struct ng_async_stat *sp)
! 770: {
! 771: ModemInfo const m = (ModemInfo) l->info;
! 772: char path[NG_PATHSIZ];
! 773: union {
! 774: u_char buf[sizeof(struct ng_mesg) + sizeof(*sp)];
! 775: struct ng_mesg resp;
! 776: } u;
! 777:
! 778: /* Get stats */
! 779: snprintf(path, sizeof(path), "%s:%s", m->ttynode, NG_TTY_HOOK);
! 780: if (NgFuncSendQuery(path, NGM_ASYNC_COOKIE, NGM_ASYNC_CMD_GET_STATS,
! 781: NULL, 0, &u.resp, sizeof(u), NULL) < 0) {
! 782: Perror("[%s] MODEM: can't get stats", l->name);
! 783: return(-1);
! 784: }
! 785:
! 786: memcpy(sp, u.resp.data, sizeof(*sp));
! 787: return(0);
! 788: }
! 789:
! 790: /*
! 791: * ModemSetCommand()
! 792: */
! 793:
! 794: static int
! 795: ModemSetCommand(Context ctx, int ac, char *av[], void *arg)
! 796: {
! 797: Link const l = ctx->lnk;
! 798: ModemInfo const m = (ModemInfo) l->info;
! 799:
! 800: switch ((intptr_t)arg) {
! 801: case SET_DEVICE:
! 802: if (ac == 1)
! 803: strlcpy(m->device, av[0], sizeof(m->device));
! 804: break;
! 805: case SET_SPEED:
! 806: {
! 807: int k, baud;
! 808:
! 809: if (ac != 1)
! 810: return(-1);
! 811: baud = atoi(*av);
! 812: for (k = 0; gSpeedList[k] != -1 && baud != gSpeedList[k]; k++);
! 813: if (gSpeedList[k] == -1)
! 814: Error("invalid speed \'%s\'", *av);
! 815: else {
! 816: char buf[32];
! 817:
! 818: m->speed = baud;
! 819: snprintf(buf, sizeof(buf), "%d", m->speed);
! 820: ChatPresetVar(m->chat, CHAT_VAR_BAUDRATE, buf);
! 821: }
! 822: }
! 823: break;
! 824: case SET_CSCRIPT:
! 825: if (ac != 1)
! 826: return(-1);
! 827: *m->connScript = 0;
! 828: strlcpy(m->connScript, av[0], sizeof(m->connScript));
! 829: break;
! 830: case SET_ISCRIPT:
! 831: if (ac != 1)
! 832: return(-1);
! 833: *m->idleScript = 0;
! 834: strlcpy(m->idleScript, av[0], sizeof(m->idleScript));
! 835: if (m->opened || TimerRemain(&m->startTimer) >= 0)
! 836: break; /* nothing needs to be done right now */
! 837: if (m->fd >= 0 && !*m->idleScript)
! 838: ModemDoClose(l, FALSE);
! 839: else if (m->fd < 0 && *m->idleScript)
! 840: ModemStart(l);
! 841: break;
! 842: case SET_SCRIPT_VAR:
! 843: if (ac != 2)
! 844: return(-1);
! 845: ChatPresetVar(m->chat, av[0], av[1]);
! 846: break;
! 847: case SET_WATCH:
! 848: {
! 849: int bit, add;
! 850:
! 851: while (ac--) {
! 852: switch (**av) {
! 853: case '+':
! 854: (*av)++;
! 855: default:
! 856: add = TRUE;
! 857: break;
! 858: case '-':
! 859: add = FALSE;
! 860: (*av)++;
! 861: break;
! 862: }
! 863: if (!strcasecmp(*av, "cd"))
! 864: bit = TIOCM_CAR;
! 865: else if (!strcasecmp(*av, "dsr"))
! 866: bit = TIOCM_DSR;
! 867: else {
! 868: Printf("[%s] modem signal \"%s\" is unknown\r\n", l->name, *av);
! 869: bit = 0;
! 870: }
! 871: if (add)
! 872: m->watch |= bit;
! 873: else
! 874: m->watch &= ~bit;
! 875: av++;
! 876: }
! 877: }
! 878: break;
! 879: default:
! 880: assert(0);
! 881: }
! 882: return(0);
! 883: }
! 884:
! 885: /*
! 886: * ModemOriginated()
! 887: */
! 888:
! 889: static int
! 890: ModemOriginated(Link l)
! 891: {
! 892: ModemInfo const m = (ModemInfo) l->info;
! 893:
! 894: return(m->originated ? LINK_ORIGINATE_LOCAL : LINK_ORIGINATE_REMOTE);
! 895: }
! 896:
! 897: /*
! 898: * ModemIsSync()
! 899: */
! 900:
! 901: static int
! 902: ModemIsSync(Link l)
! 903: {
! 904: return (0);
! 905: }
! 906:
! 907: static int
! 908: ModemSelfAddr(Link l, void *buf, size_t buf_len)
! 909: {
! 910: ModemInfo const m = (ModemInfo) l->info;
! 911:
! 912: strlcpy(buf, m->ttynode, buf_len);
! 913: return(0);
! 914: }
! 915:
! 916: static int
! 917: ModemIface(Link l, void *buf, size_t buf_len)
! 918: {
! 919: ModemInfo const m = (ModemInfo) l->info;
! 920:
! 921: strlcpy(buf, m->device, buf_len);
! 922: return(0);
! 923: }
! 924:
! 925: static int
! 926: ModemCallingNum(Link l, void *buf, size_t buf_len)
! 927: {
! 928: ModemInfo const m = (ModemInfo) l->info;
! 929: char *tmp;
! 930:
! 931: if ((tmp = ChatGetVar(m->chat, CHAT_VAR_CALLING)) == NULL) {
! 932: ((char *)buf)[0] = 0;
! 933: return (-1);
! 934: }
! 935: strlcpy((char*)buf, tmp, buf_len);
! 936: Freee(tmp);
! 937: return(0);
! 938: }
! 939:
! 940: static int
! 941: ModemCalledNum(Link l, void *buf, size_t buf_len)
! 942: {
! 943: ModemInfo const m = (ModemInfo) l->info;
! 944: char *tmp;
! 945:
! 946: if ((tmp = ChatGetVar(m->chat, CHAT_VAR_CALLED)) == NULL) {
! 947: ((char *)buf)[0] = 0;
! 948: return (-1);
! 949: }
! 950: strlcpy((char*)buf, tmp, buf_len);
! 951: Freee(tmp);
! 952: return(0);
! 953: }
! 954:
! 955: /*
! 956: * ModemStat()
! 957: */
! 958:
! 959: void
! 960: ModemStat(Context ctx)
! 961: {
! 962: ModemInfo const m = (ModemInfo) ctx->lnk->info;
! 963: struct ng_async_stat stats;
! 964: char *tmp;
! 965:
! 966: Printf("Modem info:\r\n");
! 967: Printf("\tDevice : %s\r\n", m->device);
! 968: Printf("\tPort speed : %d baud\r\n", m->speed);
! 969: Printf("\tConn. script : \"%s\"\r\n", m->connScript);
! 970: Printf("\tIdle script : \"%s\"\r\n", m->idleScript);
! 971: Printf("\tPins to watch: %s%s\r\n",
! 972: (m->watch & TIOCM_CAR) ? "CD " : "",
! 973: (m->watch & TIOCM_DSR) ? "DSR" : "");
! 974:
! 975: Printf("Modem status:\r\n");
! 976: if (ctx->lnk->state != PHYS_STATE_DOWN) {
! 977: Printf("\tOpened : %s\r\n", (m->opened?"YES":"NO"));
! 978: Printf("\tIncoming : %s\r\n", (m->originated?"NO":"YES"));
! 979:
! 980: /* Set modem's reported connection speed (if any) as the link bandwidth */
! 981: if ((tmp = ChatGetVar(m->chat, CHAT_VAR_CONNECT_SPEED)) != NULL) {
! 982: Printf("\tConnect speed: %s baud\r\n", tmp);
! 983: Freee(tmp);
! 984: }
! 985:
! 986: if ((tmp = ChatGetVar(m->chat, CHAT_VAR_CALLING)) != NULL) {
! 987: Printf("\tCalling : %s\r\n", tmp);
! 988: Freee(tmp);
! 989: }
! 990: if ((tmp = ChatGetVar(m->chat, CHAT_VAR_CALLED)) != NULL) {
! 991: Printf("\tCalled : %s\r\n", tmp);
! 992: Freee(tmp);
! 993: }
! 994:
! 995: if (ctx->lnk->state == PHYS_STATE_UP &&
! 996: ModemGetNgStats(ctx->lnk, &stats) >= 0) {
! 997: Printf("Async stats:\r\n");
! 998: Printf("\t syncOctets: %8u\r\n", stats.syncOctets);
! 999: Printf("\t syncFrames: %8u\r\n", stats.syncFrames);
! 1000: Printf("\t syncOverflows: %8u\r\n", stats.syncOverflows);
! 1001: Printf("\t asyncOctets: %8u\r\n", stats.asyncOctets);
! 1002: Printf("\t asyncFrames: %8u\r\n", stats.asyncFrames);
! 1003: Printf("\t asyncRunts: %8u\r\n", stats.asyncRunts);
! 1004: Printf("\t asyncOverflows: %8u\r\n", stats.asyncOverflows);
! 1005: Printf("\tasyncBadCheckSums: %8u\r\n", stats.asyncBadCheckSums);
! 1006: }
! 1007: }
! 1008: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>