Remove send/recv_config_pppoa
[mpls-ppp.git] / pppd / sys-sunos4.c
blob3247b737c515dcd2331245eb05cb2bc8fb6f41ba
1 /*
2 * System-dependent procedures for pppd under SunOS 4.
4 * Copyright (c) 1994-2002 Paul Mackerras. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. The name(s) of the authors of this software must not be used to
14 * endorse or promote products derived from this software without
15 * prior written permission.
17 * 3. Redistributions of any form whatsoever must retain the following
18 * acknowledgment:
19 * "This product includes software developed by Paul Mackerras
20 * <paulus@samba.org>".
22 * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
23 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
24 * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
25 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
26 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
27 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
28 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
30 * Derived from main.c and pppd.h, which are:
32 * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved.
34 * Redistribution and use in source and binary forms, with or without
35 * modification, are permitted provided that the following conditions
36 * are met:
38 * 1. Redistributions of source code must retain the above copyright
39 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in
43 * the documentation and/or other materials provided with the
44 * distribution.
46 * 3. The name "Carnegie Mellon University" must not be used to
47 * endorse or promote products derived from this software without
48 * prior written permission. For permission or any legal
49 * details, please contact
50 * Office of Technology Transfer
51 * Carnegie Mellon University
52 * 5000 Forbes Avenue
53 * Pittsburgh, PA 15213-3890
54 * (412) 268-4387, fax: (412) 268-7395
55 * tech-transfer@andrew.cmu.edu
57 * 4. Redistributions of any form whatsoever must retain the following
58 * acknowledgment:
59 * "This product includes software developed by Computing Services
60 * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
62 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
63 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
64 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
65 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
66 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
67 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
68 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
71 #define RCSID "$Id: sys-sunos4.c,v 1.33 2004/11/04 10:02:26 paulus Exp $"
73 #include <stdio.h>
74 #include <stddef.h>
75 #include <stdlib.h>
76 #include <string.h>
77 #include <ctype.h>
78 #include <errno.h>
79 #include <fcntl.h>
80 #include <unistd.h>
81 #include <termios.h>
82 #include <signal.h>
83 #include <malloc.h>
84 #include <utmp.h>
85 #include <sys/types.h>
86 #include <sys/param.h>
87 #include <sys/socket.h>
88 #include <sys/sockio.h>
89 #include <sys/stream.h>
90 #include <sys/stropts.h>
91 #include <sys/stat.h>
92 #include <sys/time.h>
93 #include <sys/poll.h>
94 #include <net/if.h>
95 #include <net/if_arp.h>
96 #include <net/nit_if.h>
97 #include <net/route.h>
98 #include <net/ppp_defs.h>
99 #include <net/pppio.h>
100 #include <netinet/in.h>
102 #include "pppd.h"
104 #if defined(sun) && defined(sparc)
105 #include <alloca.h>
106 #ifndef __GNUC__
107 extern void *alloca();
108 #endif
109 #endif /*sparc*/
111 static const char rcsid[] = RCSID;
113 static int pppfd;
114 static int fdmuxid = -1;
115 static int iffd;
116 static int sockfd;
118 static int restore_term;
119 static struct termios inittermios;
120 static struct winsize wsinfo; /* Initial window size info */
121 static pid_t parent_pid; /* PID of our parent */
123 extern u_char inpacket_buf[]; /* borrowed from main.c */
125 #define MAX_POLLFDS 32
126 static struct pollfd pollfds[MAX_POLLFDS];
127 static int n_pollfds;
129 static int link_mtu, link_mru;
131 #define NMODULES 32
132 static int tty_nmodules;
133 static char tty_modules[NMODULES][FMNAMESZ+1];
135 static int if_is_up; /* Interface has been marked up */
136 static u_int32_t ifaddrs[2]; /* local and remote addresses */
137 static u_int32_t default_route_gateway; /* Gateway for default route added */
138 static u_int32_t proxy_arp_addr; /* Addr for proxy arp entry added */
140 /* Prototypes for procedures local to this file. */
141 static int translate_speed __P((int));
142 static int baud_rate_of __P((int));
143 static int get_ether_addr __P((u_int32_t, struct sockaddr *));
144 static int strioctl __P((int, int, void *, int, int));
148 * sys_init - System-dependent initialization.
150 void
151 sys_init()
153 int x;
155 /* Get an internet socket for doing socket ioctl's on. */
156 if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
157 fatal("Couldn't create IP socket: %m");
160 * We may want to send a SIGHUP to the session leader associated
161 * with our controlling terminal later. Because SunOS doesn't
162 * have getsid(), we make do with sending the signal to our
163 * parent process.
165 parent_pid = getppid();
168 * Open the ppp device.
170 pppfd = open("/dev/ppp", O_RDWR | O_NONBLOCK, 0);
171 if (pppfd < 0)
172 fatal("Can't open /dev/ppp: %m");
173 if (kdebugflag) {
174 x = PPPDBG_LOG + PPPDBG_DRIVER;
175 strioctl(pppfd, PPPIO_DEBUG, &x, sizeof(int), 0);
178 /* Assign a new PPA and get its unit number. */
179 if (strioctl(pppfd, PPPIO_NEWPPA, &ifunit, 0, sizeof(int)) < 0)
180 fatal("Can't create new PPP interface: %m");
183 * Open the ppp device again and push the if_ppp module on it.
185 iffd = open("/dev/ppp", O_RDWR, 0);
186 if (iffd < 0)
187 fatal("Can't open /dev/ppp (2): %m");
188 if (kdebugflag) {
189 x = PPPDBG_LOG + PPPDBG_DRIVER;
190 strioctl(iffd, PPPIO_DEBUG, &x, sizeof(int), 0);
192 if (strioctl(iffd, PPPIO_ATTACH, &ifunit, sizeof(int), 0) < 0)
193 fatal("Couldn't attach ppp interface to device: %m");
194 if (ioctl(iffd, I_PUSH, "if_ppp") < 0)
195 fatal("Can't push ppp interface module: %m");
196 if (kdebugflag) {
197 x = PPPDBG_LOG + PPPDBG_IF;
198 strioctl(iffd, PPPIO_DEBUG, &x, sizeof(int), 0);
200 if (strioctl(iffd, PPPIO_NEWPPA, &ifunit, sizeof(int), 0) < 0)
201 fatal("Couldn't create ppp interface unit: %m");
202 x = PPP_IP;
203 if (strioctl(iffd, PPPIO_BIND, &x, sizeof(int), 0) < 0)
204 fatal("Couldn't bind ppp interface to IP SAP: %m");
206 n_pollfds = 0;
210 * sys_cleanup - restore any system state we modified before exiting:
211 * mark the interface down, delete default route and/or proxy arp entry.
212 * This shouldn't call die() because it's called from die().
214 void
215 sys_cleanup()
217 if (if_is_up)
218 sifdown(0);
219 if (ifaddrs[0])
220 cifaddr(0, ifaddrs[0], ifaddrs[1]);
221 if (default_route_gateway)
222 cifdefaultroute(0, 0, default_route_gateway);
223 if (proxy_arp_addr)
224 cifproxyarp(0, proxy_arp_addr);
228 * sys_close - Clean up in a child process before execing.
230 void
231 sys_close()
233 close(iffd);
234 close(pppfd);
235 close(sockfd);
239 * sys_check_options - check the options that the user specified
242 sys_check_options()
244 return 1;
247 #if 0
249 * daemon - Detach us from controlling terminal session.
252 daemon(nochdir, noclose)
253 int nochdir, noclose;
255 int pid;
257 if ((pid = fork()) < 0)
258 return -1;
259 if (pid != 0)
260 exit(0); /* parent dies */
261 setsid();
262 if (!nochdir)
263 chdir("/");
264 if (!noclose) {
265 fclose(stdin); /* don't need stdin, stdout, stderr */
266 fclose(stdout);
267 fclose(stderr);
269 return 0;
271 #endif
274 * ppp_available - check whether the system has any ppp interfaces
277 ppp_available()
279 struct stat buf;
281 return stat("/dev/ppp", &buf) >= 0;
285 * tty_establish_ppp - Turn the serial port into a ppp interface.
288 tty_establish_ppp(fd)
289 int fd;
291 int i;
293 /* Pop any existing modules off the tty stream. */
294 for (i = 0;; ++i)
295 if (ioctl(fd, I_LOOK, tty_modules[i]) < 0
296 || ioctl(fd, I_POP, 0) < 0)
297 break;
298 tty_nmodules = i;
300 /* Push the async hdlc module and the compressor module. */
301 if (ioctl(fd, I_PUSH, "ppp_ahdl") < 0)
302 fatal("Couldn't push PPP Async HDLC module: %m");
303 if (ioctl(fd, I_PUSH, "ppp_comp") < 0)
304 error("Couldn't push PPP compression module: %m");
306 /* Link the serial port under the PPP multiplexor. */
307 if ((fdmuxid = ioctl(pppfd, I_LINK, fd)) < 0)
308 fatal("Can't link tty to PPP mux: %m");
310 return pppfd;
314 * disestablish_ppp - Restore the serial port to normal operation.
315 * It attempts to reconstruct the stream with the previously popped
316 * modules. This shouldn't call die() because it's called from die().
318 void
319 tty_disestablish_ppp(fd)
320 int fd;
322 int i;
324 if (fdmuxid >= 0) {
325 if (ioctl(pppfd, I_UNLINK, fdmuxid) < 0) {
326 if (!hungup)
327 error("Can't unlink tty from PPP mux: %m");
329 fdmuxid = -1;
331 if (!hungup) {
332 while (ioctl(fd, I_POP, 0) >= 0)
334 for (i = tty_nmodules - 1; i >= 0; --i)
335 if (ioctl(fd, I_PUSH, tty_modules[i]) < 0)
336 error("Couldn't restore tty module %s: %m",
337 tty_modules[i]);
339 if (hungup && default_device && parent_pid > 0) {
341 * If we have received a hangup, we need to send a SIGHUP
342 * to the terminal's controlling process. The reason is
343 * that the original stream head for the terminal hasn't
344 * seen the M_HANGUP message (it went up through the ppp
345 * driver to the stream head for our fd to /dev/ppp).
346 * Actually we send the signal to the process that invoked
347 * pppd, since SunOS doesn't have getsid().
349 kill(parent_pid, SIGHUP);
355 * Check whether the link seems not to be 8-bit clean.
357 void
358 clean_check()
360 int x;
361 char *s;
363 if (strioctl(pppfd, PPPIO_GCLEAN, &x, 0, sizeof(x)) < 0)
364 return;
365 s = NULL;
366 switch (~x) {
367 case RCV_B7_0:
368 s = "bit 7 set to 1";
369 break;
370 case RCV_B7_1:
371 s = "bit 7 set to 0";
372 break;
373 case RCV_EVNP:
374 s = "odd parity";
375 break;
376 case RCV_ODDP:
377 s = "even parity";
378 break;
380 if (s != NULL) {
381 warn("Serial link is not 8-bit clean:");
382 warn("All received characters had %s", s);
387 * List of valid speeds.
389 struct speed {
390 int speed_int, speed_val;
391 } speeds[] = {
392 #ifdef B50
393 { 50, B50 },
394 #endif
395 #ifdef B75
396 { 75, B75 },
397 #endif
398 #ifdef B110
399 { 110, B110 },
400 #endif
401 #ifdef B134
402 { 134, B134 },
403 #endif
404 #ifdef B150
405 { 150, B150 },
406 #endif
407 #ifdef B200
408 { 200, B200 },
409 #endif
410 #ifdef B300
411 { 300, B300 },
412 #endif
413 #ifdef B600
414 { 600, B600 },
415 #endif
416 #ifdef B1200
417 { 1200, B1200 },
418 #endif
419 #ifdef B1800
420 { 1800, B1800 },
421 #endif
422 #ifdef B2000
423 { 2000, B2000 },
424 #endif
425 #ifdef B2400
426 { 2400, B2400 },
427 #endif
428 #ifdef B3600
429 { 3600, B3600 },
430 #endif
431 #ifdef B4800
432 { 4800, B4800 },
433 #endif
434 #ifdef B7200
435 { 7200, B7200 },
436 #endif
437 #ifdef B9600
438 { 9600, B9600 },
439 #endif
440 #ifdef B19200
441 { 19200, B19200 },
442 #endif
443 #ifdef B38400
444 { 38400, B38400 },
445 #endif
446 #ifdef EXTA
447 { 19200, EXTA },
448 #endif
449 #ifdef EXTB
450 { 38400, EXTB },
451 #endif
452 #ifdef B57600
453 { 57600, B57600 },
454 #endif
455 #ifdef B115200
456 { 115200, B115200 },
457 #endif
458 { 0, 0 }
462 * Translate from bits/second to a speed_t.
464 static int
465 translate_speed(bps)
466 int bps;
468 struct speed *speedp;
470 if (bps == 0)
471 return 0;
472 for (speedp = speeds; speedp->speed_int; speedp++)
473 if (bps == speedp->speed_int)
474 return speedp->speed_val;
475 warn("speed %d not supported", bps);
476 return 0;
480 * Translate from a speed_t to bits/second.
482 static int
483 baud_rate_of(speed)
484 int speed;
486 struct speed *speedp;
488 if (speed == 0)
489 return 0;
490 for (speedp = speeds; speedp->speed_int; speedp++)
491 if (speed == speedp->speed_val)
492 return speedp->speed_int;
493 return 0;
497 * set_up_tty: Set up the serial port on `fd' for 8 bits, no parity,
498 * at the requested speed, etc. If `local' is true, set CLOCAL
499 * regardless of whether the modem option was specified.
501 void
502 set_up_tty(fd, local)
503 int fd, local;
505 int speed;
506 struct termios tios;
508 if (tcgetattr(fd, &tios) < 0)
509 fatal("tcgetattr: %m");
511 if (!restore_term) {
512 inittermios = tios;
513 ioctl(fd, TIOCGWINSZ, &wsinfo);
516 tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
517 if (crtscts > 0)
518 tios.c_cflag |= CRTSCTS;
519 else if (crtscts < 0)
520 tios.c_cflag &= ~CRTSCTS;
522 tios.c_cflag |= CS8 | CREAD | HUPCL;
523 if (local || !modem)
524 tios.c_cflag |= CLOCAL;
525 tios.c_iflag = IGNBRK | IGNPAR;
526 tios.c_oflag = 0;
527 tios.c_lflag = 0;
528 tios.c_cc[VMIN] = 1;
529 tios.c_cc[VTIME] = 0;
531 if (crtscts == -2) {
532 tios.c_iflag |= IXON | IXOFF;
533 tios.c_cc[VSTOP] = 0x13; /* DC3 = XOFF = ^S */
534 tios.c_cc[VSTART] = 0x11; /* DC1 = XON = ^Q */
537 speed = translate_speed(inspeed);
538 if (speed) {
539 cfsetospeed(&tios, speed);
540 cfsetispeed(&tios, speed);
541 } else {
542 speed = cfgetospeed(&tios);
544 * We can't proceed if the serial port speed is 0,
545 * since that implies that the serial port is disabled.
547 if (speed == B0)
548 fatal("Baud rate for %s is 0; need explicit baud rate", devnam);
551 if (tcsetattr(fd, TCSAFLUSH, &tios) < 0)
552 fatal("tcsetattr: %m");
554 baud_rate = inspeed = baud_rate_of(speed);
555 restore_term = 1;
559 * restore_tty - restore the terminal to the saved settings.
561 void
562 restore_tty(fd)
563 int fd;
565 if (restore_term) {
566 if (!default_device) {
568 * Turn off echoing, because otherwise we can get into
569 * a loop with the tty and the modem echoing to each other.
570 * We presume we are the sole user of this tty device, so
571 * when we close it, it will revert to its defaults anyway.
573 inittermios.c_lflag &= ~(ECHO | ECHONL);
575 if (tcsetattr(fd, TCSAFLUSH, &inittermios) < 0)
576 if (!hungup && errno != ENXIO)
577 warn("tcsetattr: %m");
578 ioctl(fd, TIOCSWINSZ, &wsinfo);
579 restore_term = 0;
584 * setdtr - control the DTR line on the serial port.
585 * This is called from die(), so it shouldn't call die().
587 void
588 setdtr(fd, on)
589 int fd, on;
591 int modembits = TIOCM_DTR;
593 ioctl(fd, (on? TIOCMBIS: TIOCMBIC), &modembits);
597 * open_loopback - open the device we use for getting packets
598 * in demand mode. Under SunOS, we use our existing fd
599 * to the ppp driver.
602 open_ppp_loopback()
604 return pppfd;
608 * output - Output PPP packet.
610 void
611 output(unit, p, len)
612 int unit;
613 u_char *p;
614 int len;
616 struct strbuf data;
617 int retries;
618 struct pollfd pfd;
620 dump_packet("sent", p, len);
621 if (snoop_send_hook) snoop_send_hook(p, len);
623 data.len = len;
624 data.buf = (caddr_t) p;
625 retries = 4;
626 while (putmsg(pppfd, NULL, &data, 0) < 0) {
627 if (--retries < 0 || (errno != EWOULDBLOCK && errno != EAGAIN)) {
628 if (errno != ENXIO)
629 error("Couldn't send packet: %m");
630 break;
632 pfd.fd = pppfd;
633 pfd.events = POLLOUT;
634 poll(&pfd, 1, 250); /* wait for up to 0.25 seconds */
640 * wait_input - wait until there is data available,
641 * for the length of time specified by *timo (indefinite
642 * if timo is NULL).
644 void
645 wait_input(timo)
646 struct timeval *timo;
648 int t;
650 t = timo == NULL? -1: timo->tv_sec * 1000 + timo->tv_usec / 1000;
651 if (poll(pollfds, n_pollfds, t) < 0 && errno != EINTR) {
652 if (errno != EAGAIN)
653 fatal("poll: %m");
654 /* we can get EAGAIN on a heavily loaded system,
655 * just wait a short time and try again. */
656 usleep(50000);
661 * add_fd - add an fd to the set that wait_input waits for.
663 void add_fd(fd)
664 int fd;
666 int n;
668 for (n = 0; n < n_pollfds; ++n)
669 if (pollfds[n].fd == fd)
670 return;
671 if (n_pollfds < MAX_POLLFDS) {
672 pollfds[n_pollfds].fd = fd;
673 pollfds[n_pollfds].events = POLLIN | POLLPRI | POLLHUP;
674 ++n_pollfds;
675 } else
676 error("Too many inputs!");
680 * remove_fd - remove an fd from the set that wait_input waits for.
682 void remove_fd(fd)
683 int fd;
685 int n;
687 for (n = 0; n < n_pollfds; ++n) {
688 if (pollfds[n].fd == fd) {
689 while (++n < n_pollfds)
690 pollfds[n-1] = pollfds[n];
691 --n_pollfds;
692 break;
697 #if 0
699 * wait_loop_output - wait until there is data available on the
700 * loopback, for the length of time specified by *timo (indefinite
701 * if timo is NULL).
703 void
704 wait_loop_output(timo)
705 struct timeval *timo;
707 wait_input(timo);
711 * wait_time - wait for a given length of time or until a
712 * signal is received.
714 void
715 wait_time(timo)
716 struct timeval *timo;
718 int n;
720 n = select(0, NULL, NULL, NULL, timo);
721 if (n < 0 && errno != EINTR)
722 fatal("select: %m");
724 #endif
727 * read_packet - get a PPP packet from the serial device.
730 read_packet(buf)
731 u_char *buf;
733 struct strbuf ctrl, data;
734 int flags, len;
735 unsigned char ctrlbuf[64];
737 for (;;) {
738 data.maxlen = PPP_MRU + PPP_HDRLEN;
739 data.buf = (caddr_t) buf;
740 ctrl.maxlen = sizeof(ctrlbuf);
741 ctrl.buf = (caddr_t) ctrlbuf;
742 flags = 0;
743 len = getmsg(pppfd, &ctrl, &data, &flags);
744 if (len < 0) {
745 if (errno == EAGAIN || errno == EINTR)
746 return -1;
747 fatal("Error reading packet: %m");
750 if (ctrl.len <= 0)
751 return data.len;
754 * Got a M_PROTO or M_PCPROTO message. Huh?
756 if (debug)
757 dbglog("got ctrl msg len=%d", ctrl.len);
763 * get_loop_output - get outgoing packets from the ppp device,
764 * and detect when we want to bring the real link up.
765 * Return value is 1 if we need to bring up the link, 0 otherwise.
768 get_loop_output()
770 int len;
771 int rv = 0;
773 while ((len = read_packet(inpacket_buf)) > 0) {
774 if (loop_frame(inpacket_buf, len))
775 rv = 1;
777 return rv;
781 * netif_set_mtu - set the MTU on the PPP network interface.
783 void
784 netif_set_mtu(unit, mtu)
785 int unit, mtu;
787 struct ifreq ifr;
789 memset(&ifr, 0, sizeof(ifr));
790 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
791 ifr.ifr_metric = link_mtu;
792 if (ioctl(sockfd, SIOCSIFMTU, &ifr) < 0) {
793 error("Couldn't set IP MTU: %m");
798 * tty_send_config - configure the transmit characteristics of
799 * the ppp interface.
802 tty_send_config(mtu, asyncmap, pcomp, accomp)
803 int mtu;
804 u_int32_t asyncmap;
805 int pcomp, accomp;
807 int cf[2];
809 link_mtu = mtu;
810 if (strioctl(pppfd, PPPIO_MTU, &mtu, sizeof(mtu), 0) < 0) {
811 if (hungup && errno == ENXIO) {
812 ++error_count;
813 return;
815 error("Couldn't set MTU: %m");
817 if (strioctl(pppfd, PPPIO_XACCM, &asyncmap, sizeof(asyncmap), 0) < 0)
818 error("Couldn't set transmit ACCM: %m");
819 cf[0] = (pcomp? COMP_PROT: 0) + (accomp? COMP_AC: 0);
820 cf[1] = COMP_PROT | COMP_AC;
821 if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0)
822 error("Couldn't set prot/AC compression: %m");
826 * tty_set_xaccm - set the extended transmit ACCM for the interface.
828 void
829 tty_set_xaccm(unit, accm)
830 int unit;
831 ext_accm accm;
833 if (strioctl(pppfd, PPPIO_XACCM, accm, sizeof(ext_accm), 0) < 0) {
834 if (!hungup || errno != ENXIO)
835 warn("Couldn't set extended ACCM: %m");
840 * tty_recv_config - configure the receive-side characteristics of
841 * the ppp interface.
843 void
844 tty_recv_config(mru, asyncmap, pcomp, accomp)
845 int mru;
846 u_int32_t asyncmap;
847 int pcomp, accomp;
849 int cf[2];
851 link_mru = mru;
852 if (strioctl(pppfd, PPPIO_MRU, &mru, sizeof(mru), 0) < 0) {
853 if (hungup && errno == ENXIO) {
854 ++error_count;
855 return;
857 error("Couldn't set MRU: %m");
859 if (strioctl(pppfd, PPPIO_RACCM, &asyncmap, sizeof(asyncmap), 0) < 0)
860 error("Couldn't set receive ACCM: %m");
861 cf[0] = (pcomp? DECOMP_PROT: 0) + (accomp? DECOMP_AC: 0);
862 cf[1] = DECOMP_PROT | DECOMP_AC;
863 if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0)
864 error("Couldn't set prot/AC decompression: %m");
868 * ccp_test - ask kernel whether a given compression method
869 * is acceptable for use.
872 ccp_test(unit, opt_ptr, opt_len, for_transmit)
873 int unit, opt_len, for_transmit;
874 u_char *opt_ptr;
876 if (strioctl(pppfd, (for_transmit? PPPIO_XCOMP: PPPIO_RCOMP),
877 opt_ptr, opt_len, 0) >= 0)
878 return 1;
879 return (errno == ENOSR)? 0: -1;
883 * ccp_flags_set - inform kernel about the current state of CCP.
885 void
886 ccp_flags_set(unit, isopen, isup)
887 int unit, isopen, isup;
889 int cf[2];
891 cf[0] = (isopen? CCP_ISOPEN: 0) + (isup? CCP_ISUP: 0);
892 cf[1] = CCP_ISOPEN | CCP_ISUP | CCP_ERROR | CCP_FATALERROR;
893 if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) {
894 if (!hungup || errno != ENXIO)
895 error("Couldn't set kernel CCP state: %m");
900 * get_idle_time - return how long the link has been idle.
903 get_idle_time(u, ip)
904 int u;
905 struct ppp_idle *ip;
907 return strioctl(pppfd, PPPIO_GIDLE, ip, 0, sizeof(struct ppp_idle)) >= 0;
911 * get_ppp_stats - return statistics for the link.
914 get_ppp_stats(u, stats)
915 int u;
916 struct pppd_stats *stats;
918 struct ppp_stats s;
920 if (strioctl(pppfd, PPPIO_GETSTAT, &s, 0, sizeof(s)) < 0) {
921 error("Couldn't get link statistics: %m");
922 return 0;
924 stats->bytes_in = s.p.ppp_ibytes;
925 stats->bytes_out = s.p.ppp_obytes;
926 stats->pkts_in = s.p.ppp_ipackets;
927 stats->pkts_out = s.p.ppp_opackets;
928 return 1;
933 * ccp_fatal_error - returns 1 if decompression was disabled as a
934 * result of an error detected after decompression of a packet,
935 * 0 otherwise. This is necessary because of patent nonsense.
938 ccp_fatal_error(unit)
939 int unit;
941 int cf[2];
943 cf[0] = cf[1] = 0;
944 if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) {
945 if (errno != ENXIO && errno != EINVAL)
946 error("Couldn't get compression flags: %m");
947 return 0;
949 return cf[0] & CCP_FATALERROR;
953 * sifvjcomp - config tcp header compression
956 sifvjcomp(u, vjcomp, xcidcomp, xmaxcid)
957 int u, vjcomp, xcidcomp, xmaxcid;
959 int cf[2];
960 char maxcid[2];
962 if (vjcomp) {
963 maxcid[0] = xcidcomp;
964 maxcid[1] = 15; /* XXX should be rmaxcid */
965 if (strioctl(pppfd, PPPIO_VJINIT, maxcid, sizeof(maxcid), 0) < 0) {
966 error("Couldn't initialize VJ compression: %m");
970 cf[0] = (vjcomp? COMP_VJC + DECOMP_VJC: 0) /* XXX this is wrong */
971 + (xcidcomp? COMP_VJCCID + DECOMP_VJCCID: 0);
972 cf[1] = COMP_VJC + DECOMP_VJC + COMP_VJCCID + DECOMP_VJCCID;
973 if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) {
974 if (vjcomp)
975 error("Couldn't enable VJ compression: %m");
978 return 1;
982 * sifup - Config the interface up and enable IP packets to pass.
985 sifup(u)
986 int u;
988 struct ifreq ifr;
990 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
991 if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
992 error("Couldn't mark interface up (get): %m");
993 return 0;
995 ifr.ifr_flags |= IFF_UP;
996 if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
997 error("Couldn't mark interface up (set): %m");
998 return 0;
1000 if_is_up = 1;
1001 return 1;
1005 * sifdown - Config the interface down and disable IP.
1008 sifdown(u)
1009 int u;
1011 struct ifreq ifr;
1013 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1014 if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
1015 error("Couldn't mark interface down (get): %m");
1016 return 0;
1018 if ((ifr.ifr_flags & IFF_UP) != 0) {
1019 ifr.ifr_flags &= ~IFF_UP;
1020 if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
1021 error("Couldn't mark interface down (set): %m");
1022 return 0;
1025 if_is_up = 0;
1026 return 1;
1030 * sifnpmode - Set the mode for handling packets for a given NP.
1033 sifnpmode(u, proto, mode)
1034 int u;
1035 int proto;
1036 enum NPmode mode;
1038 int npi[2];
1040 npi[0] = proto;
1041 npi[1] = (int) mode;
1042 if (strioctl(pppfd, PPPIO_NPMODE, npi, 2 * sizeof(int), 0) < 0) {
1043 error("ioctl(set NP %d mode to %d): %m", proto, mode);
1044 return 0;
1046 return 1;
1049 #define INET_ADDR(x) (((struct sockaddr_in *) &(x))->sin_addr.s_addr)
1052 * sifaddr - Config the interface IP addresses and netmask.
1055 sifaddr(u, o, h, m)
1056 int u;
1057 u_int32_t o, h, m;
1059 struct ifreq ifr;
1061 memset(&ifr, 0, sizeof(ifr));
1062 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1063 ifr.ifr_addr.sa_family = AF_INET;
1064 INET_ADDR(ifr.ifr_addr) = m;
1065 if (ioctl(sockfd, SIOCSIFNETMASK, &ifr) < 0) {
1066 error("Couldn't set IP netmask: %m");
1068 ifr.ifr_addr.sa_family = AF_INET;
1069 INET_ADDR(ifr.ifr_addr) = o;
1070 if (ioctl(sockfd, SIOCSIFADDR, &ifr) < 0) {
1071 error("Couldn't set local IP address: %m");
1073 ifr.ifr_dstaddr.sa_family = AF_INET;
1074 INET_ADDR(ifr.ifr_dstaddr) = h;
1075 if (ioctl(sockfd, SIOCSIFDSTADDR, &ifr) < 0) {
1076 error("Couldn't set remote IP address: %m");
1078 #if 0 /* now done in ppp_send_config */
1079 ifr.ifr_metric = link_mtu;
1080 if (ioctl(sockfd, SIOCSIFMTU, &ifr) < 0) {
1081 error("Couldn't set IP MTU: %m");
1083 #endif
1084 ifaddrs[0] = o;
1085 ifaddrs[1] = h;
1087 return 1;
1091 * cifaddr - Clear the interface IP addresses, and delete routes
1092 * through the interface if possible.
1095 cifaddr(u, o, h)
1096 int u;
1097 u_int32_t o, h;
1099 struct rtentry rt;
1101 bzero(&rt, sizeof(rt));
1102 rt.rt_dst.sa_family = AF_INET;
1103 INET_ADDR(rt.rt_dst) = h;
1104 rt.rt_gateway.sa_family = AF_INET;
1105 INET_ADDR(rt.rt_gateway) = o;
1106 rt.rt_flags = RTF_HOST;
1107 if (ioctl(sockfd, SIOCDELRT, &rt) < 0)
1108 error("Couldn't delete route through interface: %m");
1109 ifaddrs[0] = 0;
1110 return 1;
1114 * sifdefaultroute - assign a default route through the address given.
1117 sifdefaultroute(u, l, g)
1118 int u;
1119 u_int32_t l, g;
1121 struct rtentry rt;
1123 bzero(&rt, sizeof(rt));
1124 rt.rt_dst.sa_family = AF_INET;
1125 INET_ADDR(rt.rt_dst) = 0;
1126 rt.rt_gateway.sa_family = AF_INET;
1127 INET_ADDR(rt.rt_gateway) = g;
1128 rt.rt_flags = RTF_GATEWAY;
1130 if (ioctl(sockfd, SIOCADDRT, &rt) < 0) {
1131 error("Can't add default route: %m");
1132 return 0;
1135 default_route_gateway = g;
1136 return 1;
1140 * cifdefaultroute - delete a default route through the address given.
1143 cifdefaultroute(u, l, g)
1144 int u;
1145 u_int32_t l, g;
1147 struct rtentry rt;
1149 bzero(&rt, sizeof(rt));
1150 rt.rt_dst.sa_family = AF_INET;
1151 INET_ADDR(rt.rt_dst) = 0;
1152 rt.rt_gateway.sa_family = AF_INET;
1153 INET_ADDR(rt.rt_gateway) = g;
1154 rt.rt_flags = RTF_GATEWAY;
1156 if (ioctl(sockfd, SIOCDELRT, &rt) < 0) {
1157 error("Can't delete default route: %m");
1158 return 0;
1161 default_route_gateway = 0;
1162 return 1;
1166 * sifproxyarp - Make a proxy ARP entry for the peer.
1169 sifproxyarp(unit, hisaddr)
1170 int unit;
1171 u_int32_t hisaddr;
1173 struct arpreq arpreq;
1175 bzero(&arpreq, sizeof(arpreq));
1176 if (!get_ether_addr(hisaddr, &arpreq.arp_ha))
1177 return 0;
1179 arpreq.arp_pa.sa_family = AF_INET;
1180 INET_ADDR(arpreq.arp_pa) = hisaddr;
1181 arpreq.arp_flags = ATF_PERM | ATF_PUBL;
1182 if (ioctl(sockfd, SIOCSARP, (caddr_t) &arpreq) < 0) {
1183 error("Couldn't set proxy ARP entry: %m");
1184 return 0;
1187 proxy_arp_addr = hisaddr;
1188 return 1;
1192 * cifproxyarp - Delete the proxy ARP entry for the peer.
1195 cifproxyarp(unit, hisaddr)
1196 int unit;
1197 u_int32_t hisaddr;
1199 struct arpreq arpreq;
1201 bzero(&arpreq, sizeof(arpreq));
1202 arpreq.arp_pa.sa_family = AF_INET;
1203 INET_ADDR(arpreq.arp_pa) = hisaddr;
1204 if (ioctl(sockfd, SIOCDARP, (caddr_t)&arpreq) < 0) {
1205 error("Couldn't delete proxy ARP entry: %m");
1206 return 0;
1209 proxy_arp_addr = 0;
1210 return 1;
1214 * get_ether_addr - get the hardware address of an interface on the
1215 * the same subnet as ipaddr.
1217 #define MAX_IFS 32
1219 static int
1220 get_ether_addr(ipaddr, hwaddr)
1221 u_int32_t ipaddr;
1222 struct sockaddr *hwaddr;
1224 struct ifreq *ifr, *ifend;
1225 u_int32_t ina, mask;
1226 struct ifreq ifreq;
1227 struct ifconf ifc;
1228 struct ifreq ifs[MAX_IFS];
1229 int nit_fd;
1231 ifc.ifc_len = sizeof(ifs);
1232 ifc.ifc_req = ifs;
1233 if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
1234 error("ioctl(SIOCGIFCONF): %m");
1235 return 0;
1239 * Scan through looking for an interface with an Internet
1240 * address on the same subnet as `ipaddr'.
1242 ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
1243 for (ifr = ifc.ifc_req; ifr < ifend; ifr = (struct ifreq *)
1244 ((char *)&ifr->ifr_addr + sizeof(struct sockaddr))) {
1245 if (ifr->ifr_addr.sa_family == AF_INET) {
1248 * Check that the interface is up, and not point-to-point
1249 * or loopback.
1251 strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
1252 if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0)
1253 continue;
1254 if ((ifreq.ifr_flags &
1255 (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
1256 != (IFF_UP|IFF_BROADCAST))
1257 continue;
1260 * Get its netmask and check that it's on the right subnet.
1262 if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0)
1263 continue;
1264 ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
1265 mask = ((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr.s_addr;
1266 if ((ipaddr & mask) != (ina & mask))
1267 continue;
1269 break;
1273 if (ifr >= ifend)
1274 return 0;
1275 info("found interface %s for proxy arp", ifr->ifr_name);
1278 * Grab the physical address for this interface.
1280 if ((nit_fd = open("/dev/nit", O_RDONLY)) < 0) {
1281 error("Couldn't open /dev/nit: %m");
1282 return 0;
1284 strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
1285 if (ioctl(nit_fd, NIOCBIND, &ifreq) < 0
1286 || ioctl(nit_fd, SIOCGIFADDR, &ifreq) < 0) {
1287 error("Couldn't get hardware address for %s: %m",
1288 ifreq.ifr_name);
1289 close(nit_fd);
1290 return 0;
1293 hwaddr->sa_family = AF_UNSPEC;
1294 memcpy(hwaddr->sa_data, ifreq.ifr_addr.sa_data, 6);
1295 close(nit_fd);
1296 return 1;
1300 * have_route_to - determine if the system has any route to
1301 * a given IP address.
1302 * For demand mode to work properly, we have to ignore routes
1303 * through our own interface.
1305 int have_route_to(addr)
1306 u_int32_t addr;
1308 return -1;
1311 #define WTMPFILE "/usr/adm/wtmp"
1313 void
1314 logwtmp(line, name, host)
1315 const char *line, *name, *host;
1317 int fd;
1318 struct stat buf;
1319 struct utmp ut;
1321 if ((fd = open(WTMPFILE, O_WRONLY|O_APPEND, 0)) < 0)
1322 return;
1323 if (!fstat(fd, &buf)) {
1324 strncpy(ut.ut_line, line, sizeof(ut.ut_line));
1325 strncpy(ut.ut_name, name, sizeof(ut.ut_name));
1326 strncpy(ut.ut_host, host, sizeof(ut.ut_host));
1327 (void)time(&ut.ut_time);
1328 if (write(fd, (char *)&ut, sizeof(struct utmp)) != sizeof(struct utmp))
1329 (void)ftruncate(fd, buf.st_size);
1331 close(fd);
1335 * Return user specified netmask, modified by any mask we might determine
1336 * for address `addr' (in network byte order).
1337 * Here we scan through the system's list of interfaces, looking for
1338 * any non-point-to-point interfaces which might appear to be on the same
1339 * network as `addr'. If we find any, we OR in their netmask to the
1340 * user-specified netmask.
1342 u_int32_t
1343 GetMask(addr)
1344 u_int32_t addr;
1346 u_int32_t mask, nmask, ina;
1347 struct ifreq *ifr, *ifend, ifreq;
1348 struct ifconf ifc;
1350 addr = ntohl(addr);
1351 if (IN_CLASSA(addr)) /* determine network mask for address class */
1352 nmask = IN_CLASSA_NET;
1353 else if (IN_CLASSB(addr))
1354 nmask = IN_CLASSB_NET;
1355 else
1356 nmask = IN_CLASSC_NET;
1357 /* class D nets are disallowed by bad_ip_adrs */
1358 mask = netmask | htonl(nmask);
1361 * Scan through the system's network interfaces.
1363 ifc.ifc_len = MAX_IFS * sizeof(struct ifreq);
1364 ifc.ifc_req = alloca(ifc.ifc_len);
1365 if (ifc.ifc_req == 0)
1366 return mask;
1367 if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
1368 warn("Couldn't get system interface list: %m");
1369 return mask;
1371 ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
1372 for (ifr = ifc.ifc_req; ifr < ifend; ++ifr) {
1374 * Check the interface's internet address.
1376 if (ifr->ifr_addr.sa_family != AF_INET)
1377 continue;
1378 ina = INET_ADDR(ifr->ifr_addr);
1379 if ((ntohl(ina) & nmask) != (addr & nmask))
1380 continue;
1382 * Check that the interface is up, and not point-to-point or loopback.
1384 strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
1385 if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0)
1386 continue;
1387 if ((ifreq.ifr_flags & (IFF_UP|IFF_POINTOPOINT|IFF_LOOPBACK))
1388 != IFF_UP)
1389 continue;
1391 * Get its netmask and OR it into our mask.
1393 if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0)
1394 continue;
1395 mask |= INET_ADDR(ifreq.ifr_addr);
1398 return mask;
1401 static int
1402 strioctl(fd, cmd, ptr, ilen, olen)
1403 int fd, cmd, ilen, olen;
1404 void *ptr;
1406 struct strioctl str;
1408 str.ic_cmd = cmd;
1409 str.ic_timout = 0;
1410 str.ic_len = ilen;
1411 str.ic_dp = ptr;
1412 if (ioctl(fd, I_STR, &str) == -1)
1413 return -1;
1414 if (str.ic_len != olen)
1415 dbglog("strioctl: expected %d bytes, got %d for cmd %x\n",
1416 olen, str.ic_len, cmd);
1417 return 0;
1421 * Use the hostid as part of the random number seed.
1424 get_host_seed()
1426 return gethostid();
1429 #if 0
1431 * Code for locking/unlocking the serial device.
1432 * This code is derived from chat.c.
1435 #if !defined(HDB) && !defined(SUNOS3)
1436 #define HDB 1 /* ascii lock files are the default */
1437 #endif
1439 #ifndef LOCK_DIR
1440 # if HDB
1441 # define PIDSTRING
1442 # define LOCK_PREFIX "/usr/spool/locks/LCK.."
1443 # else /* HDB */
1444 # define LOCK_PREFIX "/usr/spool/uucp/LCK.."
1445 # endif /* HDB */
1446 #endif /* LOCK_DIR */
1448 static char *lock_file; /* name of lock file created */
1451 * lock - create a lock file for the named device.
1454 lock(dev)
1455 char *dev;
1457 char hdb_lock_buffer[12];
1458 int fd, pid, n;
1459 char *p;
1460 size_t l;
1462 if ((p = strrchr(dev, '/')) != NULL)
1463 dev = p + 1;
1464 l = strlen(LOCK_PREFIX) + strlen(dev) + 1;
1465 lock_file = malloc(l);
1466 if (lock_file == NULL)
1467 novm("lock file name");
1468 slprintf(lock_file, l, "%s%s", LOCK_PREFIX, dev);
1470 while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) {
1471 if (errno == EEXIST
1472 && (fd = open(lock_file, O_RDONLY, 0)) >= 0) {
1473 /* Read the lock file to find out who has the device locked */
1474 #ifdef PIDSTRING
1475 n = read(fd, hdb_lock_buffer, 11);
1476 if (n > 0) {
1477 hdb_lock_buffer[n] = 0;
1478 pid = atoi(hdb_lock_buffer);
1480 #else
1481 n = read(fd, &pid, sizeof(pid));
1482 #endif
1483 if (n <= 0) {
1484 error("Can't read pid from lock file %s", lock_file);
1485 close(fd);
1486 } else {
1487 if (kill(pid, 0) == -1 && errno == ESRCH) {
1488 /* pid no longer exists - remove the lock file */
1489 if (unlink(lock_file) == 0) {
1490 close(fd);
1491 notice("Removed stale lock on %s (pid %d)",
1492 dev, pid);
1493 continue;
1494 } else
1495 warn("Couldn't remove stale lock on %s",
1496 dev);
1497 } else
1498 notice("Device %s is locked by pid %d",
1499 dev, pid);
1501 close(fd);
1502 } else
1503 error("Can't create lock file %s: %m", lock_file);
1504 free(lock_file);
1505 lock_file = NULL;
1506 return -1;
1509 #ifdef PIDSTRING
1510 slprintf(hdb_lock_buffer, sizeof(hdb_lock_buffer), "%10d\n", getpid());
1511 write(fd, hdb_lock_buffer, 11);
1512 #else
1513 pid = getpid();
1514 write(fd, &pid, sizeof pid);
1515 #endif
1517 close(fd);
1518 return 0;
1522 * unlock - remove our lockfile
1524 void
1525 unlock()
1527 if (lock_file) {
1528 unlink(lock_file);
1529 free(lock_file);
1530 lock_file = NULL;
1533 #endif /* lock stuff removed */
1536 * get_pty - get a pty master/slave pair and chown the slave side
1537 * to the uid given. Assumes slave_name points to >= 12 bytes of space.
1540 get_pty(master_fdp, slave_fdp, slave_name, uid)
1541 int *master_fdp;
1542 int *slave_fdp;
1543 char *slave_name;
1544 int uid;
1546 int i, mfd, sfd;
1547 char pty_name[12];
1548 struct termios tios;
1550 sfd = -1;
1551 for (i = 0; i < 64; ++i) {
1552 slprintf(pty_name, sizeof(pty_name), "/dev/pty%c%x",
1553 'p' + i / 16, i % 16);
1554 mfd = open(pty_name, O_RDWR, 0);
1555 if (mfd >= 0) {
1556 pty_name[5] = 't';
1557 sfd = open(pty_name, O_RDWR | O_NOCTTY, 0);
1558 if (sfd >= 0)
1559 break;
1560 close(mfd);
1563 if (sfd < 0)
1564 return 0;
1566 strlcpy(slave_name, pty_name, 12);
1567 *master_fdp = mfd;
1568 *slave_fdp = sfd;
1569 fchown(sfd, uid, -1);
1570 fchmod(sfd, S_IRUSR | S_IWUSR);
1571 if (tcgetattr(sfd, &tios) == 0) {
1572 tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB);
1573 tios.c_cflag |= CS8 | CREAD;
1574 tios.c_iflag = IGNPAR | CLOCAL;
1575 tios.c_oflag = 0;
1576 tios.c_lflag = 0;
1577 if (tcsetattr(sfd, TCSAFLUSH, &tios) < 0)
1578 warn("couldn't set attributes on pty: %m");
1579 } else
1580 warn("couldn't get attributes on pty: %m");
1582 return 1;
1586 * SunOS doesn't have strtoul :-(
1588 unsigned long
1589 strtoul(str, ptr, base)
1590 char *str, **ptr;
1591 int base;
1593 return (unsigned long) strtol(str, ptr, base);
1597 * Or strerror :-(
1599 extern char *sys_errlist[];
1600 extern int sys_nerr;
1602 char *
1603 strerror(n)
1604 int n;
1606 static char unknown[32];
1608 if (n > 0 && n < sys_nerr)
1609 return sys_errlist[n];
1610 slprintf(unknown, sizeof(unknown), "Error %d", n);
1611 return unknown;