Deleted Added
sdiff udiff text old ( 43888 ) new ( 44073 )
full compact
1/*
2 * PPP User command processing module
3 *
4 * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5 *
6 * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
7 *
8 * Redistribution and use in source and binary forms are permitted
9 * provided that the above copyright notice and this paragraph are
10 * duplicated in all such forms and that any documentation,
11 * advertising materials, and other materials related to such
12 * distribution and use acknowledge that the software was developed
13 * by the Internet Initiative Japan, Inc. The name of the
14 * IIJ may not be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19 *
20 * $Id: command.c,v 1.180 1999/02/11 10:14:07 brian Exp $
21 *
22 */
23#include <sys/param.h>
24#include <netinet/in_systm.h>
25#include <netinet/in.h>
26#include <netinet/ip.h>
27#include <arpa/inet.h>
28#include <sys/socket.h>
29#include <net/route.h>
30#include <netdb.h>
31#include <sys/un.h>
32
33#include <ctype.h>
34#include <errno.h>
35#include <fcntl.h>
36#include <paths.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#include <sys/wait.h>
41#include <termios.h>
42#include <unistd.h>
43
44#ifndef NOALIAS
45#ifdef __OpenBSD__
46#include "alias.h"
47#else
48#include <alias.h>
49#endif
50#endif
51#include "defs.h"
52#include "command.h"
53#include "mbuf.h"
54#include "log.h"
55#include "timer.h"
56#include "fsm.h"
57#include "lcp.h"
58#include "iplist.h"
59#include "throughput.h"
60#include "slcompress.h"
61#include "lqr.h"
62#include "hdlc.h"
63#include "ipcp.h"
64#include "modem.h"
65#ifndef NOALIAS
66#include "alias_cmd.h"
67#endif
68#include "systems.h"
69#include "filter.h"
70#include "descriptor.h"
71#include "main.h"
72#include "route.h"
73#include "ccp.h"
74#include "auth.h"
75#include "async.h"
76#include "link.h"
77#include "physical.h"
78#include "mp.h"
79#ifndef NORADIUS
80#include "radius.h"
81#endif
82#include "bundle.h"
83#include "server.h"
84#include "prompt.h"
85#include "chat.h"
86#include "chap.h"
87#include "cbcp.h"
88#include "datalink.h"
89#include "iface.h"
90
91/* ``set'' values */
92#define VAR_AUTHKEY 0
93#define VAR_DIAL 1
94#define VAR_LOGIN 2
95#define VAR_AUTHNAME 3
96#define VAR_AUTOLOAD 4
97#define VAR_WINSIZE 5
98#define VAR_DEVICE 6
99#define VAR_ACCMAP 7
100#define VAR_MRRU 8
101#define VAR_MRU 9
102#define VAR_MTU 10
103#define VAR_OPENMODE 11
104#define VAR_PHONE 12
105#define VAR_HANGUP 13
106#define VAR_IDLETIMEOUT 14
107#define VAR_LQRPERIOD 15
108#define VAR_LCPRETRY 16
109#define VAR_CHAPRETRY 17
110#define VAR_PAPRETRY 18
111#define VAR_CCPRETRY 19
112#define VAR_IPCPRETRY 20
113#define VAR_DNS 21
114#define VAR_NBNS 22
115#define VAR_MODE 23
116#define VAR_CALLBACK 24
117#define VAR_CBCP 25
118#define VAR_CHOKED 26
119#define VAR_SENDPIPE 27
120#define VAR_RECVPIPE 28
121#define VAR_RADIUS 29
122#define VAR_CD 30
123
124/* ``accept|deny|disable|enable'' masks */
125#define NEG_HISMASK (1)
126#define NEG_MYMASK (2)
127
128/* ``accept|deny|disable|enable'' values */
129#define NEG_ACFCOMP 40
130#define NEG_CHAP 41
131#define NEG_DEFLATE 42
132#define NEG_LQR 43
133#define NEG_PAP 44
134#define NEG_PPPDDEFLATE 45
135#define NEG_PRED1 46
136#define NEG_PROTOCOMP 47
137#define NEG_SHORTSEQ 48
138#define NEG_VJCOMP 49
139#define NEG_DNS 50
140
141const char Version[] = "2.11";
142const char VersionDate[] = "$Date: 1999/02/11 10:14:07 $";
143
144static int ShowCommand(struct cmdargs const *);
145static int TerminalCommand(struct cmdargs const *);
146static int QuitCommand(struct cmdargs const *);
147static int OpenCommand(struct cmdargs const *);
148static int CloseCommand(struct cmdargs const *);
149static int DownCommand(struct cmdargs const *);
150static int SetCommand(struct cmdargs const *);
151static int LinkCommand(struct cmdargs const *);
152static int AddCommand(struct cmdargs const *);
153static int DeleteCommand(struct cmdargs const *);
154static int NegotiateCommand(struct cmdargs const *);
155static int ClearCommand(struct cmdargs const *);
156static int RunListCommand(struct cmdargs const *);
157static int IfaceAddCommand(struct cmdargs const *);
158static int IfaceDeleteCommand(struct cmdargs const *);
159static int IfaceClearCommand(struct cmdargs const *);
160static int SetProcTitle(struct cmdargs const *);
161#ifndef NOALIAS
162static int AliasEnable(struct cmdargs const *);
163static int AliasOption(struct cmdargs const *);
164#endif
165
166static const char *
167showcx(struct cmdtab const *cmd)
168{
169 if (cmd->lauth & LOCAL_CX)
170 return "(c)";
171 else if (cmd->lauth & LOCAL_CX_OPT)
172 return "(o)";
173
174 return "";
175}
176
177static int
178HelpCommand(struct cmdargs const *arg)
179{
180 struct cmdtab const *cmd;
181 int n, cmax, dmax, cols, cxlen;
182 const char *cx;
183
184 if (!arg->prompt) {
185 log_Printf(LogWARN, "help: Cannot help without a prompt\n");
186 return 0;
187 }
188
189 if (arg->argc > arg->argn) {
190 for (cmd = arg->cmdtab; cmd->name || cmd->alias; cmd++)
191 if ((cmd->lauth & arg->prompt->auth) &&
192 ((cmd->name && !strcasecmp(cmd->name, arg->argv[arg->argn])) ||
193 (cmd->alias && !strcasecmp(cmd->alias, arg->argv[arg->argn])))) {
194 prompt_Printf(arg->prompt, "%s %s\n", cmd->syntax, showcx(cmd));
195 return 0;
196 }
197 return -1;
198 }
199
200 cmax = dmax = 0;
201 for (cmd = arg->cmdtab; cmd->func; cmd++)
202 if (cmd->name && (cmd->lauth & arg->prompt->auth)) {
203 if ((n = strlen(cmd->name) + strlen(showcx(cmd))) > cmax)
204 cmax = n;
205 if ((n = strlen(cmd->helpmes)) > dmax)
206 dmax = n;
207 }
208
209 cols = 80 / (dmax + cmax + 3);
210 n = 0;
211 prompt_Printf(arg->prompt, "(o) = Optional context,"
212 " (c) = Context required\n");
213 for (cmd = arg->cmdtab; cmd->func; cmd++)
214 if (cmd->name && (cmd->lauth & arg->prompt->auth)) {
215 cx = showcx(cmd);
216 cxlen = cmax - strlen(cmd->name);
217 if (n % cols != 0)
218 prompt_Printf(arg->prompt, " ");
219 prompt_Printf(arg->prompt, "%s%-*.*s: %-*.*s",
220 cmd->name, cxlen, cxlen, cx, dmax, dmax, cmd->helpmes);
221 if (++n % cols == 0)
222 prompt_Printf(arg->prompt, "\n");
223 }
224 if (n % cols != 0)
225 prompt_Printf(arg->prompt, "\n");
226
227 return 0;
228}
229
230static int
231CloneCommand(struct cmdargs const *arg)
232{
233 char namelist[LINE_LEN];
234 char *name;
235 int f;
236
237 if (arg->argc == arg->argn)
238 return -1;
239
240 namelist[sizeof namelist - 1] = '\0';
241 for (f = arg->argn; f < arg->argc; f++) {
242 strncpy(namelist, arg->argv[f], sizeof namelist - 1);
243 for(name = strtok(namelist, ", "); name; name = strtok(NULL,", "))
244 bundle_DatalinkClone(arg->bundle, arg->cx, name);
245 }
246
247 return 0;
248}
249
250static int
251RemoveCommand(struct cmdargs const *arg)
252{
253 if (arg->argc != arg->argn)
254 return -1;
255
256 if (arg->cx->state != DATALINK_CLOSED) {
257 log_Printf(LogWARN, "remove: Cannot delete links that aren't closed\n");
258 return 2;
259 }
260
261 bundle_DatalinkRemove(arg->bundle, arg->cx);
262 return 0;
263}
264
265static int
266RenameCommand(struct cmdargs const *arg)
267{
268 if (arg->argc != arg->argn + 1)
269 return -1;
270
271 if (bundle_RenameDatalink(arg->bundle, arg->cx, arg->argv[arg->argn]))
272 return 0;
273
274 log_Printf(LogWARN, "%s -> %s: target name already exists\n",
275 arg->cx->name, arg->argv[arg->argn]);
276 return 1;
277}
278
279int
280LoadCommand(struct cmdargs const *arg)
281{
282 const char *err;
283 int n, mode;
284
285 mode = arg->bundle->phys_type.all;
286
287 if (arg->argn < arg->argc) {
288 for (n = arg->argn; n < arg->argc; n++)
289 if ((err = system_IsValid(arg->argv[n], arg->prompt, mode)) != NULL) {
290 log_Printf(LogWARN, "%s: %s\n", arg->argv[n], err);
291 return 1;
292 }
293
294 for (n = arg->argn; n < arg->argc; n++) {
295 bundle_SetLabel(arg->bundle, arg->argv[arg->argc - 1]);
296 system_Select(arg->bundle, arg->argv[n], CONFFILE, arg->prompt, arg->cx);
297 }
298 bundle_SetLabel(arg->bundle, arg->argv[arg->argc - 1]);
299 } else if ((err = system_IsValid("default", arg->prompt, mode)) != NULL) {
300 log_Printf(LogWARN, "default: %s\n", err);
301 return 1;
302 } else {
303 bundle_SetLabel(arg->bundle, "default");
304 system_Select(arg->bundle, "default", CONFFILE, arg->prompt, arg->cx);
305 bundle_SetLabel(arg->bundle, "default");
306 }
307
308 return 0;
309}
310
311int
312SaveCommand(struct cmdargs const *arg)
313{
314 log_Printf(LogWARN, "save command is not implemented (yet).\n");
315 return 1;
316}
317
318static int
319DialCommand(struct cmdargs const *arg)
320{
321 int res;
322
323 if ((arg->cx && !(arg->cx->physical->type & (PHYS_INTERACTIVE|PHYS_AUTO)))
324 || (!arg->cx &&
325 (arg->bundle->phys_type.all & ~(PHYS_INTERACTIVE|PHYS_AUTO)))) {
326 log_Printf(LogWARN, "Manual dial is only available for auto and"
327 " interactive links\n");
328 return 1;
329 }
330
331 if (arg->argc > arg->argn && (res = LoadCommand(arg)) != 0)
332 return res;
333
334 bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1);
335
336 return 0;
337}
338
339#define isinword(ch) (isalnum(ch) || (ch) == '_')
340
341static char *
342strstrword(char *big, const char *little)
343{
344 /* Get the first occurance of the word ``little'' in ``big'' */
345 char *pos;
346 int len;
347
348 pos = big;
349 len = strlen(little);
350
351 while ((pos = strstr(pos, little)) != NULL)
352 if ((pos == big || !isinword(pos[-1])) && !isinword(pos[len]))
353 break;
354 else
355 pos++;
356
357 return pos;
358}
359
360static char *
361subst(char *tgt, const char *oldstr, const char *newstr)
362{
363 /* tgt is a malloc()d area... realloc() as necessary */
364 char *word, *ntgt;
365 int ltgt, loldstr, lnewstr, pos;
366
367 if ((word = strstrword(tgt, oldstr)) == NULL)
368 return tgt;
369
370 ltgt = strlen(tgt) + 1;
371 loldstr = strlen(oldstr);
372 lnewstr = strlen(newstr);
373 do {
374 pos = word - tgt;
375 if (loldstr > lnewstr)
376 bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr);
377 if (loldstr != lnewstr) {
378 ntgt = realloc(tgt, ltgt += lnewstr - loldstr);
379 if (ntgt == NULL)
380 break; /* Oh wonderful ! */
381 word = ntgt + pos;
382 tgt = ntgt;
383 }
384 if (lnewstr > loldstr)
385 bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr);
386 bcopy(newstr, word, lnewstr);
387 } while ((word = strstrword(word, oldstr)));
388
389 return tgt;
390}
391
392void
393command_Expand(char **nargv, int argc, char const *const *oargv,
394 struct bundle *bundle, int inc0)
395{
396 int arg;
397 char pid[12];
398
399 if (inc0)
400 arg = 0; /* Start at arg 0 */
401 else {
402 nargv[0] = strdup(oargv[0]);
403 arg = 1;
404 }
405 snprintf(pid, sizeof pid, "%d", getpid());
406 for (; arg < argc; arg++) {
407 nargv[arg] = strdup(oargv[arg]);
408 nargv[arg] = subst(nargv[arg], "HISADDR",
409 inet_ntoa(bundle->ncp.ipcp.peer_ip));
410 nargv[arg] = subst(nargv[arg], "AUTHNAME", bundle->cfg.auth.name);
411 nargv[arg] = subst(nargv[arg], "INTERFACE", bundle->iface->name);
412 nargv[arg] = subst(nargv[arg], "MYADDR", inet_ntoa(bundle->ncp.ipcp.my_ip));
413 nargv[arg] = subst(nargv[arg], "USER", bundle->ncp.mp.peer.authname);
414 nargv[arg] = subst(nargv[arg], "PEER_ENDDISC",
415 mp_Enddisc(bundle->ncp.mp.peer.enddisc.class,
416 bundle->ncp.mp.peer.enddisc.address,
417 bundle->ncp.mp.peer.enddisc.len));
418 nargv[arg] = subst(nargv[arg], "ENDDISC",
419 mp_Enddisc(bundle->ncp.mp.cfg.enddisc.class,
420 bundle->ncp.mp.cfg.enddisc.address,
421 bundle->ncp.mp.cfg.enddisc.len));
422 nargv[arg] = subst(nargv[arg], "PROCESSID", pid);
423 nargv[arg] = subst(nargv[arg], "LABEL", bundle_GetLabel(bundle));
424 }
425 nargv[arg] = NULL;
426}
427
428static int
429ShellCommand(struct cmdargs const *arg, int bg)
430{
431 const char *shell;
432 pid_t shpid;
433
434#ifdef SHELL_ONLY_INTERACTIVELY
435 /* we're only allowed to shell when we run ppp interactively */
436 if (arg->prompt && arg->prompt->owner) {
437 log_Printf(LogWARN, "Can't start a shell from a network connection\n");
438 return 1;
439 }
440#endif
441
442 if (arg->argc == arg->argn) {
443 if (!arg->prompt) {
444 log_Printf(LogWARN, "Can't start an interactive shell from"
445 " a config file\n");
446 return 1;
447 } else if (arg->prompt->owner) {
448 log_Printf(LogWARN, "Can't start an interactive shell from"
449 " a socket connection\n");
450 return 1;
451 } else if (bg) {
452 log_Printf(LogWARN, "Can only start an interactive shell in"
453 " the foreground mode\n");
454 return 1;
455 }
456 }
457
458 if ((shpid = fork()) == 0) {
459 int i, fd;
460
461 if ((shell = getenv("SHELL")) == 0)
462 shell = _PATH_BSHELL;
463
464 timer_TermService();
465
466 if (arg->prompt)
467 fd = arg->prompt->fd_out;
468 else if ((fd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
469 log_Printf(LogALERT, "Failed to open %s: %s\n",
470 _PATH_DEVNULL, strerror(errno));
471 exit(1);
472 }
473 for (i = 0; i < 3; i++)
474 dup2(fd, i);
475
476 fcntl(3, F_SETFD, 1); /* Set close-on-exec flag */
477
478 setuid(geteuid());
479 if (arg->argc > arg->argn) {
480 /* substitute pseudo args */
481 char *argv[MAXARGS];
482 int argc = arg->argc - arg->argn;
483
484 if (argc >= sizeof argv / sizeof argv[0]) {
485 argc = sizeof argv / sizeof argv[0] - 1;
486 log_Printf(LogWARN, "Truncating shell command to %d args\n", argc);
487 }
488 command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 0);
489 if (bg) {
490 pid_t p;
491
492 p = getpid();
493 if (daemon(1, 1) == -1) {
494 log_Printf(LogERROR, "%d: daemon: %s\n", (int)p, strerror(errno));
495 exit(1);
496 }
497 } else if (arg->prompt)
498 printf("ppp: Pausing until %s finishes\n", arg->argv[arg->argn]);
499 execvp(argv[0], argv);
500 } else {
501 if (arg->prompt)
502 printf("ppp: Pausing until %s finishes\n", shell);
503 prompt_TtyOldMode(arg->prompt);
504 execl(shell, shell, NULL);
505 }
506
507 log_Printf(LogWARN, "exec() of %s failed: %s\n",
508 arg->argc > arg->argn ? arg->argv[arg->argn] : shell,
509 strerror(errno));
510 exit(255);
511 }
512
513 if (shpid == (pid_t) - 1)
514 log_Printf(LogERROR, "Fork failed: %s\n", strerror(errno));
515 else {
516 int status;
517 waitpid(shpid, &status, 0);
518 }
519
520 if (arg->prompt && !arg->prompt->owner)
521 prompt_TtyCommandMode(arg->prompt);
522
523 return 0;
524}
525
526static int
527BgShellCommand(struct cmdargs const *arg)
528{
529 if (arg->argc == arg->argn)
530 return -1;
531 return ShellCommand(arg, 1);
532}
533
534static int
535FgShellCommand(struct cmdargs const *arg)
536{
537 return ShellCommand(arg, 0);
538}
539
540#ifndef NOALIAS
541static struct cmdtab const AliasCommands[] =
542{
543 {"addr", NULL, alias_RedirectAddr, LOCAL_AUTH,
544 "static address translation", "alias addr [addr_local addr_alias]"},
545 {"deny_incoming", NULL, AliasOption, LOCAL_AUTH,
546 "stop incoming connections", "alias deny_incoming [yes|no]",
547 (const void *) PKT_ALIAS_DENY_INCOMING},
548 {"enable", NULL, AliasEnable, LOCAL_AUTH,
549 "enable IP aliasing", "alias enable [yes|no]"},
550 {"log", NULL, AliasOption, LOCAL_AUTH,
551 "log aliasing link creation", "alias log [yes|no]",
552 (const void *) PKT_ALIAS_LOG},
553 {"port", NULL, alias_RedirectPort, LOCAL_AUTH,
554 "port redirection", "alias port [proto addr_local:port_local port_alias]"},
555 {"same_ports", NULL, AliasOption, LOCAL_AUTH,
556 "try to leave port numbers unchanged", "alias same_ports [yes|no]",
557 (const void *) PKT_ALIAS_SAME_PORTS},
558 {"unregistered_only", NULL, AliasOption, LOCAL_AUTH,
559 "alias unregistered (private) IP address space only",
560 "alias unregistered_only [yes|no]",
561 (const void *) PKT_ALIAS_UNREGISTERED_ONLY},
562 {"use_sockets", NULL, AliasOption, LOCAL_AUTH,
563 "allocate host sockets", "alias use_sockets [yes|no]",
564 (const void *) PKT_ALIAS_USE_SOCKETS},
565 {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
566 "Display this message", "alias help|? [command]", AliasCommands},
567 {NULL, NULL, NULL},
568};
569#endif
570
571static struct cmdtab const AllowCommands[] = {
572 {"modes", "mode", AllowModes, LOCAL_AUTH,
573 "Only allow certain ppp modes", "allow modes mode..."},
574 {"users", "user", AllowUsers, LOCAL_AUTH,
575 "Only allow ppp access to certain users", "allow users logname..."},
576 {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
577 "Display this message", "allow help|? [command]", AllowCommands},
578 {NULL, NULL, NULL},
579};
580
581static struct cmdtab const IfaceCommands[] =
582{
583 {"add", NULL, IfaceAddCommand, LOCAL_AUTH,
584 "Add iface address", "iface add addr[/bits| mask] peer", NULL},
585 {NULL, "add!", IfaceAddCommand, LOCAL_AUTH,
586 "Add or change an iface address", "iface add! addr[/bits| mask] peer",
587 (void *)1},
588 {"clear", NULL, IfaceClearCommand, LOCAL_AUTH,
589 "Clear iface address(es)", "iface clear"},
590 {"delete", "rm", IfaceDeleteCommand, LOCAL_AUTH,
591 "Delete iface address", "iface delete addr", NULL},
592 {NULL, "rm!", IfaceDeleteCommand, LOCAL_AUTH,
593 "Delete iface address", "iface delete addr", (void *)1},
594 {NULL, "delete!", IfaceDeleteCommand, LOCAL_AUTH,
595 "Delete iface address", "iface delete addr", (void *)1},
596 {"show", NULL, iface_Show, LOCAL_AUTH,
597 "Show iface address(es)", "iface show"},
598 {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
599 "Display this message", "alias help|? [command]", IfaceCommands},
600 {NULL, NULL, NULL},
601};
602
603static struct cmdtab const Commands[] = {
604 {"accept", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
605 "accept option request", "accept option .."},
606 {"add", NULL, AddCommand, LOCAL_AUTH,
607 "add route", "add dest mask gateway", NULL},
608 {NULL, "add!", AddCommand, LOCAL_AUTH,
609 "add or change route", "add! dest mask gateway", (void *)1},
610#ifndef NOALIAS
611 {"alias", NULL, RunListCommand, LOCAL_AUTH,
612 "alias control", "alias option [yes|no]", AliasCommands},
613#endif
614 {"allow", "auth", RunListCommand, LOCAL_AUTH,
615 "Allow ppp access", "allow users|modes ....", AllowCommands},
616 {"bg", "!bg", BgShellCommand, LOCAL_AUTH,
617 "Run a background command", "[!]bg command"},
618 {"clear", NULL, ClearCommand, LOCAL_AUTH | LOCAL_CX_OPT,
619 "Clear throughput statistics", "clear ipcp|modem [current|overall|peak]..."},
620 {"clone", NULL, CloneCommand, LOCAL_AUTH | LOCAL_CX,
621 "Clone a link", "clone newname..."},
622 {"close", NULL, CloseCommand, LOCAL_AUTH | LOCAL_CX_OPT,
623 "Close an FSM", "close [lcp|ccp]"},
624 {"delete", NULL, DeleteCommand, LOCAL_AUTH,
625 "delete route", "delete dest", NULL},
626 {NULL, "delete!", DeleteCommand, LOCAL_AUTH,
627 "delete a route if it exists", "delete! dest", (void *)1},
628 {"deny", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
629 "Deny option request", "deny option .."},
630 {"dial", "call", DialCommand, LOCAL_AUTH | LOCAL_CX_OPT,
631 "Dial and login", "dial|call [system ...]", NULL},
632 {"disable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
633 "Disable option", "disable option .."},
634 {"down", NULL, DownCommand, LOCAL_AUTH | LOCAL_CX_OPT,
635 "Generate a down event", "down"},
636 {"enable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
637 "Enable option", "enable option .."},
638 {"iface", "interface", RunListCommand, LOCAL_AUTH,
639 "interface control", "iface option ...", IfaceCommands},
640 {"link", "datalink", LinkCommand, LOCAL_AUTH,
641 "Link specific commands", "link name command ..."},
642 {"load", NULL, LoadCommand, LOCAL_AUTH | LOCAL_CX_OPT,
643 "Load settings", "load [system ...]"},
644 {"open", NULL, OpenCommand, LOCAL_AUTH | LOCAL_CX_OPT,
645 "Open an FSM", "open! [lcp|ccp|ipcp]", (void *)1},
646 {"passwd", NULL, PasswdCommand, LOCAL_NO_AUTH,
647 "Password for manipulation", "passwd LocalPassword"},
648 {"quit", "bye", QuitCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
649 "Quit PPP program", "quit|bye [all]"},
650 {"remove", "rm", RemoveCommand, LOCAL_AUTH | LOCAL_CX,
651 "Remove a link", "remove"},
652 {"rename", "mv", RenameCommand, LOCAL_AUTH | LOCAL_CX,
653 "Rename a link", "rename name"},
654 {"save", NULL, SaveCommand, LOCAL_AUTH,
655 "Save settings", "save"},
656 {"set", "setup", SetCommand, LOCAL_AUTH | LOCAL_CX_OPT,
657 "Set parameters", "set[up] var value"},
658 {"shell", "!", FgShellCommand, LOCAL_AUTH,
659 "Run a subshell", "shell|! [sh command]"},
660 {"show", NULL, ShowCommand, LOCAL_AUTH | LOCAL_CX_OPT,
661 "Show status and stats", "show var"},
662 {"term", NULL, TerminalCommand, LOCAL_AUTH | LOCAL_CX,
663 "Enter terminal mode", "term"},
664 {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
665 "Display this message", "help|? [command]", Commands},
666 {NULL, NULL, NULL},
667};
668
669static int
670ShowEscape(struct cmdargs const *arg)
671{
672 if (arg->cx->physical->async.cfg.EscMap[32]) {
673 int code, bit;
674 const char *sep = "";
675
676 for (code = 0; code < 32; code++)
677 if (arg->cx->physical->async.cfg.EscMap[code])
678 for (bit = 0; bit < 8; bit++)
679 if (arg->cx->physical->async.cfg.EscMap[code] & (1 << bit)) {
680 prompt_Printf(arg->prompt, "%s0x%02x", sep, (code << 3) + bit);
681 sep = ", ";
682 }
683 prompt_Printf(arg->prompt, "\n");
684 }
685 return 0;
686}
687
688static int
689ShowTimerList(struct cmdargs const *arg)
690{
691 timer_Show(0, arg->prompt);
692 return 0;
693}
694
695static int
696ShowStopped(struct cmdargs const *arg)
697{
698 prompt_Printf(arg->prompt, " Stopped Timer: LCP: ");
699 if (!arg->cx->physical->link.lcp.fsm.StoppedTimer.load)
700 prompt_Printf(arg->prompt, "Disabled");
701 else
702 prompt_Printf(arg->prompt, "%ld secs",
703 arg->cx->physical->link.lcp.fsm.StoppedTimer.load / SECTICKS);
704
705 prompt_Printf(arg->prompt, ", CCP: ");
706 if (!arg->cx->physical->link.ccp.fsm.StoppedTimer.load)
707 prompt_Printf(arg->prompt, "Disabled");
708 else
709 prompt_Printf(arg->prompt, "%ld secs",
710 arg->cx->physical->link.ccp.fsm.StoppedTimer.load / SECTICKS);
711
712 prompt_Printf(arg->prompt, "\n");
713
714 return 0;
715}
716
717static int
718ShowVersion(struct cmdargs const *arg)
719{
720 prompt_Printf(arg->prompt, "PPP Version %s - %s\n", Version, VersionDate);
721 return 0;
722}
723
724static int
725ShowProtocolStats(struct cmdargs const *arg)
726{
727 struct link *l = command_ChooseLink(arg);
728
729 prompt_Printf(arg->prompt, "%s:\n", l->name);
730 link_ReportProtocolStatus(l, arg->prompt);
731 return 0;
732}
733
734static struct cmdtab const ShowCommands[] = {
735 {"bundle", NULL, bundle_ShowStatus, LOCAL_AUTH,
736 "bundle details", "show bundle"},
737 {"ccp", NULL, ccp_ReportStatus, LOCAL_AUTH | LOCAL_CX_OPT,
738 "CCP status", "show cpp"},
739 {"compress", NULL, sl_Show, LOCAL_AUTH,
740 "VJ compression stats", "show compress"},
741 {"escape", NULL, ShowEscape, LOCAL_AUTH | LOCAL_CX,
742 "escape characters", "show escape"},
743 {"filter", NULL, filter_Show, LOCAL_AUTH,
744 "packet filters", "show filter [in|out|dial|alive]"},
745 {"hdlc", NULL, hdlc_ReportStatus, LOCAL_AUTH | LOCAL_CX,
746 "HDLC errors", "show hdlc"},
747 {"iface", "interface", iface_Show, LOCAL_AUTH,
748 "Interface status", "show iface"},
749 {"ipcp", NULL, ipcp_Show, LOCAL_AUTH,
750 "IPCP status", "show ipcp"},
751 {"lcp", NULL, lcp_ReportStatus, LOCAL_AUTH | LOCAL_CX,
752 "LCP status", "show lcp"},
753 {"link", "datalink", datalink_Show, LOCAL_AUTH | LOCAL_CX,
754 "(high-level) link info", "show link"},
755 {"links", NULL, bundle_ShowLinks, LOCAL_AUTH,
756 "available link names", "show links"},
757 {"log", NULL, log_ShowLevel, LOCAL_AUTH,
758 "log levels", "show log"},
759 {"mem", NULL, mbuf_Show, LOCAL_AUTH,
760 "mbuf allocations", "show mem"},
761 {"modem", NULL, modem_ShowStatus, LOCAL_AUTH | LOCAL_CX,
762 "(low-level) link info", "show modem"},
763 {"mp", "multilink", mp_ShowStatus, LOCAL_AUTH,
764 "multilink setup", "show mp"},
765 {"proto", NULL, ShowProtocolStats, LOCAL_AUTH | LOCAL_CX_OPT,
766 "protocol summary", "show proto"},
767 {"route", NULL, route_Show, LOCAL_AUTH,
768 "routing table", "show route"},
769 {"stopped", NULL, ShowStopped, LOCAL_AUTH | LOCAL_CX,
770 "STOPPED timeout", "show stopped"},
771 {"timers", NULL, ShowTimerList, LOCAL_AUTH,
772 "alarm timers", "show timers"},
773 {"version", NULL, ShowVersion, LOCAL_NO_AUTH | LOCAL_AUTH,
774 "version string", "show version"},
775 {"who", NULL, log_ShowWho, LOCAL_AUTH,
776 "client list", "show who"},
777 {"help", "?", HelpCommand, LOCAL_NO_AUTH | LOCAL_AUTH,
778 "Display this message", "show help|? [command]", ShowCommands},
779 {NULL, NULL, NULL},
780};
781
782static struct cmdtab const *
783FindCommand(struct cmdtab const *cmds, const char *str, int *pmatch)
784{
785 int nmatch;
786 int len;
787 struct cmdtab const *found;
788
789 found = NULL;
790 len = strlen(str);
791 nmatch = 0;
792 while (cmds->func) {
793 if (cmds->name && strncasecmp(str, cmds->name, len) == 0) {
794 if (cmds->name[len] == '\0') {
795 *pmatch = 1;
796 return cmds;
797 }
798 nmatch++;
799 found = cmds;
800 } else if (cmds->alias && strncasecmp(str, cmds->alias, len) == 0) {
801 if (cmds->alias[len] == '\0') {
802 *pmatch = 1;
803 return cmds;
804 }
805 nmatch++;
806 found = cmds;
807 }
808 cmds++;
809 }
810 *pmatch = nmatch;
811 return found;
812}
813
814static const char *
815mkPrefix(int argc, char const *const *argv, char *tgt, int sz)
816{
817 int f, tlen, len;
818
819 tlen = 0;
820 for (f = 0; f < argc && tlen < sz - 2; f++) {
821 if (f)
822 tgt[tlen++] = ' ';
823 len = strlen(argv[f]);
824 if (len > sz - tlen - 1)
825 len = sz - tlen - 1;
826 strncpy(tgt+tlen, argv[f], len);
827 tlen += len;
828 }
829 tgt[tlen] = '\0';
830 return tgt;
831}
832
833static int
834FindExec(struct bundle *bundle, struct cmdtab const *cmds, int argc, int argn,
835 char const *const *argv, struct prompt *prompt, struct datalink *cx)
836{
837 struct cmdtab const *cmd;
838 int val = 1;
839 int nmatch;
840 struct cmdargs arg;
841 char prefix[100];
842
843 cmd = FindCommand(cmds, argv[argn], &nmatch);
844 if (nmatch > 1)
845 log_Printf(LogWARN, "%s: Ambiguous command\n",
846 mkPrefix(argn+1, argv, prefix, sizeof prefix));
847 else if (cmd && (!prompt || (cmd->lauth & prompt->auth))) {
848 if ((cmd->lauth & LOCAL_CX) && !cx)
849 /* We've got no context, but we require it */
850 cx = bundle2datalink(bundle, NULL);
851
852 if ((cmd->lauth & LOCAL_CX) && !cx)
853 log_Printf(LogWARN, "%s: No context (use the `link' command)\n",
854 mkPrefix(argn+1, argv, prefix, sizeof prefix));
855 else {
856 if (cx && !(cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
857 log_Printf(LogWARN, "%s: Redundant context (%s) ignored\n",
858 mkPrefix(argn+1, argv, prefix, sizeof prefix), cx->name);
859 cx = NULL;
860 }
861 arg.cmdtab = cmds;
862 arg.cmd = cmd;
863 arg.argc = argc;
864 arg.argn = argn+1;
865 arg.argv = argv;
866 arg.bundle = bundle;
867 arg.cx = cx;
868 arg.prompt = prompt;
869 val = (*cmd->func) (&arg);
870 }
871 } else
872 log_Printf(LogWARN, "%s: Invalid command\n",
873 mkPrefix(argn+1, argv, prefix, sizeof prefix));
874
875 if (val == -1)
876 log_Printf(LogWARN, "Usage: %s\n", cmd->syntax);
877 else if (val)
878 log_Printf(LogWARN, "%s: Failed %d\n",
879 mkPrefix(argn+1, argv, prefix, sizeof prefix), val);
880
881 return val;
882}
883
884int
885command_Interpret(char *buff, int nb, char *argv[MAXARGS])
886{
887 char *cp;
888
889 if (nb > 0) {
890 cp = buff + strcspn(buff, "\r\n");
891 if (cp)
892 *cp = '\0';
893 return MakeArgs(buff, argv, MAXARGS);
894 }
895 return 0;
896}
897
898static int
899arghidden(int argc, char const *const *argv, int n)
900{
901 /* Is arg n of the given command to be hidden from the log ? */
902
903 /* set authkey xxxxx */
904 /* set key xxxxx */
905 if (n == 2 && !strncasecmp(argv[0], "se", 2) &&
906 (!strncasecmp(argv[1], "authk", 5) || !strncasecmp(argv[1], "ke", 2)))
907 return 1;
908
909 /* passwd xxxxx */
910 if (n == 1 && !strncasecmp(argv[0], "p", 1))
911 return 1;
912
913 /* set server port xxxxx .... */
914 if (n == 3 && !strncasecmp(argv[0], "se", 2) &&
915 !strncasecmp(argv[1], "se", 2))
916 return 1;
917
918 return 0;
919}
920
921void
922command_Run(struct bundle *bundle, int argc, char const *const *argv,
923 struct prompt *prompt, const char *label, struct datalink *cx)
924{
925 if (argc > 0) {
926 if (log_IsKept(LogCOMMAND)) {
927 static char buf[LINE_LEN];
928 int f, n;
929
930 *buf = '\0';
931 if (label) {
932 strncpy(buf, label, sizeof buf - 3);
933 buf[sizeof buf - 3] = '\0';
934 strcat(buf, ": ");
935 }
936 n = strlen(buf);
937 for (f = 0; f < argc; f++) {
938 if (n < sizeof buf - 1 && f)
939 buf[n++] = ' ';
940 if (arghidden(argc, argv, f))
941 strncpy(buf+n, "********", sizeof buf - n - 1);
942 else
943 strncpy(buf+n, argv[f], sizeof buf - n - 1);
944 n += strlen(buf+n);
945 }
946 log_Printf(LogCOMMAND, "%s\n", buf);
947 }
948 FindExec(bundle, Commands, argc, 0, argv, prompt, cx);
949 }
950}
951
952void
953command_Decode(struct bundle *bundle, char *buff, int nb, struct prompt *prompt,
954 const char *label)
955{
956 int argc;
957 char *argv[MAXARGS];
958
959 argc = command_Interpret(buff, nb, argv);
960 command_Run(bundle, argc, (char const *const *)argv, prompt, label, NULL);
961}
962
963static int
964ShowCommand(struct cmdargs const *arg)
965{
966 if (!arg->prompt)
967 log_Printf(LogWARN, "show: Cannot show without a prompt\n");
968 else if (arg->argc > arg->argn)
969 FindExec(arg->bundle, ShowCommands, arg->argc, arg->argn, arg->argv,
970 arg->prompt, arg->cx);
971 else
972 prompt_Printf(arg->prompt, "Use ``show ?'' to get a list.\n");
973
974 return 0;
975}
976
977static int
978TerminalCommand(struct cmdargs const *arg)
979{
980 if (!arg->prompt) {
981 log_Printf(LogWARN, "term: Need a prompt\n");
982 return 1;
983 }
984
985 if (arg->cx->physical->link.lcp.fsm.state > ST_CLOSED) {
986 prompt_Printf(arg->prompt, "LCP state is [%s]\n",
987 State2Nam(arg->cx->physical->link.lcp.fsm.state));
988 return 1;
989 }
990
991 datalink_Up(arg->cx, 0, 0);
992 prompt_TtyTermMode(arg->prompt, arg->cx);
993 return 0;
994}
995
996static int
997QuitCommand(struct cmdargs const *arg)
998{
999 if (!arg->prompt || prompt_IsController(arg->prompt) ||
1000 (arg->argc > arg->argn && !strcasecmp(arg->argv[arg->argn], "all") &&
1001 (arg->prompt->auth & LOCAL_AUTH)))
1002 Cleanup(EX_NORMAL);
1003 if (arg->prompt)
1004 prompt_Destroy(arg->prompt, 1);
1005
1006 return 0;
1007}
1008
1009static int
1010OpenCommand(struct cmdargs const *arg)
1011{
1012 if (arg->argc == arg->argn)
1013 bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1);
1014 else if (arg->argc == arg->argn + 1) {
1015 if (!strcasecmp(arg->argv[arg->argn], "lcp")) {
1016 struct datalink *cx = arg->cx ?
1017 arg->cx : bundle2datalink(arg->bundle, NULL);
1018 if (cx) {
1019 if (cx->physical->link.lcp.fsm.state == ST_OPENED)
1020 fsm_Reopen(&cx->physical->link.lcp.fsm);
1021 else
1022 bundle_Open(arg->bundle, cx->name, PHYS_ALL, 1);
1023 } else
1024 log_Printf(LogWARN, "open lcp: You must specify a link\n");
1025 } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) {
1026 struct fsm *fp;
1027
1028 fp = &command_ChooseLink(arg)->ccp.fsm;
1029 if (fp->link->lcp.fsm.state != ST_OPENED)
1030 log_Printf(LogWARN, "open: LCP must be open before opening CCP\n");
1031 else if (fp->state == ST_OPENED)
1032 fsm_Reopen(fp);
1033 else {
1034 fp->open_mode = 0; /* Not passive any more */
1035 if (fp->state == ST_STOPPED) {
1036 fsm_Down(fp);
1037 fsm_Up(fp);
1038 } else {
1039 fsm_Up(fp);
1040 fsm_Open(fp);
1041 }
1042 }
1043 } else if (!strcasecmp(arg->argv[arg->argn], "ipcp")) {
1044 if (arg->cx)
1045 log_Printf(LogWARN, "open ipcp: You need not specify a link\n");
1046 if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED)
1047 fsm_Reopen(&arg->bundle->ncp.ipcp.fsm);
1048 else
1049 bundle_Open(arg->bundle, NULL, PHYS_ALL, 1);
1050 } else
1051 return -1;
1052 } else
1053 return -1;
1054
1055 return 0;
1056}
1057
1058static int
1059CloseCommand(struct cmdargs const *arg)
1060{
1061 if (arg->argc == arg->argn)
1062 bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_STAYDOWN);
1063 else if (arg->argc == arg->argn + 1) {
1064 if (!strcasecmp(arg->argv[arg->argn], "lcp"))
1065 bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_LCP);
1066 else if (!strcasecmp(arg->argv[arg->argn], "ccp") ||
1067 !strcasecmp(arg->argv[arg->argn], "ccp!")) {
1068 struct fsm *fp;
1069
1070 fp = &command_ChooseLink(arg)->ccp.fsm;
1071 if (fp->state == ST_OPENED) {
1072 fsm_Close(fp);
1073 if (arg->argv[arg->argn][3] == '!')
1074 fp->open_mode = 0; /* Stay ST_CLOSED */
1075 else
1076 fp->open_mode = OPEN_PASSIVE; /* Wait for the peer to start */
1077 }
1078 } else
1079 return -1;
1080 } else
1081 return -1;
1082
1083 return 0;
1084}
1085
1086static int
1087DownCommand(struct cmdargs const *arg)
1088{
1089 if (arg->argc == arg->argn) {
1090 if (arg->cx)
1091 datalink_Down(arg->cx, CLOSE_STAYDOWN);
1092 else
1093 bundle_Down(arg->bundle, CLOSE_STAYDOWN);
1094 } else if (arg->argc == arg->argn + 1) {
1095 if (!strcasecmp(arg->argv[arg->argn], "lcp")) {
1096 if (arg->cx)
1097 datalink_Down(arg->cx, CLOSE_LCP);
1098 else
1099 bundle_Down(arg->bundle, CLOSE_LCP);
1100 } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) {
1101 struct fsm *fp = arg->cx ? &arg->cx->physical->link.ccp.fsm :
1102 &arg->bundle->ncp.mp.link.ccp.fsm;
1103 fsm2initial(fp);
1104 } else
1105 return -1;
1106 } else
1107 return -1;
1108
1109 return 0;
1110}
1111
1112static int
1113SetModemSpeed(struct cmdargs const *arg)
1114{
1115 long speed;
1116 char *end;
1117
1118 if (arg->argc > arg->argn && *arg->argv[arg->argn]) {
1119 if (arg->argc > arg->argn+1) {
1120 log_Printf(LogWARN, "SetModemSpeed: Too many arguments");
1121 return -1;
1122 }
1123 if (strcasecmp(arg->argv[arg->argn], "sync") == 0) {
1124 physical_SetSync(arg->cx->physical);
1125 return 0;
1126 }
1127 end = NULL;
1128 speed = strtol(arg->argv[arg->argn], &end, 10);
1129 if (*end) {
1130 log_Printf(LogWARN, "SetModemSpeed: Bad argument \"%s\"",
1131 arg->argv[arg->argn]);
1132 return -1;
1133 }
1134 if (physical_SetSpeed(arg->cx->physical, speed))
1135 return 0;
1136 log_Printf(LogWARN, "%s: Invalid speed\n", arg->argv[arg->argn]);
1137 } else
1138 log_Printf(LogWARN, "SetModemSpeed: No speed specified\n");
1139
1140 return -1;
1141}
1142
1143static int
1144SetStoppedTimeout(struct cmdargs const *arg)
1145{
1146 struct link *l = &arg->cx->physical->link;
1147
1148 l->lcp.fsm.StoppedTimer.load = 0;
1149 l->ccp.fsm.StoppedTimer.load = 0;
1150 if (arg->argc <= arg->argn+2) {
1151 if (arg->argc > arg->argn) {
1152 l->lcp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn]) * SECTICKS;
1153 if (arg->argc > arg->argn+1)
1154 l->ccp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn+1]) * SECTICKS;
1155 }
1156 return 0;
1157 }
1158 return -1;
1159}
1160
1161#define ismask(x) \
1162 (*x == '0' && strlen(x) == 4 && strspn(x+1, "0123456789.") == 3)
1163
1164static int
1165SetServer(struct cmdargs const *arg)
1166{
1167 int res = -1;
1168
1169 if (arg->argc > arg->argn && arg->argc < arg->argn+4) {
1170 const char *port, *passwd, *mask;
1171
1172 /* What's what ? */
1173 port = arg->argv[arg->argn];
1174 if (arg->argc == arg->argn + 2) {
1175 passwd = arg->argv[arg->argn+1];
1176 mask = NULL;
1177 } else if (arg->argc == arg->argn + 3) {
1178 passwd = arg->argv[arg->argn+1];
1179 mask = arg->argv[arg->argn+2];
1180 if (!ismask(mask))
1181 return -1;
1182 } else if (strcasecmp(port, "none") == 0) {
1183 if (server_Close(arg->bundle))
1184 log_Printf(LogPHASE, "Disabled server port.\n");
1185 return 0;
1186 } else
1187 return -1;
1188
1189 strncpy(server.passwd, passwd, sizeof server.passwd - 1);
1190 server.passwd[sizeof server.passwd - 1] = '\0';
1191
1192 if (*port == '/') {
1193 mode_t imask;
1194 char *ptr, name[LINE_LEN + 12];
1195
1196 if (mask != NULL) {
1197 unsigned m;
1198
1199 if (sscanf(mask, "%o", &m) == 1)
1200 imask = m;
1201 else
1202 return -1;
1203 } else
1204 imask = (mode_t)-1;
1205
1206 ptr = strstr(port, "%d");
1207 if (ptr) {
1208 snprintf(name, sizeof name, "%.*s%d%s",
1209 (int)(ptr - port), port, arg->bundle->unit, ptr + 2);
1210 port = name;
1211 }
1212 res = server_LocalOpen(arg->bundle, port, imask);
1213 } else {
1214 int iport, add = 0;
1215
1216 if (mask != NULL)
1217 return -1;
1218
1219 if (*port == '+') {
1220 port++;
1221 add = 1;
1222 }
1223 if (strspn(port, "0123456789") != strlen(port)) {
1224 struct servent *s;
1225
1226 if ((s = getservbyname(port, "tcp")) == NULL) {
1227 iport = 0;
1228 log_Printf(LogWARN, "%s: Invalid port or service\n", port);
1229 } else
1230 iport = ntohs(s->s_port);
1231 } else
1232 iport = atoi(port);
1233
1234 if (iport) {
1235 if (add)
1236 iport += arg->bundle->unit;
1237 res = server_TcpOpen(arg->bundle, iport);
1238 } else
1239 res = -1;
1240 }
1241 }
1242
1243 return res;
1244}
1245
1246static int
1247SetModemParity(struct cmdargs const *arg)
1248{
1249 return arg->argc > arg->argn ? modem_SetParity(arg->cx->physical,
1250 arg->argv[arg->argn]) : -1;
1251}
1252
1253static int
1254SetEscape(struct cmdargs const *arg)
1255{
1256 int code;
1257 int argc = arg->argc - arg->argn;
1258 char const *const *argv = arg->argv + arg->argn;
1259
1260 for (code = 0; code < 33; code++)
1261 arg->cx->physical->async.cfg.EscMap[code] = 0;
1262
1263 while (argc-- > 0) {
1264 sscanf(*argv++, "%x", &code);
1265 code &= 0xff;
1266 arg->cx->physical->async.cfg.EscMap[code >> 3] |= (1 << (code & 7));
1267 arg->cx->physical->async.cfg.EscMap[32] = 1;
1268 }
1269 return 0;
1270}
1271
1272static struct in_addr
1273GetIpAddr(const char *cp)
1274{
1275 struct hostent *hp;
1276 struct in_addr ipaddr;
1277
1278 if (inet_aton(cp, &ipaddr) == 0) {
1279 hp = gethostbyname(cp);
1280 if (hp && hp->h_addrtype == AF_INET)
1281 memcpy(&ipaddr, hp->h_addr, hp->h_length);
1282 else
1283 ipaddr.s_addr = 0;
1284 }
1285 return (ipaddr);
1286}
1287
1288static int
1289SetInterfaceAddr(struct cmdargs const *arg)
1290{
1291 struct ipcp *ipcp = &arg->bundle->ncp.ipcp;
1292 const char *hisaddr;
1293
1294 if (arg->argc > arg->argn + 4)
1295 return -1;
1296
1297 hisaddr = NULL;
1298 ipcp->cfg.my_range.ipaddr.s_addr = INADDR_ANY;
1299 ipcp->cfg.peer_range.ipaddr.s_addr = INADDR_ANY;
1300 ipcp->cfg.HaveTriggerAddress = 0;
1301 ipcp->cfg.netmask.s_addr = INADDR_ANY;
1302 iplist_reset(&ipcp->cfg.peer_list);
1303
1304 if (arg->argc > arg->argn) {
1305 if (!ParseAddr(ipcp, arg->argv[arg->argn],
1306 &ipcp->cfg.my_range.ipaddr, &ipcp->cfg.my_range.mask,
1307 &ipcp->cfg.my_range.width))
1308 return 1;
1309 if (arg->argc > arg->argn+1) {
1310 hisaddr = arg->argv[arg->argn+1];
1311 if (arg->argc > arg->argn+2) {
1312 ipcp->cfg.netmask = GetIpAddr(arg->argv[arg->argn+2]);
1313 if (arg->argc > arg->argn+3) {
1314 ipcp->cfg.TriggerAddress = GetIpAddr(arg->argv[arg->argn+3]);
1315 ipcp->cfg.HaveTriggerAddress = 1;
1316 }
1317 }
1318 }
1319 }
1320
1321 /* 0.0.0.0 means any address (0 bits) */
1322 if (ipcp->cfg.my_range.ipaddr.s_addr == INADDR_ANY) {
1323 ipcp->cfg.my_range.mask.s_addr = INADDR_ANY;
1324 ipcp->cfg.my_range.width = 0;
1325 }
1326 ipcp->my_ip.s_addr = ipcp->cfg.my_range.ipaddr.s_addr;
1327
1328 if (hisaddr && !ipcp_UseHisaddr(arg->bundle, hisaddr,
1329 arg->bundle->phys_type.all & PHYS_AUTO))
1330 return 4;
1331
1332 return 0;
1333}
1334
1335static int
1336SetVariable(struct cmdargs const *arg)
1337{
1338 long long_val, param = (long)arg->cmd->args;
1339 int mode, dummyint;
1340 const char *argp;
1341 struct datalink *cx = arg->cx; /* LOCAL_CX uses this */
1342 const char *err = NULL;
1343 struct link *l = command_ChooseLink(arg); /* LOCAL_CX_OPT uses this */
1344 struct in_addr dummyaddr, *addr;
1345
1346 if (arg->argc > arg->argn)
1347 argp = arg->argv[arg->argn];
1348 else
1349 argp = "";
1350
1351 if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
1352 log_Printf(LogWARN, "set %s: No context (use the `link' command)\n",
1353 arg->cmd->name);
1354 return 1;
1355 } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
1356 log_Printf(LogWARN, "set %s: Redundant context (%s) ignored\n",
1357 arg->cmd->name, cx->name);
1358 cx = NULL;
1359 }
1360
1361 switch (param) {
1362 case VAR_AUTHKEY:
1363 switch (bundle_Phase(arg->bundle)) {
1364 case PHASE_DEAD:
1365 case PHASE_ESTABLISH:
1366 strncpy(arg->bundle->cfg.auth.key, argp,
1367 sizeof arg->bundle->cfg.auth.key - 1);
1368 arg->bundle->cfg.auth.key[sizeof arg->bundle->cfg.auth.key - 1] = '\0';
1369 break;
1370 default:
1371 err = "set authkey: Only available at phase DEAD/ESTABLISH\n";
1372 log_Printf(LogWARN, err);
1373 break;
1374 }
1375 break;
1376
1377 case VAR_AUTHNAME:
1378 switch (bundle_Phase(arg->bundle)) {
1379 case PHASE_DEAD:
1380 case PHASE_ESTABLISH:
1381 strncpy(arg->bundle->cfg.auth.name, argp,
1382 sizeof arg->bundle->cfg.auth.name - 1);
1383 arg->bundle->cfg.auth.name[sizeof arg->bundle->cfg.auth.name-1] = '\0';
1384 break;
1385 default:
1386 err = "set authname: Only available at phase DEAD/ESTABLISH\n";
1387 log_Printf(LogWARN, err);
1388 break;
1389 }
1390 break;
1391
1392 case VAR_AUTOLOAD:
1393 if (arg->argc == arg->argn + 2 || arg->argc == arg->argn + 4) {
1394 arg->bundle->autoload.running = 1;
1395 arg->bundle->cfg.autoload.max.timeout = atoi(arg->argv[arg->argn]);
1396 arg->bundle->cfg.autoload.max.packets = atoi(arg->argv[arg->argn + 1]);
1397 if (arg->argc == arg->argn + 4) {
1398 arg->bundle->cfg.autoload.min.timeout = atoi(arg->argv[arg->argn + 2]);
1399 arg->bundle->cfg.autoload.min.packets = atoi(arg->argv[arg->argn + 3]);
1400 } else {
1401 arg->bundle->cfg.autoload.min.timeout = 0;
1402 arg->bundle->cfg.autoload.min.packets = 0;
1403 }
1404 } else {
1405 err = "Set autoload requires two or four arguments\n";
1406 log_Printf(LogWARN, err);
1407 }
1408 break;
1409
1410 case VAR_DIAL:
1411 strncpy(cx->cfg.script.dial, argp, sizeof cx->cfg.script.dial - 1);
1412 cx->cfg.script.dial[sizeof cx->cfg.script.dial - 1] = '\0';
1413 break;
1414
1415 case VAR_LOGIN:
1416 strncpy(cx->cfg.script.login, argp, sizeof cx->cfg.script.login - 1);
1417 cx->cfg.script.login[sizeof cx->cfg.script.login - 1] = '\0';
1418 break;
1419
1420 case VAR_WINSIZE:
1421 if (arg->argc > arg->argn) {
1422 l->ccp.cfg.deflate.out.winsize = atoi(arg->argv[arg->argn]);
1423 if (l->ccp.cfg.deflate.out.winsize < 8 ||
1424 l->ccp.cfg.deflate.out.winsize > 15) {
1425 log_Printf(LogWARN, "%d: Invalid outgoing window size\n",
1426 l->ccp.cfg.deflate.out.winsize);
1427 l->ccp.cfg.deflate.out.winsize = 15;
1428 }
1429 if (arg->argc > arg->argn+1) {
1430 l->ccp.cfg.deflate.in.winsize = atoi(arg->argv[arg->argn+1]);
1431 if (l->ccp.cfg.deflate.in.winsize < 8 ||
1432 l->ccp.cfg.deflate.in.winsize > 15) {
1433 log_Printf(LogWARN, "%d: Invalid incoming window size\n",
1434 l->ccp.cfg.deflate.in.winsize);
1435 l->ccp.cfg.deflate.in.winsize = 15;
1436 }
1437 } else
1438 l->ccp.cfg.deflate.in.winsize = 0;
1439 } else {
1440 err = "No window size specified\n";
1441 log_Printf(LogWARN, err);
1442 }
1443 break;
1444
1445 case VAR_DEVICE:
1446 physical_SetDeviceList(cx->physical, arg->argc - arg->argn,
1447 arg->argv + arg->argn);
1448 break;
1449
1450 case VAR_ACCMAP:
1451 if (arg->argc > arg->argn) {
1452 u_long ulong_val;
1453 sscanf(argp, "%lx", &ulong_val);
1454 cx->physical->link.lcp.cfg.accmap = (u_int32_t)ulong_val;
1455 } else {
1456 err = "No accmap specified\n";
1457 log_Printf(LogWARN, err);
1458 }
1459 break;
1460
1461 case VAR_MODE:
1462 mode = Nam2mode(argp);
1463 if (mode == PHYS_NONE || mode == PHYS_ALL) {
1464 log_Printf(LogWARN, "%s: Invalid mode\n", argp);
1465 return -1;
1466 }
1467 bundle_SetMode(arg->bundle, cx, mode);
1468 break;
1469
1470 case VAR_MRRU:
1471 switch (bundle_Phase(arg->bundle)) {
1472 case PHASE_DEAD:
1473 break;
1474 case PHASE_ESTABLISH:
1475 /* Make sure none of our links are DATALINK_LCP or greater */
1476 if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) {
1477 log_Printf(LogWARN, "mrru: Only changable before LCP negotiations\n");
1478 return 1;
1479 }
1480 break;
1481 default:
1482 log_Printf(LogWARN, "mrru: Only changable at phase DEAD/ESTABLISH\n");
1483 return 1;
1484 }
1485 long_val = atol(argp);
1486 if (long_val && long_val < MIN_MRU) {
1487 log_Printf(LogWARN, "MRRU %ld: too small - min %d\n", long_val, MIN_MRU);
1488 return 1;
1489 } else if (long_val > MAX_MRU) {
1490 log_Printf(LogWARN, "MRRU %ld: too big - max %d\n", long_val, MAX_MRU);
1491 return 1;
1492 } else
1493 arg->bundle->ncp.mp.cfg.mrru = long_val;
1494 break;
1495
1496 case VAR_MRU:
1497 long_val = atol(argp);
1498 if (long_val == 0)
1499 l->lcp.cfg.mru = DEF_MRU;
1500 else if (long_val < MIN_MRU) {
1501 log_Printf(LogWARN, "MRU %ld: too small - min %d\n", long_val, MIN_MRU);
1502 return 1;
1503 } else if (long_val > MAX_MRU) {
1504 log_Printf(LogWARN, "MRU %ld: too big - max %d\n", long_val, MAX_MRU);
1505 return 1;
1506 } else
1507 l->lcp.cfg.mru = long_val;
1508 break;
1509
1510 case VAR_MTU:
1511 long_val = atol(argp);
1512 if (long_val && long_val < MIN_MTU) {
1513 log_Printf(LogWARN, "MTU %ld: too small - min %d\n", long_val, MIN_MTU);
1514 return 1;
1515 } else if (long_val > MAX_MTU) {
1516 log_Printf(LogWARN, "MTU %ld: too big - max %d\n", long_val, MAX_MTU);
1517 return 1;
1518 } else
1519 arg->bundle->cfg.mtu = long_val;
1520 break;
1521
1522 case VAR_OPENMODE:
1523 if (strcasecmp(argp, "active") == 0)
1524 cx->physical->link.lcp.cfg.openmode = arg->argc > arg->argn+1 ?
1525 atoi(arg->argv[arg->argn+1]) : 1;
1526 else if (strcasecmp(argp, "passive") == 0)
1527 cx->physical->link.lcp.cfg.openmode = OPEN_PASSIVE;
1528 else {
1529 err = "%s: Invalid openmode\n";
1530 log_Printf(LogWARN, err, argp);
1531 }
1532 break;
1533
1534 case VAR_PHONE:
1535 strncpy(cx->cfg.phone.list, argp, sizeof cx->cfg.phone.list - 1);
1536 cx->cfg.phone.list[sizeof cx->cfg.phone.list - 1] = '\0';
1537 cx->phone.alt = cx->phone.next = NULL;
1538 break;
1539
1540 case VAR_HANGUP:
1541 strncpy(cx->cfg.script.hangup, argp, sizeof cx->cfg.script.hangup - 1);
1542 cx->cfg.script.hangup[sizeof cx->cfg.script.hangup - 1] = '\0';
1543 break;
1544
1545 case VAR_IDLETIMEOUT:
1546 if (arg->argc > arg->argn+1)
1547 err = "Too many idle timeout values\n";
1548 else if (arg->argc == arg->argn+1)
1549 bundle_SetIdleTimer(arg->bundle, atoi(argp));
1550 if (err)
1551 log_Printf(LogWARN, err);
1552 break;
1553
1554 case VAR_LQRPERIOD:
1555 long_val = atol(argp);
1556 if (long_val < MIN_LQRPERIOD) {
1557 log_Printf(LogWARN, "%ld: Invalid lqr period - min %d\n",
1558 long_val, MIN_LQRPERIOD);
1559 return 1;
1560 } else
1561 l->lcp.cfg.lqrperiod = long_val;
1562 break;
1563
1564 case VAR_LCPRETRY:
1565 long_val = atol(argp);
1566 if (long_val < MIN_FSMRETRY) {
1567 log_Printf(LogWARN, "%ld: Invalid LCP FSM retry period - min %d\n",
1568 long_val, MIN_FSMRETRY);
1569 return 1;
1570 } else
1571 cx->physical->link.lcp.cfg.fsmretry = long_val;
1572 break;
1573
1574 case VAR_CHAPRETRY:
1575 long_val = atol(argp);
1576 if (long_val < MIN_FSMRETRY) {
1577 log_Printf(LogWARN, "%ld: Invalid CHAP FSM retry period - min %d\n",
1578 long_val, MIN_FSMRETRY);
1579 return 1;
1580 } else
1581 cx->chap.auth.cfg.fsmretry = long_val;
1582 break;
1583
1584 case VAR_PAPRETRY:
1585 long_val = atol(argp);
1586 if (long_val < MIN_FSMRETRY) {
1587 log_Printf(LogWARN, "%ld: Invalid PAP FSM retry period - min %d\n",
1588 long_val, MIN_FSMRETRY);
1589 return 1;
1590 } else
1591 cx->pap.cfg.fsmretry = long_val;
1592 break;
1593
1594 case VAR_CCPRETRY:
1595 long_val = atol(argp);
1596 if (long_val < MIN_FSMRETRY) {
1597 log_Printf(LogWARN, "%ld: Invalid CCP FSM retry period - min %d\n",
1598 long_val, MIN_FSMRETRY);
1599 return 1;
1600 } else
1601 l->ccp.cfg.fsmretry = long_val;
1602 break;
1603
1604 case VAR_IPCPRETRY:
1605 long_val = atol(argp);
1606 if (long_val < MIN_FSMRETRY) {
1607 log_Printf(LogWARN, "%ld: Invalid IPCP FSM retry period - min %d\n",
1608 long_val, MIN_FSMRETRY);
1609 return 1;
1610 } else
1611 arg->bundle->ncp.ipcp.cfg.fsmretry = long_val;
1612 break;
1613
1614 case VAR_NBNS:
1615 case VAR_DNS:
1616 if (param == VAR_DNS)
1617 addr = arg->bundle->ncp.ipcp.cfg.ns.dns;
1618 else
1619 addr = arg->bundle->ncp.ipcp.cfg.ns.nbns;
1620
1621 addr[0].s_addr = addr[1].s_addr = INADDR_ANY;
1622
1623 if (arg->argc > arg->argn) {
1624 ParseAddr(&arg->bundle->ncp.ipcp, arg->argv[arg->argn],
1625 addr, &dummyaddr, &dummyint);
1626 if (arg->argc > arg->argn+1)
1627 ParseAddr(&arg->bundle->ncp.ipcp, arg->argv[arg->argn + 1],
1628 addr + 1, &dummyaddr, &dummyint);
1629
1630 if (addr[1].s_addr == INADDR_ANY)
1631 addr[1].s_addr = addr[0].s_addr;
1632 if (addr[0].s_addr == INADDR_ANY)
1633 addr[0].s_addr = addr[1].s_addr;
1634 }
1635 break;
1636
1637 case VAR_CALLBACK:
1638 cx->cfg.callback.opmask = 0;
1639 for (dummyint = arg->argn; dummyint < arg->argc; dummyint++) {
1640 if (!strcasecmp(arg->argv[dummyint], "auth"))
1641 cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_AUTH);
1642 else if (!strcasecmp(arg->argv[dummyint], "cbcp"))
1643 cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_CBCP);
1644 else if (!strcasecmp(arg->argv[dummyint], "e.164")) {
1645 if (dummyint == arg->argc - 1)
1646 log_Printf(LogWARN, "No E.164 arg (E.164 ignored) !\n");
1647 else {
1648 cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_E164);
1649 strncpy(cx->cfg.callback.msg, arg->argv[++dummyint],
1650 sizeof cx->cfg.callback.msg - 1);
1651 cx->cfg.callback.msg[sizeof cx->cfg.callback.msg - 1] = '\0';
1652 }
1653 } else if (!strcasecmp(arg->argv[dummyint], "none"))
1654 cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_NONE);
1655 else
1656 return -1;
1657 }
1658 if (cx->cfg.callback.opmask == CALLBACK_BIT(CALLBACK_NONE))
1659 cx->cfg.callback.opmask = 0;
1660 break;
1661
1662 case VAR_CBCP:
1663 cx->cfg.cbcp.delay = 0;
1664 *cx->cfg.cbcp.phone = '\0';
1665 cx->cfg.cbcp.fsmretry = DEF_FSMRETRY;
1666 if (arg->argc > arg->argn) {
1667 strncpy(cx->cfg.cbcp.phone, arg->argv[arg->argn],
1668 sizeof cx->cfg.cbcp.phone - 1);
1669 cx->cfg.cbcp.phone[sizeof cx->cfg.cbcp.phone - 1] = '\0';
1670 if (arg->argc > arg->argn + 1) {
1671 cx->cfg.cbcp.delay = atoi(arg->argv[arg->argn + 1]);
1672 if (arg->argc > arg->argn + 2) {
1673 long_val = atol(arg->argv[arg->argn + 2]);
1674 if (long_val < MIN_FSMRETRY)
1675 log_Printf(LogWARN, "%ld: Invalid CBCP FSM retry period - min %d\n",
1676 long_val, MIN_FSMRETRY);
1677 else
1678 cx->cfg.cbcp.fsmretry = long_val;
1679 }
1680 }
1681 }
1682 break;
1683
1684 case VAR_CHOKED:
1685 arg->bundle->cfg.choked.timeout = atoi(argp);
1686 if (arg->bundle->cfg.choked.timeout <= 0)
1687 arg->bundle->cfg.choked.timeout = CHOKED_TIMEOUT;
1688 break;
1689
1690 case VAR_SENDPIPE:
1691 long_val = atol(argp);
1692 arg->bundle->ncp.ipcp.cfg.sendpipe = long_val;
1693 break;
1694
1695 case VAR_RECVPIPE:
1696 long_val = atol(argp);
1697 arg->bundle->ncp.ipcp.cfg.recvpipe = long_val;
1698 break;
1699
1700#ifndef NORADIUS
1701 case VAR_RADIUS:
1702 if (!*argp)
1703 *arg->bundle->radius.cfg.file = '\0';
1704 else if (access(argp, R_OK)) {
1705 log_Printf(LogWARN, "%s: %s\n", argp, strerror(errno));
1706 return 1;
1707 } else {
1708 strncpy(arg->bundle->radius.cfg.file, argp,
1709 sizeof arg->bundle->radius.cfg.file - 1);
1710 arg->bundle->radius.cfg.file
1711 [sizeof arg->bundle->radius.cfg.file - 1] = '\0';
1712 }
1713 break;
1714#endif
1715
1716 case VAR_CD:
1717 if (*argp) {
1718 long_val = atol(argp);
1719 if (long_val < 0)
1720 long_val = 0;
1721 cx->physical->cfg.cd.delay = long_val;
1722 cx->physical->cfg.cd.required = argp[strlen(argp)-1] == '!';
1723 } else {
1724 cx->physical->cfg.cd.delay = DEF_CDDELAY;
1725 cx->physical->cfg.cd.required = 0;
1726 }
1727 break;
1728 }
1729
1730 return err ? 1 : 0;
1731}
1732
1733static int
1734SetCtsRts(struct cmdargs const *arg)
1735{
1736 if (arg->argc == arg->argn+1) {
1737 if (strcmp(arg->argv[arg->argn], "on") == 0)
1738 physical_SetRtsCts(arg->cx->physical, 1);
1739 else if (strcmp(arg->argv[arg->argn], "off") == 0)
1740 physical_SetRtsCts(arg->cx->physical, 0);
1741 else
1742 return -1;
1743 return 0;
1744 }
1745 return -1;
1746}
1747
1748static struct cmdtab const SetCommands[] = {
1749 {"accmap", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
1750 "accmap value", "set accmap hex-value", (const void *)VAR_ACCMAP},
1751 {"authkey", "key", SetVariable, LOCAL_AUTH,
1752 "authentication key", "set authkey|key key", (const void *)VAR_AUTHKEY},
1753 {"authname", NULL, SetVariable, LOCAL_AUTH,
1754 "authentication name", "set authname name", (const void *)VAR_AUTHNAME},
1755 {"autoload", NULL, SetVariable, LOCAL_AUTH,
1756 "auto link [de]activation", "set autoload maxtime maxload mintime minload",
1757 (const void *)VAR_AUTOLOAD},
1758 {"callback", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
1759 "callback control", "set callback [none|auth|cbcp|"
1760 "E.164 *|number[,number]...]...", (const void *)VAR_CALLBACK},
1761 {"cbcp", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
1762 "CBCP control", "set cbcp [*|phone[,phone...] [delay [timeout]]]",
1763 (const void *)VAR_CBCP},
1764 {"ccpretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
1765 "FSM retry period", "set ccpretry value", (const void *)VAR_CCPRETRY},
1766 {"cd", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "Carrier delay requirement",
1767 "set cd value[!]", (const void *)VAR_CD},
1768 {"chapretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
1769 "CHAP retry period", "set chapretry value", (const void *)VAR_CHAPRETRY},
1770 {"choked", NULL, SetVariable, LOCAL_AUTH,
1771 "choked timeout", "set choked [secs]", (const void *)VAR_CHOKED},
1772 {"ctsrts", "crtscts", SetCtsRts, LOCAL_AUTH | LOCAL_CX,
1773 "Use hardware flow control", "set ctsrts [on|off]"},
1774 {"deflate", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
1775 "deflate window sizes", "set deflate out-winsize in-winsize",
1776 (const void *) VAR_WINSIZE},
1777 {"device", "line", SetVariable, LOCAL_AUTH | LOCAL_CX,
1778 "modem device name", "set device|line device-name[,device-name]",
1779 (const void *) VAR_DEVICE},
1780 {"dial", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
1781 "dialing script", "set dial chat-script", (const void *) VAR_DIAL},
1782 {"dns", NULL, SetVariable, LOCAL_AUTH, "Domain Name Server",
1783 "set dns pri-addr [sec-addr]", (const void *)VAR_DNS},
1784 {"enddisc", NULL, mp_SetEnddisc, LOCAL_AUTH,
1785 "Endpoint Discriminator", "set enddisc [IP|magic|label|psn value]"},
1786 {"escape", NULL, SetEscape, LOCAL_AUTH | LOCAL_CX,
1787 "escape characters", "set escape hex-digit ..."},
1788 {"filter", NULL, filter_Set, LOCAL_AUTH,
1789 "packet filters", "set filter alive|dial|in|out rule-no permit|deny "
1790 "[src_addr[/width]] [dst_addr[/width]] [tcp|udp|icmp [src [lt|eq|gt port]] "
1791 "[dst [lt|eq|gt port]] [estab] [syn] [finrst]]"},
1792 {"hangup", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
1793 "hangup script", "set hangup chat-script", (const void *) VAR_HANGUP},
1794 {"ifaddr", NULL, SetInterfaceAddr, LOCAL_AUTH, "destination address",
1795 "set ifaddr [src-addr [dst-addr [netmask [trg-addr]]]]"},
1796 {"ipcpretry", NULL, SetVariable, LOCAL_AUTH,
1797 "FSM retry period", "set ipcpretry value", (const void *)VAR_IPCPRETRY},
1798 {"lcpretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
1799 "FSM retry period", "set lcpretry value", (const void *)VAR_LCPRETRY},
1800 {"log", NULL, log_SetLevel, LOCAL_AUTH, "log level",
1801 "set log [local] [+|-]async|cbcp|ccp|chat|command|connect|debug|hdlc|id0|"
1802 "ipcp|lcp|lqm|phase|tcp/ip|timer|tun..."},
1803 {"login", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
1804 "login script", "set login chat-script", (const void *) VAR_LOGIN},
1805 {"lqrperiod", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
1806 "LQR period", "set lqrperiod value", (const void *)VAR_LQRPERIOD},
1807 {"mode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "mode value",
1808 "set mode interactive|auto|ddial|background", (const void *)VAR_MODE},
1809 {"mrru", NULL, SetVariable, LOCAL_AUTH, "MRRU value",
1810 "set mrru value", (const void *)VAR_MRRU},
1811 {"mru", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
1812 "MRU value", "set mru value", (const void *)VAR_MRU},
1813 {"mtu", NULL, SetVariable, LOCAL_AUTH,
1814 "interface MTU value", "set mtu value", (const void *)VAR_MTU},
1815 {"nbns", NULL, SetVariable, LOCAL_AUTH, "NetBIOS Name Server",
1816 "set nbns pri-addr [sec-addr]", (const void *)VAR_NBNS},
1817 {"openmode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "open mode",
1818 "set openmode active|passive [secs]", (const void *)VAR_OPENMODE},
1819 {"papretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
1820 "PAP retry period", "set papretry value", (const void *)VAR_PAPRETRY},
1821 {"parity", NULL, SetModemParity, LOCAL_AUTH | LOCAL_CX,
1822 "modem parity", "set parity [odd|even|none]"},
1823 {"phone", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "telephone number(s)",
1824 "set phone phone1[:phone2[...]]", (const void *)VAR_PHONE},
1825 {"proctitle", "title", SetProcTitle, LOCAL_AUTH,
1826 "Process title", "set proctitle [value]"},
1827#ifndef NORADIUS
1828 {"radius", NULL, SetVariable, LOCAL_AUTH,
1829 "RADIUS Config", "set radius cfgfile", (const void *)VAR_RADIUS},
1830#endif
1831 {"reconnect", NULL, datalink_SetReconnect, LOCAL_AUTH | LOCAL_CX,
1832 "Reconnect timeout", "set reconnect value ntries"},
1833 {"recvpipe", NULL, SetVariable, LOCAL_AUTH,
1834 "RECVPIPE value", "set recvpipe value", (const void *)VAR_RECVPIPE},
1835 {"redial", NULL, datalink_SetRedial, LOCAL_AUTH | LOCAL_CX,
1836 "Redial timeout", "set redial value|random[.value|random] [attempts]"},
1837 {"sendpipe", NULL, SetVariable, LOCAL_AUTH,
1838 "SENDPIPE value", "set sendpipe value", (const void *)VAR_SENDPIPE},
1839 {"server", "socket", SetServer, LOCAL_AUTH,
1840 "server port", "set server|socket TcpPort|LocalName|none password [mask]"},
1841 {"speed", NULL, SetModemSpeed, LOCAL_AUTH | LOCAL_CX,
1842 "modem speed", "set speed value"},
1843 {"stopped", NULL, SetStoppedTimeout, LOCAL_AUTH | LOCAL_CX,
1844 "STOPPED timeouts", "set stopped [LCPseconds [CCPseconds]]"},
1845 {"timeout", NULL, SetVariable, LOCAL_AUTH, "Idle timeout",
1846 "set timeout idletime", (const void *)VAR_IDLETIMEOUT},
1847 {"vj", NULL, ipcp_vjset, LOCAL_AUTH,
1848 "vj values", "set vj slots|slotcomp [value]"},
1849 {"weight", NULL, mp_SetDatalinkWeight, LOCAL_AUTH | LOCAL_CX,
1850 "datalink weighting", "set weight n"},
1851 {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
1852 "Display this message", "set help|? [command]", SetCommands},
1853 {NULL, NULL, NULL},
1854};
1855
1856static int
1857SetCommand(struct cmdargs const *arg)
1858{
1859 if (arg->argc > arg->argn)
1860 FindExec(arg->bundle, SetCommands, arg->argc, arg->argn, arg->argv,
1861 arg->prompt, arg->cx);
1862 else if (arg->prompt)
1863 prompt_Printf(arg->prompt, "Use `set ?' to get a list or `set ? <var>' for"
1864 " syntax help.\n");
1865 else
1866 log_Printf(LogWARN, "set command must have arguments\n");
1867
1868 return 0;
1869}
1870
1871static int
1872AddCommand(struct cmdargs const *arg)
1873{
1874 struct in_addr dest, gateway, netmask;
1875 int gw, addrs;
1876
1877 if (arg->argc != arg->argn+3 && arg->argc != arg->argn+2)
1878 return -1;
1879
1880 addrs = 0;
1881 if (arg->argc == arg->argn+2) {
1882 if (!strcasecmp(arg->argv[arg->argn], "default"))
1883 dest.s_addr = netmask.s_addr = INADDR_ANY;
1884 else {
1885 int width;
1886
1887 if (!ParseAddr(&arg->bundle->ncp.ipcp, arg->argv[arg->argn],
1888 &dest, &netmask, &width))
1889 return -1;
1890 if (!strncasecmp(arg->argv[arg->argn], "MYADDR", 6))
1891 addrs = ROUTE_DSTMYADDR;
1892 else if (!strncasecmp(arg->argv[arg->argn], "HISADDR", 7))
1893 addrs = ROUTE_DSTHISADDR;
1894 }
1895 gw = 1;
1896 } else {
1897 if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
1898 addrs = ROUTE_DSTMYADDR;
1899 dest = arg->bundle->ncp.ipcp.my_ip;
1900 } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
1901 addrs = ROUTE_DSTHISADDR;
1902 dest = arg->bundle->ncp.ipcp.peer_ip;
1903 } else
1904 dest = GetIpAddr(arg->argv[arg->argn]);
1905 netmask = GetIpAddr(arg->argv[arg->argn+1]);
1906 gw = 2;
1907 }
1908
1909 if (strcasecmp(arg->argv[arg->argn+gw], "HISADDR") == 0) {
1910 gateway = arg->bundle->ncp.ipcp.peer_ip;
1911 addrs |= ROUTE_GWHISADDR;
1912 } else
1913 gateway = GetIpAddr(arg->argv[arg->argn+gw]);
1914
1915 if (bundle_SetRoute(arg->bundle, RTM_ADD, dest, gateway, netmask,
1916 arg->cmd->args ? 1 : 0, (addrs & ROUTE_GWHISADDR) ? 1 : 0)
1917 && addrs != ROUTE_STATIC)
1918 route_Add(&arg->bundle->ncp.ipcp.route, addrs, dest, netmask, gateway);
1919
1920 return 0;
1921}
1922
1923static int
1924DeleteCommand(struct cmdargs const *arg)
1925{
1926 struct in_addr dest, none;
1927 int addrs;
1928
1929 if (arg->argc == arg->argn+1) {
1930 if(strcasecmp(arg->argv[arg->argn], "all") == 0) {
1931 route_IfDelete(arg->bundle, 0);
1932 route_DeleteAll(&arg->bundle->ncp.ipcp.route);
1933 } else {
1934 addrs = 0;
1935 if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
1936 dest = arg->bundle->ncp.ipcp.my_ip;
1937 addrs = ROUTE_DSTMYADDR;
1938 } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
1939 dest = arg->bundle->ncp.ipcp.peer_ip;
1940 addrs = ROUTE_DSTHISADDR;
1941 } else {
1942 if (strcasecmp(arg->argv[arg->argn], "default") == 0)
1943 dest.s_addr = INADDR_ANY;
1944 else
1945 dest = GetIpAddr(arg->argv[arg->argn]);
1946 addrs = ROUTE_STATIC;
1947 }
1948 none.s_addr = INADDR_ANY;
1949 bundle_SetRoute(arg->bundle, RTM_DELETE, dest, none, none,
1950 arg->cmd->args ? 1 : 0, 0);
1951 route_Delete(&arg->bundle->ncp.ipcp.route, addrs, dest);
1952 }
1953 } else
1954 return -1;
1955
1956 return 0;
1957}
1958
1959#ifndef NOALIAS
1960static int
1961AliasEnable(struct cmdargs const *arg)
1962{
1963 if (arg->argc == arg->argn+1) {
1964 if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
1965 arg->bundle->AliasEnabled = 1;
1966 return 0;
1967 } else if (strcasecmp(arg->argv[arg->argn], "no") == 0) {
1968 arg->bundle->AliasEnabled = 0;
1969 arg->bundle->cfg.opt &= ~OPT_IFACEALIAS;
1970 /* Don't iface_Clear() - there may be manually configured addresses */
1971 return 0;
1972 }
1973 }
1974
1975 return -1;
1976}
1977
1978
1979static int
1980AliasOption(struct cmdargs const *arg)
1981{
1982 long param = (long)arg->cmd->args;
1983
1984 if (arg->argc == arg->argn+1) {
1985 if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
1986 if (arg->bundle->AliasEnabled) {
1987 PacketAliasSetMode(param, param);
1988 return 0;
1989 }
1990 log_Printf(LogWARN, "alias not enabled\n");
1991 } else if (strcmp(arg->argv[arg->argn], "no") == 0) {
1992 if (arg->bundle->AliasEnabled) {
1993 PacketAliasSetMode(0, param);
1994 return 0;
1995 }
1996 log_Printf(LogWARN, "alias not enabled\n");
1997 }
1998 }
1999 return -1;
2000}
2001#endif /* #ifndef NOALIAS */
2002
2003static int
2004LinkCommand(struct cmdargs const *arg)
2005{
2006 if (arg->argc > arg->argn+1) {
2007 char namelist[LINE_LEN];
2008 struct datalink *cx;
2009 char *name;
2010 int result = 0;
2011
2012 if (!strcmp(arg->argv[arg->argn], "*")) {
2013 struct datalink *dl;
2014
2015 cx = arg->bundle->links;
2016 while (cx) {
2017 /* Watch it, the command could be a ``remove'' */
2018 dl = cx->next;
2019 FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
2020 arg->prompt, cx);
2021 for (cx = arg->bundle->links; cx; cx = cx->next)
2022 if (cx == dl)
2023 break; /* Pointer's still valid ! */
2024 }
2025 } else {
2026 strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
2027 namelist[sizeof namelist - 1] = '\0';
2028 for(name = strtok(namelist, ", "); name; name = strtok(NULL,", "))
2029 if (!bundle2datalink(arg->bundle, name)) {
2030 log_Printf(LogWARN, "link: %s: Invalid link name\n", name);
2031 return 1;
2032 }
2033
2034 strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
2035 namelist[sizeof namelist - 1] = '\0';
2036 for(name = strtok(namelist, ", "); name; name = strtok(NULL,", ")) {
2037 cx = bundle2datalink(arg->bundle, name);
2038 if (cx)
2039 FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
2040 arg->prompt, cx);
2041 else {
2042 log_Printf(LogWARN, "link: %s: Invalidated link name !\n", name);
2043 result++;
2044 }
2045 }
2046 }
2047 return result;
2048 }
2049
2050 log_Printf(LogWARN, "Usage: %s\n", arg->cmd->syntax);
2051 return 2;
2052}
2053
2054struct link *
2055command_ChooseLink(struct cmdargs const *arg)
2056{
2057 if (arg->cx)
2058 return &arg->cx->physical->link;
2059 else if (!arg->bundle->ncp.mp.cfg.mrru) {
2060 struct datalink *dl = bundle2datalink(arg->bundle, NULL);
2061 if (dl)
2062 return &dl->physical->link;
2063 }
2064 return &arg->bundle->ncp.mp.link;
2065}
2066
2067static const char *
2068ident_cmd(const char *cmd, unsigned *keep, unsigned *add)
2069{
2070 const char *result;
2071
2072 switch (*cmd) {
2073 case 'A':
2074 case 'a':
2075 result = "accept";
2076 *keep = NEG_MYMASK;
2077 *add = NEG_ACCEPTED;
2078 break;
2079 case 'D':
2080 case 'd':
2081 switch (cmd[1]) {
2082 case 'E':
2083 case 'e':
2084 result = "deny";
2085 *keep = NEG_MYMASK;
2086 *add = 0;
2087 break;
2088 case 'I':
2089 case 'i':
2090 result = "disable";
2091 *keep = NEG_HISMASK;
2092 *add = 0;
2093 break;
2094 default:
2095 return NULL;
2096 }
2097 break;
2098 case 'E':
2099 case 'e':
2100 result = "enable";
2101 *keep = NEG_HISMASK;
2102 *add = NEG_ENABLED;
2103 break;
2104 default:
2105 return NULL;
2106 }
2107
2108 return result;
2109}
2110
2111static int
2112OptSet(struct cmdargs const *arg)
2113{
2114 int bit = (int)(long)arg->cmd->args;
2115 const char *cmd;
2116 unsigned keep; /* Keep these bits */
2117 unsigned add; /* Add these bits */
2118
2119 if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL)
2120 return 1;
2121
2122 if (add)
2123 arg->bundle->cfg.opt |= bit;
2124 else
2125 arg->bundle->cfg.opt &= ~bit;
2126 return 0;
2127}
2128
2129static int
2130IfaceAliasOptSet(struct cmdargs const *arg)
2131{
2132 unsigned save = arg->bundle->cfg.opt;
2133 int result = OptSet(arg);
2134
2135 if (result == 0)
2136 if (Enabled(arg->bundle, OPT_IFACEALIAS) && !arg->bundle->AliasEnabled) {
2137 arg->bundle->cfg.opt = save;
2138 log_Printf(LogWARN, "Cannot enable iface-alias without IP aliasing\n");
2139 result = 2;
2140 }
2141
2142 return result;
2143}
2144
2145static int
2146NegotiateSet(struct cmdargs const *arg)
2147{
2148 long param = (long)arg->cmd->args;
2149 struct link *l = command_ChooseLink(arg); /* LOCAL_CX_OPT uses this */
2150 struct datalink *cx = arg->cx; /* LOCAL_CX uses this */
2151 const char *cmd;
2152 unsigned keep; /* Keep these bits */
2153 unsigned add; /* Add these bits */
2154
2155 if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL)
2156 return 1;
2157
2158 if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
2159 log_Printf(LogWARN, "%s %s: No context (use the `link' command)\n",
2160 cmd, arg->cmd->name);
2161 return 2;
2162 } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
2163 log_Printf(LogWARN, "%s %s: Redundant context (%s) ignored\n",
2164 cmd, arg->cmd->name, cx->name);
2165 cx = NULL;
2166 }
2167
2168 switch (param) {
2169 case NEG_ACFCOMP:
2170 cx->physical->link.lcp.cfg.acfcomp &= keep;
2171 cx->physical->link.lcp.cfg.acfcomp |= add;
2172 break;
2173 case NEG_CHAP:
2174 cx->physical->link.lcp.cfg.chap &= keep;
2175 cx->physical->link.lcp.cfg.chap |= add;
2176 break;
2177 case NEG_DEFLATE:
2178 l->ccp.cfg.neg[CCP_NEG_DEFLATE] &= keep;
2179 l->ccp.cfg.neg[CCP_NEG_DEFLATE] |= add;
2180 break;
2181 case NEG_DNS:
2182 arg->bundle->ncp.ipcp.cfg.ns.dns_neg &= keep;
2183 arg->bundle->ncp.ipcp.cfg.ns.dns_neg |= add;
2184 break;
2185 case NEG_LQR:
2186 cx->physical->link.lcp.cfg.lqr &= keep;
2187 cx->physical->link.lcp.cfg.lqr |= add;
2188 break;
2189 case NEG_PAP:
2190 cx->physical->link.lcp.cfg.pap &= keep;
2191 cx->physical->link.lcp.cfg.pap |= add;
2192 break;
2193 case NEG_PPPDDEFLATE:
2194 l->ccp.cfg.neg[CCP_NEG_DEFLATE24] &= keep;
2195 l->ccp.cfg.neg[CCP_NEG_DEFLATE24] |= add;
2196 break;
2197 case NEG_PRED1:
2198 l->ccp.cfg.neg[CCP_NEG_PRED1] &= keep;
2199 l->ccp.cfg.neg[CCP_NEG_PRED1] |= add;
2200 break;
2201 case NEG_PROTOCOMP:
2202 cx->physical->link.lcp.cfg.protocomp &= keep;
2203 cx->physical->link.lcp.cfg.protocomp |= add;
2204 break;
2205 case NEG_SHORTSEQ:
2206 switch (bundle_Phase(arg->bundle)) {
2207 case PHASE_DEAD:
2208 break;
2209 case PHASE_ESTABLISH:
2210 /* Make sure none of our links are DATALINK_LCP or greater */
2211 if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) {
2212 log_Printf(LogWARN, "shortseq: Only changable before"
2213 " LCP negotiations\n");
2214 return 1;
2215 }
2216 break;
2217 default:
2218 log_Printf(LogWARN, "shortseq: Only changable at phase"
2219 " DEAD/ESTABLISH\n");
2220 return 1;
2221 }
2222 arg->bundle->ncp.mp.cfg.shortseq &= keep;
2223 arg->bundle->ncp.mp.cfg.shortseq |= add;
2224 break;
2225 case NEG_VJCOMP:
2226 arg->bundle->ncp.ipcp.cfg.vj.neg &= keep;
2227 arg->bundle->ncp.ipcp.cfg.vj.neg |= add;
2228 break;
2229 }
2230
2231 return 0;
2232}
2233
2234static struct cmdtab const NegotiateCommands[] = {
2235 {"idcheck", NULL, OptSet, LOCAL_AUTH, "Check FSM reply ids",
2236 "disable|enable", (const void *)OPT_IDCHECK},
2237 {"iface-alias", NULL, IfaceAliasOptSet, LOCAL_AUTH,
2238 "retain interface addresses", "disable|enable",
2239 (const void *)OPT_IFACEALIAS},
2240 {"loopback", NULL, OptSet, LOCAL_AUTH, "Loop packets for local iface",
2241 "disable|enable", (const void *)OPT_LOOPBACK},
2242 {"passwdauth", NULL, OptSet, LOCAL_AUTH, "Use passwd file",
2243 "disable|enable", (const void *)OPT_PASSWDAUTH},
2244 {"proxy", NULL, OptSet, LOCAL_AUTH, "Create a proxy ARP entry",
2245 "disable|enable", (const void *)OPT_PROXY},
2246 {"proxyall", NULL, OptSet, LOCAL_AUTH, "Proxy ARP for all remote hosts",
2247 "disable|enable", (const void *)OPT_PROXYALL},
2248 {"sroutes", NULL, OptSet, LOCAL_AUTH, "Use sticky routes",
2249 "disable|enable", (const void *)OPT_SROUTES},
2250 {"throughput", NULL, OptSet, LOCAL_AUTH, "Rolling throughput",
2251 "disable|enable", (const void *)OPT_THROUGHPUT},
2252 {"utmp", NULL, OptSet, LOCAL_AUTH, "Log connections in utmp",
2253 "disable|enable", (const void *)OPT_UTMP},
2254
2255#define OPT_MAX 9 /* accept/deny allowed below and not above */
2256
2257 {"acfcomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
2258 "Address & Control field compression", "accept|deny|disable|enable",
2259 (const void *)NEG_ACFCOMP},
2260 {"chap", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
2261 "Challenge Handshake Authentication Protocol", "accept|deny|disable|enable",
2262 (const void *)NEG_CHAP},
2263 {"deflate", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
2264 "Deflate compression", "accept|deny|disable|enable",
2265 (const void *)NEG_DEFLATE},
2266 {"deflate24", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
2267 "Deflate (type 24) compression", "accept|deny|disable|enable",
2268 (const void *)NEG_PPPDDEFLATE},
2269 {"dns", NULL, NegotiateSet, LOCAL_AUTH,
2270 "DNS specification", "accept|deny|disable|enable", (const void *)NEG_DNS},
2271 {"lqr", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
2272 "Link Quality Reports", "accept|deny|disable|enable",
2273 (const void *)NEG_LQR},
2274 {"pap", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
2275 "Password Authentication protocol", "accept|deny|disable|enable",
2276 (const void *)NEG_PAP},
2277 {"pred1", "predictor1", NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
2278 "Predictor 1 compression", "accept|deny|disable|enable",
2279 (const void *)NEG_PRED1},
2280 {"protocomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
2281 "Protocol field compression", "accept|deny|disable|enable",
2282 (const void *)NEG_PROTOCOMP},
2283 {"shortseq", NULL, NegotiateSet, LOCAL_AUTH,
2284 "MP Short Sequence Numbers", "accept|deny|disable|enable",
2285 (const void *)NEG_SHORTSEQ},
2286 {"vjcomp", NULL, NegotiateSet, LOCAL_AUTH,
2287 "Van Jacobson header compression", "accept|deny|disable|enable",
2288 (const void *)NEG_VJCOMP},
2289 {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
2290 "Display this message", "accept|deny|disable|enable help|? [value]",
2291 NegotiateCommands},
2292 {NULL, NULL, NULL},
2293};
2294
2295static int
2296NegotiateCommand(struct cmdargs const *arg)
2297{
2298 if (arg->argc > arg->argn) {
2299 char const *argv[3];
2300 unsigned keep, add;
2301 int n;
2302
2303 if ((argv[0] = ident_cmd(arg->argv[arg->argn-1], &keep, &add)) == NULL)
2304 return -1;
2305 argv[2] = NULL;
2306
2307 for (n = arg->argn; n < arg->argc; n++) {
2308 argv[1] = arg->argv[n];
2309 FindExec(arg->bundle, NegotiateCommands + (keep == NEG_HISMASK ?
2310 0 : OPT_MAX), 2, 1, argv, arg->prompt, arg->cx);
2311 }
2312 } else if (arg->prompt)
2313 prompt_Printf(arg->prompt, "Use `%s ?' to get a list.\n",
2314 arg->argv[arg->argn-1]);
2315 else
2316 log_Printf(LogWARN, "%s command must have arguments\n",
2317 arg->argv[arg->argn] );
2318
2319 return 0;
2320}
2321
2322const char *
2323command_ShowNegval(unsigned val)
2324{
2325 switch (val&3) {
2326 case 1: return "disabled & accepted";
2327 case 2: return "enabled & denied";
2328 case 3: return "enabled & accepted";
2329 }
2330 return "disabled & denied";
2331}
2332
2333static int
2334ClearCommand(struct cmdargs const *arg)
2335{
2336 struct pppThroughput *t;
2337 struct datalink *cx;
2338 int i, clear_type;
2339
2340 if (arg->argc < arg->argn + 1)
2341 return -1;
2342
2343 if (strcasecmp(arg->argv[arg->argn], "modem") == 0) {
2344 cx = arg->cx;
2345 if (!cx)
2346 cx = bundle2datalink(arg->bundle, NULL);
2347 if (!cx) {
2348 log_Printf(LogWARN, "A link must be specified for ``clear modem''\n");
2349 return 1;
2350 }
2351 t = &cx->physical->link.throughput;
2352 } else if (strcasecmp(arg->argv[arg->argn], "ipcp") == 0)
2353 t = &arg->bundle->ncp.ipcp.throughput;
2354 else
2355 return -1;
2356
2357 if (arg->argc > arg->argn + 1) {
2358 clear_type = 0;
2359 for (i = arg->argn + 1; i < arg->argc; i++)
2360 if (strcasecmp(arg->argv[i], "overall") == 0)
2361 clear_type |= THROUGHPUT_OVERALL;
2362 else if (strcasecmp(arg->argv[i], "current") == 0)
2363 clear_type |= THROUGHPUT_CURRENT;
2364 else if (strcasecmp(arg->argv[i], "peak") == 0)
2365 clear_type |= THROUGHPUT_PEAK;
2366 else
2367 return -1;
2368 } else
2369 clear_type = THROUGHPUT_ALL;
2370
2371 throughput_clear(t, clear_type, arg->prompt);
2372 return 0;
2373}
2374
2375static int
2376RunListCommand(struct cmdargs const *arg)
2377{
2378 const char *cmd = arg->argc ? arg->argv[arg->argc - 1] : "???";
2379
2380 if (arg->argc > arg->argn)
2381 FindExec(arg->bundle, arg->cmd->args, arg->argc, arg->argn, arg->argv,
2382 arg->prompt, arg->cx);
2383 else if (arg->prompt)
2384 prompt_Printf(arg->prompt, "Use `%s help' to get a list or `%s help"
2385 " <option>' for syntax help.\n", cmd, cmd);
2386 else
2387 log_Printf(LogWARN, "%s command must have arguments\n", cmd);
2388
2389 return 0;
2390}
2391
2392static int
2393IfaceAddCommand(struct cmdargs const *arg)
2394{
2395 int bits, n, how;
2396 struct in_addr ifa, mask, brd;
2397
2398 if (arg->argc == arg->argn + 1) {
2399 if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, NULL, NULL))
2400 return -1;
2401 mask.s_addr = brd.s_addr = INADDR_BROADCAST;
2402 } else {
2403 if (arg->argc == arg->argn + 2) {
2404 if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, &mask, &bits))
2405 return -1;
2406 n = 1;
2407 } else if (arg->argc == arg->argn + 3) {
2408 if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, NULL, NULL))
2409 return -1;
2410 if (!ParseAddr(NULL, arg->argv[arg->argn + 1], &mask, NULL, NULL))
2411 return -1;
2412 n = 2;
2413 } else
2414 return -1;
2415
2416 if (!ParseAddr(NULL, arg->argv[arg->argn + n], &brd, NULL, NULL))
2417 return -1;
2418 }
2419
2420 how = IFACE_ADD_LAST;
2421 if (arg->cmd->args)
2422 how |= IFACE_FORCE_ADD;
2423
2424 return !iface_inAdd(arg->bundle->iface, ifa, mask, brd, how);
2425}
2426
2427static int
2428IfaceDeleteCommand(struct cmdargs const *arg)
2429{
2430 struct in_addr ifa;
2431 int ok;
2432
2433 if (arg->argc != arg->argn + 1)
2434 return -1;
2435
2436 if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, NULL, NULL))
2437 return -1;
2438
2439 if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED &&
2440 arg->bundle->ncp.ipcp.my_ip.s_addr == ifa.s_addr) {
2441 log_Printf(LogWARN, "%s: Cannot remove active interface address\n",
2442 inet_ntoa(ifa));
2443 return 1;
2444 }
2445
2446 ok = iface_inDelete(arg->bundle->iface, ifa);
2447 if (!ok) {
2448 if (arg->cmd->args)
2449 ok = 1;
2450 else if (arg->prompt)
2451 prompt_Printf(arg->prompt, "%s: No such address\n", inet_ntoa(ifa));
2452 else
2453 log_Printf(LogWARN, "%s: No such address\n", inet_ntoa(ifa));
2454 }
2455
2456 return !ok;
2457}
2458
2459static int
2460IfaceClearCommand(struct cmdargs const *arg)
2461{
2462 int how;
2463
2464 if (arg->argc != arg->argn)
2465 return -1;
2466
2467 how = arg->bundle->ncp.ipcp.fsm.state == ST_OPENED ||
2468 arg->bundle->phys_type.all & PHYS_AUTO ?
2469 IFACE_CLEAR_ALIASES : IFACE_CLEAR_ALL;
2470 iface_Clear(arg->bundle->iface, how);
2471
2472 return 0;
2473}
2474
2475static int
2476SetProcTitle(struct cmdargs const *arg)
2477{
2478 static char title[LINE_LEN];
2479 char *argv[MAXARGS], *ptr;
2480 int len, remaining, f, argc = arg->argc - arg->argn;
2481
2482 if (arg->argc == arg->argn) {
2483 arg->bundle->argv[0] = arg->bundle->argv0;
2484 arg->bundle->argv[1] = arg->bundle->argv1;
2485 return 0;
2486 }
2487
2488 if (argc >= sizeof argv / sizeof argv[0]) {
2489 argc = sizeof argv / sizeof argv[0] - 1;
2490 log_Printf(LogWARN, "Truncating proc title to %d args\n", argc);
2491 }
2492 command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 1);
2493
2494 ptr = title;
2495 remaining = sizeof title - 1;
2496 for (f = 0; f < argc && remaining; f++) {
2497 if (f) {
2498 *ptr++ = ' ';
2499 remaining--;
2500 }
2501 len = strlen(argv[f]);
2502 if (len > remaining)
2503 len = remaining;
2504 memcpy(ptr, argv[f], len);
2505 remaining -= len;
2506 ptr += len;
2507 }
2508 *ptr = '\0';
2509
2510 arg->bundle->argv[0] = title;
2511 arg->bundle->argv[1] = NULL;
2512
2513 return 0;
2514}