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