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