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