2 * System-dependent procedures for pppd under SunOS 4.
4 * Copyright (c) 1994 The Australian National University.
7 * Permission to use, copy, modify, and distribute this software and its
8 * documentation is hereby granted, provided that the above copyright
9 * notice appears in all copies. This software is provided without any
10 * warranty, express or implied. The Australian National University
11 * makes no representations about the suitability of this software for
14 * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
15 * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
16 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
17 * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
20 * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
21 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
22 * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
23 * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
24 * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
29 static char rcsid
[] = "$Id: sys-sunos4.c,v 1.9 1998/03/25 02:19:29 paulus Exp $";
44 #include <sys/types.h>
45 #include <sys/param.h>
46 #include <sys/socket.h>
47 #include <sys/sockio.h>
48 #include <sys/stream.h>
49 #include <sys/stropts.h>
50 #include <sys/syslog.h>
55 #include <net/if_arp.h>
56 #include <net/nit_if.h>
57 #include <net/route.h>
58 #include <net/ppp_defs.h>
59 #include <net/pppio.h>
60 #include <netinet/in.h>
64 #if defined(sun) && defined(sparc)
67 extern void *alloca();
72 static int fdmuxid
= -1;
76 static int restore_term
;
77 static struct termios inittermios
;
78 static struct winsize wsinfo
; /* Initial window size info */
79 static pid_t parent_pid
; /* PID of our parent */
81 extern u_char inpacket_buf
[]; /* borrowed from main.c */
83 static int link_mtu
, link_mru
;
86 static int tty_nmodules
;
87 static char tty_modules
[NMODULES
][FMNAMESZ
+1];
89 static int if_is_up
; /* Interface has been marked up */
90 static u_int32_t ifaddrs
[2]; /* local and remote addresses */
91 static u_int32_t default_route_gateway
; /* Gateway for default route added */
92 static u_int32_t proxy_arp_addr
; /* Addr for proxy arp entry added */
94 /* Prototypes for procedures local to this file. */
95 static int translate_speed
__P((int));
96 static int baud_rate_of
__P((int));
97 static int get_ether_addr
__P((u_int32_t
, struct sockaddr
*));
98 static int strioctl
__P((int, int, void *, int, int));
102 * sys_init - System-dependent initialization.
109 /* Get an internet socket for doing socket ioctl's on. */
110 if ((sockfd
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
111 syslog(LOG_ERR
, "Couldn't create IP socket: %m");
116 * We may want to send a SIGHUP to the session leader associated
117 * with our controlling terminal later. Because SunOS doesn't
118 * have getsid(), we make do with sending the signal to our
121 parent_pid
= getppid();
124 * Open the ppp device.
126 pppfd
= open("/dev/ppp", O_RDWR
| O_NONBLOCK
, 0);
128 syslog(LOG_ERR
, "Can't open /dev/ppp: %m");
132 x
= PPPDBG_LOG
+ PPPDBG_DRIVER
;
133 strioctl(pppfd
, PPPIO_DEBUG
, &x
, sizeof(int), 0);
136 /* Assign a new PPA and get its unit number. */
137 if (strioctl(pppfd
, PPPIO_NEWPPA
, &ifunit
, 0, sizeof(int)) < 0) {
138 syslog(LOG_ERR
, "Can't create new PPP interface: %m");
143 * Open the ppp device again and push the if_ppp module on it.
145 iffd
= open("/dev/ppp", O_RDWR
, 0);
147 syslog(LOG_ERR
, "Can't open /dev/ppp (2): %m");
151 x
= PPPDBG_LOG
+ PPPDBG_DRIVER
;
152 strioctl(iffd
, PPPIO_DEBUG
, &x
, sizeof(int), 0);
154 if (strioctl(iffd
, PPPIO_ATTACH
, &ifunit
, sizeof(int), 0) < 0) {
155 syslog(LOG_ERR
, "Couldn't attach ppp interface to device: %m");
158 if (ioctl(iffd
, I_PUSH
, "if_ppp") < 0) {
159 syslog(LOG_ERR
, "Can't push ppp interface module: %m");
163 x
= PPPDBG_LOG
+ PPPDBG_IF
;
164 strioctl(iffd
, PPPIO_DEBUG
, &x
, sizeof(int), 0);
166 if (strioctl(iffd
, PPPIO_NEWPPA
, &ifunit
, sizeof(int), 0) < 0) {
167 syslog(LOG_ERR
, "Couldn't create ppp interface unit: %m");
171 if (strioctl(iffd
, PPPIO_BIND
, &x
, sizeof(int), 0) < 0) {
172 syslog(LOG_ERR
, "Couldn't bind ppp interface to IP SAP: %m");
178 * sys_cleanup - restore any system state we modified before exiting:
179 * mark the interface down, delete default route and/or proxy arp entry.
180 * This shouldn't call die() because it's called from die().
188 cifaddr(0, ifaddrs
[0], ifaddrs
[1]);
189 if (default_route_gateway
)
190 cifdefaultroute(0, 0, default_route_gateway
);
192 cifproxyarp(0, proxy_arp_addr
);
196 * sys_close - Clean up in a child process before execing.
207 * sys_check_options - check the options that the user specified
216 * daemon - Detach us from controlling terminal session.
219 daemon(nochdir
, noclose
)
220 int nochdir
, noclose
;
224 if ((pid
= fork()) < 0)
227 exit(0); /* parent dies */
232 fclose(stdin
); /* don't need stdin, stdout, stderr */
240 * ppp_available - check whether the system has any ppp interfaces
247 return stat("/dev/ppp", &buf
) >= 0;
251 * establish_ppp - Turn the serial port into a ppp interface.
259 /* Pop any existing modules off the tty stream. */
261 if (ioctl(fd
, I_LOOK
, tty_modules
[i
]) < 0
262 || ioctl(fd
, I_POP
, 0) < 0)
266 /* Push the async hdlc module and the compressor module. */
267 if (ioctl(fd
, I_PUSH
, "ppp_ahdl") < 0) {
268 syslog(LOG_ERR
, "Couldn't push PPP Async HDLC module: %m");
271 if (ioctl(fd
, I_PUSH
, "ppp_comp") < 0) {
272 syslog(LOG_ERR
, "Couldn't push PPP compression module: %m");
276 /* Link the serial port under the PPP multiplexor. */
277 if ((fdmuxid
= ioctl(pppfd
, I_LINK
, fd
)) < 0) {
278 syslog(LOG_ERR
, "Can't link tty to PPP mux: %m");
284 * restore_loop - reattach the ppp unit to the loopback.
285 * This doesn't need to do anything because disestablish_ppp does it.
293 * disestablish_ppp - Restore the serial port to normal operation.
294 * It attempts to reconstruct the stream with the previously popped
295 * modules. This shouldn't call die() because it's called from die().
304 if (ioctl(pppfd
, I_UNLINK
, fdmuxid
) < 0) {
306 syslog(LOG_ERR
, "Can't unlink tty from PPP mux: %m");
311 while (ioctl(fd
, I_POP
, 0) >= 0)
313 for (i
= tty_nmodules
- 1; i
>= 0; --i
)
314 if (ioctl(fd
, I_PUSH
, tty_modules
[i
]) < 0)
315 syslog(LOG_ERR
, "Couldn't restore tty module %s: %m",
318 if (hungup
&& default_device
&& parent_pid
> 0) {
320 * If we have received a hangup, we need to send a SIGHUP
321 * to the terminal's controlling process. The reason is
322 * that the original stream head for the terminal hasn't
323 * seen the M_HANGUP message (it went up through the ppp
324 * driver to the stream head for our fd to /dev/ppp).
325 * Actually we send the signal to the process that invoked
326 * pppd, since SunOS doesn't have getsid().
328 kill(parent_pid
, SIGHUP
);
334 * Check whether the link seems not to be 8-bit clean.
342 if (strioctl(pppfd
, PPPIO_GCLEAN
, &x
, 0, sizeof(x
)) < 0)
347 s
= "bit 7 set to 1";
350 s
= "bit 7 set to 0";
360 syslog(LOG_WARNING
, "Serial link is not 8-bit clean:");
361 syslog(LOG_WARNING
, "All received characters had %s", s
);
366 * List of valid speeds.
369 int speed_int
, speed_val
;
441 * Translate from bits/second to a speed_t.
447 struct speed
*speedp
;
451 for (speedp
= speeds
; speedp
->speed_int
; speedp
++)
452 if (bps
== speedp
->speed_int
)
453 return speedp
->speed_val
;
454 syslog(LOG_WARNING
, "speed %d not supported", bps
);
459 * Translate from a speed_t to bits/second.
465 struct speed
*speedp
;
469 for (speedp
= speeds
; speedp
->speed_int
; speedp
++)
470 if (speed
== speedp
->speed_val
)
471 return speedp
->speed_int
;
476 * set_up_tty: Set up the serial port on `fd' for 8 bits, no parity,
477 * at the requested speed, etc. If `local' is true, set CLOCAL
478 * regardless of whether the modem option was specified.
481 set_up_tty(fd
, local
)
487 if (tcgetattr(fd
, &tios
) < 0) {
488 syslog(LOG_ERR
, "tcgetattr: %m");
494 ioctl(fd
, TIOCGWINSZ
, &wsinfo
);
497 tios
.c_cflag
&= ~(CSIZE
| CSTOPB
| PARENB
| CLOCAL
);
499 tios
.c_cflag
|= CRTSCTS
;
500 else if (crtscts
< 0)
501 tios
.c_cflag
&= ~CRTSCTS
;
503 tios
.c_cflag
|= CS8
| CREAD
| HUPCL
;
505 tios
.c_cflag
|= CLOCAL
;
506 tios
.c_iflag
= IGNBRK
| IGNPAR
;
510 tios
.c_cc
[VTIME
] = 0;
513 tios
.c_iflag
|= IXON
| IXOFF
;
514 tios
.c_cc
[VSTOP
] = 0x13; /* DC3 = XOFF = ^S */
515 tios
.c_cc
[VSTART
] = 0x11; /* DC1 = XON = ^Q */
518 speed
= translate_speed(inspeed
);
520 cfsetospeed(&tios
, speed
);
521 cfsetispeed(&tios
, speed
);
523 speed
= cfgetospeed(&tios
);
525 * We can't proceed if the serial port speed is 0,
526 * since that implies that the serial port is disabled.
529 syslog(LOG_ERR
, "Baud rate for %s is 0; need explicit baud rate",
535 if (tcsetattr(fd
, TCSAFLUSH
, &tios
) < 0) {
536 syslog(LOG_ERR
, "tcsetattr: %m");
540 baud_rate
= inspeed
= baud_rate_of(speed
);
545 * restore_tty - restore the terminal to the saved settings.
552 if (!default_device
) {
554 * Turn off echoing, because otherwise we can get into
555 * a loop with the tty and the modem echoing to each other.
556 * We presume we are the sole user of this tty device, so
557 * when we close it, it will revert to its defaults anyway.
559 inittermios
.c_lflag
&= ~(ECHO
| ECHONL
);
561 if (tcsetattr(fd
, TCSAFLUSH
, &inittermios
) < 0)
562 if (!hungup
&& errno
!= ENXIO
)
563 syslog(LOG_WARNING
, "tcsetattr: %m");
564 ioctl(fd
, TIOCSWINSZ
, &wsinfo
);
570 * setdtr - control the DTR line on the serial port.
571 * This is called from die(), so it shouldn't call die().
577 int modembits
= TIOCM_DTR
;
579 ioctl(fd
, (on
? TIOCMBIS
: TIOCMBIC
), &modembits
);
583 * open_loopback - open the device we use for getting packets
584 * in demand mode. Under Solaris 2, we use our existing fd
593 * output - Output PPP packet.
606 log_packet(p
, len
, "sent ", LOG_DEBUG
);
609 data
.buf
= (caddr_t
) p
;
611 while (putmsg(pppfd
, NULL
, &data
, 0) < 0) {
612 if (--retries
< 0 || (errno
!= EWOULDBLOCK
&& errno
!= EAGAIN
)) {
614 syslog(LOG_ERR
, "Couldn't send packet: %m");
618 pfd
.events
= POLLOUT
;
619 poll(&pfd
, 1, 250); /* wait for up to 0.25 seconds */
625 * wait_input - wait until there is data available on fd,
626 * for the length of time specified by *timo (indefinite
631 struct timeval
*timo
;
636 t
= timo
== NULL
? -1: timo
->tv_sec
* 1000 + timo
->tv_usec
/ 1000;
638 pfd
.events
= POLLIN
| POLLPRI
| POLLHUP
;
639 if (poll(&pfd
, 1, t
) < 0 && errno
!= EINTR
) {
640 syslog(LOG_ERR
, "poll: %m");
646 * wait_loop_output - wait until there is data available on the
647 * loopback, for the length of time specified by *timo (indefinite
651 wait_loop_output(timo
)
652 struct timeval
*timo
;
658 * wait_time - wait for a given length of time or until a
659 * signal is received.
663 struct timeval
*timo
;
667 n
= select(0, NULL
, NULL
, NULL
, timo
);
668 if (n
< 0 && errno
!= EINTR
) {
669 syslog(LOG_ERR
, "select: %m");
676 * read_packet - get a PPP packet from the serial device.
682 struct strbuf ctrl
, data
;
684 unsigned char ctrlbuf
[64];
687 data
.maxlen
= PPP_MRU
+ PPP_HDRLEN
;
688 data
.buf
= (caddr_t
) buf
;
689 ctrl
.maxlen
= sizeof(ctrlbuf
);
690 ctrl
.buf
= (caddr_t
) ctrlbuf
;
692 len
= getmsg(pppfd
, &ctrl
, &data
, &flags
);
694 if (errno
= EAGAIN
|| errno
== EINTR
)
696 syslog(LOG_ERR
, "Error reading packet: %m");
704 * Got a M_PROTO or M_PCPROTO message. Huh?
707 syslog(LOG_DEBUG
, "got ctrl msg len=%d", ctrl
.len
);
713 * get_loop_output - get outgoing packets from the ppp device,
714 * and detect when we want to bring the real link up.
715 * Return value is 1 if we need to bring up the link, 0 otherwise.
723 while ((len
= read_packet(inpacket_buf
)) > 0) {
724 if (loop_frame(inpacket_buf
, len
))
731 * ppp_send_config - configure the transmit characteristics of
735 ppp_send_config(unit
, mtu
, asyncmap
, pcomp
, accomp
)
744 if (strioctl(pppfd
, PPPIO_MTU
, &mtu
, sizeof(mtu
), 0) < 0) {
745 if (hungup
&& errno
== ENXIO
)
747 syslog(LOG_ERR
, "Couldn't set MTU: %m");
749 if (strioctl(pppfd
, PPPIO_XACCM
, &asyncmap
, sizeof(asyncmap
), 0) < 0) {
750 syslog(LOG_ERR
, "Couldn't set transmit ACCM: %m");
752 cf
[0] = (pcomp
? COMP_PROT
: 0) + (accomp
? COMP_AC
: 0);
753 cf
[1] = COMP_PROT
| COMP_AC
;
754 if (strioctl(pppfd
, PPPIO_CFLAGS
, cf
, sizeof(cf
), sizeof(int)) < 0) {
755 syslog(LOG_ERR
, "Couldn't set prot/AC compression: %m");
758 /* set mtu for ip as well */
759 memset(&ifr
, 0, sizeof(ifr
));
760 strncpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
761 ifr
.ifr_metric
= link_mtu
;
762 if (ioctl(sockfd
, SIOCSIFMTU
, &ifr
) < 0) {
763 syslog(LOG_ERR
, "Couldn't set IP MTU: %m");
768 * ppp_set_xaccm - set the extended transmit ACCM for the interface.
771 ppp_set_xaccm(unit
, accm
)
775 if (strioctl(pppfd
, PPPIO_XACCM
, accm
, sizeof(ext_accm
), 0) < 0) {
776 if (!hungup
|| errno
!= ENXIO
)
777 syslog(LOG_WARNING
, "Couldn't set extended ACCM: %m");
782 * ppp_recv_config - configure the receive-side characteristics of
786 ppp_recv_config(unit
, mru
, asyncmap
, pcomp
, accomp
)
794 if (strioctl(pppfd
, PPPIO_MRU
, &mru
, sizeof(mru
), 0) < 0) {
795 if (hungup
&& errno
== ENXIO
)
797 syslog(LOG_ERR
, "Couldn't set MRU: %m");
799 if (strioctl(pppfd
, PPPIO_RACCM
, &asyncmap
, sizeof(asyncmap
), 0) < 0) {
800 syslog(LOG_ERR
, "Couldn't set receive ACCM: %m");
802 cf
[0] = (pcomp
? DECOMP_PROT
: 0) + (accomp
? DECOMP_AC
: 0);
803 cf
[1] = DECOMP_PROT
| DECOMP_AC
;
804 if (strioctl(pppfd
, PPPIO_CFLAGS
, cf
, sizeof(cf
), sizeof(int)) < 0) {
805 syslog(LOG_ERR
, "Couldn't set prot/AC decompression: %m");
810 * ccp_test - ask kernel whether a given compression method
811 * is acceptable for use.
814 ccp_test(unit
, opt_ptr
, opt_len
, for_transmit
)
815 int unit
, opt_len
, for_transmit
;
818 if (strioctl(pppfd
, (for_transmit
? PPPIO_XCOMP
: PPPIO_RCOMP
),
819 opt_ptr
, opt_len
, 0) >= 0)
821 return (errno
== ENOSR
)? 0: -1;
825 * ccp_flags_set - inform kernel about the current state of CCP.
828 ccp_flags_set(unit
, isopen
, isup
)
829 int unit
, isopen
, isup
;
833 cf
[0] = (isopen
? CCP_ISOPEN
: 0) + (isup
? CCP_ISUP
: 0);
834 cf
[1] = CCP_ISOPEN
| CCP_ISUP
| CCP_ERROR
| CCP_FATALERROR
;
835 if (strioctl(pppfd
, PPPIO_CFLAGS
, cf
, sizeof(cf
), sizeof(int)) < 0) {
836 if (!hungup
|| errno
!= ENXIO
)
837 syslog(LOG_ERR
, "Couldn't set kernel CCP state: %m");
842 * get_idle_time - return how long the link has been idle.
849 return strioctl(pppfd
, PPPIO_GIDLE
, ip
, 0, sizeof(struct ppp_idle
)) >= 0;
854 * ccp_fatal_error - returns 1 if decompression was disabled as a
855 * result of an error detected after decompression of a packet,
856 * 0 otherwise. This is necessary because of patent nonsense.
859 ccp_fatal_error(unit
)
865 if (strioctl(pppfd
, PPPIO_CFLAGS
, cf
, sizeof(cf
), sizeof(int)) < 0) {
866 if (errno
!= ENXIO
&& errno
!= EINVAL
)
867 syslog(LOG_ERR
, "Couldn't get compression flags: %m");
870 return cf
[0] & CCP_FATALERROR
;
874 * sifvjcomp - config tcp header compression
877 sifvjcomp(u
, vjcomp
, xcidcomp
, xmaxcid
)
878 int u
, vjcomp
, xcidcomp
, xmaxcid
;
884 maxcid
[0] = xcidcomp
;
885 maxcid
[1] = 15; /* XXX should be rmaxcid */
886 if (strioctl(pppfd
, PPPIO_VJINIT
, maxcid
, sizeof(maxcid
), 0) < 0) {
887 syslog(LOG_ERR
, "Couldn't initialize VJ compression: %m");
891 cf
[0] = (vjcomp
? COMP_VJC
+ DECOMP_VJC
: 0) /* XXX this is wrong */
892 + (xcidcomp
? COMP_VJCCID
+ DECOMP_VJCCID
: 0);
893 cf
[1] = COMP_VJC
+ DECOMP_VJC
+ COMP_VJCCID
+ DECOMP_VJCCID
;
894 if (strioctl(pppfd
, PPPIO_CFLAGS
, cf
, sizeof(cf
), sizeof(int)) < 0) {
896 syslog(LOG_ERR
, "Couldn't enable VJ compression: %m");
903 * sifup - Config the interface up and enable IP packets to pass.
911 strncpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
912 if (ioctl(sockfd
, SIOCGIFFLAGS
, &ifr
) < 0) {
913 syslog(LOG_ERR
, "Couldn't mark interface up (get): %m");
916 ifr
.ifr_flags
|= IFF_UP
;
917 if (ioctl(sockfd
, SIOCSIFFLAGS
, &ifr
) < 0) {
918 syslog(LOG_ERR
, "Couldn't mark interface up (set): %m");
926 * sifdown - Config the interface down and disable IP.
934 strncpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
935 if (ioctl(sockfd
, SIOCGIFFLAGS
, &ifr
) < 0) {
936 syslog(LOG_ERR
, "Couldn't mark interface down (get): %m");
939 if ((ifr
.ifr_flags
& IFF_UP
) != 0) {
940 ifr
.ifr_flags
&= ~IFF_UP
;
941 if (ioctl(sockfd
, SIOCSIFFLAGS
, &ifr
) < 0) {
942 syslog(LOG_ERR
, "Couldn't mark interface down (set): %m");
951 * sifnpmode - Set the mode for handling packets for a given NP.
954 sifnpmode(u
, proto
, mode
)
963 if (strioctl(pppfd
, PPPIO_NPMODE
, npi
, 2 * sizeof(int), 0) < 0) {
964 syslog(LOG_ERR
, "ioctl(set NP %d mode to %d): %m", proto
, mode
);
970 #define INET_ADDR(x) (((struct sockaddr_in *) &(x))->sin_addr.s_addr)
973 * sifaddr - Config the interface IP addresses and netmask.
982 memset(&ifr
, 0, sizeof(ifr
));
983 strncpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
984 ifr
.ifr_addr
.sa_family
= AF_INET
;
985 INET_ADDR(ifr
.ifr_addr
) = m
;
986 if (ioctl(sockfd
, SIOCSIFNETMASK
, &ifr
) < 0) {
987 syslog(LOG_ERR
, "Couldn't set IP netmask: %m");
989 ifr
.ifr_addr
.sa_family
= AF_INET
;
990 INET_ADDR(ifr
.ifr_addr
) = o
;
991 if (ioctl(sockfd
, SIOCSIFADDR
, &ifr
) < 0) {
992 syslog(LOG_ERR
, "Couldn't set local IP address: %m");
994 ifr
.ifr_dstaddr
.sa_family
= AF_INET
;
995 INET_ADDR(ifr
.ifr_dstaddr
) = h
;
996 if (ioctl(sockfd
, SIOCSIFDSTADDR
, &ifr
) < 0) {
997 syslog(LOG_ERR
, "Couldn't set remote IP address: %m");
999 #if 0 /* now done in ppp_send_config */
1000 ifr
.ifr_metric
= link_mtu
;
1001 if (ioctl(sockfd
, SIOCSIFMTU
, &ifr
) < 0) {
1002 syslog(LOG_ERR
, "Couldn't set IP MTU: %m");
1012 * cifaddr - Clear the interface IP addresses, and delete routes
1013 * through the interface if possible.
1022 bzero(&rt
, sizeof(rt
));
1023 rt
.rt_dst
.sa_family
= AF_INET
;
1024 INET_ADDR(rt
.rt_dst
) = h
;
1025 rt
.rt_gateway
.sa_family
= AF_INET
;
1026 INET_ADDR(rt
.rt_gateway
) = o
;
1027 rt
.rt_flags
= RTF_HOST
;
1028 if (ioctl(sockfd
, SIOCDELRT
, &rt
) < 0)
1029 syslog(LOG_ERR
, "Couldn't delete route through interface: %m");
1035 * sifdefaultroute - assign a default route through the address given.
1038 sifdefaultroute(u
, l
, g
)
1044 bzero(&rt
, sizeof(rt
));
1045 rt
.rt_dst
.sa_family
= AF_INET
;
1046 INET_ADDR(rt
.rt_dst
) = 0;
1047 rt
.rt_gateway
.sa_family
= AF_INET
;
1048 INET_ADDR(rt
.rt_gateway
) = g
;
1049 rt
.rt_flags
= RTF_GATEWAY
;
1051 if (ioctl(sockfd
, SIOCADDRT
, &rt
) < 0) {
1052 syslog(LOG_ERR
, "Can't add default route: %m");
1056 default_route_gateway
= g
;
1061 * cifdefaultroute - delete a default route through the address given.
1064 cifdefaultroute(u
, l
, g
)
1070 bzero(&rt
, sizeof(rt
));
1071 rt
.rt_dst
.sa_family
= AF_INET
;
1072 INET_ADDR(rt
.rt_dst
) = 0;
1073 rt
.rt_gateway
.sa_family
= AF_INET
;
1074 INET_ADDR(rt
.rt_gateway
) = g
;
1075 rt
.rt_flags
= RTF_GATEWAY
;
1077 if (ioctl(sockfd
, SIOCDELRT
, &rt
) < 0) {
1078 syslog(LOG_ERR
, "Can't delete default route: %m");
1082 default_route_gateway
= 0;
1087 * sifproxyarp - Make a proxy ARP entry for the peer.
1090 sifproxyarp(unit
, hisaddr
)
1094 struct arpreq arpreq
;
1096 bzero(&arpreq
, sizeof(arpreq
));
1097 if (!get_ether_addr(hisaddr
, &arpreq
.arp_ha
))
1100 arpreq
.arp_pa
.sa_family
= AF_INET
;
1101 INET_ADDR(arpreq
.arp_pa
) = hisaddr
;
1102 arpreq
.arp_flags
= ATF_PERM
| ATF_PUBL
;
1103 if (ioctl(sockfd
, SIOCSARP
, (caddr_t
) &arpreq
) < 0) {
1104 syslog(LOG_ERR
, "Couldn't set proxy ARP entry: %m");
1108 proxy_arp_addr
= hisaddr
;
1113 * cifproxyarp - Delete the proxy ARP entry for the peer.
1116 cifproxyarp(unit
, hisaddr
)
1120 struct arpreq arpreq
;
1122 bzero(&arpreq
, sizeof(arpreq
));
1123 arpreq
.arp_pa
.sa_family
= AF_INET
;
1124 INET_ADDR(arpreq
.arp_pa
) = hisaddr
;
1125 if (ioctl(sockfd
, SIOCDARP
, (caddr_t
)&arpreq
) < 0) {
1126 syslog(LOG_ERR
, "Couldn't delete proxy ARP entry: %m");
1135 * get_ether_addr - get the hardware address of an interface on the
1136 * the same subnet as ipaddr.
1141 get_ether_addr(ipaddr
, hwaddr
)
1143 struct sockaddr
*hwaddr
;
1145 struct ifreq
*ifr
, *ifend
;
1146 u_int32_t ina
, mask
;
1149 struct ifreq ifs
[MAX_IFS
];
1152 ifc
.ifc_len
= sizeof(ifs
);
1154 if (ioctl(sockfd
, SIOCGIFCONF
, &ifc
) < 0) {
1155 syslog(LOG_ERR
, "ioctl(SIOCGIFCONF): %m");
1160 * Scan through looking for an interface with an Internet
1161 * address on the same subnet as `ipaddr'.
1163 ifend
= (struct ifreq
*) (ifc
.ifc_buf
+ ifc
.ifc_len
);
1164 for (ifr
= ifc
.ifc_req
; ifr
< ifend
; ifr
= (struct ifreq
*)
1165 ((char *)&ifr
->ifr_addr
+ sizeof(struct sockaddr
))) {
1166 if (ifr
->ifr_addr
.sa_family
== AF_INET
) {
1169 * Check that the interface is up, and not point-to-point
1172 strncpy(ifreq
.ifr_name
, ifr
->ifr_name
, sizeof(ifreq
.ifr_name
));
1173 if (ioctl(sockfd
, SIOCGIFFLAGS
, &ifreq
) < 0)
1175 if ((ifreq
.ifr_flags
&
1176 (IFF_UP
|IFF_BROADCAST
|IFF_POINTOPOINT
|IFF_LOOPBACK
|IFF_NOARP
))
1177 != (IFF_UP
|IFF_BROADCAST
))
1181 * Get its netmask and check that it's on the right subnet.
1183 if (ioctl(sockfd
, SIOCGIFNETMASK
, &ifreq
) < 0)
1185 ina
= ((struct sockaddr_in
*) &ifr
->ifr_addr
)->sin_addr
.s_addr
;
1186 mask
= ((struct sockaddr_in
*) &ifreq
.ifr_addr
)->sin_addr
.s_addr
;
1187 if ((ipaddr
& mask
) != (ina
& mask
))
1196 syslog(LOG_INFO
, "found interface %s for proxy arp", ifr
->ifr_name
);
1199 * Grab the physical address for this interface.
1201 if ((nit_fd
= open("/dev/nit", O_RDONLY
)) < 0) {
1202 syslog(LOG_ERR
, "Couldn't open /dev/nit: %m");
1205 strncpy(ifreq
.ifr_name
, ifr
->ifr_name
, sizeof(ifreq
.ifr_name
));
1206 if (ioctl(nit_fd
, NIOCBIND
, &ifreq
) < 0
1207 || ioctl(nit_fd
, SIOCGIFADDR
, &ifreq
) < 0) {
1208 syslog(LOG_ERR
, "Couldn't get hardware address for %s: %m",
1214 hwaddr
->sa_family
= AF_UNSPEC
;
1215 memcpy(hwaddr
->sa_data
, ifreq
.ifr_addr
.sa_data
, 6);
1220 #define WTMPFILE "/usr/adm/wtmp"
1223 logwtmp(line
, name
, host
)
1224 const char *line
, *name
, *host
;
1230 if ((fd
= open(WTMPFILE
, O_WRONLY
|O_APPEND
, 0)) < 0)
1232 if (!fstat(fd
, &buf
)) {
1233 (void)strncpy(ut
.ut_line
, line
, sizeof(ut
.ut_line
));
1234 (void)strncpy(ut
.ut_name
, name
, sizeof(ut
.ut_name
));
1235 (void)strncpy(ut
.ut_host
, host
, sizeof(ut
.ut_host
));
1236 (void)time(&ut
.ut_time
);
1237 if (write(fd
, (char *)&ut
, sizeof(struct utmp
)) != sizeof(struct utmp
))
1238 (void)ftruncate(fd
, buf
.st_size
);
1244 * Return user specified netmask, modified by any mask we might determine
1245 * for address `addr' (in network byte order).
1246 * Here we scan through the system's list of interfaces, looking for
1247 * any non-point-to-point interfaces which might appear to be on the same
1248 * network as `addr'. If we find any, we OR in their netmask to the
1249 * user-specified netmask.
1255 u_int32_t mask
, nmask
, ina
;
1256 struct ifreq
*ifr
, *ifend
, ifreq
;
1260 if (IN_CLASSA(addr
)) /* determine network mask for address class */
1261 nmask
= IN_CLASSA_NET
;
1262 else if (IN_CLASSB(addr
))
1263 nmask
= IN_CLASSB_NET
;
1265 nmask
= IN_CLASSC_NET
;
1266 /* class D nets are disallowed by bad_ip_adrs */
1267 mask
= netmask
| htonl(nmask
);
1270 * Scan through the system's network interfaces.
1272 ifc
.ifc_len
= MAX_IFS
* sizeof(struct ifreq
);
1273 ifc
.ifc_req
= alloca(ifc
.ifc_len
);
1274 if (ifc
.ifc_req
== 0)
1276 if (ioctl(sockfd
, SIOCGIFCONF
, &ifc
) < 0) {
1277 syslog(LOG_WARNING
, "Couldn't get system interface list: %m");
1280 ifend
= (struct ifreq
*) (ifc
.ifc_buf
+ ifc
.ifc_len
);
1281 for (ifr
= ifc
.ifc_req
; ifr
< ifend
; ++ifr
) {
1283 * Check the interface's internet address.
1285 if (ifr
->ifr_addr
.sa_family
!= AF_INET
)
1287 ina
= INET_ADDR(ifr
->ifr_addr
);
1288 if ((ntohl(ina
) & nmask
) != (addr
& nmask
))
1291 * Check that the interface is up, and not point-to-point or loopback.
1293 strncpy(ifreq
.ifr_name
, ifr
->ifr_name
, sizeof(ifreq
.ifr_name
));
1294 if (ioctl(sockfd
, SIOCGIFFLAGS
, &ifreq
) < 0)
1296 if ((ifreq
.ifr_flags
& (IFF_UP
|IFF_POINTOPOINT
|IFF_LOOPBACK
))
1300 * Get its netmask and OR it into our mask.
1302 if (ioctl(sockfd
, SIOCGIFNETMASK
, &ifreq
) < 0)
1304 mask
|= INET_ADDR(ifreq
.ifr_addr
);
1311 strioctl(fd
, cmd
, ptr
, ilen
, olen
)
1312 int fd
, cmd
, ilen
, olen
;
1315 struct strioctl str
;
1321 if (ioctl(fd
, I_STR
, &str
) == -1)
1323 if (str
.ic_len
!= olen
)
1324 syslog(LOG_DEBUG
, "strioctl: expected %d bytes, got %d for cmd %x\n",
1325 olen
, str
.ic_len
, cmd
);
1330 * Use the hostid as part of the random number seed.
1339 * Code for locking/unlocking the serial device.
1340 * This code is derived from chat.c.
1343 #if !defined(HDB) && !defined(SUNOS3)
1344 #define HDB 1 /* ascii lock files are the default */
1350 # define LOCK_PREFIX "/usr/spool/locks/LCK.."
1352 # define LOCK_PREFIX "/usr/spool/uucp/LCK.."
1354 #endif /* LOCK_DIR */
1356 static char *lock_file
; /* name of lock file created */
1359 * lock - create a lock file for the named device.
1365 char hdb_lock_buffer
[12];
1369 if ((p
= strrchr(dev
, '/')) != NULL
)
1371 lock_file
= malloc(strlen(LOCK_PREFIX
) + strlen(dev
) + 1);
1372 if (lock_file
== NULL
)
1373 novm("lock file name");
1374 strcat(strcpy(lock_file
, LOCK_PREFIX
), dev
);
1376 while ((fd
= open(lock_file
, O_EXCL
| O_CREAT
| O_RDWR
, 0644)) < 0) {
1378 && (fd
= open(lock_file
, O_RDONLY
, 0)) >= 0) {
1379 /* Read the lock file to find out who has the device locked */
1381 n
= read(fd
, hdb_lock_buffer
, 11);
1383 hdb_lock_buffer
[n
] = 0;
1384 pid
= atoi(hdb_lock_buffer
);
1387 n
= read(fd
, &pid
, sizeof(pid
));
1390 syslog(LOG_ERR
, "Can't read pid from lock file %s", lock_file
);
1393 if (kill(pid
, 0) == -1 && errno
== ESRCH
) {
1394 /* pid no longer exists - remove the lock file */
1395 if (unlink(lock_file
) == 0) {
1397 syslog(LOG_NOTICE
, "Removed stale lock on %s (pid %d)",
1401 syslog(LOG_WARNING
, "Couldn't remove stale lock on %s",
1404 syslog(LOG_NOTICE
, "Device %s is locked by pid %d",
1409 syslog(LOG_ERR
, "Can't create lock file %s: %m", lock_file
);
1416 sprintf(hdb_lock_buffer
, "%10d\n", getpid());
1417 write(fd
, hdb_lock_buffer
, 11);
1420 write(fd
, &pid
, sizeof pid
);
1428 * unlock - remove our lockfile
1441 * SunOS doesn't have strtoul :-(
1444 strtoul(str
, ptr
, base
)
1448 return (unsigned long) strtol(str
, ptr
, base
);
1454 extern char *sys_errlist
[];
1455 extern int sys_nerr
;
1461 static char unknown
[32];
1463 if (n
> 0 && n
< sys_nerr
)
1464 return sys_errlist
[n
];
1465 sprintf(unknown
, "Error %d", n
);