]> git.ozlabs.org Git - ppp.git/blob - pppd/sys-NeXT.c
support Deflate and Predictor
[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.1 1995/08/10 06:48:34 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
60 extern int errno;
61
62 static int      restore_term;   /* 1 => we've munged the terminal */
63 static struct termios inittermios; /* Initial TTY termios */
64
65 static char *lock_file;
66
67 int sockfd;                     /* socket for doing interface ioctls */
68
69 #if defined(i386) && defined(HAS_BROKEN_IOCTL)
70 #define ioctl   myioctl
71 #endif
72
73 /*
74  * sys_init - System-dependent initialization.
75  */
76 void
77 sys_init()
78 {
79     openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP);
80     setlogmask(LOG_UPTO(LOG_INFO));
81     if (debug)
82         setlogmask(LOG_UPTO(LOG_DEBUG));
83
84     /* Get an internet socket for doing socket ioctl's on. */
85     if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
86         syslog(LOG_ERR, "Couldn't create IP socket: %m");
87         die(1);
88     }
89 }
90
91 /*
92  * note_debug_level - note a change in the debug level.
93  */
94 void
95 note_debug_level()
96 {
97     if (debug) {
98         syslog(LOG_INFO, "Debug turned ON, Level %d", debug);
99         setlogmask(LOG_UPTO(LOG_DEBUG));
100     } else {
101         setlogmask(LOG_UPTO(LOG_WARNING));
102     }
103 }
104
105 /*
106  * ppp_available - check whether the system has any ppp interfaces
107  * (in fact we check whether we can do an ioctl on ppp0).
108  */
109 int
110 ppp_available()
111 {
112     int s, ok;
113     struct ifreq ifr;
114
115     if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
116         return 1;               /* can't tell - maybe we're not root */
117
118     strncpy(ifr.ifr_name, "ppp0", sizeof (ifr.ifr_name));
119     ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 0;
120     close(s);
121
122     return ok;
123 }
124
125 /*
126  * establish_ppp - Turn the serial port into a ppp interface.
127  */
128 void
129 establish_ppp()
130 {
131     int pppdisc = PPPDISC;
132     int x;
133
134     if (ioctl(fd, TIOCGETD, &initdisc) < 0) {
135         syslog(LOG_ERR, "ioctl(TIOCGETD): %m");
136         die(1);
137     }
138     if (ioctl(fd, TIOCSETD, &pppdisc) < 0) {
139         syslog(LOG_ERR, "ioctl(establish TIOCSETD): %m");
140         die(1);
141     }
142
143     /*
144      * Find out which interface we were given.
145      */
146     if (ioctl(fd, PPPIOCGUNIT, &ifunit) < 0) {  
147         syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m");
148         die(1);
149     }
150
151     /*
152      * Enable debug in the driver if requested.
153      */
154     if (kdebugflag) {
155         if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
156             syslog(LOG_WARNING, "ioctl(PPPIOCGFLAGS): %m");
157         } else {
158             x |= (kdebugflag & 0xFF) * SC_DEBUG;
159             if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0)
160                 syslog(LOG_WARNING, "ioctl(PPPIOCSFLAGS): %m");
161         }
162     }
163 }
164
165
166 /*
167  * disestablish_ppp - Restore the serial port to normal operation.
168  * This shouldn't call die() because it's called from die().
169  */
170 void
171 disestablish_ppp()
172 {
173     int x;
174     char *s;
175
176     if (initdisc >= 0) {
177         /*
178          * Check whether the link seems not to be 8-bit clean.
179          */
180         if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) == 0) {
181             s = NULL;
182             switch (~x & (SC_RCV_B7_0|SC_RCV_B7_1|SC_RCV_EVNP|SC_RCV_ODDP)) {
183             case SC_RCV_B7_0:
184                 s = "bit 7 set to 1";
185                 break;
186             case SC_RCV_B7_1:
187                 s = "bit 7 set to 0";
188                 break;
189             case SC_RCV_EVNP:
190                 s = "odd parity";
191                 break;
192             case SC_RCV_ODDP:
193                 s = "even parity";
194                 break;
195             }
196             if (s != NULL) {
197                 syslog(LOG_WARNING, "Serial link is not 8-bit clean:");
198                 syslog(LOG_WARNING, "All received characters had %s", s);
199             }
200         }
201         if (ioctl(fd, TIOCSETD, &initdisc) < 0)
202             syslog(LOG_ERR, "ioctl(disestablish TIOCSETD): %m");
203     }
204 }
205
206 /*
207  * List of valid speeds.
208  */
209 struct speed {
210     int speed_int, speed_val;
211 } speeds[] = {
212 #ifdef B50
213     { 50, B50 },
214 #endif
215 #ifdef B75
216     { 75, B75 },
217 #endif
218 #ifdef B110
219     { 110, B110 },
220 #endif
221 #ifdef B134
222     { 134, B134 },
223 #endif
224 #ifdef B150
225     { 150, B150 },
226 #endif
227 #ifdef B200
228     { 200, B200 },
229 #endif
230 #ifdef B300
231     { 300, B300 },
232 #endif
233 #ifdef B600
234     { 600, B600 },
235 #endif
236 #ifdef B1200
237     { 1200, B1200 },
238 #endif
239 #ifdef B1800
240     { 1800, B1800 },
241 #endif
242 #ifdef B2000
243     { 2000, B2000 },
244 #endif
245 #ifdef B2400
246     { 2400, B2400 },
247 #endif
248 #ifdef B3600
249     { 3600, B3600 },
250 #endif
251 #ifdef B4800
252     { 4800, B4800 },
253 #endif
254 #ifdef B7200
255     { 7200, B7200 },
256 #endif
257 #ifdef B9600
258     { 9600, B9600 },
259 #endif
260 #ifdef B19200
261     { 19200, B19200 },
262 #endif
263 #ifdef B38400
264     { 38400, B38400 },
265 #endif
266 #ifdef EXTA
267     { 19200, EXTA },
268 #endif
269 #ifdef EXTB
270     { 38400, EXTB },
271 #endif
272 #ifdef B14400
273     { 14400, B14400 },
274 #endif
275 #ifdef B28800
276     { 28800, B28800 },
277 #endif
278 #ifdef B43200
279     { 43200, B43200 },
280 #endif
281 #ifdef B57600
282     { 57600, B57600 },
283 #endif
284 #ifdef B115200
285     { 115200, B115200 },
286 #endif
287     { 0, 0 }
288 };
289
290 /*
291  * Translate from bits/second to a speed_t.
292  */
293 int
294 translate_speed(bps)
295     int bps;
296 {
297     struct speed *speedp;
298
299     if (bps == 0)
300         return 0;
301     for (speedp = speeds; speedp->speed_int; speedp++)
302         if (bps == speedp->speed_int)
303             return speedp->speed_val;
304     syslog(LOG_WARNING, "speed %d not supported", bps);
305     return 0;
306 }
307
308 /*
309  * Translate from a speed_t to bits/second.
310  */
311 int
312 baud_rate_of(speed)
313     int speed;
314 {
315     struct speed *speedp;
316
317     if (speed == 0)
318         return 0;
319     for (speedp = speeds; speedp->speed_int; speedp++)
320         if (speed == speedp->speed_val)
321             return speedp->speed_int;
322     return 0;
323 }
324
325
326 /*
327  * set_up_tty: Set up the serial port on `fd' for 8 bits, no parity,
328  * at the requested speed, etc.  If `local' is true, set CLOCAL
329  * regardless of whether the modem option was specified.
330  */
331 set_up_tty(fd, local)
332     int fd, local;
333 {
334     int speed, x, modembits;
335     struct termios tios;
336
337     if (tcgetattr(fd, &tios) < 0) {
338         syslog(LOG_ERR, "tcgetattr: %m");
339         die(1);
340     }
341
342     if (!restore_term)
343         inittermios = tios;
344
345     tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
346
347     tios.c_cflag |= CS8 | CREAD | HUPCL;
348     if (local || !modem)
349         tios.c_cflag |= CLOCAL;
350     tios.c_iflag = IGNBRK | IGNPAR;
351     tios.c_oflag = 0;
352     tios.c_lflag = 0;
353     tios.c_cc[VMIN] = 1;
354     tios.c_cc[VTIME] = 0;
355
356     if (crtscts == 2) {
357         tios.c_iflag |= IXOFF;
358         tios.c_cc[VSTOP] = 0x13;        /* DC3 = XOFF = ^S */
359         tios.c_cc[VSTART] = 0x11;       /* DC1 = XON  = ^Q */
360     }
361
362     speed = translate_speed(inspeed);
363     if (speed) {
364         cfsetospeed(&tios, speed);
365         cfsetispeed(&tios, speed);
366     } else {
367         speed = cfgetospeed(&tios);
368     }
369
370     if (modem) {
371       modembits = TIOCM_RTS | TIOCM_CTS;
372       if (ioctl(fd, (crtscts ? TIOCMBIS : TIOCMBIC), &modembits) < 0)
373         syslog(LOG_ERR, "ioctl: TIOCMBIS/BIC: %m");
374     }
375
376     if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) {
377         syslog(LOG_ERR, "tcsetattr: %m");
378         die(1);
379     }
380
381    baud_rate = inspeed = baud_rate_of(speed);
382    restore_term = 1;
383 }
384
385 /*
386  * restore_tty - restore the terminal to the saved settings.
387  */
388 void
389 restore_tty()
390 {
391     if (restore_term) {
392         if (tcsetattr(fd, TCSAFLUSH, &inittermios) < 0)
393             if (errno != ENXIO)
394                 syslog(LOG_WARNING, "tcsetattr: %m");
395         restore_term = 0;
396     }
397 }
398
399 /*
400  * setdtr - control the DTR line on the serial port.
401  * This is called from die(), so it shouldn't call die().
402  *
403  * The write hack is to get NXFax to recognize that there is
404  * activity on the port.  Not using the write nukes
405  * NXFax's capability to determine port usage.
406  *
407  */
408 setdtr(fd, on)
409 int fd, on;
410 {
411     int modembits = TIOCM_DTR;
412
413     if (!on)
414       {
415         write(fd, " ", 1);
416         sleep(1);
417       }
418
419 /*    ioctl(fd, (on? TIOCMBIS: TIOCMBIC), &modembits); */
420     ioctl(fd, (on? TIOCSDTR: TIOCCDTR), 0);
421 }
422
423
424 /*
425  * output - Output PPP packet.
426  */
427 void
428 output(unit, p, len)
429     int unit;
430     u_char *p;
431     int len;
432 {
433     if (unit != 0)
434         MAINDEBUG((LOG_WARNING, "output: unit != 0!"));
435     if (debug)
436         log_packet(p, len, "sent ");
437
438     if (write(fd, p, len) < 0) {
439         syslog(LOG_ERR, "write: %m");
440         die(1);
441     }
442 }
443
444
445 /*
446  * wait_input - wait until there is data available on fd,
447  * for the length of time specified by *timo (indefinite
448  * if timo is NULL).
449  */
450 wait_input(timo)
451     struct timeval *timo;
452 {
453     fd_set ready;
454     int n;
455
456     FD_ZERO(&ready);
457     FD_SET(fd, &ready);
458     n = select(fd+1, &ready, NULL, &ready, timo);
459     if (n < 0 && errno != EINTR) {
460         syslog(LOG_ERR, "select: %m");
461         die(1);
462     }
463 }
464
465
466 /*
467  * read_packet - get a PPP packet from the serial device.
468  */
469 int
470 read_packet(buf)
471     u_char *buf;
472 {
473     int len;
474
475     if ((len = read(fd, buf, PPP_MTU + PPP_HDRLEN)) < 0) {
476         if (errno == EWOULDBLOCK || errno == EINTR) {
477             MAINDEBUG((LOG_DEBUG, "read(fd): %m"));
478             return -1;
479         }
480         syslog(LOG_ERR, "read(fd): %m");
481         die(1);
482     }
483     return len;
484 }
485
486
487 /*
488  * ppp_send_config - configure the transmit characteristics of
489  * the ppp interface.
490  */
491 void
492 ppp_send_config(unit, mtu, asyncmap, pcomp, accomp)
493     int unit, mtu;
494     u_int32_t asyncmap;
495     int pcomp, accomp;
496 {
497     u_int x;
498     struct ifreq ifr;
499
500     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
501     ifr.ifr_mtu = mtu;
502     if (ioctl(sockfd, SIOCSIFMTU, (caddr_t) &ifr) < 0) {
503         syslog(LOG_ERR, "ioctl(SIOCSIFMTU): %m");
504         quit();
505     }
506
507     if (ioctl(fd, PPPIOCSASYNCMAP, (caddr_t) &asyncmap) < 0) {
508         syslog(LOG_ERR, "ioctl(PPPIOCSASYNCMAP): %m");
509         quit();
510     }
511
512     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
513         syslog(LOG_ERR, "ioctl(PPPIOCGFLAGS): %m");
514         quit();
515     }
516     x = pcomp? x | SC_COMP_PROT: x &~ SC_COMP_PROT;
517     x = accomp? x | SC_COMP_AC: x &~ SC_COMP_AC;
518     if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
519         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
520         quit();
521     }
522 }
523
524
525 /*
526  * ppp_set_xaccm - set the extended transmit ACCM for the interface.
527  */
528 void
529 ppp_set_xaccm(unit, accm)
530     int unit;
531     ext_accm accm;
532 {
533     if (ioctl(fd, PPPIOCSXASYNCMAP, accm) < 0 && errno != ENOTTY)
534         syslog(LOG_WARNING, "ioctl(PPPIOCSXASYNCMAP): %m");
535 }
536
537
538 /*
539  * ppp_recv_config - configure the receive-side characteristics of
540  * the ppp interface.
541  */
542 void
543 ppp_recv_config(unit, mru, asyncmap, pcomp, accomp)
544     int unit, mru;
545     u_int32_t asyncmap;
546     int pcomp, accomp;
547 {
548     int x;
549
550     if (ioctl(fd, PPPIOCSMRU, (caddr_t) &mru) < 0) {
551         syslog(LOG_ERR, "ioctl(PPPIOCSMRU): %m");
552         quit();
553     }
554     if (ioctl(fd, PPPIOCSRASYNCMAP, (caddr_t) &asyncmap) < 0) {
555         syslog(LOG_ERR, "ioctl(PPPIOCSRASYNCMAP): %m");
556         quit();
557     }
558     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
559         syslog(LOG_ERR, "ioctl(PPPIOCGFLAGS): %m");
560         quit();
561     }
562     x = !accomp? x | SC_REJ_COMP_AC: x &~ SC_REJ_COMP_AC;
563     if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
564         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
565         quit();
566     }
567 }
568
569 /*
570  * ccp_test - ask kernel whether a given compression method
571  * is acceptable for use.
572  */
573 ccp_test(unit, opt_ptr, opt_len, for_transmit)
574     int unit, opt_len, for_transmit;
575     u_char *opt_ptr;
576 {
577     struct ppp_option_data data;
578
579     data.ptr = opt_ptr;
580     data.length = opt_len;
581     data.transmit = for_transmit;
582     return ioctl(fd, PPPIOCSCOMPRESS, (caddr_t) &data) >= 0;
583 }
584
585 /*
586  * ccp_flags_set - inform kernel about the current state of CCP.
587  */
588 void
589 ccp_flags_set(unit, isopen, isup)
590     int unit, isopen, isup;
591 {
592     int x;
593
594     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
595         syslog(LOG_ERR, "ioctl(PPPIOCGFLAGS): %m");
596         return;
597     }
598     x = isopen? x | SC_CCP_OPEN: x &~ SC_CCP_OPEN;
599     x = isup? x | SC_CCP_UP: x &~ SC_CCP_UP;
600     if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0)
601         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
602 }
603
604 /*
605  * ccp_fatal_error - returns 1 if decompression was disabled as a
606  * result of an error detected after decompression of a packet,
607  * 0 otherwise.  This is necessary because of patent nonsense.
608  */
609 int
610 ccp_fatal_error(unit)
611     int unit;
612 {
613     int x;
614
615     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
616         syslog(LOG_ERR, "ioctl(PPPIOCGFLAGS): %m");
617         return 0;
618     }
619     return x & SC_DC_FERROR;
620 }
621
622 /*
623  * sifvjcomp - config tcp header compression
624  */
625 int
626 sifvjcomp(u, vjcomp, cidcomp, maxcid)
627     int u, vjcomp, cidcomp, maxcid;
628 {
629     u_int x;
630
631     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
632         syslog(LOG_ERR, "ioctl(PPIOCGFLAGS): %m");
633         return 0;
634     }
635     x = vjcomp ? x | SC_COMP_TCP: x &~ SC_COMP_TCP;
636     x = cidcomp? x & ~SC_NO_TCP_CCID: x | SC_NO_TCP_CCID;
637     if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
638         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
639         return 0;
640     }
641     if (ioctl(fd, PPPIOCSMAXCID, (caddr_t) &maxcid) < 0) {
642         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
643         return 0;
644     }
645     return 1;
646 }
647
648 /*
649  * sifup - Config the interface up and enable IP packets to pass.
650  */
651 #ifndef SC_ENABLE_IP
652 #define SC_ENABLE_IP    0x100   /* compat for old versions of kernel code */
653 #endif
654
655 int
656 sifup(u)
657     int u;
658 {
659     struct ifreq ifr;
660     u_int x;
661     struct npioctl npi;
662
663     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
664     if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
665         syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
666         return 0;
667     }
668     ifr.ifr_flags |= IFF_UP;
669     if (ioctl(sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
670         syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
671         return 0;
672     }
673     npi.protocol = PPP_IP;
674     npi.mode = NPMODE_PASS;
675     if (ioctl(fd, PPPIOCSNPMODE, &npi) < 0) {
676         if (errno != ENOTTY) {
677             syslog(LOG_ERR, "ioctl(PPPIOCSNPMODE): %m");
678             return 0;
679         }
680         /* for backwards compatibility */
681         if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
682             syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
683             return 0;
684         }
685         x |= SC_ENABLE_IP;
686         if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
687             syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
688             return 0;
689         }
690     }
691     return 1;
692 }
693
694 /*
695  * sifdown - Config the interface down and disable IP.
696  */
697 int
698 sifdown(u)
699     int u;
700 {
701     struct ifreq ifr;
702     u_int x;
703     int rv;
704     struct npioctl npi;
705
706     rv = 1;
707     npi.protocol = PPP_IP;
708     npi.mode = NPMODE_ERROR;
709     if (ioctl(fd, PPPIOCSNPMODE, (caddr_t) &npi) < 0) {
710         if (errno != ENOTTY) {
711             syslog(LOG_ERR, "ioctl(PPPIOCSNPMODE): %m");
712             rv = 0;
713         } else {
714             /* backwards compatibility */
715             if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
716                 syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
717                 rv = 0;
718             } else {
719                 x &= ~SC_ENABLE_IP;
720                 if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
721                     syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
722                     rv = 0;
723                 }
724             }
725         }
726     }
727
728     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
729     if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
730         syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
731         rv = 0;
732     } else {
733         ifr.ifr_flags &= ~IFF_UP;
734         if (ioctl(sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
735             syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
736             rv = 0;
737         }
738     }
739     return rv;
740 }
741
742 /*
743  * SET_SA_FAMILY - set the sa_family field of a struct sockaddr,
744  * if it exists.
745  */
746 #define SET_SA_FAMILY(addr, family)             \
747     BZERO((char *) &(addr), sizeof(addr));      \
748     addr.sa_family = (family); 
749
750 /*
751  * sifaddr - Config the interface IP addresses and netmask.
752  */
753 int
754 sifaddr(u, o, h, m)
755     int u;
756     u_int32_t o, h, m;
757 {
758     int ret;
759     struct ifreq ifr;
760
761     ret = 1;
762     strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
763     SET_SA_FAMILY(ifr.ifr_addr, AF_INET);
764     ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = o;
765     if (ioctl(sockfd, SIOCSIFADDR, (caddr_t) &ifr) < 0) {
766         syslog(LOG_ERR, "ioctl(SIOCAIFADDR): %m");
767         ret = 0;
768     }
769     ((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr = h;
770     if (ioctl(sockfd, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) {
771         syslog(LOG_ERR, "ioctl(SIOCSIFDSTADDR): %m");
772         ret = 0;
773     }
774     if (m != 0) {
775         ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = m;
776         syslog(LOG_INFO, "Setting interface mask to %s\n", ip_ntoa(m));
777         if (ioctl(sockfd, SIOCSIFNETMASK, (caddr_t) &ifr) < 0) {
778             syslog(LOG_ERR, "ioctl(SIOCSIFNETMASK): %m");
779             ret = 0;
780         }
781     }
782     return ret;
783 }
784
785 /*
786  * cifaddr - Clear the interface IP addresses, and delete routes
787  * through the interface if possible.
788  *
789  * N.B.: under NextStep, you can't *delete* an address on an interface,
790  * so we change it to 0.0.0.0...  A real hack.  But it simplifies
791  * reconnection on the server side.
792  */
793 int
794 cifaddr(u, o, h)
795     int u;
796     u_int32_t o, h;
797 {
798     struct rtentry rt;
799
800 #if 1
801     h = o = 0L;
802     (void) sifaddr(u, o, h, 0L);
803 #endif
804     SET_SA_FAMILY(rt.rt_dst, AF_INET);
805     ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = h;
806     SET_SA_FAMILY(rt.rt_gateway, AF_INET);
807     ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = o;
808     rt.rt_flags = RTF_HOST;
809     if (ioctl(sockfd, SIOCDELRT, (caddr_t) &rt) < 0) {
810         syslog(LOG_ERR, "ioctl(SIOCDELRT): %m");
811         return 0;
812     }
813     return 1;
814 }
815
816 /*
817  * sifdefaultroute - assign a default route through the address given.
818  */
819 int
820 sifdefaultroute(u, g)
821     int u;
822     u_int32_t g;
823 {
824     return dodefaultroute(g, 's');
825 }
826
827 /*
828  * cifdefaultroute - delete a default route through the address given.
829  */
830 int
831 cifdefaultroute(u, g)
832     int u;
833     u_int32_t g;
834 {
835     return dodefaultroute(g, 'c');
836 }
837
838 /*
839  * dodefaultroute - talk to a routing socket to add/delete a default route.
840  */
841 int
842 dodefaultroute(g, cmd)
843     u_int32_t g;
844     int cmd;
845 {
846     struct rtentry rt;
847
848     SET_SA_FAMILY(rt.rt_dst, AF_INET);
849     ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = 0L;
850     SET_SA_FAMILY(rt.rt_gateway, AF_INET);
851     ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g;
852     rt.rt_flags = RTF_GATEWAY;
853     if (ioctl(sockfd, (cmd == 's') ? SIOCADDRT : SIOCDELRT, &rt) < 0) {
854         syslog(LOG_ERR, "%cifdefaultroute: ioctl(%s): %m", cmd,
855                (cmd == 's') ? "SIOCADDRT" : "SIOCDELRT");
856         return 0;
857     }
858     return 1;
859 }
860
861 /*
862  * sifproxyarp - Make a proxy ARP entry for the peer.
863  */
864 int
865 sifproxyarp(unit, hisaddr)
866     int unit;
867     u_int32_t hisaddr;
868 {
869     struct arpreq arpreq;
870
871     BZERO(&arpreq, sizeof(arpreq));
872
873     /*
874      * Get the hardware address of an interface on the same subnet
875      * as our local address.
876      */
877     if (!get_ether_addr(hisaddr, &arpreq.arp_ha)) {
878         syslog(LOG_ERR, "Cannot determine ethernet address for proxy ARP");
879         return 0;
880     }
881
882     SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
883     ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
884     arpreq.arp_flags = ATF_PERM | ATF_PUBL;
885     if (ioctl(sockfd, SIOCSARP, (caddr_t)&arpreq) < 0) {
886         syslog(LOG_ERR, "ioctl(SIOCSARP): %m");
887         return 0;
888     }
889
890     return 1;
891 }
892
893 /*
894  * cifproxyarp - Delete the proxy ARP entry for the peer.
895  */
896 int
897 cifproxyarp(unit, hisaddr)
898     int unit;
899     u_int32_t hisaddr;
900 {
901     struct arpreq arpreq;
902
903     BZERO(&arpreq, sizeof(arpreq));
904     SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
905     ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
906     if (ioctl(sockfd, SIOCDARP, (caddr_t)&arpreq) < 0) {
907         syslog(LOG_WARNING, "ioctl(SIOCDARP): %m");
908         return 0;
909     }
910     return 1;
911 }
912
913 /*
914  * get_ether_addr - get the hardware address of an interface on the
915  * the same subnet as ipaddr.
916  */
917 #define MAX_IFS         32
918
919 int
920 get_ether_addr(ipaddr, hwaddr)
921     u_int32_t ipaddr;
922     struct sockaddr *hwaddr;
923 {
924     struct ifreq *ifr, *ifend, *ifp;
925     u_int32_t ina, mask;
926     struct ether_addr dla;
927     struct ifreq ifreq;
928     struct ifconf ifc;
929     struct ifreq ifs[MAX_IFS];
930     struct hostent *hostent;
931
932     ifc.ifc_len = sizeof(ifs);
933     ifc.ifc_req = ifs;
934     if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
935         syslog(LOG_ERR, "ioctl(SIOCGIFCONF): %m");
936         return 0;
937     }
938
939     /*
940      * Scan through looking for an interface with an Internet
941      * address on the same subnet as `ipaddr'.
942      */
943     ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
944     for (ifr = ifc.ifc_req; ifr < ifend; ifr = (struct ifreq *)
945                 ((char *)&ifr->ifr_addr + sizeof(struct sockaddr))) {
946         if (ifr->ifr_addr.sa_family == AF_INET) {
947             ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
948             strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
949             /*
950              * Check that the interface is up, and not point-to-point
951              * or loopback.
952              */
953             if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0)
954                 continue;
955             if ((ifreq.ifr_flags &
956                  (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
957                  != (IFF_UP|IFF_BROADCAST))
958                 continue;
959             /*
960              * Get its netmask and check that it's on the right subnet.
961              */
962             if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0)
963                 continue;
964             mask = ((struct sockaddr_in*)&ifreq.ifr_addr)->sin_addr.s_addr;
965             if ((ipaddr & mask) != (ina & mask))
966                 continue;
967
968             break;
969         }
970     }
971
972     if (ifr >= ifend)
973         return 0;
974     syslog(LOG_INFO, "found interface %s for proxy arp", ifr->ifr_name);
975
976     /*
977      * Get the hostname and look for an entry using the ethers database.
978      * Under NeXTStep this is the best we can do for now.
979      */
980     if ((hostent = gethostbyaddr((char*)&ina, sizeof(ina), AF_INET)) == NULL)
981         return 0;
982
983     if (ether_by_host(hostent->h_name, &dla)) {
984         syslog(LOG_INFO, "Add entry for %s in /etc/ethers", hostent->h_name);
985         return 0;       /* it's not there */
986     }
987     hwaddr->sa_family = AF_UNSPEC;
988     BCOPY(&dla, hwaddr->sa_data, sizeof(dla));
989     return 1;
990 }
991
992 int
993 ether_by_host(hostname, etherptr)
994     char *hostname;
995     struct ether_addr *etherptr;
996 {
997     struct ether_addr *thisptr;
998     void *conn;
999     ni_id root;
1000     ni_namelist val;
1001     char path[256];
1002
1003     if (!ether_hostton(hostname, etherptr))
1004         return 0;
1005     /*
1006      * We shall now try and
1007      * find the address in the
1008      * top domain of netinfo.
1009      */
1010     strcat(strcpy(path, "/machines/"), hostname);
1011
1012     if (ni_open((void *)0, "/", &conn)
1013      || ni_root(conn, &root)
1014      || ni_pathsearch(conn, &root, path)
1015      || ni_lookupprop(conn, &root, "en_address", &val))
1016         return 1;
1017
1018     /*
1019      * Now we can convert the returned string into an ethernet address.
1020      */
1021     strcpy(path, val.ni_namelist_val[0]);
1022     ni_free(conn);
1023     if ((thisptr = (struct ether_addr*)ether_aton(path)) == NULL)
1024         return 1;
1025     BCOPY(thisptr, etherptr, sizeof(struct ether_addr));
1026     return 0;
1027 }
1028
1029
1030
1031 /*
1032  * Return user specified netmask, modified by any mask we might determine
1033  * for address `addr' (in network byte order).
1034  * Here we scan through the system's list of interfaces, looking for
1035  * any non-point-to-point interfaces which might appear to be on the same
1036  * network as `addr'.  If we find any, we OR in their netmask to the
1037  * user-specified netmask.
1038  */
1039 u_int32_t
1040 GetMask(addr)
1041     u_int32_t addr;
1042 {
1043     u_int32_t mask, nmask, ina;
1044     struct ifreq *ifr, *ifend, ifreq;
1045     struct ifconf ifc;
1046     struct ifreq ifs[MAX_IFS];
1047
1048     addr = ntohl(addr);
1049     if (IN_CLASSA(addr))        /* determine network mask for address class */
1050         nmask = IN_CLASSA_NET;
1051     else if (IN_CLASSB(addr))
1052         nmask = IN_CLASSB_NET;
1053     else
1054         nmask = IN_CLASSC_NET;
1055     /* class D nets are disallowed by bad_ip_adrs */
1056     mask = netmask | htonl(nmask);
1057
1058     /*
1059      * Scan through the system's network interfaces.
1060      */
1061     ifc.ifc_len = sizeof(ifs);
1062     ifc.ifc_req = ifs;
1063     if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
1064         syslog(LOG_WARNING, "ioctl(SIOCGIFCONF): %m");
1065         return mask;
1066     }
1067     ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
1068     for (ifr = ifc.ifc_req; ifr < ifend; ifr = (struct ifreq *)
1069                 ((char *)&ifr->ifr_addr + sizeof(struct sockaddr))) {
1070         /*
1071          * Check the interface's internet address.
1072          */
1073         if (ifr->ifr_addr.sa_family != AF_INET)
1074             continue;
1075         ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
1076         if ((ntohl(ina) & nmask) != (addr & nmask))
1077             continue;
1078         /*
1079          * Check that the interface is up, and not point-to-point or loopback.
1080          */
1081         strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
1082         if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0)
1083             continue;
1084         if ((ifreq.ifr_flags & (IFF_UP|IFF_POINTOPOINT|IFF_LOOPBACK))
1085             != IFF_UP)
1086             continue;
1087         /*
1088          * Get its netmask and OR it into our mask.
1089          */
1090         if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0)
1091             continue;
1092         mask |= ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr.s_addr;
1093     }
1094
1095     return mask;
1096 }
1097
1098
1099
1100 /*
1101  * daemon - Detach us from the terminal session.
1102  */
1103 int
1104 daemon(nochdir, noclose)
1105     int nochdir, noclose;
1106 {
1107     int pid;
1108
1109     if ((pid = fork()) < 0)
1110         return -1;
1111     if (pid != 0)
1112         exit(0);                /* parent dies */
1113     (void)setsid();
1114     if (!nochdir)
1115         chdir("/");
1116     if (!noclose) {
1117         fclose(stdin);          /* don't need stdin, stdout, stderr */
1118         fclose(stdout);
1119         fclose(stderr);
1120     }
1121     return 0;
1122 }
1123
1124
1125 char *
1126 strdup(s)
1127     const char *s;
1128 {
1129     char *d = malloc(strlen(s) + 1);
1130
1131     if (d) strcpy(d, s);
1132     return d;
1133 }
1134
1135 /*
1136  * This logwtmp() implementation is subject to the following copyright:
1137  *
1138  * Copyright (c) 1988 The Regents of the University of California.
1139  * All rights reserved.
1140  *
1141  * Redistribution and use in source and binary forms are permitted
1142  * provided that the above copyright notice and this paragraph are
1143  * duplicated in all such forms and that any documentation,
1144  * advertising materials, and other materials related to such
1145  * distribution and use acknowledge that the software was developed
1146  * by the University of California, Berkeley.  The name of the
1147  * University may not be used to endorse or promote products derived
1148  * from this software without specific prior written permission.
1149  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1150  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1151  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1152  */
1153
1154 #define WTMPFILE        "/usr/adm/wtmp"
1155
1156 int
1157 logwtmp(line, name, host)
1158     char *line, *name, *host;
1159 {
1160     int fd;
1161     struct stat buf;
1162     struct utmp ut;
1163
1164     if ((fd = open(WTMPFILE, O_WRONLY|O_APPEND, 0)) < 0)
1165         return;
1166     if (!fstat(fd, &buf)) {
1167         (void)strncpy(ut.ut_line, line, sizeof(ut.ut_line));
1168         (void)strncpy(ut.ut_name, name, sizeof(ut.ut_name));
1169         (void)strncpy(ut.ut_host, host, sizeof(ut.ut_host));
1170         (void)time(&ut.ut_time);
1171         if (write(fd, (char *)&ut, sizeof(struct utmp)) != sizeof(struct utmp))
1172             (void)ftruncate(fd, buf.st_size);
1173     }
1174     close(fd);
1175 }
1176
1177 /*
1178  * Routines for locking and unlocking the serial device, moved here
1179  * from chat.c.
1180  */
1181
1182 #define LOCK_PREFIX     "/usr/spool/uucp/LCK/LCK.."
1183
1184 /*
1185  * lock - create a lock file for the named device
1186  */
1187 int
1188 lock(dev)
1189     char *dev;
1190 {
1191     int fd, pid, n;
1192     char *p;
1193
1194     if ((p = strrchr(dev, '/')) != NULL)
1195         dev = p + 1;
1196     lock_file = malloc(strlen(LOCK_PREFIX) + strlen(dev) + 1);
1197     if (lock_file == NULL)
1198         novm("lock file name");
1199     strcat(strcpy(lock_file, LOCK_PREFIX), dev);
1200
1201     while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) {
1202         if (errno == EEXIST
1203             && (fd = open(lock_file, O_RDONLY, 0)) >= 0) {
1204             /* Read the lock file to find out who has the device locked */
1205             n = read(fd, &pid, sizeof(pid));
1206             if (n <= 0) {
1207                 syslog(LOG_ERR, "Can't read pid from lock file %s", lock_file);
1208                 close(fd);
1209             } else {
1210                 if (kill(pid, 0) == -1 && errno == ESRCH) {
1211                     /* pid no longer exists - remove the lock file */
1212                     if (unlink(lock_file) == 0) {
1213                         close(fd);
1214                         syslog(LOG_NOTICE, "Removed stale lock on %s (pid %d)",
1215                                dev, pid);
1216                         continue;
1217                     } else
1218                         syslog(LOG_WARNING, "Couldn't remove stale lock on %s",
1219                                dev);
1220                 } else
1221                     syslog(LOG_NOTICE, "Device %s is locked by pid %d",
1222                            dev, pid);
1223             }
1224             close(fd);
1225         } else
1226             syslog(LOG_ERR, "Can't create lock file %s: %m", lock_file);
1227         free(lock_file);
1228         lock_file = NULL;
1229         return -1;
1230     }
1231
1232     pid = getpid();
1233     write(fd, &pid, sizeof pid);
1234
1235     close(fd);
1236     return 0;
1237 }
1238
1239 /*
1240  * unlock - remove our lockfile
1241  */
1242 void
1243 unlock()
1244 {
1245     if (lock_file) {
1246         unlink(lock_file);
1247         free(lock_file);
1248         lock_file = NULL;
1249     }
1250 }
1251
1252 #if defined(i386) && defined(HAS_BROKEN_IOCTL)
1253 int
1254 ioctl(fd, cmd, c)
1255     int fd, cmd;
1256     caddr_t c;
1257 {
1258 #undef  ioctl
1259     int ret;
1260
1261 #ifdef DEBUGIOCTL
1262     int serrno;
1263     u_char let, code, size;
1264
1265     size = (cmd >> 16) & IOCPARM_MASK;
1266     let = (cmd >> 8);
1267     code = cmd;
1268
1269     if (let == 't' && (75 <= code && code <= 90))
1270     syslog(LOG_INFO, "ioctl(%d, 0x%x ('%c', %d, %d), 0x%x)\n", fd, cmd,
1271            let, code, size, c);
1272 #endif
1273
1274     ret = ioctl(fd, cmd, c);
1275
1276 #ifdef DEBUGIOCTL
1277     serrno = errno;
1278     if (ret == -1)
1279         syslog(LOG_INFO, "ioctl('%c', %d, %d) errno = %d (%m)\n",
1280                 let, code, size, errno);
1281     if (let == 't' && (75 <= code && code <= 90) && (cmd & IOC_OUT)) {
1282         int i, len = ((cmd >> 16) & IOCPARM_MASK);
1283         for (i = 0; i < len / 4; ++i)
1284                 syslog(LOG_INFO, "word[%d] @ 0x%06x = 0x%x\n",
1285                        i, &((int *) c)[i],((int *)c)[i]);
1286     }
1287     errno = serrno;
1288 #endif
1289
1290     if (ret == -1 && errno == EPERM)
1291         errno = ret = 0;
1292     return ret;
1293 }
1294 #endif  /* HAS_BROKEN_IOCTL */
1295
1296
1297 #if defined(FIXSIGS) && (defined (hppa) || defined(sparc))
1298
1299 /*
1300  * These redefinitions of Posix functions are necessary
1301  * because HPPA systems have an OS bug that causes 
1302  * sigaction to core dump:
1303  *
1304  * AlainF 9-Nov-1994    HACK FOR HP-PA/NEXTSTEP
1305  *                      sigaction(3) seems broken in the HP-PA NeXTSTEP 3.2
1306  *                      Posix lib. This causes pppd to SIGBUS at the expiration
1307  *                      of the first timeout (_sigtramp seems to invoke
1308  *                      the SIGALRM handler at an unreasonably low address).
1309  *                      All calls so sigaction(3) have been changed to calls
1310  *                      to sigvec(2) and sigprocmask(SIG_BLOCK,...) to
1311  *                      sigblock(2).
1312  *                      This is kind of a hack, especially since there are
1313  *                      other routines of the Posix lib still used, but
1314  *                      it worked for me.
1315  *
1316  * Dave Hess <David-Hess@net.tamu.edu> noted that 3.3 Sparc seems to
1317  * have the same bug.  Thus this fix has been enabled for SPARC also.
1318  *
1319  *
1320  */
1321
1322 int sigemptyset(sigset_t *mask)
1323 {
1324   *mask = 0;
1325 }
1326
1327 sigaddset(sigset_t *mask, int which_sig)
1328 {
1329   *mask |= sigmask(which_sig);
1330 }
1331
1332
1333 int sigaction(int sig, const struct sigaction *act, struct sigaction *oact)
1334 {
1335    struct sigvec sv;
1336    static int in = 0;
1337
1338    sv.sv_handler = act->sa_handler;
1339    sv.sv_mask = act->sa_mask;
1340    sv.sv_flags = 0;
1341
1342    if (!in)
1343      {
1344        in = 1;
1345        syslog(LOG_WARNING, "PPPD: Inside modified HP and SPARC sigaction\n");
1346      }
1347
1348    return sigvec(sig, &sv, NULL);
1349 }
1350
1351 #endif