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>