]> git.ozlabs.org Git - ppp.git/blob - pppd/sys-ultrix.c
only clear CRTSCTS if -crtscts option given
[ppp.git] / pppd / sys-ultrix.c
1 /*
2  * sys-ultrix.c - System-dependent procedures for setting up
3  * PPP interfaces on Ultrix systems.
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-ultrix.c,v 1.5 1994/09/01 00:39:09 paulus Exp $";
23 #endif
24
25 /*
26  * TODO:
27  */
28
29 #include <stdio.h>
30 #include <syslog.h>
31 #include <termios.h>
32 #include <utmp.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
41 #include <net/if.h>
42
43 #include <net/if_ppp.h>
44 #include <net/route.h>
45 #include <netinet/in.h>
46
47 #include "pppd.h"
48 #include "ppp.h"
49
50 static int initdisc = -1;               /* Initial TTY discipline */
51
52 static int restore_term;        /* 1 => we've munged the terminal */
53 static struct termios inittermios;      /* Initial TTY termios */
54
55 /*
56  * sys_init - System-dependent initialization.
57  */
58 void
59 sys_init()
60 {
61     openlog("pppd", LOG_PID);
62     if (debug)
63         setlogmask(LOG_UPTO(LOG_DEBUG));
64 }
65
66 /*
67  * note_debug_level - note a change in the debug level.
68  */
69 void
70 note_debug_level()
71 {
72     if (debug) {
73         syslog(LOG_INFO, "Debug turned ON, Level %d", debug);
74     }
75 }
76
77 /*
78  * establish_ppp - Turn the serial port into a ppp interface.
79  */
80 void
81 establish_ppp()
82 {
83     int pppdisc = PPPDISC;
84     int x;
85
86     if (ioctl(fd, TIOCGETD, &initdisc) < 0) {
87         syslog(LOG_ERR, "ioctl(TIOCGETD): %m");
88         die(1);
89     }
90     if (ioctl(fd, TIOCSETD, &pppdisc) < 0) {
91         syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
92         die(1);
93     }
94
95     /*
96      * Find out which interface we were given.
97      */
98     if (ioctl(fd, PPPIOCGUNIT, &ifunit) < 0) {  
99         syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m");
100         die(1);
101     }
102
103     /*
104      * Enable debug in the driver if requested.
105      */
106     if (kdebugflag) {
107         if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
108             syslog(LOG_WARNING, "ioctl (PPPIOCGFLAGS): %m");
109         } else {
110             x |= (kdebugflag & 0xFF) * SC_DEBUG;
111             if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0)
112                 syslog(LOG_WARNING, "ioctl(PPPIOCSFLAGS): %m");
113         }
114     }
115 }
116
117
118 /*
119  * disestablish_ppp - Restore the serial port to normal operation.
120  * This shouldn't call die() because it's called from die().
121  */
122 void
123 disestablish_ppp()
124 {
125     int x;
126     char *s;
127
128     if (initdisc >= 0) {
129         /*
130          * Check whether the link seems not to be 8-bit clean.
131          */
132         if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) == 0) {
133             s = NULL;
134             switch (~x & (SC_RCV_B7_0|SC_RCV_B7_1|SC_RCV_EVNP|SC_RCV_ODDP)) {
135             case SC_RCV_B7_0:
136                 s = "bit 7 set to 1";
137                 break;
138             case SC_RCV_B7_1:
139                 s = "bit 7 set to 0";
140                 break;
141             case SC_RCV_EVNP:
142                 s = "odd parity";
143                 break;
144             case SC_RCV_ODDP:
145                 s = "even parity";
146                 break;
147             }
148             if (s != NULL) {
149                 syslog(LOG_WARNING, "Serial link is not 8-bit clean:");
150                 syslog(LOG_WARNING, "All received characters had %s", s);
151             }
152         }
153         if (ioctl(fd, TIOCSETD, &initdisc) < 0)
154             syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
155     }
156 }
157
158
159 /*
160  * List of valid speeds.
161  */
162 struct speed {
163     int speed_int, speed_val;
164 } speeds[] = {
165 #ifdef B50
166     { 50, B50 },
167 #endif
168 #ifdef B75
169     { 75, B75 },
170 #endif
171 #ifdef B110
172     { 110, B110 },
173 #endif
174 #ifdef B134
175     { 134, B134 },
176 #endif
177 #ifdef B150
178     { 150, B150 },
179 #endif
180 #ifdef B200
181     { 200, B200 },
182 #endif
183 #ifdef B300
184     { 300, B300 },
185 #endif
186 #ifdef B600
187     { 600, B600 },
188 #endif
189 #ifdef B1200
190     { 1200, B1200 },
191 #endif
192 #ifdef B1800
193     { 1800, B1800 },
194 #endif
195 #ifdef B2000
196     { 2000, B2000 },
197 #endif
198 #ifdef B2400
199     { 2400, B2400 },
200 #endif
201 #ifdef B3600
202     { 3600, B3600 },
203 #endif
204 #ifdef B4800
205     { 4800, B4800 },
206 #endif
207 #ifdef B7200
208     { 7200, B7200 },
209 #endif
210 #ifdef B9600
211     { 9600, B9600 },
212 #endif
213 #ifdef B19200
214     { 19200, B19200 },
215 #endif
216 #ifdef B38400
217     { 38400, B38400 },
218 #endif
219 #ifdef EXTA
220     { 19200, EXTA },
221 #endif
222 #ifdef EXTB
223     { 38400, EXTB },
224 #endif
225 #ifdef B57600
226     { 57600, B57600 },
227 #endif
228 #ifdef B115200
229     { 115200, B115200 },
230 #endif
231     { 0, 0 }
232 };
233
234 /*
235  * Translate from bits/second to a speed_t.
236  */
237 int
238 translate_speed(bps)
239     int bps;
240 {
241     struct speed *speedp;
242
243     if (bps == 0)
244         return 0;
245     for (speedp = speeds; speedp->speed_int; speedp++)
246         if (bps == speedp->speed_int)
247             return speedp->speed_val;
248     syslog(LOG_WARNING, "speed %d not supported", bps);
249     return 0;
250 }
251
252 /*
253  * Translate from a speed_t to bits/second.
254  */
255 int
256 baud_rate_of(speed)
257     int speed;
258 {
259     struct speed *speedp;
260
261     if (speed == 0)
262         return 0;
263     for (speedp = speeds; speedp->speed_int; speedp++)
264         if (speed == speedp->speed_val)
265             return speedp->speed_int;
266     return 0;
267 }
268
269 /*
270  * set_up_tty: Set up the serial port on `fd' for 8 bits, no parity,
271  * at the requested speed, etc.  If `local' is true, set CLOCAL
272  * regardless of whether the modem option was specified.
273  */
274 set_up_tty(fd, local)
275     int fd, local;
276 {
277     int speed, x;
278     struct termios tios;
279
280     if (tcgetattr(fd, &tios) < 0) {
281         syslog(LOG_ERR, "tcgetattr: %m");
282         die(1);
283     }
284
285     if (!restore_term)
286         inittermios = tios;
287
288 #ifdef CRTSCTS
289     tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL | CRTSCTS);
290     if (crtscts == 1)
291         tios.c_cflag |= CRTSCTS;
292 #else
293     tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
294 #endif  /* CRTSCTS */
295
296     tios.c_cflag |= CS8 | CREAD | HUPCL;
297     if (local || !modem)
298         tios.c_cflag |= CLOCAL;
299     tios.c_iflag = IGNBRK | IGNPAR;
300     tios.c_oflag = 0;
301     tios.c_lflag = 0;
302     tios.c_cc[VMIN] = 1;
303     tios.c_cc[VTIME] = 0;
304
305     if (crtscts == 2) {
306         tios.c_iflag |= IXOFF;
307         tios.c_cc[VSTOP] = 0x13;        /* DC3 = XOFF = ^S */
308         tios.c_cc[VSTART] = 0x11;       /* DC1 = XON  = ^Q */
309     }
310
311     speed = translate_speed(inspeed);
312     if (speed) {
313         cfsetospeed(&tios, speed);
314         cfsetispeed(&tios, speed);
315     } else {
316         speed = cfgetospeed(&tios);
317     }
318
319     if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) {
320         syslog(LOG_ERR, "tcsetattr: %m");
321         die(1);
322     }
323
324     x = 0;
325     if (ioctl(fd, (crtscts || modem)? TIOCMODEM: TIOCNMODEM, &x) < 0)
326         syslog(LOG_WARNING, "TIOC(N)MODEM: %m");
327     if (ioctl(fd, (local || !modem)? TIOCNCAR: TIOCCAR) < 0)
328         syslog(LOG_WARNING, "TIOC(N)CAR: %m");
329
330     baud_rate = inspeed = baud_rate_of(speed);
331     restore_term = TRUE;
332 }
333
334 /*
335  * restore_tty - restore the terminal to the saved settings.
336  */
337 void
338 restore_tty()
339 {
340     if (restore_term) {
341         if (tcsetattr(fd, TCSAFLUSH, &inittermios) < 0)
342             if (errno != ENXIO)
343                 syslog(LOG_WARNING, "tcsetattr: %m");
344         restore_term = FALSE;
345     }
346 }
347
348 /*
349  * setdtr - control the DTR line on the serial port.
350  * This is called from die(), so it shouldn't call die().
351  */
352 setdtr(fd, on)
353 int fd, on;
354 {
355     int modembits = TIOCM_DTR;
356
357     ioctl(fd, (on? TIOCMBIS: TIOCMBIC), &modembits);
358 }
359
360
361 /*
362  * output - Output PPP packet.
363  */
364 void
365 output(unit, p, len)
366     int unit;
367     u_char *p;
368     int len;
369 {
370     if (unit != 0)
371         MAINDEBUG((LOG_WARNING, "output: unit != 0!"));
372     if (debug)
373         log_packet(p, len, "sent ");
374
375     if (write(fd, p, len) < 0) {
376         syslog(LOG_ERR, "write: %m");
377         die(1);
378     }
379 }
380
381
382 /*
383  * wait_input - wait until there is data available on fd,
384  * for the length of time specified by *timo (indefinite
385  * if timo is NULL).
386  */
387 wait_input(timo)
388     struct timeval *timo;
389 {
390     fd_set ready;
391     int n;
392
393     FD_ZERO(&ready);
394     FD_SET(fd, &ready);
395     n = select(fd+1, &ready, NULL, &ready, timo);
396     if (n < 0 && errno != EINTR) {
397         syslog(LOG_ERR, "select: %m");
398         die(1);
399     }
400 }
401
402
403 /*
404  * read_packet - get a PPP packet from the serial device.
405  */
406 int
407 read_packet(buf)
408     u_char *buf;
409 {
410     int len;
411
412     if ((len = read(fd, buf, MTU + DLLHEADERLEN)) < 0) {
413         if (errno == EWOULDBLOCK) {
414             MAINDEBUG((LOG_DEBUG, "read(fd): EWOULDBLOCK"));
415             return -1;
416         }
417         syslog(LOG_ERR, "read(fd): %m");
418         die(1);
419     }
420     return len;
421 }
422
423
424 /*
425  * ppp_send_config - configure the transmit characteristics of
426  * the ppp interface.
427  */
428 void
429 ppp_send_config(unit, mtu, asyncmap, pcomp, accomp)
430     int unit, mtu;
431     uint32 asyncmap;
432     int pcomp, accomp;
433 {
434     u_int x;
435     struct ifreq ifr;
436
437     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
438     ifr.ifr_mtu = mtu;
439     if (ioctl(s, SIOCSIFMTU, (caddr_t) &ifr) < 0) {
440         syslog(LOG_ERR, "ioctl(SIOCSIFMTU): %m");
441         quit();
442     }
443
444     if (ioctl(fd, PPPIOCSASYNCMAP, (caddr_t) &asyncmap) < 0) {
445         syslog(LOG_ERR, "ioctl(PPPIOCSASYNCMAP): %m");
446         quit();
447     }
448
449     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
450         syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
451         quit();
452     }
453     x = pcomp? x | SC_COMP_PROT: x &~ SC_COMP_PROT;
454     x = accomp? x | SC_COMP_AC: x &~ SC_COMP_AC;
455     if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
456         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
457         quit();
458     }
459 }
460
461
462 /*
463  * ppp_set_xaccm - set the extended transmit ACCM for the interface.
464  */
465 void
466 ppp_set_xaccm(unit, accm)
467     int unit;
468     ext_accm accm;
469 {
470     if (ioctl(fd, PPPIOCSXASYNCMAP, accm) < 0 && errno != ENOTTY)
471         syslog(LOG_WARNING, "ioctl(set extended ACCM): %m");
472 }
473
474
475 /*
476  * ppp_recv_config - configure the receive-side characteristics of
477  * the ppp interface.
478  */
479 void
480 ppp_recv_config(unit, mru, asyncmap, pcomp, accomp)
481     int unit, mru;
482     uint32 asyncmap;
483     int pcomp, accomp;
484 {
485     int x;
486
487     if (ioctl(fd, PPPIOCSMRU, (caddr_t) &mru) < 0) {
488         syslog(LOG_ERR, "ioctl(PPPIOCSMRU): %m");
489         quit();
490     }
491     if (ioctl(fd, PPPIOCSRASYNCMAP, (caddr_t) &asyncmap) < 0) {
492         syslog(LOG_ERR, "ioctl(PPPIOCSRASYNCMAP): %m");
493         quit();
494     }
495     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
496         syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
497         quit();
498     }
499     x = !accomp? x | SC_REJ_COMP_AC: x &~ SC_REJ_COMP_AC;
500     if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
501         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
502         quit();
503     }
504 }
505
506 /*
507  * ccp_flags_set - inform kernel about the current state of CCP.
508  */
509 void
510 ccp_flags_set(unit, isopen, isup)
511     int unit, isopen, isup;
512 {
513     int x;
514
515     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
516         syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
517         return;
518     }
519     x = isopen? x | SC_CCP_OPEN: x &~ SC_CCP_OPEN;
520     x = isup? x | SC_CCP_UP: x &~ SC_CCP_UP;
521     if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0)
522         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
523 }
524
525 /*
526  * sifvjcomp - config tcp header compression
527  */
528 int
529 sifvjcomp(u, vjcomp, cidcomp, maxcid)
530     int u, vjcomp, cidcomp, maxcid;
531 {
532     u_int x;
533
534     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
535         syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
536         return 0;
537     }
538     x = vjcomp ? x | SC_COMP_TCP: x &~ SC_COMP_TCP;
539     x = cidcomp? x & ~SC_NO_TCP_CCID: x | SC_NO_TCP_CCID;
540     if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
541         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
542         return 0;
543     }
544     if (ioctl(fd, PPPIOCSMAXCID, (caddr_t) &maxcid) < 0) {
545         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
546         return 0;
547     }
548     return 1;
549 }
550
551 /*
552  * sifup - Config the interface up and enable IP packets to pass.
553  */
554 int
555 sifup(u)
556 {
557     struct ifreq ifr;
558     u_int x;
559
560     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
561     if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
562         syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
563         return 0;
564     }
565     ifr.ifr_flags |= IFF_UP;
566     if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
567         syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
568         return 0;
569     }
570     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
571         syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
572         return 0;
573     }
574     x |= SC_ENABLE_IP;
575     if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
576         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
577         return 0;
578     }
579     return 1;
580 }
581
582 /*
583  * sifdown - Config the interface down and disable IP.
584  */
585 int
586 sifdown(u)
587 {
588     struct ifreq ifr;
589     u_int x;
590     int rv;
591
592     rv = 1;
593     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
594         syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
595         rv = 0;
596     } else {
597         x &= ~SC_ENABLE_IP;
598         if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
599             syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
600             rv = 0;
601         }
602     }
603     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
604     if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
605         syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
606         rv = 0;
607     } else {
608         ifr.ifr_flags &= ~IFF_UP;
609         if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
610             syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
611             rv = 0;
612         }
613     }
614     return rv;
615 }
616
617 /*
618  * SET_SA_FAMILY - set the sa_family field of a struct sockaddr,
619  * if it exists.
620  */
621 #define SET_SA_FAMILY(addr, family)             \
622     BZERO((char *) &(addr), sizeof(addr));      \
623     addr.sa_family = (family); 
624
625 /*
626  * sifaddr - Config the interface IP addresses and netmask.
627  */
628 int
629 sifaddr(u, o, h, m)
630 {
631     int ret;
632     struct ifreq ifr;
633
634     ret = 1;
635     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
636     SET_SA_FAMILY(ifr.ifr_addr, AF_INET);
637     ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = o;
638     if (ioctl(s, SIOCSIFADDR, (caddr_t) &ifr) < 0) {
639         syslog(LOG_ERR, "ioctl(SIOCSIFADDR): %m");
640         ret = 0;
641     }
642     ((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr = h;
643     if (ioctl(s, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) {
644         syslog(LOG_ERR, "ioctl(SIOCSIFDSTADDR): %m");
645         ret = 0;
646     }
647     if (m != 0) {
648         ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = m;
649         syslog(LOG_INFO, "Setting interface mask to %s\n", ip_ntoa(m));
650         if (ioctl(s, SIOCSIFNETMASK, (caddr_t) &ifr) < 0) {
651             syslog(LOG_ERR, "ioctl(SIOCSIFNETMASK): %m");
652             ret = 0;
653         }
654     }
655     return ret;
656 }
657
658 /*
659  * cifaddr - Clear the interface IP addresses, and delete routes
660  * through the interface if possible.
661  */
662 int
663 cifaddr(u, o, h)
664 {
665     struct rtentry rt;
666
667     SET_SA_FAMILY(rt.rt_dst, AF_INET);
668     ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = h;
669     SET_SA_FAMILY(rt.rt_gateway, AF_INET);
670     ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = o;
671     rt.rt_flags = RTF_HOST;
672     if (ioctl(s, SIOCDELRT, (caddr_t) &rt) < 0) {
673         syslog(LOG_ERR, "ioctl(SIOCDELRT): %m");
674         return 0;
675     }
676     return 1;
677 }
678
679 /*
680  * sifdefaultroute - assign a default route through the address given.
681  */
682 int
683 sifdefaultroute(u, g)
684 {
685     struct rtentry rt;
686
687     SET_SA_FAMILY(rt.rt_dst, AF_INET);
688     SET_SA_FAMILY(rt.rt_gateway, AF_INET);
689     ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g;
690     rt.rt_flags = RTF_GATEWAY;
691     if (ioctl(s, SIOCADDRT, &rt) < 0) {
692         syslog(LOG_ERR, "default route ioctl(SIOCADDRT): %m");
693         return 0;
694     }
695     return 1;
696 }
697
698 /*
699  * cifdefaultroute - delete a default route through the address given.
700  */
701 int
702 cifdefaultroute(u, g)
703 {
704     struct rtentry rt;
705
706     SET_SA_FAMILY(rt.rt_dst, AF_INET);
707     SET_SA_FAMILY(rt.rt_gateway, AF_INET);
708     ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g;
709     rt.rt_flags = RTF_GATEWAY;
710     if (ioctl(s, SIOCDELRT, &rt) < 0)
711         syslog(LOG_WARNING, "default route ioctl(SIOCDELRT): %m");
712 }
713
714 /*
715  * sifproxyarp - Make a proxy ARP entry for the peer.
716  */
717 int
718 sifproxyarp(unit, hisaddr)
719     int unit;
720     uint32 hisaddr;
721 {
722     struct arpreq arpreq;
723
724     BZERO(&arpreq, sizeof(arpreq));
725
726     /*
727      * Get the hardware address of an interface on the same subnet
728      * as our local address.
729      */
730     if (!get_ether_addr(hisaddr, &arpreq.arp_ha)) {
731         syslog(LOG_ERR, "Cannot determine ethernet address for proxy ARP");
732         return 0;
733     }
734
735     SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
736     ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
737     arpreq.arp_flags = ATF_PERM | ATF_PUBL;
738     if (ioctl(s, SIOCSARP, (caddr_t)&arpreq) < 0) {
739         syslog(LOG_ERR, "ioctl(SIOCSARP): %m");
740         return 0;
741     }
742
743     return 1;
744 }
745
746 /*
747  * cifproxyarp - Delete the proxy ARP entry for the peer.
748  */
749 int
750 cifproxyarp(unit, hisaddr)
751     int unit;
752     uint32 hisaddr;
753 {
754     struct arpreq arpreq;
755
756     BZERO(&arpreq, sizeof(arpreq));
757     SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
758     ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
759     if (ioctl(s, SIOCDARP, (caddr_t)&arpreq) < 0) {
760         syslog(LOG_WARNING, "ioctl(SIOCDARP): %m");
761         return 0;
762     }
763     return 1;
764 }
765
766 /*
767  * get_ether_addr - get the hardware address of an interface on the
768  * the same subnet as ipaddr.
769  */
770 #define MAX_IFS         32
771
772 int
773 get_ether_addr(ipaddr, hwaddr)
774     uint32 ipaddr;
775     struct sockaddr *hwaddr;
776 {
777     struct ifreq *ifr, *ifend, *ifp;
778     uint32 ina, mask;
779     struct sockaddr_dl *dla;
780     struct ifreq ifreq;
781     struct ifconf ifc;
782     struct ifreq ifs[MAX_IFS];
783
784     ifc.ifc_len = sizeof(ifs);
785     ifc.ifc_req = ifs;
786     if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
787         syslog(LOG_ERR, "ioctl(SIOCGIFCONF): %m");
788         return 0;
789     }
790
791     /*
792      * Scan through looking for an interface with an Internet
793      * address on the same subnet as `ipaddr'.
794      */
795     ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
796     for (ifr = ifc.ifc_req; ifr < ifend; ) {
797         if (ifr->ifr_addr.sa_family == AF_INET) {
798             ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
799             strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
800             /*
801              * Check that the interface is up, and not point-to-point
802              * or loopback.
803              */
804             if (ioctl(s, SIOCGIFFLAGS, &ifreq) < 0)
805                 continue;
806             if ((ifreq.ifr_flags &
807                  (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
808                  != (IFF_UP|IFF_BROADCAST))
809                 continue;
810             /*
811              * Get its netmask and check that it's on the right subnet.
812              */
813             if (ioctl(s, SIOCGIFNETMASK, &ifreq) < 0)
814                 continue;
815             mask = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
816             if ((ipaddr & mask) != (ina & mask))
817                 continue;
818
819             break;
820         }
821         ifr = (struct ifreq *) ((char *)&ifr->ifr_addr + sizeof(struct sockaddr)
822 );
823     }
824
825     if (ifr >= ifend)
826         return 0;
827     syslog(LOG_DEBUG, "found interface %s for proxy arp", ifr->ifr_name);
828
829     /*
830      * Now scan through again looking for a link-level address
831      * for this interface.
832      */
833     ifp = ifr;
834     for (ifr = ifc.ifc_req; ifr < ifend; ) {
835         if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0
836             && ifr->ifr_addr.sa_family == AF_DLI) {
837 /*          && ifr->ifr_addr.sa_family == AF_LINK) { Per! Kolla !!! ROHACK */
838             /*
839              * Found the link-level address - copy it out
840              */
841             dla = (struct sockaddr_dl *)&ifr->ifr_addr;
842             hwaddr->sa_family = AF_UNSPEC;
843             BCOPY(dla, hwaddr->sa_data, sizeof(hwaddr->sa_data));
844             return 1;
845         }
846         ifr = (struct ifreq *) ((char *)&ifr->ifr_addr + sizeof(struct sockaddr)
847 );
848     }
849
850     return 0;
851 }
852
853
854 /*
855  * ppp_available - check whether the system has any ppp interfaces
856  * (in fact we check whether we can do an ioctl on ppp0).
857  */
858
859 int
860 ppp_available()
861 {
862     int s, ok;
863     struct ifreq ifr;
864
865     if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
866         return 1;               /* can't tell - maybe we're not root */
867
868     strncpy(ifr.ifr_name, "ppp0", sizeof (ifr.ifr_name));
869     ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 0;
870     close(s);
871
872     return ok;
873 }
874
875
876 /*
877   Seems like strdup() is not part of string package in Ultrix.
878   If I understood the man-page on the sun this should work.
879
880   Robert Olsson
881 */
882
883 char *strdup( in ) char *in;
884 {
885   char* dup;
886   if(! (dup = (char *) malloc( strlen( in ) +1 ))) return NULL;
887   (void) strcpy( dup, in );
888   return dup;
889 }
890
891 /*
892  * This logwtmp() implementation is subject to the following copyright:
893  *
894  * Copyright (c) 1988 The Regents of the University of California.
895  * All rights reserved.
896  *
897  * Redistribution and use in source and binary forms are permitted
898  * provided that the above copyright notice and this paragraph are
899  * duplicated in all such forms and that any documentation,
900  * advertising materials, and other materials related to such
901  * distribution and use acknowledge that the software was developed
902  * by the University of California, Berkeley.  The name of the
903  * University may not be used to endorse or promote products derived
904  * from this software without specific prior written permission.
905  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
906  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
907  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
908  */
909
910 #define WTMPFILE        "/usr/adm/wtmp"
911
912 int
913 logwtmp(line, name, host)
914     char *line, *name, *host;
915 {
916     int fd;
917     struct stat buf;
918     struct utmp ut;
919
920     if ((fd = open(WTMPFILE, O_WRONLY|O_APPEND, 0)) < 0)
921         return;
922     if (!fstat(fd, &buf)) {
923         (void)strncpy(ut.ut_line, line, sizeof(ut.ut_line));
924         (void)strncpy(ut.ut_name, name, sizeof(ut.ut_name));
925         (void)strncpy(ut.ut_host, host, sizeof(ut.ut_host));
926         (void)time(&ut.ut_time);
927         if (write(fd, (char *)&ut, sizeof(struct utmp)) != sizeof(struct utmp))
928             (void)ftruncate(fd, buf.st_size);
929     }
930     close(fd);
931 }