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