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