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