old DLPI doesn't have dl_sap_length
[ppp.git] / pppd / sys-aix4.c
1 /*
2  * sys-aix4.c - System-dependent procedures for setting up
3  * PPP interfaces on AIX systems which use the STREAMS ppp interface.
4  *
5  * Copyright (c) 1989 Carnegie Mellon University.
6  * All rights reserved.
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 Carnegie Mellon University.  The name of the
14  * University 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
21 #ifndef lint
22 static char rcsid[] = "$Id: sys-aix4.c,v 1.7 1995/10/27 03:45:34 paulus Exp $";
23 #endif
24
25 /*
26  * TODO:
27  */
28
29 #include <stdio.h>
30 /*
31 #include <stdlib.h>
32 */
33 #include <errno.h>
34 #include <syslog.h>
35 #include <termios.h>
36 #include <sys/termiox.h>
37 #include <fcntl.h>
38 #include <string.h>
39 #include <time.h>
40 #include <utmp.h>
41 #include <poll.h>
42 #include <sys/types.h>
43 #include <sys/socket.h>
44 #include <sys/time.h>
45 #include <sys/stream.h>
46 #include <sys/stropts.h>
47
48 #include <net/if.h>
49 #include <net/ppp_defs.h>
50 #include <net/ppp_str.h>
51 #include <net/route.h>
52 #include <net/if_arp.h>
53 #include <netinet/in.h>
54
55 #include "pppd.h"
56
57 #ifndef ifr_mtu
58 #define ifr_mtu         ifr_metric
59 #endif
60
61 #define MAXMODULES      10      /* max number of module names to save */
62 static struct   modlist {
63     char        modname[FMNAMESZ+1];
64 } str_modules[MAXMODULES];
65 static int      str_module_count = 0;
66 static int      pushed_ppp;
67 static int      closed_stdio;
68
69 static int      restore_term;   /* 1 => we've munged the terminal */
70 static struct termios inittermios; /* Initial TTY termios */
71 static int      initfdflags = -1; /* Initial file descriptor flags for fd */
72
73 static int sockfd;              /* socket for doing interface ioctls */
74
75 static int      if_is_up;       /* Interface has been marked up */
76 static u_int32_t default_route_gateway; /* Gateway for default route added */
77 static u_int32_t proxy_arp_addr;        /* Addr for proxy arp entry added */
78
79 /* Prototypes for procedures local to this file. */
80 static int translate_speed __P((int));
81 static int baud_rate_of __P((int));
82 static int get_ether_addr __P((u_int32_t, struct sockaddr *));
83
84
85 /*
86  * sys_init - System-dependent initialization.
87  */
88 void
89 sys_init()
90 {
91     openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP);
92     setlogmask(LOG_UPTO(LOG_INFO));
93     if (debug)
94         setlogmask(LOG_UPTO(LOG_DEBUG));
95
96     /* Get an internet socket for doing socket ioctl's on. */
97     if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
98         syslog(LOG_ERR, "Couldn't create IP socket: %m");
99         die(1);
100     }
101 }
102
103 /*
104  * sys_cleanup - restore any system state we modified before exiting:
105  * mark the interface down, delete default route and/or proxy arp entry.
106  * This should call die() because it's called from die().
107  */
108 void
109 sys_cleanup()
110 {
111     struct ifreq ifr;
112
113     if (if_is_up) {
114         strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
115         if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) >= 0
116             && ((ifr.ifr_flags & IFF_UP) != 0)) {
117             ifr.ifr_flags &= ~IFF_UP;
118             ioctl(sockfd, SIOCSIFFLAGS, &ifr);
119         }
120     }
121
122     if (default_route_gateway)
123         cifdefaultroute(0, default_route_gateway);
124     if (proxy_arp_addr)
125         cifproxyarp(0, proxy_arp_addr);
126 }
127
128 /*
129  * note_debug_level - note a change in the debug level.
130  */
131 void
132 note_debug_level()
133 {
134     if (debug) {
135         syslog(LOG_INFO, "Debug turned ON, Level %d", debug);
136         setlogmask(LOG_UPTO(LOG_DEBUG));
137     } else {
138         setlogmask(LOG_UPTO(LOG_WARNING));
139     }
140 }
141
142 /*
143  * daemon - Detach us from the terminal session.
144  */
145 int
146 daemon(nochdir, noclose)
147     int nochdir, noclose;
148 {
149     int pid;
150
151     if ((pid = fork()) < 0)
152         return -1;
153     if (pid != 0)
154         exit(0);                /* parent dies */
155     setsid();
156     if (!nochdir)
157         chdir("/");
158     if (!noclose) {
159         fclose(stdin);          /* don't need stdin, stdout, stderr */
160         fclose(stdout);
161         fclose(stderr);
162     }
163     return 0;
164 }
165
166
167 /*
168  * ppp_available - check if this kernel supports PPP.
169  */
170 int
171 ppp_available()
172 {
173     int fd, ret;
174
175     fd = open("/dev/tty", O_RDONLY, 0);
176     if (fd < 0)
177         return 1;               /* can't find out - assume we have ppp */
178     ret = ioctl(fd, I_FIND, "pppasync") >= 0;
179     close(fd);
180     return ret;
181 }
182
183
184 /*
185  * establish_ppp - Turn the serial port into a ppp interface.
186  */
187 void
188 establish_ppp()
189 {
190     /* go through and save the name of all the modules, then pop em */
191     for (;;) { 
192         if (ioctl(fd, I_LOOK, str_modules[str_module_count].modname) < 0 ||
193             ioctl(fd, I_POP, 0) < 0)
194             break;
195         MAINDEBUG((LOG_DEBUG, "popped stream module : %s",
196                    str_modules[str_module_count].modname));
197         str_module_count++;
198     }
199
200     /* now push the async/fcs module */
201     if (ioctl(fd, I_PUSH, "pppasync") < 0) {
202         syslog(LOG_ERR, "ioctl(I_PUSH, ppp_async): %m");
203         die(1);
204     }
205     /* push the compress module */
206     if (ioctl(fd, I_PUSH, "pppcomp") < 0) {
207         syslog(LOG_WARNING, "ioctl(I_PUSH, ppp_comp): %m");
208     }
209     /* finally, push the ppp_if module that actually handles the */
210     /* network interface */ 
211     if (ioctl(fd, I_PUSH, "pppif") < 0) {
212         syslog(LOG_ERR, "ioctl(I_PUSH, ppp_if): %m");
213         die(1);
214     }
215     pushed_ppp = 1;
216     /* read mode, message non-discard mode
217     if (ioctl(fd, I_SRDOPT, RMSGN) < 0) {
218         syslog(LOG_ERR, "ioctl(I_SRDOPT, RMSGN): %m");
219         die(1);
220     }
221 */
222     /*
223      * Find out which interface we were given.
224      * (ppp_if handles this ioctl)
225      */
226     if (ioctl(fd, SIOCGETU, &ifunit) < 0) {
227         syslog(LOG_ERR, "ioctl(SIOCGETU): %m");
228         die(1);
229     }
230
231     /* Set debug flags in driver */
232     if (ioctl(fd, SIOCSIFDEBUG, kdebugflag) < 0) {
233         syslog(LOG_ERR, "ioctl(SIOCSIFDEBUG): %m");
234     }
235
236     /* close stdin, stdout, stderr if they might refer to the device */
237     if (default_device && !closed_stdio) {
238         int i;
239
240         for (i = 0; i <= 2; ++i)
241             if (i != fd && i != sockfd)
242                 close(i);
243         closed_stdio = 1;
244     }
245
246     /*
247      * Set device for non-blocking reads.
248      */
249     if ((initfdflags = fcntl(fd, F_GETFL)) == -1
250         || fcntl(fd, F_SETFL, initfdflags | O_NONBLOCK) == -1) {
251         syslog(LOG_WARNING, "Couldn't set device to non-blocking mode: %m");
252     }
253 }
254
255 /*
256  * disestablish_ppp - Restore the serial port to normal operation.
257  * It attempts to reconstruct the stream with the previously popped
258  * modules.  This shouldn't call die() because it's called from die().
259  */
260 void
261 disestablish_ppp()
262 {
263     int flags;
264     char *s;
265
266     /* Reset non-blocking mode on the file descriptor. */
267     if (initfdflags != -1 && fcntl(fd, F_SETFL, initfdflags) < 0)
268         syslog(LOG_WARNING, "Couldn't restore device fd flags: %m");
269     initfdflags = -1;
270
271     if (hungup) {
272         /* we can't push or pop modules after the stream has hung up */
273         str_module_count = 0;
274         restore_term = 0;       /* nor can we fix up terminal settings */
275         return;
276     }
277
278     if (pushed_ppp) {
279         /*
280          * Check whether the link seems not to be 8-bit clean.
281          */
282         if (ioctl(fd, SIOCGIFDEBUG, (caddr_t) &flags) == 0) {
283             s = NULL;
284             switch (~flags & PAI_FLAGS_HIBITS) {
285             case PAI_FLAGS_B7_0:
286                 s = "bit 7 set to 1";
287                 break;
288             case PAI_FLAGS_B7_1:
289                 s = "bit 7 set to 0";
290                 break;
291             case PAI_FLAGS_PAR_EVEN:
292                 s = "odd parity";
293                 break;
294             case PAI_FLAGS_PAR_ODD:
295                 s = "even parity";
296                 break;
297             }
298             if (s != NULL) {
299                 syslog(LOG_WARNING, "Serial link is not 8-bit clean:");
300                 syslog(LOG_WARNING, "All received characters had %s", s);
301             }
302         }
303     }
304
305     while (ioctl(fd, I_POP, 0) == 0)    /* pop any we pushed */
306         ;
307     pushed_ppp = 0;
308   
309     for (; str_module_count > 0; str_module_count--) {
310         if (ioctl(fd, I_PUSH, str_modules[str_module_count-1].modname)) {
311             if (errno != ENXIO)
312                 syslog(LOG_WARNING, "str_restore: couldn't push module %s: %m",
313                        str_modules[str_module_count-1].modname);
314         } else {
315             MAINDEBUG((LOG_INFO, "str_restore: pushed module %s",
316                        str_modules[str_module_count-1].modname));
317         }
318     }
319 }
320
321
322 /*
323  * List of valid speeds.
324  */
325 struct speed {
326     int speed_int, speed_val;
327 } speeds[] = {
328 #ifdef B50
329     { 50, B50 },
330 #endif
331 #ifdef B75
332     { 75, B75 },
333 #endif
334 #ifdef B110
335     { 110, B110 },
336 #endif
337 #ifdef B134
338     { 134, B134 },
339 #endif
340 #ifdef B150
341     { 150, B150 },
342 #endif
343 #ifdef B200
344     { 200, B200 },
345 #endif
346 #ifdef B300
347     { 300, B300 },
348 #endif
349 #ifdef B600
350     { 600, B600 },
351 #endif
352 #ifdef B1200
353     { 1200, B1200 },
354 #endif
355 #ifdef B1800
356     { 1800, B1800 },
357 #endif
358 #ifdef B2000
359     { 2000, B2000 },
360 #endif
361 #ifdef B2400
362     { 2400, B2400 },
363 #endif
364 #ifdef B3600
365     { 3600, B3600 },
366 #endif
367 #ifdef B4800
368     { 4800, B4800 },
369 #endif
370 #ifdef B7200
371     { 7200, B7200 },
372 #endif
373 #ifdef B9600
374     { 9600, B9600 },
375 #endif
376 #ifdef B19200
377     { 19200, B19200 },
378 #endif
379 #ifdef B38400
380     { 38400, B38400 },
381 #endif
382 #ifdef EXTA
383     { 19200, EXTA },
384 #endif
385 #ifdef EXTB
386     { 38400, EXTB },
387 #endif
388 #ifdef B57600
389     { 57600, B57600 },
390 #endif
391 #ifdef B115200
392     { 115200, B115200 },
393 #endif
394     { 0, 0 }
395 };
396
397 /*
398  * Translate from bits/second to a speed_t.
399  */
400 static int
401 translate_speed(bps)
402     int bps;
403 {
404     struct speed *speedp;
405
406     if (bps == 0)
407         return 0;
408     for (speedp = speeds; speedp->speed_int; speedp++)
409         if (bps == speedp->speed_int)
410             return speedp->speed_val;
411     syslog(LOG_WARNING, "speed %d not supported", bps);
412     return 0;
413 }
414
415 /*
416  * Translate from a speed_t to bits/second.
417  */
418 static int
419 baud_rate_of(speed)
420     int speed;
421 {
422     struct speed *speedp;
423
424     if (speed == 0)
425         return 0;
426     for (speedp = speeds; speedp->speed_int; speedp++)
427         if (speed == speedp->speed_val)
428             return speedp->speed_int;
429     return 0;
430 }
431
432 /*
433  * set_up_tty: Set up the serial port on `fd' for 8 bits, no parity,
434  * at the requested speed, etc.  If `local' is true, set CLOCAL
435  * regardless of whether the modem option was specified.
436  */
437 void
438 set_up_tty(fd, local)
439     int fd, local;
440 {
441     int speed;
442     struct termios tios;
443     struct termiox tiox;
444
445     if (tcgetattr(fd, &tios) < 0) {
446         syslog(LOG_ERR, "tcgetattr: %m");
447         die(1);
448     }
449
450     if (!restore_term)
451         inittermios = tios;
452
453     tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
454     if (crtscts > 0) {
455         bzero(&tiox, sizeof(tiox));
456         ioctl(fd, TCGETX, &tiox);
457         tiox.x_hflag = RTSXOFF;
458         ioctl(fd, TCSETX, &tiox);
459         tios.c_cflag &= ~(IXON | IXOFF);
460     } else if (crtscts < 0) {
461         bzero(&tiox, sizeof(tiox));
462         ioctl(fd, TCGETX, &tiox);
463         tiox.x_hflag &= ~RTSXOFF;
464         ioctl(fd, TCSETX, &tiox);
465     }
466
467
468     tios.c_cflag |= CS8 | CREAD | HUPCL;
469     if (local || !modem)
470         tios.c_cflag |= CLOCAL;
471     tios.c_iflag = IGNBRK | IGNPAR;
472     tios.c_oflag = 0;
473     tios.c_lflag = 0;
474     tios.c_cc[VMIN] = 1;
475     tios.c_cc[VTIME] = 0;
476
477     if (crtscts == -2) {
478         tios.c_iflag |= IXON | IXOFF;
479         tios.c_cc[VSTOP] = 0x13;        /* DC3 = XOFF = ^S */
480         tios.c_cc[VSTART] = 0x11;       /* DC1 = XON  = ^Q */
481     }
482
483     speed = translate_speed(inspeed);
484     if (speed) {
485         cfsetospeed(&tios, speed);
486         cfsetispeed(&tios, speed);
487     } else {
488         speed = cfgetospeed(&tios);
489         /*
490          * We can't proceed if the serial port speed is B0,
491          * since that implies that the serial port is disabled.
492          */
493         if (speed == B0) {
494             syslog(LOG_ERR, "Baud rate for %s is 0; need explicit baud rate",
495                    devnam);
496             die(1);
497         }
498     }
499
500     if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) {
501         syslog(LOG_ERR, "tcsetattr: %m");
502         die(1);
503     }
504
505     baud_rate = inspeed = baud_rate_of(speed);
506     restore_term = 1;
507 }
508
509 /*
510  * restore_tty - restore the terminal to the saved settings.
511  */
512 void
513 restore_tty()
514 {
515     if (restore_term) {
516         if (!default_device) {
517             /*
518              * Turn off echoing, because otherwise we can get into
519              * a loop with the tty and the modem echoing to each other.
520              * We presume we are the sole user of this tty device, so
521              * when we close it, it will revert to its defaults anyway.
522              */
523             inittermios.c_lflag &= ~(ECHO | ECHONL);
524         }
525         if (tcsetattr(fd, TCSAFLUSH, &inittermios) < 0)
526             if (errno != ENXIO)
527                 syslog(LOG_WARNING, "tcsetattr: %m");
528         restore_term = 0;
529     }
530 }
531
532 /*
533  * setdtr - control the DTR line on the serial port.
534  * This is called from die(), so it shouldn't call die().
535  */
536 void
537 setdtr(fd, on)
538 int fd, on;
539 {
540     int modembits = TIOCM_DTR;
541
542     ioctl(fd, (on? TIOCMBIS: TIOCMBIC), &modembits);
543 }
544
545
546 /*
547  * output - Output PPP packet.
548  */
549 void
550 output(unit, p, len)
551     int unit;
552     u_char *p;
553     int len;
554 {
555     struct strbuf str;
556     int retries;
557     struct pollfd pfd;
558
559     if (debug)
560         log_packet(p, len, "sent ");
561
562     str.len = len;
563     str.buf = (caddr_t) p;
564     retries = 4;
565     while (putmsg(fd, NULL, &str, 0) < 0) {
566         if (--retries < 0 || (errno != EWOULDBLOCK && errno != EAGAIN)) {
567             if (errno != ENXIO)
568                 syslog(LOG_ERR, "Couldn't send packet: %m");
569             break;
570         }
571         pfd.fd = fd;
572         pfd.events = POLLOUT;
573         poll(&pfd, 1, 250);     /* wait for up to 0.25 seconds */
574     }
575 }
576
577 /*
578  * wait_input - wait for input, for a length of time specified in *timo.
579  */
580 void
581 wait_input(timo)
582     struct timeval *timo;
583 {
584     int t;
585     struct pollfd pfd;
586
587     t = timo == NULL? -1: timo->tv_sec * 1000 + timo->tv_usec / 1000;
588     pfd.fd = fd;
589     pfd.events = POLLIN | POLLPRI | POLLHUP;
590     if (poll(&pfd, 1, t) < 0 && errno != EINTR) {
591         syslog(LOG_ERR, "poll: %m");
592         die(1);
593     }
594 }
595
596 /*
597  * read_packet - get a PPP packet from the serial device.
598  */
599 int
600 read_packet(buf)
601     u_char *buf;
602 {
603     struct strbuf str, ctl;
604     int len, i;
605     unsigned char ctlbuf[16];
606
607     str.maxlen = PPP_MTU + PPP_HDRLEN;
608     str.buf = (caddr_t) buf;
609     ctl.maxlen = sizeof(ctlbuf);
610     ctl.buf = (caddr_t) ctlbuf;
611     i = 0;
612     len = getmsg(fd, &ctl, &str, &i);
613     if (len < 0) {
614         if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
615             return -1;
616         }
617         syslog(LOG_ERR, "getmsg(fd) %m");
618         die(1);
619     }
620     if (len) 
621         MAINDEBUG((LOG_DEBUG, "getmsg returned 0x%x",len));
622     if (ctl.len > 0)
623         syslog(LOG_NOTICE, "got ctrl msg len %d %x %x\n", ctl.len,
624                ctlbuf[0], ctlbuf[1]);
625
626     if (str.len < 0) {
627         MAINDEBUG((LOG_DEBUG, "getmsg short return length %d", str.len));
628         return -1;
629     }
630
631     return str.len;
632 }
633
634
635 /*
636  * ppp_send_config - configure the transmit characteristics of
637  * the ppp interface.
638  */
639 void
640 ppp_send_config(unit, mtu, asyncmap, pcomp, accomp)
641     int unit, mtu;
642     u_int32_t asyncmap;
643     int pcomp, accomp;
644 {
645     int c;
646     struct ifreq ifr;
647
648     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
649     ifr.ifr_mtu = mtu;
650     if (ioctl(sockfd, SIOCSIFMTU, (caddr_t) &ifr) < 0) {
651         syslog(LOG_ERR, "ioctl(SIOCSIFMTU): %m");
652         quit();
653     }
654
655     if(ioctl(fd, SIOCSIFASYNCMAP, asyncmap) < 0) {
656         syslog(LOG_ERR, "ioctl(SIOCSIFASYNCMAP): %m");
657         quit();
658     }
659
660     c = (pcomp? 1: 0);
661     if(ioctl(fd, SIOCSIFCOMPPROT, c) < 0) {
662         syslog(LOG_ERR, "ioctl(SIOCSIFCOMPPROT): %m");
663         quit();
664     }
665
666     c = (accomp? 1: 0);
667     if(ioctl(fd, SIOCSIFCOMPAC, c) < 0) {
668         syslog(LOG_ERR, "ioctl(SIOCSIFCOMPAC): %m");
669         quit();
670     }
671 }
672
673
674 /*
675  * ppp_set_xaccm - set the extended transmit ACCM for the interface.
676  */
677 void
678 ppp_set_xaccm(unit, accm)
679     int unit;
680     ext_accm accm;
681 {
682     if (ioctl(fd, SIOCSIFXASYNCMAP, accm) < 0 && errno != ENOTTY)
683         syslog(LOG_WARNING, "ioctl(set extended ACCM): %m");
684 }
685
686
687 /*
688  * ppp_recv_config - configure the receive-side characteristics of
689  * the ppp interface.
690  */
691 void
692 ppp_recv_config(unit, mru, asyncmap, pcomp, accomp)
693     int unit, mru;
694     u_int32_t asyncmap;
695     int pcomp, accomp;
696 {
697     char c;
698
699     if (ioctl(fd, SIOCSIFMRU, mru) < 0) {
700         syslog(LOG_ERR, "ioctl(SIOCSIFMRU): %m");
701     }
702
703     if (ioctl(fd, SIOCSIFRASYNCMAP, (caddr_t) asyncmap) < 0) {
704         syslog(LOG_ERR, "ioctl(SIOCSIFRASYNCMAP): %m");
705     }
706
707     c = 2 + (pcomp? 1: 0);
708     if(ioctl(fd, SIOCSIFCOMPPROT, c) < 0) {
709         syslog(LOG_ERR, "ioctl(SIOCSIFCOMPPROT): %m");
710     }
711
712     c = 2 + (accomp? 1: 0);
713     if (ioctl(fd, SIOCSIFCOMPAC, c) < 0) {
714         syslog(LOG_ERR, "ioctl(SIOCSIFCOMPAC): %m");
715     }
716 }
717
718 /*
719  * ccp_test - ask kernel whether a given compression method
720  * is acceptable for use.
721  */
722 int
723 ccp_test(unit, opt_ptr, opt_len, for_transmit)
724     int unit, opt_len, for_transmit;
725     u_char *opt_ptr;
726 {
727     struct ppp_option_data data;
728
729     if ((unsigned) opt_len > MAX_PPP_OPTION)
730         opt_len = MAX_PPP_OPTION;
731     data.length = opt_len;
732     data.transmit = for_transmit;
733     BCOPY(opt_ptr, data.opt_data, opt_len);
734     if (ioctl(fd, SIOCSCOMPRESS, &data) >= 0)
735         return 1;
736     return (errno == ENOSR)? 0: -1;
737 }
738
739 /*
740  * ccp_flags_set - inform kernel about the current state of CCP.
741  */
742 void
743 ccp_flags_set(unit, isopen, isup)
744     int unit, isopen, isup;
745 {
746     int x;
747
748     x = (isopen? 1: 0) + (isup? 2: 0);
749     if (ioctl(fd, SIOCSIFCOMP, x) < 0 && errno != ENOTTY)
750         syslog(LOG_ERR, "ioctl (SIOCSIFCOMP): %m");
751 }
752
753 /*
754  * ccp_fatal_error - returns 1 if decompression was disabled as a
755  * result of an error detected after decompression of a packet,
756  * 0 otherwise.  This is necessary because of patent nonsense.
757  */
758 int
759 ccp_fatal_error(unit)
760     int unit;
761 {
762     int x;
763
764     if (ioctl(fd, SIOCGIFCOMP, &x) < 0) {
765         syslog(LOG_ERR, "ioctl(SIOCGIFCOMP): %m");
766         return 0;
767     }
768     return x & CCP_FATALERROR;
769 }
770
771 /*
772  * sifvjcomp - config tcp header compression
773  */
774 int
775 sifvjcomp(u, vjcomp, cidcomp, maxcid)
776     int u, vjcomp, cidcomp, maxcid;
777 {
778     int x;
779
780     x = (vjcomp? 1: 0) + (cidcomp? 0: 2) + (maxcid << 4);
781     if (ioctl(fd, SIOCSIFVJCOMP, x) < 0) {
782         syslog(LOG_ERR, "ioctl(SIOCSIFVJCOMP): %m");
783         return 0;
784     }
785     return 1;
786 }
787
788 /*
789  * sifup - Config the interface up and enable IP packets to pass.
790  */
791 int
792 sifup(u)
793     int u;
794 {
795     struct ifreq ifr;
796     struct npioctl npi;
797
798     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
799     if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
800         syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
801         return 0;
802     }
803     ifr.ifr_flags |= IFF_UP;
804     if (ioctl(sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
805         syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
806         return 0;
807     }
808     if_is_up = 1;
809     npi.protocol = PPP_IP;
810     npi.mode = NPMODE_PASS;
811     if (ioctl(fd, SIOCSETNPMODE, &npi) < 0) {
812         if (errno != ENOTTY) {
813             syslog(LOG_ERR, "ioctl(SIOCSETNPMODE): %m");
814             return 0;
815         }
816     }
817
818     return 1;
819 }
820
821 /*
822  * sifdown - Config the interface down.
823  */
824 int
825 sifdown(u)
826     int u;
827 {
828     struct ifreq ifr;
829     int rv;
830     struct npioctl npi;
831
832     rv = 1;
833     npi.protocol = PPP_IP;
834     npi.mode = NPMODE_ERROR;
835     if (ioctl(fd, SIOCSETNPMODE, &npi) < 0) {
836         if (errno != ENOTTY) {
837             syslog(LOG_ERR, "ioctl(SIOCSETNPMODE): %m");
838             rv = 0;
839         }
840     }
841
842     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
843     if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
844         syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
845         rv = 0;
846     } else {
847         ifr.ifr_flags &= ~IFF_UP;
848         if (ioctl(sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
849             syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
850             rv = 0;
851         } else
852             if_is_up = 0;
853     }
854     return rv;
855 }
856
857 /*
858  * SET_SA_FAMILY - initialize a struct sockaddr, setting the sa_family field.
859  */
860 #define SET_SA_FAMILY(addr, family)             \
861     BZERO((char *) &(addr), sizeof(addr));      \
862     addr.sa_family = (family);
863
864 /*
865  * sifaddr - Config the interface IP addresses and netmask.
866  */
867 int
868 sifaddr(u, o, h, m)
869     int u;
870     u_int32_t o, h, m;
871 {
872     int ret;
873     struct ifreq ifr;
874
875     ret = 1;
876     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
877     SET_SA_FAMILY(ifr.ifr_addr, AF_INET);
878     if (m != 0) {
879         syslog(LOG_INFO, "Setting interface mask to %s\n", ip_ntoa(m));
880         ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = m;
881         if (ioctl(sockfd, SIOCSIFNETMASK, (caddr_t) &ifr) < 0) {
882             syslog(LOG_ERR, "ioctl(SIOCSIFNETMASK): %m");
883             ret = 0;
884         }
885     }
886
887     ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = o;
888     if (ioctl(sockfd, SIOCSIFADDR, (caddr_t) &ifr) < 0) {
889         syslog(LOG_ERR, "ioctl(SIOCSIFADDR): %m");
890         ret = 0;
891     }
892
893     SET_SA_FAMILY(ifr.ifr_dstaddr, AF_INET);
894     ((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr = h;
895     if (ioctl(sockfd, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) {
896         syslog(LOG_ERR, "ioctl(SIOCSIFDSTADDR): %m");
897         ret = 0;
898     }
899     ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = o;
900     if (ioctl(sockfd, SIOCSIFADDR, (caddr_t) &ifr) < 0) {
901         syslog(LOG_ERR, "ioctl(SIOCSIFADDR): %m");
902         ret = 0;
903     }
904     return ret;
905 }
906
907 /*
908  * cifaddr - Clear the interface IP addresses, and delete routes
909  * through the interface if possible.
910  */
911 int
912 cifaddr(u, o, h)
913     int u;
914     u_int32_t o, h;
915 {
916     struct ortentry rt;
917
918     SET_SA_FAMILY(rt.rt_dst, AF_INET);
919     ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = h;
920     SET_SA_FAMILY(rt.rt_gateway, AF_INET);
921     ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = o;
922     rt.rt_flags = RTF_HOST;
923     if (ioctl(sockfd, SIOCDELRT, (caddr_t) &rt) < 0) {
924         syslog(LOG_ERR, "ioctl(SIOCDELRT): %m");
925         return 0;
926     }
927     return 1;
928 }
929
930 /*
931  * sifdefaultroute - assign a default route through the address given.
932  */
933 int
934 sifdefaultroute(u, g)
935     int u;
936     u_int32_t g;
937 {
938     struct ortentry rt;
939
940     SET_SA_FAMILY(rt.rt_dst, AF_INET);
941     SET_SA_FAMILY(rt.rt_gateway, AF_INET);
942     ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g;
943     rt.rt_flags = RTF_GATEWAY;
944     if (ioctl(sockfd, SIOCADDRT, &rt) < 0) {
945         syslog(LOG_ERR, "default route ioctl(SIOCADDRT): %m");
946         return 0;
947     }
948     default_route_gateway = g;
949     return 1;
950 }
951
952 /*
953  * cifdefaultroute - delete a default route through the address given.
954  */
955 int
956 cifdefaultroute(u, g)
957     int u;
958     u_int32_t g;
959 {
960     struct ortentry rt;
961
962     SET_SA_FAMILY(rt.rt_dst, AF_INET);
963     SET_SA_FAMILY(rt.rt_gateway, AF_INET);
964     ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g;
965     rt.rt_flags = RTF_GATEWAY;
966     if (ioctl(sockfd, SIOCDELRT, &rt) < 0) {
967         syslog(LOG_ERR, "default route ioctl(SIOCDELRT): %m");
968         return 0;
969     }
970     default_route_gateway = 0;
971     return 1;
972 }
973
974 /*
975  * sifproxyarp - Make a proxy ARP entry for the peer.
976  */
977 int
978 sifproxyarp(unit, hisaddr)
979     int unit;
980     u_int32_t hisaddr;
981 {
982     struct arpreq arpreq;
983
984     BZERO(&arpreq, sizeof(arpreq));
985
986     /*
987      * Get the hardware address of an interface on the same subnet
988      * as our local address.
989      */
990     if (!get_ether_addr(hisaddr, &arpreq.arp_ha)) {
991         syslog(LOG_WARNING, "Cannot determine ethernet address for proxy ARP");
992         return 0;
993     }
994
995     SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
996     ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
997     arpreq.arp_flags = ATF_PERM | ATF_PUBL;
998     if (ioctl(sockfd, SIOCSARP, (caddr_t)&arpreq) < 0) {
999         syslog(LOG_ERR, "ioctl(SIOCSARP): %m");
1000         return 0;
1001     }
1002
1003     proxy_arp_addr = hisaddr;
1004     return 1;
1005 }
1006
1007 /*
1008  * cifproxyarp - Delete the proxy ARP entry for the peer.
1009  */
1010 int
1011 cifproxyarp(unit, hisaddr)
1012     int unit;
1013     u_int32_t hisaddr;
1014 {
1015     struct arpreq arpreq;
1016
1017     BZERO(&arpreq, sizeof(arpreq));
1018     SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
1019     ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
1020     if (ioctl(sockfd, SIOCDARP, (caddr_t)&arpreq) < 0) {
1021         syslog(LOG_ERR, "ioctl(SIOCDARP): %m");
1022         return 0;
1023     }
1024     proxy_arp_addr = 0;
1025     return 1;
1026 }
1027
1028 /*
1029  * get_ether_addr - get the hardware address of an interface on the
1030  * the same subnet as ipaddr.  Code borrowed from myetheraddr.c
1031  * in the cslip-2.6 distribution, which is subject to the following
1032  * copyright notice (which also applies to logwtmp below):
1033  *
1034  * Copyright (c) 1990, 1992 The Regents of the University of California.
1035  * All rights reserved.
1036  *
1037  * Redistribution and use in source and binary forms, with or without
1038  * modification, are permitted provided that: (1) source code distributions
1039  * retain the above copyright notice and this paragraph in its entirety, (2)
1040  * distributions including binary code include the above copyright notice and
1041  * this paragraph in its entirety in the documentation or other materials
1042  * provided with the distribution, and (3) all advertising materials mentioning
1043  * features or use of this software display the following acknowledgement:
1044  * ``This product includes software developed by the University of California,
1045  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1046  * the University nor the names of its contributors may be used to endorse
1047  * or promote products derived from this software without specific prior
1048  * written permission.
1049  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1050  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1051  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1052  */
1053
1054 #include <nlist.h>
1055 #include <arpa/inet.h>
1056 #include <netinet/in_var.h>
1057 #include <net/if_dl.h>
1058
1059 /* Cast a struct sockaddr to a structaddr_in */
1060 #define SATOSIN(sa) ((struct sockaddr_in *)(sa))
1061
1062 /* Determine if "bits" is set in "flag" */
1063 #define ALLSET(flag, bits) (((flag) & (bits)) == (bits))
1064
1065 static struct nlist nl[] = {
1066 #define N_IFNET 0
1067         { "ifnet" },
1068         { 0 }
1069 };
1070
1071 int kvm_read(int fd, off_t offset, void *buf, int nbytes)
1072 {
1073     if (lseek(fd, offset, SEEK_SET) != offset) {
1074         syslog(LOG_ERR,"lseek in kmem: %m");
1075         return(0);
1076     }
1077     return(read(fd, buf, nbytes));
1078 }
1079
1080 int
1081 get_ether_addr(ipaddr, hwaddr)
1082     u_long ipaddr;
1083     struct sockaddr *hwaddr;
1084 {
1085     int         kd;
1086     register struct ifnet *ifp;
1087     register struct arpcom *ac;
1088     struct arpcom arpcom;
1089     struct in_addr *inp;
1090     register struct ifaddr *ifa;
1091     register struct in_ifaddr *in;
1092     union {
1093         struct ifaddr ifa;
1094         struct in_ifaddr in;
1095     } ifaddr;
1096     struct ifaddr       *ifap;
1097     struct sockaddr     ifaddrsaddr;
1098     struct sockaddr_in  ifmasksaddr;
1099     struct sockaddr_in  *ifinetptr;
1100     struct sockaddr_dl  *iflinkptr;
1101     u_long addr, mask, ifip;
1102     int         found = 0;
1103
1104 /* Open kernel memory for reading */
1105     if ((kd = open("/dev/kmem", O_RDONLY)) < 0) {
1106         syslog(LOG_ERR, "/dev/kmem: %m");
1107         return 0;
1108     }
1109
1110 /* Fetch namelist */
1111     if (nlist("/unix", nl) != 0) {
1112         syslog(LOG_ERR, "nlist(): %m");
1113         return 0;
1114     }
1115
1116     ac = &arpcom;
1117     ifp = &arpcom.ac_if;
1118     ifa = &ifaddr.ifa;
1119     in = &ifaddr.in;
1120
1121     if (kvm_read(kd, nl[N_IFNET].n_value, (char *)&addr, sizeof(addr))
1122         != sizeof(addr)) {
1123         syslog(LOG_ERR, "error reading ifnet addr");
1124         return 0;
1125     }
1126     for ( ; addr && !found; addr = (u_long)ifp->if_next) {
1127         if (kvm_read(kd, addr, (char *)ac, sizeof(*ac)) != sizeof(*ac)) {
1128             syslog(LOG_ERR, "error reading ifnet");
1129             return 0;
1130         }
1131
1132 /* Only look at configured, broadcast interfaces */
1133         if (!ALLSET(ifp->if_flags, IFF_UP | IFF_BROADCAST))
1134             continue;
1135 /* This probably can't happen... */
1136         if (ifp->if_addrlist == 0)
1137             continue;
1138
1139 /* Get interface ip address */
1140         for (ifap = ifp->if_addrlist; ifap; ifap=ifaddr.ifa.ifa_next) {
1141             if (kvm_read(kd, (u_long)ifap, (char *)&ifaddr,
1142                      sizeof(ifaddr)) != sizeof(ifaddr)) {
1143                 syslog(LOG_ERR, "error reading ifaddr");
1144                 return 0;
1145             }
1146             if (kvm_read(kd, (u_long)ifaddr.ifa.ifa_addr, &ifaddrsaddr,
1147                 sizeof(struct sockaddr_in)) != sizeof(struct sockaddr_in)) {
1148                 syslog(LOG_ERR, "error reading ifaddrsaddr");
1149                 return(0);
1150             }
1151             if (kvm_read(kd, (u_long)ifaddr.ifa.ifa_netmask, &ifmasksaddr,
1152                 sizeof(struct sockaddr_in)) != sizeof(struct sockaddr_in)) {
1153                 syslog(LOG_ERR, "error reading ifmasksaddr");
1154                 return(0);
1155             }
1156     /* Check if this interface on the right subnet */
1157             switch (ifaddrsaddr.sa_family) {
1158             case AF_LINK :
1159                 hwaddr->sa_family = AF_UNSPEC;
1160                 iflinkptr = (struct sockaddr_dl *) &ifaddrsaddr;
1161                 bcopy(LLADDR(iflinkptr),hwaddr->sa_data,iflinkptr->sdl_alen);
1162                 break;
1163             case AF_INET:
1164                 ifinetptr= (struct sockaddr_in *) &ifaddrsaddr;
1165                 ifip = ifinetptr->sin_addr.s_addr;
1166                 if (kvm_read(kd, (u_long)ifaddr.ifa.ifa_netmask, &ifmasksaddr,
1167                     sizeof(struct sockaddr_in)) != sizeof(struct sockaddr_in)) {
1168                     syslog(LOG_ERR, "error reading ifmasksaddr");
1169                     return(0);
1170                 }
1171                 mask = ifmasksaddr.sin_addr.s_addr;
1172                 if ((ipaddr & mask) == (ifip & mask))
1173                     ++found;
1174                 break;
1175             default:
1176                 break;
1177             }
1178    
1179         }
1180     }
1181     return(found);
1182 }
1183
1184 /*
1185  * Return user specified netmask, modified by any mask we might determine
1186  * for address `addr' (in network byte order).
1187  * Here we scan through the system's list of interfaces, looking for
1188  * any non-point-to-point interfaces which might appear to be on the same
1189  * network as `addr'.  If we find any, we OR in their netmask to the
1190  * user-specified netmask.
1191  */
1192 #define MAX_IFS         32
1193
1194 u_int32_t
1195 GetMask(addr)
1196     u_int32_t addr;
1197 {
1198     u_int32_t mask, nmask, ina;
1199     struct ifreq *ifr, *ifend, ifreq;
1200     struct ifconf ifc;
1201     struct ifreq ifs[MAX_IFS];
1202
1203     addr = ntohl(addr);
1204     if (IN_CLASSA(addr))        /* determine network mask for address class */
1205         nmask = IN_CLASSA_NET;
1206     else if (IN_CLASSB(addr))
1207         nmask = IN_CLASSB_NET;
1208     else
1209         nmask = IN_CLASSC_NET;
1210     /* class D nets are disallowed by bad_ip_adrs */
1211     mask = netmask | htonl(nmask);
1212
1213     /*
1214      * Scan through the system's network interfaces.
1215      */
1216     ifc.ifc_len = sizeof(ifs);
1217     ifc.ifc_req = ifs;
1218     if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
1219         syslog(LOG_WARNING, "ioctl(SIOCGIFCONF): %m");
1220         return mask;
1221     }
1222     ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
1223     for (ifr = ifc.ifc_req; ifr < ifend; ++ifr) {
1224         /*
1225          * Check the interface's internet address.
1226          */
1227         if (ifr->ifr_addr.sa_family != AF_INET)
1228             continue;
1229         ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
1230         if ((ntohl(ina) & nmask) != (addr & nmask))
1231             continue;
1232         /*
1233          * Check that the interface is up, and not point-to-point or loopback.
1234          */
1235         strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
1236         if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0)
1237             continue;
1238         if ((ifreq.ifr_flags & (IFF_UP|IFF_POINTOPOINT|IFF_LOOPBACK))
1239             != IFF_UP)
1240             continue;
1241         /*
1242          * Get its netmask and OR it into our mask.
1243          */
1244         if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0)
1245             continue;
1246         mask |= ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr.s_addr;
1247     }
1248
1249     return mask;
1250 }
1251
1252 #define WTMPFILE        "/var/adm/wtmp"
1253
1254 int
1255 logwtmp(line, name, host)
1256     char *line, *name, *host;
1257 {
1258     int fd;
1259     struct stat buf;
1260     struct utmp ut;
1261
1262     if ((fd = open(WTMPFILE, O_WRONLY|O_APPEND, 0)) < 0)
1263         return;
1264     if (!fstat(fd, &buf)) {
1265         (void)strncpy(ut.ut_line, line, sizeof(ut.ut_line));
1266         (void)strncpy(ut.ut_name, name, sizeof(ut.ut_name));
1267         (void)strncpy(ut.ut_host, host, sizeof(ut.ut_host));
1268         (void)time(&ut.ut_time);
1269         if (write(fd, (char *)&ut, sizeof(struct utmp)) != sizeof(struct utmp))
1270             (void)ftruncate(fd, buf.st_size);
1271     }
1272     close(fd);
1273 }
1274
1275 /*
1276  * Code for locking/unlocking the serial device.
1277  */
1278
1279 static  char *devlocked = (char *) 0;
1280
1281 int lock(char *device)
1282 {
1283     char        *devname;
1284     int         rc;
1285
1286     if (devname = strrchr(device,'/'))
1287         ++devname;
1288     else
1289         devname = device;
1290
1291     if ((rc = ttylock(devname)) == 0) {
1292         devlocked = (char *) malloc(strlen(devname) + 1);
1293         sprintf(devlocked,"%s",devname);
1294     } else
1295         devlocked = (char *) 0;
1296
1297     return(rc);
1298 }
1299
1300 int unlock()
1301 {
1302     int rc = 0;
1303
1304     if (devlocked) {
1305         rc = ttyunlock(devlocked);
1306         free(devlocked);
1307         devlocked = (char *) 0;
1308     }
1309     return(rc);
1310 }
1311