Annotation of embedaddon/mpd/src/modem.c, revision 1.1.1.2

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: 
1.1.1.2 ! misho     119:   static int           ModemSetCommand(Context ctx, int ac, const char *const av[], const void *arg);
1.1       misho     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 },
1.1.1.2 ! misho     164:     { NULL, NULL, NULL, NULL, 0, NULL },
1.1       misho     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
1.1.1.2 ! misho     795: ModemSetCommand(Context ctx, int ac, const char *const av[], const void *arg)
1.1       misho     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;
1.1.1.2 ! misho     850:                const char *s;
1.1       misho     851: 
                    852:                while (ac--) {
1.1.1.2 ! misho     853:                    s = *av;
        !           854:                    switch (*s) {
1.1       misho     855:                        case '+':
1.1.1.2 ! misho     856:                            s++;
1.1       misho     857:                        default:
                    858:                            add = TRUE;
                    859:                            break;
                    860:                        case '-':
                    861:                            add = FALSE;
1.1.1.2 ! misho     862:                            s++;
1.1       misho     863:                            break;
                    864:                    }
1.1.1.2 ! misho     865:                    if (!strcasecmp(s, "cd"))
1.1       misho     866:                        bit = TIOCM_CAR;
1.1.1.2 ! misho     867:                    else if (!strcasecmp(s, "dsr"))
1.1       misho     868:                        bit = TIOCM_DSR;
                    869:                    else {
1.1.1.2 ! misho     870:                        Printf("[%s] modem signal \"%s\" is unknown\r\n", l->name, s);
1.1       misho     871:                        bit = 0;
                    872:                    }
                    873:                    if (add)
                    874:                        m->watch |= bit;
                    875:                    else
                    876:                        m->watch &= ~bit;
                    877:                    av++;
                    878:                }
                    879:            }
                    880:            break;
                    881:        default:
                    882:            assert(0);
                    883:     }
                    884:     return(0);
                    885: }
                    886: 
                    887: /*
                    888:  * ModemOriginated()
                    889:  */
                    890: 
                    891: static int
                    892: ModemOriginated(Link l)
                    893: {
                    894:     ModemInfo  const m = (ModemInfo) l->info;
                    895: 
                    896:     return(m->originated ? LINK_ORIGINATE_LOCAL : LINK_ORIGINATE_REMOTE);
                    897: }
                    898: 
                    899: /*
                    900:  * ModemIsSync()
                    901:  */
                    902: 
                    903: static int
                    904: ModemIsSync(Link l)
                    905: {
1.1.1.2 ! misho     906:     (void)l;
1.1       misho     907:     return (0);
                    908: }
                    909: 
                    910: static int
                    911: ModemSelfAddr(Link l, void *buf, size_t buf_len)
                    912: {
                    913:     ModemInfo  const m = (ModemInfo) l->info;
                    914: 
                    915:     strlcpy(buf, m->ttynode, buf_len);
                    916:     return(0);
                    917: }
                    918: 
                    919: static int
                    920: ModemIface(Link l, void *buf, size_t buf_len)
                    921: {
                    922:     ModemInfo  const m = (ModemInfo) l->info;
                    923: 
                    924:     strlcpy(buf, m->device, buf_len);
                    925:     return(0);
                    926: }
                    927: 
                    928: static int
                    929: ModemCallingNum(Link l, void *buf, size_t buf_len)
                    930: {
                    931:     ModemInfo  const m = (ModemInfo) l->info;
                    932:     char       *tmp;
                    933: 
                    934:     if ((tmp = ChatGetVar(m->chat, CHAT_VAR_CALLING)) == NULL) {
                    935:        ((char *)buf)[0] = 0;
                    936:        return (-1);
                    937:     }
                    938:     strlcpy((char*)buf, tmp, buf_len);
                    939:     Freee(tmp);
                    940:     return(0);
                    941: }
                    942: 
                    943: static int
                    944: ModemCalledNum(Link l, void *buf, size_t buf_len)
                    945: {
                    946:     ModemInfo  const m = (ModemInfo) l->info;
                    947:     char       *tmp;
                    948: 
                    949:     if ((tmp = ChatGetVar(m->chat, CHAT_VAR_CALLED)) == NULL) {
                    950:        ((char *)buf)[0] = 0;
                    951:        return (-1);
                    952:     }
                    953:     strlcpy((char*)buf, tmp, buf_len);
                    954:     Freee(tmp);
                    955:     return(0);
                    956: }
                    957: 
                    958: /*
                    959:  * ModemStat()
                    960:  */
                    961: 
                    962: void
                    963: ModemStat(Context ctx)
                    964: {
                    965:     ModemInfo                  const m = (ModemInfo) ctx->lnk->info;
                    966:     struct ng_async_stat       stats;
                    967:     char                       *tmp;
                    968: 
                    969:     Printf("Modem info:\r\n");
                    970:     Printf("\tDevice       : %s\r\n", m->device);
                    971:     Printf("\tPort speed   : %d baud\r\n", m->speed);
                    972:     Printf("\tConn. script : \"%s\"\r\n", m->connScript);
                    973:     Printf("\tIdle script  : \"%s\"\r\n", m->idleScript);
                    974:     Printf("\tPins to watch: %s%s\r\n",
                    975:        (m->watch & TIOCM_CAR) ? "CD " : "",
                    976:        (m->watch & TIOCM_DSR) ? "DSR" : "");
                    977: 
                    978:     Printf("Modem status:\r\n");
                    979:     if (ctx->lnk->state != PHYS_STATE_DOWN) {
                    980:        Printf("\tOpened       : %s\r\n", (m->opened?"YES":"NO"));
                    981:        Printf("\tIncoming     : %s\r\n", (m->originated?"NO":"YES"));
                    982: 
                    983:        /* Set modem's reported connection speed (if any) as the link bandwidth */
                    984:        if ((tmp = ChatGetVar(m->chat, CHAT_VAR_CONNECT_SPEED)) != NULL) {
                    985:            Printf("\tConnect speed: %s baud\r\n", tmp);
                    986:            Freee(tmp);
                    987:        }
                    988: 
                    989:        if ((tmp = ChatGetVar(m->chat, CHAT_VAR_CALLING)) != NULL) {
                    990:            Printf("\tCalling      : %s\r\n", tmp);
                    991:            Freee(tmp);
                    992:        }
                    993:        if ((tmp = ChatGetVar(m->chat, CHAT_VAR_CALLED)) != NULL) {
                    994:            Printf("\tCalled       : %s\r\n", tmp);
                    995:            Freee(tmp);
                    996:        }
                    997: 
                    998:        if (ctx->lnk->state == PHYS_STATE_UP && 
                    999:                ModemGetNgStats(ctx->lnk, &stats) >= 0) {
                   1000:            Printf("Async stats:\r\n");
                   1001:            Printf("\t       syncOctets: %8u\r\n", stats.syncOctets);
                   1002:            Printf("\t       syncFrames: %8u\r\n", stats.syncFrames);
                   1003:            Printf("\t    syncOverflows: %8u\r\n", stats.syncOverflows);
                   1004:            Printf("\t      asyncOctets: %8u\r\n", stats.asyncOctets);
                   1005:            Printf("\t      asyncFrames: %8u\r\n", stats.asyncFrames);
                   1006:            Printf("\t       asyncRunts: %8u\r\n", stats.asyncRunts);
                   1007:            Printf("\t   asyncOverflows: %8u\r\n", stats.asyncOverflows);
                   1008:            Printf("\tasyncBadCheckSums: %8u\r\n", stats.asyncBadCheckSums);
                   1009:        }
                   1010:     }
                   1011: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>