]> git.ozlabs.org Git - ppp.git/blob - pppd/sys-NeXT.c
*** empty log message ***
[ppp.git] / pppd / sys-NeXT.c
1 /*
2  * sys-next.c - System-dependent procedures for setting up
3  * PPP interfaces on NeXT 3.2/3.3  systems
4  *
5  * Copyright (c) 1989 Carnegie Mellon University.
6  * Copyright (c) 1994 Philippe-Andre Prindeville.
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.  The name of the
15  * University may not be used to endorse or promote products derived
16  * from this software without specific prior written permission.
17  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
19  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20  */
21
22 #ifndef lint
23 static char rcsid[] = "$Id: sys-NeXT.c,v 1.8 1997/04/30 05:57:14 paulus Exp $";
24 #endif
25
26 #include <stdio.h>
27 #include <syslog.h>
28 #include <termios.h>
29 #include <utmp.h>
30 #include <unistd.h>
31 #include <stdlib.h>
32 #include <strings.h>
33 #include <sys/types.h>
34 #include <sys/file.h>
35 #include <sys/socket.h>
36 #include <sys/ioctl.h>
37 #include <sys/time.h>
38 #include <sys/errno.h>
39 #include <sys/stat.h>
40 #include <sys/fcntl.h>
41
42 #include <net/if.h>
43 #include <net/ppp_defs.h>
44 #include <net/if_ppp.h>
45 #include <netdb.h>
46 #include <netinet/in.h>
47 #include <netinet/in_systm.h>
48 #include <netinet/in_var.h>
49 #include <netinet/ip.h>
50 #include <netinet/if_ether.h>
51 #include <net/route.h>
52 #include <netinet/in.h>
53
54 #include <netinfo/ni.h>
55
56 #include "pppd.h"
57
58 static int initdisc = -1;       /* Initial TTY discipline */
59 static int initfdflags = -1;    /* Initial file descriptor flags for fd */
60 static int ppp_fd = -1;         /* fd which is set to PPP discipline */
61 static int loop_slave = -1;
62 static int loop_master;
63 static char loop_name[20];
64
65 extern int errno;
66
67 static int      restore_term;   /* 1 => we've munged the terminal */
68 static struct termios inittermios; /* Initial TTY termios */
69
70 static char *lock_file;
71
72 static int sockfd;              /* socket for doing interface ioctls */
73
74 #if defined(i386) && defined(HAS_BROKEN_IOCTL)
75 #define ioctl   myioctl
76 #endif
77
78 static int if_is_up;            /* the interface is currently up */
79 static u_int32_t default_route_gateway; /* gateway addr for default route */
80 static u_int32_t proxy_arp_addr;        /* remote addr for proxy arp */
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 dodefaultroute __P((u_int32_t, int));
86 static int get_ether_addr __P((u_int32_t, struct sockaddr *));
87 static int ether_by_host __P((char *, struct ether_addr *));
88
89
90 /*
91  * sys_init - System-dependent initialization.
92  */
93 void
94 sys_init()
95 {
96     openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP);
97     setlogmask(LOG_UPTO(LOG_INFO));
98
99     /* Get an internet socket for doing socket ioctl's on. */
100     if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
101         syslog(LOG_ERR, "Couldn't create IP socket: %m");
102         die(1);
103     }
104 }
105
106 /*
107  * sys_cleanup - restore any system state we modified before exiting:
108  * mark the interface down, delete default route and/or proxy arp entry.
109  * This should call die() because it's called from die().
110  */
111 void
112 sys_cleanup()
113 {
114     struct ifreq ifr;
115
116     if (if_is_up) {
117         strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
118         if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) >= 0
119             && ((ifr.ifr_flags & IFF_UP) != 0)) {
120             ifr.ifr_flags &= ~IFF_UP;
121             ioctl(sockfd, SIOCSIFFLAGS, &ifr);
122         }
123     }
124
125     if (default_route_gateway)
126         cifdefaultroute(0, 0, default_route_gateway);
127     if (proxy_arp_addr)
128         cifproxyarp(0, proxy_arp_addr);
129 }
130
131 /*
132  * note_debug_level - note a change in the debug level.
133  */
134 void
135 note_debug_level()
136 {
137     if (debug) {
138         syslog(LOG_INFO, "Debug turned ON, Level %d", debug);
139         setlogmask(LOG_UPTO(LOG_DEBUG));
140     } else {
141         setlogmask(LOG_UPTO(LOG_WARNING));
142     }
143 }
144
145 /*
146  * ppp_available - check whether the system has any ppp interfaces
147  * (in fact we check whether we can do an ioctl on ppp0).
148  */
149 int
150 ppp_available()
151 {
152     int s, ok;
153     struct ifreq ifr;
154     extern char *no_ppp_msg;
155
156     if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
157         return 1;               /* can't tell - maybe we're not root */
158
159     strncpy(ifr.ifr_name, "ppp0", sizeof (ifr.ifr_name));
160     ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 0;
161     close(s);
162
163     no_ppp_msg = "\
164 This system lacks kernel support for PPP.  To include PPP support\n\
165 in the kernel, please follow the steps detailed in the README.NeXT\n\
166 file in the ppp-2.2 distribution.\n";
167
168     return ok;
169 }
170
171 /*
172  * establish_ppp - Turn the serial port into a ppp interface.
173  */
174 void
175 establish_ppp(fd)
176     int fd;
177 {
178     int pppdisc = PPPDISC;
179     int x;
180
181     if (ioctl(fd, TIOCGETD, &initdisc) < 0) {
182         syslog(LOG_ERR, "ioctl(TIOCGETD): %m");
183         die(1);
184     }
185     if (ioctl(fd, TIOCSETD, &pppdisc) < 0) {
186         syslog(LOG_ERR, "ioctl(establish TIOCSETD): %m");
187         die(1);
188     }
189
190     /*
191      * Find out which interface we were given.
192      */
193     if (ioctl(fd, PPPIOCGUNIT, &ifunit) < 0) {  
194         syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m");
195         die(1);
196     }
197
198     /*
199      * Enable debug in the driver if requested.
200      */
201     if (kdebugflag) {
202         if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
203             syslog(LOG_WARNING, "ioctl(PPPIOCGFLAGS): %m");
204         } else {
205             x |= (kdebugflag & 0xFF) * SC_DEBUG;
206             if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0)
207                 syslog(LOG_WARNING, "ioctl(PPPIOCSFLAGS): %m");
208         }
209     }
210
211     /*
212      * Set device for non-blocking reads so PPPD can poll for
213      * input from the kernel.
214      */
215     if ((initfdflags = fcntl(fd, F_GETFL)) == -1
216         || fcntl(fd, F_SETFL, initfdflags | O_NONBLOCK) == -1) {
217         syslog(LOG_WARNING, "Couldn't set device to non-blocking mode: %m");
218     }
219
220 }
221
222
223 /*
224  * disestablish_ppp - Restore the serial port to normal operation.
225  * This shouldn't call die() because it's called from die().
226  */
227 void
228 disestablish_ppp(fd)
229     int fd;
230 {
231     /* Reset non-blocking mode on fd. */
232     if (initfdflags != -1 && fcntl(fd, F_SETFL, initfdflags) < 0)
233         syslog(LOG_WARNING, "Couldn't restore device fd flags: %m");
234     initfdflags = -1;
235
236     /* Restore old line discipline. */
237     if (initdisc >= 0 && ioctl(fd, TIOCSETD, &initdisc) < 0)
238         syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
239     initdisc = -1;
240 }
241
242 /*
243  * Check whether the link seems not to be 8-bit clean.
244  */
245 void
246 clean_check()
247 {
248     int x;
249     char *s;
250
251     if (ioctl(ttyfd, PPPIOCGFLAGS, (caddr_t) &x) == 0) {
252         s = NULL;
253         switch (~x & (SC_RCV_B7_0|SC_RCV_B7_1|SC_RCV_EVNP|SC_RCV_ODDP)) {
254         case SC_RCV_B7_0:
255             s = "bit 7 set to 1";
256             break;
257         case SC_RCV_B7_1:
258             s = "bit 7 set to 0";
259             break;
260         case SC_RCV_EVNP:
261             s = "odd parity";
262             break;
263         case SC_RCV_ODDP:
264             s = "even parity";
265             break;
266         }
267         if (s != NULL) {
268             syslog(LOG_WARNING, "Serial link is not 8-bit clean:");
269             syslog(LOG_WARNING, "All received characters had %s", s);
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 B14400
341     { 14400, B14400 },
342 #endif
343 #ifdef B28800
344     { 28800, B28800 },
345 #endif
346 #ifdef B43200
347     { 43200, B43200 },
348 #endif
349 #ifdef B57600
350     { 57600, B57600 },
351 #endif
352 /*
353 #ifndef B115200
354 #warning Defining B115200
355 #define B115200 20
356 #endif
357 */
358 #ifdef B115200
359     { 115200, B115200 },
360 #endif
361     { 0, 0 }
362 };
363
364 /*
365  * Translate from bits/second to a speed_t.
366  */
367 int
368 translate_speed(bps)
369     int bps;
370 {
371     struct speed *speedp;
372
373     if (bps == 0)
374         return 0;
375     for (speedp = speeds; speedp->speed_int; speedp++)
376         if (bps == speedp->speed_int)
377             return speedp->speed_val;
378     syslog(LOG_WARNING, "speed %d not supported", bps);
379     return 0;
380 }
381
382 /*
383  * Translate from a speed_t to bits/second.
384  */
385 static int
386 baud_rate_of(speed)
387     int speed;
388 {
389     struct speed *speedp;
390
391     if (speed == 0)
392         return 0;
393     for (speedp = speeds; speedp->speed_int; speedp++)
394         if (speed == speedp->speed_val)
395             return speedp->speed_int;
396     return 0;
397 }
398
399
400 /*
401  * set_up_tty: Set up the serial port on `fd' for 8 bits, no parity,
402  * at the requested speed, etc.  If `local' is true, set CLOCAL
403  * regardless of whether the modem option was specified.
404  */
405 void
406 set_up_tty(fd, local)
407     int fd, local;
408 {
409     int speed, x, modembits;
410     struct termios tios;
411
412     if (tcgetattr(fd, &tios) < 0) {
413         syslog(LOG_ERR, "tcgetattr: %m");
414         die(1);
415     }
416
417     if (!restore_term)
418         inittermios = tios;
419
420     tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
421
422     tios.c_cflag |= CS8 | CREAD | HUPCL;
423     if (local || !modem)
424         tios.c_cflag |= CLOCAL;
425
426     tios.c_iflag = IGNBRK | IGNPAR;
427     tios.c_oflag = 0;
428     tios.c_lflag = 0;
429     tios.c_cc[VMIN] = 1;
430     tios.c_cc[VTIME] = 0;
431
432     if (crtscts == -2) {
433         tios.c_iflag |= IXON | IXOFF;
434         tios.c_cc[VSTOP] = 0x13;        /* DC3 = XOFF = ^S */
435         tios.c_cc[VSTART] = 0x11;       /* DC1 = XON  = ^Q */
436     }
437
438     speed = translate_speed(inspeed);
439     if (speed) {
440         cfsetospeed(&tios, speed);
441         cfsetispeed(&tios, speed);
442     } else {
443         speed = cfgetospeed(&tios);
444         /*
445          * We can't proceed if the serial port speed is B0,
446          * since that implies that the serial port is disabled.
447          */
448         if (speed == B0) {
449             syslog(LOG_ERR, "Baud rate for %s is 0; need explicit baud rate",
450                    devnam);
451             die(1);
452         }
453     }
454
455     if (modem) {
456       modembits = TIOCM_RTS | TIOCM_CTS;
457       if (ioctl(fd, (crtscts ? TIOCMBIS : TIOCMBIC), &modembits) < 0)
458         syslog(LOG_ERR, "ioctl: TIOCMBIS/BIC: %m");
459     }
460
461     if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) {
462         syslog(LOG_ERR, "tcsetattr: %m");
463         die(1);
464     }
465
466    baud_rate = inspeed = baud_rate_of(speed);
467    restore_term = 1;
468 }
469
470 /*
471  * restore_tty - restore the terminal to the saved settings.
472  */
473 void
474 restore_tty(fd)
475     int fd;
476 {
477     if (restore_term) {
478         if (tcsetattr(fd, TCSAFLUSH, &inittermios) < 0)
479             if (errno != ENXIO)
480                 syslog(LOG_WARNING, "tcsetattr: %m");
481         restore_term = 0;
482     }
483 }
484
485 /*
486  * setdtr - control the DTR line on the serial port.
487  * This is called from die(), so it shouldn't call die().
488  *
489  * The write hack is to get NXFax to recognize that there is
490  * activity on the port.  Not using the write nukes
491  * NXFax's capability to determine port usage.
492  *
493  */
494 void
495 setdtr(fd, on)
496 int fd, on;
497 {
498     int modembits = TIOCM_DTR;
499
500     if (!on)
501       {
502         write(fd, " ", 1);
503         sleep(1);
504       }
505
506 /*    ioctl(fd, (on? TIOCMBIS: TIOCMBIC), &modembits); */
507     ioctl(fd, (on? TIOCSDTR: TIOCCDTR), 0);
508 }
509
510
511 /*
512  * output - Output PPP packet.
513  */
514 void
515 output(unit, p, len)
516     int unit;
517     u_char *p;
518     int len;
519 {
520     if (debug)
521         log_packet(p, len, "sent ", LOG_DEBUG);
522
523     if (write(ttyfd, p, len) < 0) {
524         if (errno == EWOULDBLOCK || errno == ENOBUFS
525             || errno == ENXIO || errno == EIO) {
526             syslog(LOG_WARNING, "write: warning: %m");
527         } else {
528             syslog(LOG_ERR, "write: %m");
529             die(1);
530         }
531     }
532 }
533
534
535 /*
536  * wait_input - wait until there is data available on ttyfd,
537  * for the length of time specified by *timo (indefinite
538  * if timo is NULL).
539  */
540 void
541 wait_input(timo)
542     struct timeval *timo;
543 {
544     fd_set ready;
545     int n;
546
547     FD_ZERO(&ready);
548     FD_SET(ttyfd, &ready);
549     n = select(ttyfd+1, &ready, NULL, &ready, timo);
550     if (n < 0 && errno != EINTR) {
551         syslog(LOG_ERR, "select: %m");
552         die(1);
553     }
554 }
555
556
557 /*
558  * read_packet - get a PPP packet from the serial device.
559  */
560 int
561 read_packet(buf)
562     u_char *buf;
563 {
564     int len;
565
566     if ((len = read(ttyfd, buf, PPP_MTU + PPP_HDRLEN)) < 0) {
567         if (errno == EWOULDBLOCK || errno == EINTR) {
568             MAINDEBUG((LOG_DEBUG, "read: %m"));
569             return -1;
570         }
571         syslog(LOG_ERR, "read: %m");
572         die(1);
573     }
574     return len;
575 }
576
577
578 /*
579  * ppp_send_config - configure the transmit characteristics of
580  * the ppp interface.
581  */
582 void
583 ppp_send_config(unit, mtu, asyncmap, pcomp, accomp)
584     int unit, mtu;
585     u_int32_t asyncmap;
586     int pcomp, accomp;
587 {
588     u_int x;
589     struct ifreq ifr;
590
591     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
592     ifr.ifr_mtu = mtu;
593     if (ioctl(sockfd, SIOCSIFMTU, (caddr_t) &ifr) < 0) {
594         syslog(LOG_ERR, "ioctl(SIOCSIFMTU): %m");
595         quit();
596     }
597
598     if (ioctl(ttyfd, PPPIOCSASYNCMAP, (caddr_t) &asyncmap) < 0) {
599         syslog(LOG_ERR, "ioctl(PPPIOCSASYNCMAP): %m");
600         quit();
601     }
602
603     if (ioctl(ttyfd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
604         syslog(LOG_ERR, "ioctl(PPPIOCGFLAGS): %m");
605         quit();
606     }
607     x = pcomp? x | SC_COMP_PROT: x &~ SC_COMP_PROT;
608     x = accomp? x | SC_COMP_AC: x &~ SC_COMP_AC;
609     if (ioctl(ttyfd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
610         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
611         quit();
612     }
613 }
614
615
616 /*
617  * ppp_set_xaccm - set the extended transmit ACCM for the interface.
618  */
619 void
620 ppp_set_xaccm(unit, accm)
621     int unit;
622     ext_accm accm;
623 {
624     if (ioctl(ttyfd, PPPIOCSXASYNCMAP, accm) < 0 && errno != ENOTTY)
625         syslog(LOG_WARNING, "ioctl(PPPIOCSXASYNCMAP): %m");
626 }
627
628
629 /*
630  * ppp_recv_config - configure the receive-side characteristics of
631  * the ppp interface.
632  */
633 void
634 ppp_recv_config(unit, mru, asyncmap, pcomp, accomp)
635     int unit, mru;
636     u_int32_t asyncmap;
637     int pcomp, accomp;
638 {
639     int x;
640
641     if (ioctl(ttyfd, PPPIOCSMRU, (caddr_t) &mru) < 0) {
642         syslog(LOG_ERR, "ioctl(PPPIOCSMRU): %m");
643         quit();
644     }
645     if (ioctl(ttyfd, PPPIOCSRASYNCMAP, (caddr_t) &asyncmap) < 0) {
646         syslog(LOG_ERR, "ioctl(PPPIOCSRASYNCMAP): %m");
647         quit();
648     }
649     if (ioctl(ttyfd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
650         syslog(LOG_ERR, "ioctl(PPPIOCGFLAGS): %m");
651         quit();
652     }
653     x = !accomp? x | SC_REJ_COMP_AC: x &~ SC_REJ_COMP_AC;
654     if (ioctl(ttyfd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
655         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
656         quit();
657     }
658 }
659
660 /*
661  * ccp_test - ask kernel whether a given compression method
662  * is acceptable for use.
663  */
664 int
665 ccp_test(unit, opt_ptr, opt_len, for_transmit)
666     int unit, opt_len, for_transmit;
667     u_char *opt_ptr;
668 {
669     struct ppp_option_data data;
670
671     data.ptr = opt_ptr;
672     data.length = opt_len;
673     data.transmit = for_transmit;
674     if (ioctl(ttyfd, PPPIOCSCOMPRESS, (caddr_t) &data) >= 0)
675         return 1;
676     return (errno == ENOBUFS)? 0: -1;
677 }
678
679 /*
680  * ccp_flags_set - inform kernel about the current state of CCP.
681  */
682 void
683 ccp_flags_set(unit, isopen, isup)
684     int unit, isopen, isup;
685 {
686     int x;
687
688     if (ioctl(ttyfd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
689         syslog(LOG_ERR, "ioctl(PPPIOCGFLAGS): %m");
690         return;
691     }
692     x = isopen? x | SC_CCP_OPEN: x &~ SC_CCP_OPEN;
693     x = isup? x | SC_CCP_UP: x &~ SC_CCP_UP;
694     if (ioctl(ttyfd, PPPIOCSFLAGS, (caddr_t) &x) < 0)
695         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
696 }
697
698 /*
699  * ccp_fatal_error - returns 1 if decompression was disabled as a
700  * result of an error detected after decompression of a packet,
701  * 0 otherwise.  This is necessary because of patent nonsense.
702  */
703 int
704 ccp_fatal_error(unit)
705     int unit;
706 {
707     int x;
708
709     if (ioctl(ttyfd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
710         syslog(LOG_ERR, "ioctl(PPPIOCGFLAGS): %m");
711         return 0;
712     }
713     return x & SC_DC_FERROR;
714 }
715
716 /*
717  * sifvjcomp - config tcp header compression
718  */
719 int
720 sifvjcomp(u, vjcomp, cidcomp, maxcid)
721     int u, vjcomp, cidcomp, maxcid;
722 {
723     u_int x;
724
725     if (ioctl(ttyfd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
726         syslog(LOG_ERR, "ioctl(PPIOCGFLAGS): %m");
727         return 0;
728     }
729     x = vjcomp ? x | SC_COMP_TCP: x &~ SC_COMP_TCP;
730     x = cidcomp? x & ~SC_NO_TCP_CCID: x | SC_NO_TCP_CCID;
731     if (ioctl(ttyfd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
732         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
733         return 0;
734     }
735     if (ioctl(ttyfd, PPPIOCSMAXCID, (caddr_t) &maxcid) < 0) {
736         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
737         return 0;
738     }
739     return 1;
740 }
741
742 /*
743  * sifup - Config the interface up and enable IP packets to pass.
744  */
745 #ifndef SC_ENABLE_IP
746 #define SC_ENABLE_IP    0x100   /* compat for old versions of kernel code */
747 #endif
748
749 int
750 sifup(u)
751     int u;
752 {
753     struct ifreq ifr;
754     u_int x;
755     struct npioctl npi;
756
757     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
758     if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
759         syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
760         return 0;
761     }
762     ifr.ifr_flags |= IFF_UP;
763     if (ioctl(sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
764         syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
765         return 0;
766     }
767     if_is_up = 1;
768     npi.protocol = PPP_IP;
769     npi.mode = NPMODE_PASS;
770     if (ioctl(ttyfd, PPPIOCSNPMODE, &npi) < 0) {
771         if (errno != ENOTTY) {
772             syslog(LOG_ERR, "ioctl(PPPIOCSNPMODE): %m");
773             return 0;
774         }
775         /* for backwards compatibility */
776         if (ioctl(ttyfd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
777             syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
778             return 0;
779         }
780         x |= SC_ENABLE_IP;
781         if (ioctl(ttyfd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
782             syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
783             return 0;
784         }
785     }
786     return 1;
787 }
788
789 /*
790  * sifdown - Config the interface down and disable IP.
791  */
792 int
793 sifdown(u)
794     int u;
795 {
796     struct ifreq ifr;
797     u_int x;
798     int rv;
799     struct npioctl npi;
800
801     rv = 1;
802     npi.protocol = PPP_IP;
803     npi.mode = NPMODE_ERROR;
804     ioctl(ttyfd, PPPIOCSNPMODE, (caddr_t) &npi);
805     /* ignore errors, because ttyfd might have been closed by now. */
806
807
808     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
809     if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
810         syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
811         rv = 0;
812     } else {
813         ifr.ifr_flags &= ~IFF_UP;
814         if (ioctl(sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
815             syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
816             rv = 0;
817         } else
818             if_is_up = 0;
819     }
820     return rv;
821 }
822
823 /*
824  * SET_SA_FAMILY - set the sa_family field of a struct sockaddr,
825  * if it exists.
826  */
827 #define SET_SA_FAMILY(addr, family)             \
828     BZERO((char *) &(addr), sizeof(addr));      \
829     addr.sa_family = (family); 
830
831 /*
832  * sifaddr - Config the interface IP addresses and netmask.
833  */
834 int
835 sifaddr(u, o, h, m)
836     int u;
837     u_int32_t o, h, m;
838 {
839     int ret;
840     struct ifreq ifr;
841
842     ret = 1;
843     strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
844     SET_SA_FAMILY(ifr.ifr_addr, AF_INET);
845     ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = o;
846     if (ioctl(sockfd, SIOCSIFADDR, (caddr_t) &ifr) < 0) {
847         syslog(LOG_ERR, "ioctl(SIOCAIFADDR): %m");
848         ret = 0;
849     }
850     ((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr = h;
851     if (ioctl(sockfd, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) {
852         syslog(LOG_ERR, "ioctl(SIOCSIFDSTADDR): %m");
853         ret = 0;
854     }
855     if (m != 0) {
856         ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = m;
857         syslog(LOG_INFO, "Setting interface mask to %s\n", ip_ntoa(m));
858         if (ioctl(sockfd, SIOCSIFNETMASK, (caddr_t) &ifr) < 0) {
859             syslog(LOG_ERR, "ioctl(SIOCSIFNETMASK): %m");
860             ret = 0;
861         }
862     }
863     return ret;
864 }
865
866 /*
867  * cifaddr - Clear the interface IP addresses, and delete routes
868  * through the interface if possible.
869  *
870  * N.B.: under NextStep, you can't *delete* an address on an interface,
871  * so we change it to 0.0.0.0...  A real hack.  But it simplifies
872  * reconnection on the server side.
873  */
874 int
875 cifaddr(u, o, h)
876     int u;
877     u_int32_t o, h;
878 {
879     struct rtentry rt;
880
881 #if 1
882     h = o = 0L;
883     (void) sifaddr(u, o, h, 0L);
884 #endif
885     SET_SA_FAMILY(rt.rt_dst, AF_INET);
886     ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = h;
887     SET_SA_FAMILY(rt.rt_gateway, AF_INET);
888     ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = o;
889     rt.rt_flags = RTF_HOST;
890     if (ioctl(sockfd, SIOCDELRT, (caddr_t) &rt) < 0) {
891         syslog(LOG_ERR, "ioctl(SIOCDELRT): %m");
892         return 0;
893     }
894     return 1;
895 }
896
897 /*
898  * sifdefaultroute - assign a default route through the address given.
899  */
900 int
901 sifdefaultroute(u, l, g)
902     int u;
903     u_int32_t l, g;
904 {
905     return dodefaultroute(g, 's');
906 }
907
908 /*
909  * cifdefaultroute - delete a default route through the address given.
910  */
911 int
912 cifdefaultroute(u, l, g)
913     int u;
914     u_int32_t l, g;
915 {
916     return dodefaultroute(g, 'c');
917 }
918
919 /*
920  * dodefaultroute - talk to a routing socket to add/delete a default route.
921  */
922 int
923 dodefaultroute(g, cmd)
924     u_int32_t g;
925     int cmd;
926 {
927     struct rtentry rt;
928
929     SET_SA_FAMILY(rt.rt_dst, AF_INET);
930     ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = 0L;
931     SET_SA_FAMILY(rt.rt_gateway, AF_INET);
932     ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g;
933     rt.rt_flags = RTF_GATEWAY;
934     if (ioctl(sockfd, (cmd == 's') ? SIOCADDRT : SIOCDELRT, &rt) < 0) {
935         syslog(LOG_ERR, "%cifdefaultroute: ioctl(%s): %m", cmd,
936                (cmd == 's') ? "SIOCADDRT" : "SIOCDELRT");
937         return 0;
938     }
939     default_route_gateway = (cmd == 's')? g: 0;
940     return 1;
941 }
942
943 /*
944  * sifproxyarp - Make a proxy ARP entry for the peer.
945  */
946 int
947 sifproxyarp(unit, hisaddr)
948     int unit;
949     u_int32_t hisaddr;
950 {
951     struct arpreq arpreq;
952
953     BZERO(&arpreq, sizeof(arpreq));
954
955     /*
956      * Get the hardware address of an interface on the same subnet
957      * as our local address.
958      */
959     if (!get_ether_addr(hisaddr, &arpreq.arp_ha)) {
960         syslog(LOG_ERR, "Cannot determine ethernet address for proxy ARP");
961         return 0;
962     }
963
964     SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
965     ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
966     arpreq.arp_flags = ATF_PERM | ATF_PUBL;
967     if (ioctl(sockfd, SIOCSARP, (caddr_t)&arpreq) < 0) {
968         syslog(LOG_ERR, "ioctl(SIOCSARP): %m");
969         return 0;
970     }
971
972     proxy_arp_addr = hisaddr;
973     return 1;
974 }
975
976 /*
977  * cifproxyarp - Delete the proxy ARP entry for the peer.
978  */
979 int
980 cifproxyarp(unit, hisaddr)
981     int unit;
982     u_int32_t hisaddr;
983 {
984     struct arpreq arpreq;
985
986     BZERO(&arpreq, sizeof(arpreq));
987     SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
988     ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
989     if (ioctl(sockfd, SIOCDARP, (caddr_t)&arpreq) < 0) {
990         syslog(LOG_WARNING, "ioctl(SIOCDARP): %m");
991         return 0;
992     }
993     proxy_arp_addr = 0;
994     return 1;
995 }
996
997 /*
998  * get_ether_addr - get the hardware address of an interface on the
999  * the same subnet as ipaddr.
1000  */
1001 #define MAX_IFS         32
1002
1003 int
1004 get_ether_addr(ipaddr, hwaddr)
1005     u_int32_t ipaddr;
1006     struct sockaddr *hwaddr;
1007 {
1008     struct ifreq *ifr, *ifend, *ifp;
1009     u_int32_t ina, mask;
1010     struct ether_addr dla;
1011     struct ifreq ifreq;
1012     struct ifconf ifc;
1013     struct ifreq ifs[MAX_IFS];
1014     struct hostent *hostent;
1015
1016     ifc.ifc_len = sizeof(ifs);
1017     ifc.ifc_req = ifs;
1018     if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
1019         syslog(LOG_ERR, "ioctl(SIOCGIFCONF): %m");
1020         return 0;
1021     }
1022
1023     /*
1024      * Scan through looking for an interface with an Internet
1025      * address on the same subnet as `ipaddr'.
1026      */
1027     ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
1028     for (ifr = ifc.ifc_req; ifr < ifend; ifr = (struct ifreq *)
1029                 ((char *)&ifr->ifr_addr + sizeof(struct sockaddr))) {
1030         if (ifr->ifr_addr.sa_family == AF_INET) {
1031             ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
1032             strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
1033             /*
1034              * Check that the interface is up, and not point-to-point
1035              * or loopback.
1036              */
1037             if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0)
1038                 continue;
1039             if ((ifreq.ifr_flags &
1040                  (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
1041                  != (IFF_UP|IFF_BROADCAST))
1042                 continue;
1043             /*
1044              * Get its netmask and check that it's on the right subnet.
1045              */
1046             if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0)
1047                 continue;
1048             mask = ((struct sockaddr_in*)&ifreq.ifr_addr)->sin_addr.s_addr;
1049             if ((ipaddr & mask) != (ina & mask))
1050                 continue;
1051
1052             break;
1053         }
1054     }
1055
1056     if (ifr >= ifend)
1057         return 0;
1058     syslog(LOG_INFO, "found interface %s for proxy arp", ifr->ifr_name);
1059
1060     /*
1061      * Get the hostname and look for an entry using the ethers database.
1062      * Under NeXTStep this is the best we can do for now.
1063      */
1064     if ((hostent = gethostbyaddr((char*)&ina, sizeof(ina), AF_INET)) == NULL)
1065         return 0;
1066
1067     if (ether_by_host(hostent->h_name, &dla)) {
1068         syslog(LOG_INFO, "Add entry for %s in /etc/ethers", hostent->h_name);
1069         return 0;       /* it's not there */
1070     }
1071     hwaddr->sa_family = AF_UNSPEC;
1072     BCOPY(&dla, hwaddr->sa_data, sizeof(dla));
1073     return 1;
1074 }
1075
1076 static int
1077 ether_by_host(hostname, etherptr)
1078     char *hostname;
1079     struct ether_addr *etherptr;
1080 {
1081     struct ether_addr *thisptr;
1082     void *conn;
1083     ni_id root;
1084     ni_namelist val;
1085     char path[256];
1086
1087     if (!ether_hostton(hostname, etherptr))
1088         return 0;
1089     /*
1090      * We shall now try and
1091      * find the address in the
1092      * top domain of netinfo.
1093      */
1094     strcat(strcpy(path, "/machines/"), hostname);
1095
1096     if (ni_open((void *)0, "/", &conn)
1097      || ni_root(conn, &root)
1098      || ni_pathsearch(conn, &root, path)
1099      || ni_lookupprop(conn, &root, "en_address", &val))
1100         return 1;
1101
1102     /*
1103      * Now we can convert the returned string into an ethernet address.
1104      */
1105     strcpy(path, val.ni_namelist_val[0]);
1106     ni_free(conn);
1107     if ((thisptr = (struct ether_addr*)ether_aton(path)) == NULL)
1108         return 1;
1109     BCOPY(thisptr, etherptr, sizeof(struct ether_addr));
1110     return 0;
1111 }
1112
1113
1114
1115 /*
1116  * Return user specified netmask, modified by any mask we might determine
1117  * for address `addr' (in network byte order).
1118  * Here we scan through the system's list of interfaces, looking for
1119  * any non-point-to-point interfaces which might appear to be on the same
1120  * network as `addr'.  If we find any, we OR in their netmask to the
1121  * user-specified netmask.
1122  */
1123 u_int32_t
1124 GetMask(addr)
1125     u_int32_t addr;
1126 {
1127     u_int32_t mask, nmask, ina;
1128     struct ifreq *ifr, *ifend, ifreq;
1129     struct ifconf ifc;
1130     struct ifreq ifs[MAX_IFS];
1131
1132     addr = ntohl(addr);
1133     if (IN_CLASSA(addr))        /* determine network mask for address class */
1134         nmask = IN_CLASSA_NET;
1135     else if (IN_CLASSB(addr))
1136         nmask = IN_CLASSB_NET;
1137     else
1138         nmask = IN_CLASSC_NET;
1139     /* class D nets are disallowed by bad_ip_adrs */
1140     mask = netmask | htonl(nmask);
1141
1142     /*
1143      * Scan through the system's network interfaces.
1144      */
1145     ifc.ifc_len = sizeof(ifs);
1146     ifc.ifc_req = ifs;
1147     if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
1148         syslog(LOG_WARNING, "ioctl(SIOCGIFCONF): %m");
1149         return mask;
1150     }
1151     ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
1152     for (ifr = ifc.ifc_req; ifr < ifend; ifr = (struct ifreq *)
1153                 ((char *)&ifr->ifr_addr + sizeof(struct sockaddr))) {
1154         /*
1155          * Check the interface's internet address.
1156          */
1157         if (ifr->ifr_addr.sa_family != AF_INET)
1158             continue;
1159         ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
1160         if ((ntohl(ina) & nmask) != (addr & nmask))
1161             continue;
1162         /*
1163          * Check that the interface is up, and not point-to-point or loopback.
1164          */
1165         strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
1166         if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0)
1167             continue;
1168         if ((ifreq.ifr_flags & (IFF_UP|IFF_POINTOPOINT|IFF_LOOPBACK))
1169             != IFF_UP)
1170             continue;
1171         /*
1172          * Get its netmask and OR it into our mask.
1173          */
1174         if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0)
1175             continue;
1176         mask |= ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr.s_addr;
1177     }
1178
1179     return mask;
1180 }
1181
1182
1183
1184 /*
1185  * daemon - Detach us from the terminal session.
1186  */
1187 int
1188 daemon(nochdir, noclose)
1189     int nochdir, noclose;
1190 {
1191     int pid;
1192
1193     if ((pid = fork()) < 0)
1194         return -1;
1195     if (pid != 0)
1196         exit(0);                /* parent dies */
1197     (void)setsid();
1198     if (!nochdir)
1199         chdir("/");
1200     if (!noclose) {
1201         fclose(stdin);          /* don't need stdin, stdout, stderr */
1202         fclose(stdout);
1203         fclose(stderr);
1204     }
1205     return 0;
1206 }
1207
1208
1209 char *
1210 strdup(s)
1211     const char *s;
1212 {
1213     char *d = malloc(strlen(s) + 1);
1214
1215     if (d) strcpy(d, s);
1216     return d;
1217 }
1218
1219 /*
1220  * This logwtmp() implementation is subject to the following copyright:
1221  *
1222  * Copyright (c) 1988 The Regents of the University of California.
1223  * All rights reserved.
1224  *
1225  * Redistribution and use in source and binary forms are permitted
1226  * provided that the above copyright notice and this paragraph are
1227  * duplicated in all such forms and that any documentation,
1228  * advertising materials, and other materials related to such
1229  * distribution and use acknowledge that the software was developed
1230  * by the University of California, Berkeley.  The name of the
1231  * University may not be used to endorse or promote products derived
1232  * from this software without specific prior written permission.
1233  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1234  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1235  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1236  */
1237
1238 #define WTMPFILE        "/usr/adm/wtmp"
1239
1240 void
1241 logwtmp(line, name, host)
1242     const char *line, *name, *host;
1243 {
1244     int fd;
1245     struct stat buf;
1246     struct utmp ut;
1247
1248     if ((fd = open(WTMPFILE, O_WRONLY|O_APPEND, 0)) < 0)
1249         return;
1250     if (!fstat(fd, &buf)) {
1251         (void)strncpy(ut.ut_line, line, sizeof(ut.ut_line));
1252         (void)strncpy(ut.ut_name, name, sizeof(ut.ut_name));
1253         (void)strncpy(ut.ut_host, host, sizeof(ut.ut_host));
1254         (void)time(&ut.ut_time);
1255         if (write(fd, (char *)&ut, sizeof(struct utmp)) != sizeof(struct utmp))
1256             (void)ftruncate(fd, buf.st_size);
1257     }
1258     close(fd);
1259 }
1260
1261 /*
1262  * Routines for locking and unlocking the serial device, moved here
1263  * from chat.c.
1264  */
1265
1266 #define LOCK_PREFIX     "/usr/spool/uucp/LCK/LCK.."
1267
1268 /*
1269  * lock - create a lock file for the named device
1270  */
1271 int
1272 lock(dev)
1273     char *dev;
1274 {
1275     int fd, pid, n;
1276     char *p;
1277
1278     if ((p = strrchr(dev, '/')) != NULL)
1279         dev = p + 1;
1280     lock_file = malloc(strlen(LOCK_PREFIX) + strlen(dev) + 1);
1281     if (lock_file == NULL)
1282         novm("lock file name");
1283     strcat(strcpy(lock_file, LOCK_PREFIX), dev);
1284
1285     while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) {
1286         if (errno == EEXIST
1287             && (fd = open(lock_file, O_RDONLY, 0)) >= 0) {
1288             /* Read the lock file to find out who has the device locked */
1289             n = read(fd, &pid, sizeof(pid));
1290             if (n <= 0) {
1291                 syslog(LOG_ERR, "Can't read pid from lock file %s", lock_file);
1292                 close(fd);
1293             } else {
1294                 if (kill(pid, 0) == -1 && errno == ESRCH) {
1295                     /* pid no longer exists - remove the lock file */
1296                     if (unlink(lock_file) == 0) {
1297                         close(fd);
1298                         syslog(LOG_NOTICE, "Removed stale lock on %s (pid %d)",
1299                                dev, pid);
1300                         continue;
1301                     } else
1302                         syslog(LOG_WARNING, "Couldn't remove stale lock on %s",
1303                                dev);
1304                 } else
1305                     syslog(LOG_NOTICE, "Device %s is locked by pid %d",
1306                            dev, pid);
1307             }
1308             close(fd);
1309         } else
1310             syslog(LOG_ERR, "Can't create lock file %s: %m", lock_file);
1311         free(lock_file);
1312         lock_file = NULL;
1313         return -1;
1314     }
1315
1316     pid = getpid();
1317     write(fd, &pid, sizeof pid);
1318
1319     close(fd);
1320     return 0;
1321 }
1322
1323 /*
1324  * unlock - remove our lockfile
1325  */
1326 void
1327 unlock()
1328 {
1329     if (lock_file) {
1330         unlink(lock_file);
1331         free(lock_file);
1332         lock_file = NULL;
1333     }
1334 }
1335
1336 #if defined(i386) && defined(HAS_BROKEN_IOCTL)
1337 int
1338 ioctl(fd, cmd, c)
1339     int fd, cmd;
1340     caddr_t c;
1341 {
1342 #undef  ioctl
1343     int ret;
1344
1345 #ifdef DEBUGIOCTL
1346     int serrno;
1347     u_char let, code, size;
1348
1349     size = (cmd >> 16) & IOCPARM_MASK;
1350     let = (cmd >> 8);
1351     code = cmd;
1352
1353     if (let == 't' && (75 <= code && code <= 90))
1354     syslog(LOG_INFO, "ioctl(%d, 0x%x ('%c', %d, %d), 0x%x)\n", fd, cmd,
1355            let, code, size, c);
1356 #endif
1357
1358     ret = ioctl(fd, cmd, c);
1359
1360 #ifdef DEBUGIOCTL
1361     serrno = errno;
1362     if (ret == -1)
1363         syslog(LOG_INFO, "ioctl('%c', %d, %d) errno = %d (%m)\n",
1364                 let, code, size, errno);
1365     if (let == 't' && (75 <= code && code <= 90) && (cmd & IOC_OUT)) {
1366         int i, len = ((cmd >> 16) & IOCPARM_MASK);
1367         for (i = 0; i < len / 4; ++i)
1368                 syslog(LOG_INFO, "word[%d] @ 0x%06x = 0x%x\n",
1369                        i, &((int *) c)[i],((int *)c)[i]);
1370     }
1371     errno = serrno;
1372 #endif
1373
1374     if (ret == -1 && errno == EPERM)
1375         errno = ret = 0;
1376     return ret;
1377 }
1378 #endif  /* HAS_BROKEN_IOCTL */
1379
1380
1381 #if defined(FIXSIGS) && (defined (hppa) || defined(sparc))
1382
1383 /*
1384  * These redefinitions of Posix functions are necessary
1385  * because HPPA systems have an OS bug that causes 
1386  * sigaction to core dump:
1387  *
1388  * AlainF 9-Nov-1994    HACK FOR HP-PA/NEXTSTEP
1389  *                      sigaction(3) seems broken in the HP-PA NeXTSTEP 3.2
1390  *                      Posix lib. This causes pppd to SIGBUS at the expiration
1391  *                      of the first timeout (_sigtramp seems to invoke
1392  *                      the SIGALRM handler at an unreasonably low address).
1393  *                      All calls so sigaction(3) have been changed to calls
1394  *                      to sigvec(2) and sigprocmask(SIG_BLOCK,...) to
1395  *                      sigblock(2).
1396  *                      This is kind of a hack, especially since there are
1397  *                      other routines of the Posix lib still used, but
1398  *                      it worked for me.
1399  *
1400  * Dave Hess <David-Hess@net.tamu.edu> noted that 3.3 Sparc seems to
1401  * have the same bug.  Thus this fix has been enabled for SPARC also.
1402  *
1403  *
1404  */
1405
1406 int sigemptyset(sigset_t *mask)
1407 {
1408   *mask = 0;
1409 }
1410
1411 sigaddset(sigset_t *mask, int which_sig)
1412 {
1413   *mask |= sigmask(which_sig);
1414 }
1415
1416
1417 int sigaction(int sig, const struct sigaction *act, struct sigaction *oact)
1418 {
1419    struct sigvec sv;
1420    static int in = 0;
1421
1422    sv.sv_handler = act->sa_handler;
1423    sv.sv_mask = act->sa_mask;
1424    sv.sv_flags = 0;
1425
1426    if (!in)
1427      {
1428        in = 1;
1429        syslog(LOG_WARNING, "PPPD: Inside modified HP and SPARC sigaction\n");
1430      }
1431
1432    return sigvec(sig, &sv, NULL);
1433 }
1434
1435 #endif
1436
1437
1438 /*
1439  * Code following is added for 2.3 compatibility
1440  */
1441
1442 /*
1443  * get_idle_time - return how long the link has been idle.
1444  */
1445 int
1446 get_idle_time(u, ip)
1447     int u;
1448     struct ppp_idle *ip;
1449 {
1450   return (ioctl(ttyfd, PPPIOCGIDLE, ip) >= 0); 
1451 }
1452
1453
1454 /*
1455  * get_loop_output - read characters from the loopback, form them
1456  * into frames, and detect when we want to bring the real link up.
1457  * Return value is 1 if we need to bring up the link, 0 otherwise.
1458  */
1459 int
1460 get_loop_output()
1461 {
1462
1463 #if 0
1464     int rv = 0;
1465     int n;
1466
1467     while ((n = read(loop_master, inbuf, sizeof(inbuf))) >= 0) {
1468         if (loop_chars(inbuf, n))
1469             rv = 1;
1470     }
1471
1472     if (n == 0) {
1473         syslog(LOG_ERR, "eof on loopback");
1474         die(1);
1475     } else if (errno != EWOULDBLOCK){
1476         syslog(LOG_ERR, "read from loopback: %m");
1477         die(1);
1478     }
1479
1480     return rv;
1481 #endif
1482
1483     return 0;
1484 }
1485
1486 /*
1487  * sifnpmode - Set the mode for handling packets for a given NP.
1488  */
1489 int
1490 sifnpmode(u, proto, mode)
1491     int u;
1492     int proto;
1493     enum NPmode mode;
1494 {
1495     struct npioctl npi;
1496
1497     npi.protocol = proto;
1498     npi.mode = mode;
1499     if (ioctl(ttyfd, PPPIOCSNPMODE, &npi) < 0) {
1500         syslog(LOG_ERR, "ioctl(set NP %d mode to %d): %m", proto, mode);
1501         return 0;
1502     }
1503     return 1;
1504 }
1505
1506
1507 /*
1508  * open_ppp_loopback - open the device we use for getting
1509  * packets in demand mode, and connect it to a ppp interface.
1510  * Here we use a pty.
1511  */
1512 void
1513 open_ppp_loopback()
1514 {
1515
1516 #if 0
1517     int flags;
1518     struct termios tios;
1519     int pppdisc = PPPDISC;
1520
1521     syslog(LOG_ERR, "open_ppp_loopback called!");
1522     die(1);
1523
1524     if (openpty(&loop_master, &loop_slave, loop_name, NULL, NULL) < 0) {
1525         syslog(LOG_ERR, "No free pty for loopback");
1526         die(1);
1527     }
1528     SYSDEBUG((LOG_DEBUG, "using %s for loopback", loop_name));
1529
1530     if (tcgetattr(loop_slave, &tios) == 0) {
1531         tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB);
1532         tios.c_cflag |= CS8 | CREAD;
1533         tios.c_iflag = IGNPAR;
1534         tios.c_oflag = 0;
1535         tios.c_lflag = 0;
1536         if (tcsetattr(loop_slave, TCSAFLUSH, &tios) < 0)
1537             syslog(LOG_WARNING, "couldn't set attributes on loopback: %m");
1538     }
1539
1540     if ((flags = fcntl(loop_master, F_GETFL)) != -1) 
1541         if (fcntl(loop_master, F_SETFL, flags | O_NONBLOCK) == -1)
1542             syslog(LOG_WARNING, "couldn't set loopback to nonblock: %m");
1543
1544     ttyfd = loop_slave;
1545     if (ioctl(ttyfd, TIOCSETD, &pppdisc) < 0) {
1546         syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
1547         die(1);
1548     }
1549
1550     /*
1551      * Find out which interface we were given.
1552      */
1553     if (ioctl(ttyfd, PPPIOCGUNIT, &ifunit) < 0) {       
1554         syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m");
1555         die(1);
1556     }
1557
1558     /*
1559      * Enable debug in the driver if requested.
1560      */
1561     if (kdebugflag) {
1562         if (ioctl(ttyfd, PPPIOCGFLAGS, (caddr_t) &flags) < 0) {
1563             syslog(LOG_WARNING, "ioctl (PPPIOCGFLAGS): %m");
1564         } else {
1565             flags |= (kdebugflag & 0xFF) * SC_DEBUG;
1566             if (ioctl(ttyfd, PPPIOCSFLAGS, (caddr_t) &flags) < 0)
1567                 syslog(LOG_WARNING, "ioctl(PPPIOCSFLAGS): %m");
1568         }
1569     }
1570
1571 #endif
1572
1573 }
1574
1575 /*
1576  * restore_loop - reattach the ppp unit to the loopback.
1577  */
1578 void
1579 restore_loop()
1580 {
1581     int x;
1582
1583     /*
1584      * Transfer the ppp interface back to the loopback.
1585      */
1586     if (ioctl(ttyfd, PPPIOCXFERUNIT, 0) < 0) {
1587         syslog(LOG_ERR, "ioctl(transfer ppp unit): %m");
1588         die(1);
1589     }
1590     x = PPPDISC;
1591     if (ioctl(loop_slave, TIOCSETD, &x) < 0) {
1592         syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
1593         die(1);
1594     }
1595
1596     /*
1597      * Check that we got the same unit again.
1598      */
1599     if (ioctl(loop_slave, PPPIOCGUNIT, &x) < 0) {       
1600         syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m");
1601         die(1);
1602     }
1603     if (x != ifunit) {
1604         syslog(LOG_ERR, "transfer_ppp failed: wanted unit %d, got %d",
1605                ifunit, x);
1606         die(1);
1607     }
1608     ttyfd = loop_slave;
1609 }
1610
1611
1612 /*
1613  * sys_check_options - check the options that the user specified
1614  */
1615 void
1616 sys_check_options()
1617 {
1618   /*
1619    * We don't support demand dialing yet.
1620    */
1621   if(demand)
1622     {
1623       syslog(LOG_WARNING, "PPP-2.3 for NeXTSTEP does not yet support demand dialing\n");
1624       demand = 0;
1625     }
1626 }
1627
1628
1629 /*
1630  * sys_close - Clean up in a child process before execing.
1631  */
1632 void
1633 sys_close()
1634 {
1635     close(sockfd);
1636     if (loop_slave >= 0) {
1637         close(loop_slave);
1638         close(loop_master);
1639     }
1640     closelog();
1641 }
1642
1643
1644 /*
1645  * wait_loop_output - wait until there is data available on the
1646  * loopback, for the length of time specified by *timo (indefinite
1647  * if timo is NULL).
1648  */
1649 void wait_loop_output(timo)
1650     struct timeval *timo;
1651 {
1652     fd_set ready;
1653     int n;
1654
1655     FD_ZERO(&ready);
1656     FD_SET(loop_master, &ready);
1657     n = select(loop_master + 1, &ready, NULL, &ready, timo);
1658     if (n < 0 && errno != EINTR) {
1659         syslog(LOG_ERR, "select: %m");
1660         die(1);
1661     }
1662 }
1663
1664
1665 /*
1666  * wait_time - wait for a given length of time or until a
1667  * signal is received.
1668  */
1669 void wait_time(timo)
1670     struct timeval *timo;
1671 {
1672     int n;
1673
1674     n = select(0, NULL, NULL, NULL, timo);
1675     if (n < 0 && errno != EINTR) {
1676         syslog(LOG_ERR, "select: %m");
1677         die(1);
1678     }
1679 }