2 * System-dependent procedures for pppd under SunOS 4.
4 * Copyright (c) 1994-2002 Paul Mackerras. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. The name(s) of the authors of this software must not be used to
14 * endorse or promote products derived from this software without
15 * prior written permission.
17 * 3. Redistributions of any form whatsoever must retain the following
19 * "This product includes software developed by Paul Mackerras
20 * <paulus@samba.org>".
22 * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
23 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
24 * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
25 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
26 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
27 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
28 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
30 * Derived from main.c and pppd.h, which are:
32 * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved.
34 * Redistribution and use in source and binary forms, with or without
35 * modification, are permitted provided that the following conditions
38 * 1. Redistributions of source code must retain the above copyright
39 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in
43 * the documentation and/or other materials provided with the
46 * 3. The name "Carnegie Mellon University" must not be used to
47 * endorse or promote products derived from this software without
48 * prior written permission. For permission or any legal
49 * details, please contact
50 * Office of Technology Transfer
51 * Carnegie Mellon University
53 * Pittsburgh, PA 15213-3890
54 * (412) 268-4387, fax: (412) 268-7395
55 * tech-transfer@andrew.cmu.edu
57 * 4. Redistributions of any form whatsoever must retain the following
59 * "This product includes software developed by Computing Services
60 * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
62 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
63 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
64 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
65 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
66 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
67 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
68 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
71 #define RCSID "$Id: sys-sunos4.c,v 1.33 2004/11/04 10:02:26 paulus Exp $"
85 #include <sys/types.h>
86 #include <sys/param.h>
87 #include <sys/socket.h>
88 #include <sys/sockio.h>
89 #include <sys/stream.h>
90 #include <sys/stropts.h>
95 #include <net/if_arp.h>
96 #include <net/nit_if.h>
97 #include <net/route.h>
98 #include <net/ppp_defs.h>
99 #include <net/pppio.h>
100 #include <netinet/in.h>
104 #if defined(sun) && defined(sparc)
107 extern void *alloca();
111 static const char rcsid
[] = RCSID
;
114 static int fdmuxid
= -1;
118 static int restore_term
;
119 static struct termios inittermios
;
120 static struct winsize wsinfo
; /* Initial window size info */
121 static pid_t parent_pid
; /* PID of our parent */
123 extern u_char inpacket_buf
[]; /* borrowed from main.c */
125 #define MAX_POLLFDS 32
126 static struct pollfd pollfds
[MAX_POLLFDS
];
127 static int n_pollfds
;
129 static int link_mtu
, link_mru
;
132 static int tty_nmodules
;
133 static char tty_modules
[NMODULES
][FMNAMESZ
+1];
135 static int if_is_up
; /* Interface has been marked up */
136 static u_int32_t ifaddrs
[2]; /* local and remote addresses */
137 static u_int32_t default_route_gateway
; /* Gateway for default route added */
138 static u_int32_t proxy_arp_addr
; /* Addr for proxy arp entry added */
140 /* Prototypes for procedures local to this file. */
141 static int translate_speed
__P((int));
142 static int baud_rate_of
__P((int));
143 static int get_ether_addr
__P((u_int32_t
, struct sockaddr
*));
144 static int strioctl
__P((int, int, void *, int, int));
148 * sys_init - System-dependent initialization.
155 /* Get an internet socket for doing socket ioctl's on. */
156 if ((sockfd
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0)
157 fatal("Couldn't create IP socket: %m");
160 * We may want to send a SIGHUP to the session leader associated
161 * with our controlling terminal later. Because SunOS doesn't
162 * have getsid(), we make do with sending the signal to our
165 parent_pid
= getppid();
168 * Open the ppp device.
170 pppfd
= open("/dev/ppp", O_RDWR
| O_NONBLOCK
, 0);
172 fatal("Can't open /dev/ppp: %m");
174 x
= PPPDBG_LOG
+ PPPDBG_DRIVER
;
175 strioctl(pppfd
, PPPIO_DEBUG
, &x
, sizeof(int), 0);
178 /* Assign a new PPA and get its unit number. */
179 if (strioctl(pppfd
, PPPIO_NEWPPA
, &ifunit
, 0, sizeof(int)) < 0)
180 fatal("Can't create new PPP interface: %m");
183 * Open the ppp device again and push the if_ppp module on it.
185 iffd
= open("/dev/ppp", O_RDWR
, 0);
187 fatal("Can't open /dev/ppp (2): %m");
189 x
= PPPDBG_LOG
+ PPPDBG_DRIVER
;
190 strioctl(iffd
, PPPIO_DEBUG
, &x
, sizeof(int), 0);
192 if (strioctl(iffd
, PPPIO_ATTACH
, &ifunit
, sizeof(int), 0) < 0)
193 fatal("Couldn't attach ppp interface to device: %m");
194 if (ioctl(iffd
, I_PUSH
, "if_ppp") < 0)
195 fatal("Can't push ppp interface module: %m");
197 x
= PPPDBG_LOG
+ PPPDBG_IF
;
198 strioctl(iffd
, PPPIO_DEBUG
, &x
, sizeof(int), 0);
200 if (strioctl(iffd
, PPPIO_NEWPPA
, &ifunit
, sizeof(int), 0) < 0)
201 fatal("Couldn't create ppp interface unit: %m");
203 if (strioctl(iffd
, PPPIO_BIND
, &x
, sizeof(int), 0) < 0)
204 fatal("Couldn't bind ppp interface to IP SAP: %m");
210 * sys_cleanup - restore any system state we modified before exiting:
211 * mark the interface down, delete default route and/or proxy arp entry.
212 * This shouldn't call die() because it's called from die().
220 cifaddr(0, ifaddrs
[0], ifaddrs
[1]);
221 if (default_route_gateway
)
222 cifdefaultroute(0, 0, default_route_gateway
);
224 cifproxyarp(0, proxy_arp_addr
);
228 * sys_close - Clean up in a child process before execing.
239 * sys_check_options - check the options that the user specified
249 * daemon - Detach us from controlling terminal session.
252 daemon(nochdir
, noclose
)
253 int nochdir
, noclose
;
257 if ((pid
= fork()) < 0)
260 exit(0); /* parent dies */
265 fclose(stdin
); /* don't need stdin, stdout, stderr */
274 * ppp_available - check whether the system has any ppp interfaces
281 return stat("/dev/ppp", &buf
) >= 0;
285 * tty_establish_ppp - Turn the serial port into a ppp interface.
288 tty_establish_ppp(fd
)
293 /* Pop any existing modules off the tty stream. */
295 if (ioctl(fd
, I_LOOK
, tty_modules
[i
]) < 0
296 || ioctl(fd
, I_POP
, 0) < 0)
300 /* Push the async hdlc module and the compressor module. */
301 if (ioctl(fd
, I_PUSH
, "ppp_ahdl") < 0)
302 fatal("Couldn't push PPP Async HDLC module: %m");
303 if (ioctl(fd
, I_PUSH
, "ppp_comp") < 0)
304 error("Couldn't push PPP compression module: %m");
306 /* Link the serial port under the PPP multiplexor. */
307 if ((fdmuxid
= ioctl(pppfd
, I_LINK
, fd
)) < 0)
308 fatal("Can't link tty to PPP mux: %m");
314 * disestablish_ppp - Restore the serial port to normal operation.
315 * It attempts to reconstruct the stream with the previously popped
316 * modules. This shouldn't call die() because it's called from die().
319 tty_disestablish_ppp(fd
)
325 if (ioctl(pppfd
, I_UNLINK
, fdmuxid
) < 0) {
327 error("Can't unlink tty from PPP mux: %m");
332 while (ioctl(fd
, I_POP
, 0) >= 0)
334 for (i
= tty_nmodules
- 1; i
>= 0; --i
)
335 if (ioctl(fd
, I_PUSH
, tty_modules
[i
]) < 0)
336 error("Couldn't restore tty module %s: %m",
339 if (hungup
&& default_device
&& parent_pid
> 0) {
341 * If we have received a hangup, we need to send a SIGHUP
342 * to the terminal's controlling process. The reason is
343 * that the original stream head for the terminal hasn't
344 * seen the M_HANGUP message (it went up through the ppp
345 * driver to the stream head for our fd to /dev/ppp).
346 * Actually we send the signal to the process that invoked
347 * pppd, since SunOS doesn't have getsid().
349 kill(parent_pid
, SIGHUP
);
355 * Check whether the link seems not to be 8-bit clean.
363 if (strioctl(pppfd
, PPPIO_GCLEAN
, &x
, 0, sizeof(x
)) < 0)
368 s
= "bit 7 set to 1";
371 s
= "bit 7 set to 0";
381 warn("Serial link is not 8-bit clean:");
382 warn("All received characters had %s", s
);
387 * List of valid speeds.
390 int speed_int
, speed_val
;
462 * Translate from bits/second to a speed_t.
468 struct speed
*speedp
;
472 for (speedp
= speeds
; speedp
->speed_int
; speedp
++)
473 if (bps
== speedp
->speed_int
)
474 return speedp
->speed_val
;
475 warn("speed %d not supported", bps
);
480 * Translate from a speed_t to bits/second.
486 struct speed
*speedp
;
490 for (speedp
= speeds
; speedp
->speed_int
; speedp
++)
491 if (speed
== speedp
->speed_val
)
492 return speedp
->speed_int
;
497 * set_up_tty: Set up the serial port on `fd' for 8 bits, no parity,
498 * at the requested speed, etc. If `local' is true, set CLOCAL
499 * regardless of whether the modem option was specified.
502 set_up_tty(fd
, local
)
508 if (tcgetattr(fd
, &tios
) < 0)
509 fatal("tcgetattr: %m");
513 ioctl(fd
, TIOCGWINSZ
, &wsinfo
);
516 tios
.c_cflag
&= ~(CSIZE
| CSTOPB
| PARENB
| CLOCAL
);
518 tios
.c_cflag
|= CRTSCTS
;
519 else if (crtscts
< 0)
520 tios
.c_cflag
&= ~CRTSCTS
;
522 tios
.c_cflag
|= CS8
| CREAD
| HUPCL
;
524 tios
.c_cflag
|= CLOCAL
;
525 tios
.c_iflag
= IGNBRK
| IGNPAR
;
529 tios
.c_cc
[VTIME
] = 0;
532 tios
.c_iflag
|= IXON
| IXOFF
;
533 tios
.c_cc
[VSTOP
] = 0x13; /* DC3 = XOFF = ^S */
534 tios
.c_cc
[VSTART
] = 0x11; /* DC1 = XON = ^Q */
537 speed
= translate_speed(inspeed
);
539 cfsetospeed(&tios
, speed
);
540 cfsetispeed(&tios
, speed
);
542 speed
= cfgetospeed(&tios
);
544 * We can't proceed if the serial port speed is 0,
545 * since that implies that the serial port is disabled.
548 fatal("Baud rate for %s is 0; need explicit baud rate", devnam
);
551 if (tcsetattr(fd
, TCSAFLUSH
, &tios
) < 0)
552 fatal("tcsetattr: %m");
554 baud_rate
= inspeed
= baud_rate_of(speed
);
559 * restore_tty - restore the terminal to the saved settings.
566 if (!default_device
) {
568 * Turn off echoing, because otherwise we can get into
569 * a loop with the tty and the modem echoing to each other.
570 * We presume we are the sole user of this tty device, so
571 * when we close it, it will revert to its defaults anyway.
573 inittermios
.c_lflag
&= ~(ECHO
| ECHONL
);
575 if (tcsetattr(fd
, TCSAFLUSH
, &inittermios
) < 0)
576 if (!hungup
&& errno
!= ENXIO
)
577 warn("tcsetattr: %m");
578 ioctl(fd
, TIOCSWINSZ
, &wsinfo
);
584 * setdtr - control the DTR line on the serial port.
585 * This is called from die(), so it shouldn't call die().
591 int modembits
= TIOCM_DTR
;
593 ioctl(fd
, (on
? TIOCMBIS
: TIOCMBIC
), &modembits
);
597 * open_loopback - open the device we use for getting packets
598 * in demand mode. Under SunOS, we use our existing fd
608 * output - Output PPP packet.
620 dump_packet("sent", p
, len
);
621 if (snoop_send_hook
) snoop_send_hook(p
, len
);
624 data
.buf
= (caddr_t
) p
;
626 while (putmsg(pppfd
, NULL
, &data
, 0) < 0) {
627 if (--retries
< 0 || (errno
!= EWOULDBLOCK
&& errno
!= EAGAIN
)) {
629 error("Couldn't send packet: %m");
633 pfd
.events
= POLLOUT
;
634 poll(&pfd
, 1, 250); /* wait for up to 0.25 seconds */
640 * wait_input - wait until there is data available,
641 * for the length of time specified by *timo (indefinite
646 struct timeval
*timo
;
650 t
= timo
== NULL
? -1: timo
->tv_sec
* 1000 + timo
->tv_usec
/ 1000;
651 if (poll(pollfds
, n_pollfds
, t
) < 0 && errno
!= EINTR
) {
654 /* we can get EAGAIN on a heavily loaded system,
655 * just wait a short time and try again. */
661 * add_fd - add an fd to the set that wait_input waits for.
668 for (n
= 0; n
< n_pollfds
; ++n
)
669 if (pollfds
[n
].fd
== fd
)
671 if (n_pollfds
< MAX_POLLFDS
) {
672 pollfds
[n_pollfds
].fd
= fd
;
673 pollfds
[n_pollfds
].events
= POLLIN
| POLLPRI
| POLLHUP
;
676 error("Too many inputs!");
680 * remove_fd - remove an fd from the set that wait_input waits for.
687 for (n
= 0; n
< n_pollfds
; ++n
) {
688 if (pollfds
[n
].fd
== fd
) {
689 while (++n
< n_pollfds
)
690 pollfds
[n
-1] = pollfds
[n
];
699 * wait_loop_output - wait until there is data available on the
700 * loopback, for the length of time specified by *timo (indefinite
704 wait_loop_output(timo
)
705 struct timeval
*timo
;
711 * wait_time - wait for a given length of time or until a
712 * signal is received.
716 struct timeval
*timo
;
720 n
= select(0, NULL
, NULL
, NULL
, timo
);
721 if (n
< 0 && errno
!= EINTR
)
727 * read_packet - get a PPP packet from the serial device.
733 struct strbuf ctrl
, data
;
735 unsigned char ctrlbuf
[64];
738 data
.maxlen
= PPP_MRU
+ PPP_HDRLEN
;
739 data
.buf
= (caddr_t
) buf
;
740 ctrl
.maxlen
= sizeof(ctrlbuf
);
741 ctrl
.buf
= (caddr_t
) ctrlbuf
;
743 len
= getmsg(pppfd
, &ctrl
, &data
, &flags
);
745 if (errno
== EAGAIN
|| errno
== EINTR
)
747 fatal("Error reading packet: %m");
754 * Got a M_PROTO or M_PCPROTO message. Huh?
757 dbglog("got ctrl msg len=%d", ctrl
.len
);
763 * get_loop_output - get outgoing packets from the ppp device,
764 * and detect when we want to bring the real link up.
765 * Return value is 1 if we need to bring up the link, 0 otherwise.
773 while ((len
= read_packet(inpacket_buf
)) > 0) {
774 if (loop_frame(inpacket_buf
, len
))
781 * netif_set_mtu - set the MTU on the PPP network interface.
784 netif_set_mtu(unit
, mtu
)
789 memset(&ifr
, 0, sizeof(ifr
));
790 strlcpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
791 ifr
.ifr_metric
= link_mtu
;
792 if (ioctl(sockfd
, SIOCSIFMTU
, &ifr
) < 0) {
793 error("Couldn't set IP MTU: %m");
798 * tty_send_config - configure the transmit characteristics of
802 tty_send_config(mtu
, asyncmap
, pcomp
, accomp
)
810 if (strioctl(pppfd
, PPPIO_MTU
, &mtu
, sizeof(mtu
), 0) < 0) {
811 if (hungup
&& errno
== ENXIO
) {
815 error("Couldn't set MTU: %m");
817 if (strioctl(pppfd
, PPPIO_XACCM
, &asyncmap
, sizeof(asyncmap
), 0) < 0)
818 error("Couldn't set transmit ACCM: %m");
819 cf
[0] = (pcomp
? COMP_PROT
: 0) + (accomp
? COMP_AC
: 0);
820 cf
[1] = COMP_PROT
| COMP_AC
;
821 if (strioctl(pppfd
, PPPIO_CFLAGS
, cf
, sizeof(cf
), sizeof(int)) < 0)
822 error("Couldn't set prot/AC compression: %m");
826 * tty_set_xaccm - set the extended transmit ACCM for the interface.
829 tty_set_xaccm(unit
, accm
)
833 if (strioctl(pppfd
, PPPIO_XACCM
, accm
, sizeof(ext_accm
), 0) < 0) {
834 if (!hungup
|| errno
!= ENXIO
)
835 warn("Couldn't set extended ACCM: %m");
840 * tty_recv_config - configure the receive-side characteristics of
844 tty_recv_config(mru
, asyncmap
, pcomp
, accomp
)
852 if (strioctl(pppfd
, PPPIO_MRU
, &mru
, sizeof(mru
), 0) < 0) {
853 if (hungup
&& errno
== ENXIO
) {
857 error("Couldn't set MRU: %m");
859 if (strioctl(pppfd
, PPPIO_RACCM
, &asyncmap
, sizeof(asyncmap
), 0) < 0)
860 error("Couldn't set receive ACCM: %m");
861 cf
[0] = (pcomp
? DECOMP_PROT
: 0) + (accomp
? DECOMP_AC
: 0);
862 cf
[1] = DECOMP_PROT
| DECOMP_AC
;
863 if (strioctl(pppfd
, PPPIO_CFLAGS
, cf
, sizeof(cf
), sizeof(int)) < 0)
864 error("Couldn't set prot/AC decompression: %m");
868 * ccp_test - ask kernel whether a given compression method
869 * is acceptable for use.
872 ccp_test(unit
, opt_ptr
, opt_len
, for_transmit
)
873 int unit
, opt_len
, for_transmit
;
876 if (strioctl(pppfd
, (for_transmit
? PPPIO_XCOMP
: PPPIO_RCOMP
),
877 opt_ptr
, opt_len
, 0) >= 0)
879 return (errno
== ENOSR
)? 0: -1;
883 * ccp_flags_set - inform kernel about the current state of CCP.
886 ccp_flags_set(unit
, isopen
, isup
)
887 int unit
, isopen
, isup
;
891 cf
[0] = (isopen
? CCP_ISOPEN
: 0) + (isup
? CCP_ISUP
: 0);
892 cf
[1] = CCP_ISOPEN
| CCP_ISUP
| CCP_ERROR
| CCP_FATALERROR
;
893 if (strioctl(pppfd
, PPPIO_CFLAGS
, cf
, sizeof(cf
), sizeof(int)) < 0) {
894 if (!hungup
|| errno
!= ENXIO
)
895 error("Couldn't set kernel CCP state: %m");
900 * get_idle_time - return how long the link has been idle.
907 return strioctl(pppfd
, PPPIO_GIDLE
, ip
, 0, sizeof(struct ppp_idle
)) >= 0;
911 * get_ppp_stats - return statistics for the link.
914 get_ppp_stats(u
, stats
)
916 struct pppd_stats
*stats
;
920 if (strioctl(pppfd
, PPPIO_GETSTAT
, &s
, 0, sizeof(s
)) < 0) {
921 error("Couldn't get link statistics: %m");
924 stats
->bytes_in
= s
.p
.ppp_ibytes
;
925 stats
->bytes_out
= s
.p
.ppp_obytes
;
926 stats
->pkts_in
= s
.p
.ppp_ipackets
;
927 stats
->pkts_out
= s
.p
.ppp_opackets
;
933 * ccp_fatal_error - returns 1 if decompression was disabled as a
934 * result of an error detected after decompression of a packet,
935 * 0 otherwise. This is necessary because of patent nonsense.
938 ccp_fatal_error(unit
)
944 if (strioctl(pppfd
, PPPIO_CFLAGS
, cf
, sizeof(cf
), sizeof(int)) < 0) {
945 if (errno
!= ENXIO
&& errno
!= EINVAL
)
946 error("Couldn't get compression flags: %m");
949 return cf
[0] & CCP_FATALERROR
;
953 * sifvjcomp - config tcp header compression
956 sifvjcomp(u
, vjcomp
, xcidcomp
, xmaxcid
)
957 int u
, vjcomp
, xcidcomp
, xmaxcid
;
963 maxcid
[0] = xcidcomp
;
964 maxcid
[1] = 15; /* XXX should be rmaxcid */
965 if (strioctl(pppfd
, PPPIO_VJINIT
, maxcid
, sizeof(maxcid
), 0) < 0) {
966 error("Couldn't initialize VJ compression: %m");
970 cf
[0] = (vjcomp
? COMP_VJC
+ DECOMP_VJC
: 0) /* XXX this is wrong */
971 + (xcidcomp
? COMP_VJCCID
+ DECOMP_VJCCID
: 0);
972 cf
[1] = COMP_VJC
+ DECOMP_VJC
+ COMP_VJCCID
+ DECOMP_VJCCID
;
973 if (strioctl(pppfd
, PPPIO_CFLAGS
, cf
, sizeof(cf
), sizeof(int)) < 0) {
975 error("Couldn't enable VJ compression: %m");
982 * sifup - Config the interface up and enable IP packets to pass.
990 strlcpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
991 if (ioctl(sockfd
, SIOCGIFFLAGS
, &ifr
) < 0) {
992 error("Couldn't mark interface up (get): %m");
995 ifr
.ifr_flags
|= IFF_UP
;
996 if (ioctl(sockfd
, SIOCSIFFLAGS
, &ifr
) < 0) {
997 error("Couldn't mark interface up (set): %m");
1005 * sifdown - Config the interface down and disable IP.
1013 strlcpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
1014 if (ioctl(sockfd
, SIOCGIFFLAGS
, &ifr
) < 0) {
1015 error("Couldn't mark interface down (get): %m");
1018 if ((ifr
.ifr_flags
& IFF_UP
) != 0) {
1019 ifr
.ifr_flags
&= ~IFF_UP
;
1020 if (ioctl(sockfd
, SIOCSIFFLAGS
, &ifr
) < 0) {
1021 error("Couldn't mark interface down (set): %m");
1030 * sifnpmode - Set the mode for handling packets for a given NP.
1033 sifnpmode(u
, proto
, mode
)
1041 npi
[1] = (int) mode
;
1042 if (strioctl(pppfd
, PPPIO_NPMODE
, npi
, 2 * sizeof(int), 0) < 0) {
1043 error("ioctl(set NP %d mode to %d): %m", proto
, mode
);
1049 #define INET_ADDR(x) (((struct sockaddr_in *) &(x))->sin_addr.s_addr)
1052 * sifaddr - Config the interface IP addresses and netmask.
1061 memset(&ifr
, 0, sizeof(ifr
));
1062 strlcpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
1063 ifr
.ifr_addr
.sa_family
= AF_INET
;
1064 INET_ADDR(ifr
.ifr_addr
) = m
;
1065 if (ioctl(sockfd
, SIOCSIFNETMASK
, &ifr
) < 0) {
1066 error("Couldn't set IP netmask: %m");
1068 ifr
.ifr_addr
.sa_family
= AF_INET
;
1069 INET_ADDR(ifr
.ifr_addr
) = o
;
1070 if (ioctl(sockfd
, SIOCSIFADDR
, &ifr
) < 0) {
1071 error("Couldn't set local IP address: %m");
1073 ifr
.ifr_dstaddr
.sa_family
= AF_INET
;
1074 INET_ADDR(ifr
.ifr_dstaddr
) = h
;
1075 if (ioctl(sockfd
, SIOCSIFDSTADDR
, &ifr
) < 0) {
1076 error("Couldn't set remote IP address: %m");
1078 #if 0 /* now done in ppp_send_config */
1079 ifr
.ifr_metric
= link_mtu
;
1080 if (ioctl(sockfd
, SIOCSIFMTU
, &ifr
) < 0) {
1081 error("Couldn't set IP MTU: %m");
1091 * cifaddr - Clear the interface IP addresses, and delete routes
1092 * through the interface if possible.
1101 bzero(&rt
, sizeof(rt
));
1102 rt
.rt_dst
.sa_family
= AF_INET
;
1103 INET_ADDR(rt
.rt_dst
) = h
;
1104 rt
.rt_gateway
.sa_family
= AF_INET
;
1105 INET_ADDR(rt
.rt_gateway
) = o
;
1106 rt
.rt_flags
= RTF_HOST
;
1107 if (ioctl(sockfd
, SIOCDELRT
, &rt
) < 0)
1108 error("Couldn't delete route through interface: %m");
1114 * sifdefaultroute - assign a default route through the address given.
1117 sifdefaultroute(u
, l
, g
)
1123 bzero(&rt
, sizeof(rt
));
1124 rt
.rt_dst
.sa_family
= AF_INET
;
1125 INET_ADDR(rt
.rt_dst
) = 0;
1126 rt
.rt_gateway
.sa_family
= AF_INET
;
1127 INET_ADDR(rt
.rt_gateway
) = g
;
1128 rt
.rt_flags
= RTF_GATEWAY
;
1130 if (ioctl(sockfd
, SIOCADDRT
, &rt
) < 0) {
1131 error("Can't add default route: %m");
1135 default_route_gateway
= g
;
1140 * cifdefaultroute - delete a default route through the address given.
1143 cifdefaultroute(u
, l
, g
)
1149 bzero(&rt
, sizeof(rt
));
1150 rt
.rt_dst
.sa_family
= AF_INET
;
1151 INET_ADDR(rt
.rt_dst
) = 0;
1152 rt
.rt_gateway
.sa_family
= AF_INET
;
1153 INET_ADDR(rt
.rt_gateway
) = g
;
1154 rt
.rt_flags
= RTF_GATEWAY
;
1156 if (ioctl(sockfd
, SIOCDELRT
, &rt
) < 0) {
1157 error("Can't delete default route: %m");
1161 default_route_gateway
= 0;
1166 * sifproxyarp - Make a proxy ARP entry for the peer.
1169 sifproxyarp(unit
, hisaddr
)
1173 struct arpreq arpreq
;
1175 bzero(&arpreq
, sizeof(arpreq
));
1176 if (!get_ether_addr(hisaddr
, &arpreq
.arp_ha
))
1179 arpreq
.arp_pa
.sa_family
= AF_INET
;
1180 INET_ADDR(arpreq
.arp_pa
) = hisaddr
;
1181 arpreq
.arp_flags
= ATF_PERM
| ATF_PUBL
;
1182 if (ioctl(sockfd
, SIOCSARP
, (caddr_t
) &arpreq
) < 0) {
1183 error("Couldn't set proxy ARP entry: %m");
1187 proxy_arp_addr
= hisaddr
;
1192 * cifproxyarp - Delete the proxy ARP entry for the peer.
1195 cifproxyarp(unit
, hisaddr
)
1199 struct arpreq arpreq
;
1201 bzero(&arpreq
, sizeof(arpreq
));
1202 arpreq
.arp_pa
.sa_family
= AF_INET
;
1203 INET_ADDR(arpreq
.arp_pa
) = hisaddr
;
1204 if (ioctl(sockfd
, SIOCDARP
, (caddr_t
)&arpreq
) < 0) {
1205 error("Couldn't delete proxy ARP entry: %m");
1214 * get_ether_addr - get the hardware address of an interface on the
1215 * the same subnet as ipaddr.
1220 get_ether_addr(ipaddr
, hwaddr
)
1222 struct sockaddr
*hwaddr
;
1224 struct ifreq
*ifr
, *ifend
;
1225 u_int32_t ina
, mask
;
1228 struct ifreq ifs
[MAX_IFS
];
1231 ifc
.ifc_len
= sizeof(ifs
);
1233 if (ioctl(sockfd
, SIOCGIFCONF
, &ifc
) < 0) {
1234 error("ioctl(SIOCGIFCONF): %m");
1239 * Scan through looking for an interface with an Internet
1240 * address on the same subnet as `ipaddr'.
1242 ifend
= (struct ifreq
*) (ifc
.ifc_buf
+ ifc
.ifc_len
);
1243 for (ifr
= ifc
.ifc_req
; ifr
< ifend
; ifr
= (struct ifreq
*)
1244 ((char *)&ifr
->ifr_addr
+ sizeof(struct sockaddr
))) {
1245 if (ifr
->ifr_addr
.sa_family
== AF_INET
) {
1248 * Check that the interface is up, and not point-to-point
1251 strlcpy(ifreq
.ifr_name
, ifr
->ifr_name
, sizeof(ifreq
.ifr_name
));
1252 if (ioctl(sockfd
, SIOCGIFFLAGS
, &ifreq
) < 0)
1254 if ((ifreq
.ifr_flags
&
1255 (IFF_UP
|IFF_BROADCAST
|IFF_POINTOPOINT
|IFF_LOOPBACK
|IFF_NOARP
))
1256 != (IFF_UP
|IFF_BROADCAST
))
1260 * Get its netmask and check that it's on the right subnet.
1262 if (ioctl(sockfd
, SIOCGIFNETMASK
, &ifreq
) < 0)
1264 ina
= ((struct sockaddr_in
*) &ifr
->ifr_addr
)->sin_addr
.s_addr
;
1265 mask
= ((struct sockaddr_in
*) &ifreq
.ifr_addr
)->sin_addr
.s_addr
;
1266 if ((ipaddr
& mask
) != (ina
& mask
))
1275 info("found interface %s for proxy arp", ifr
->ifr_name
);
1278 * Grab the physical address for this interface.
1280 if ((nit_fd
= open("/dev/nit", O_RDONLY
)) < 0) {
1281 error("Couldn't open /dev/nit: %m");
1284 strlcpy(ifreq
.ifr_name
, ifr
->ifr_name
, sizeof(ifreq
.ifr_name
));
1285 if (ioctl(nit_fd
, NIOCBIND
, &ifreq
) < 0
1286 || ioctl(nit_fd
, SIOCGIFADDR
, &ifreq
) < 0) {
1287 error("Couldn't get hardware address for %s: %m",
1293 hwaddr
->sa_family
= AF_UNSPEC
;
1294 memcpy(hwaddr
->sa_data
, ifreq
.ifr_addr
.sa_data
, 6);
1300 * have_route_to - determine if the system has any route to
1301 * a given IP address.
1302 * For demand mode to work properly, we have to ignore routes
1303 * through our own interface.
1305 int have_route_to(addr
)
1311 #define WTMPFILE "/usr/adm/wtmp"
1314 logwtmp(line
, name
, host
)
1315 const char *line
, *name
, *host
;
1321 if ((fd
= open(WTMPFILE
, O_WRONLY
|O_APPEND
, 0)) < 0)
1323 if (!fstat(fd
, &buf
)) {
1324 strncpy(ut
.ut_line
, line
, sizeof(ut
.ut_line
));
1325 strncpy(ut
.ut_name
, name
, sizeof(ut
.ut_name
));
1326 strncpy(ut
.ut_host
, host
, sizeof(ut
.ut_host
));
1327 (void)time(&ut
.ut_time
);
1328 if (write(fd
, (char *)&ut
, sizeof(struct utmp
)) != sizeof(struct utmp
))
1329 (void)ftruncate(fd
, buf
.st_size
);
1335 * Return user specified netmask, modified by any mask we might determine
1336 * for address `addr' (in network byte order).
1337 * Here we scan through the system's list of interfaces, looking for
1338 * any non-point-to-point interfaces which might appear to be on the same
1339 * network as `addr'. If we find any, we OR in their netmask to the
1340 * user-specified netmask.
1346 u_int32_t mask
, nmask
, ina
;
1347 struct ifreq
*ifr
, *ifend
, ifreq
;
1351 if (IN_CLASSA(addr
)) /* determine network mask for address class */
1352 nmask
= IN_CLASSA_NET
;
1353 else if (IN_CLASSB(addr
))
1354 nmask
= IN_CLASSB_NET
;
1356 nmask
= IN_CLASSC_NET
;
1357 /* class D nets are disallowed by bad_ip_adrs */
1358 mask
= netmask
| htonl(nmask
);
1361 * Scan through the system's network interfaces.
1363 ifc
.ifc_len
= MAX_IFS
* sizeof(struct ifreq
);
1364 ifc
.ifc_req
= alloca(ifc
.ifc_len
);
1365 if (ifc
.ifc_req
== 0)
1367 if (ioctl(sockfd
, SIOCGIFCONF
, &ifc
) < 0) {
1368 warn("Couldn't get system interface list: %m");
1371 ifend
= (struct ifreq
*) (ifc
.ifc_buf
+ ifc
.ifc_len
);
1372 for (ifr
= ifc
.ifc_req
; ifr
< ifend
; ++ifr
) {
1374 * Check the interface's internet address.
1376 if (ifr
->ifr_addr
.sa_family
!= AF_INET
)
1378 ina
= INET_ADDR(ifr
->ifr_addr
);
1379 if ((ntohl(ina
) & nmask
) != (addr
& nmask
))
1382 * Check that the interface is up, and not point-to-point or loopback.
1384 strlcpy(ifreq
.ifr_name
, ifr
->ifr_name
, sizeof(ifreq
.ifr_name
));
1385 if (ioctl(sockfd
, SIOCGIFFLAGS
, &ifreq
) < 0)
1387 if ((ifreq
.ifr_flags
& (IFF_UP
|IFF_POINTOPOINT
|IFF_LOOPBACK
))
1391 * Get its netmask and OR it into our mask.
1393 if (ioctl(sockfd
, SIOCGIFNETMASK
, &ifreq
) < 0)
1395 mask
|= INET_ADDR(ifreq
.ifr_addr
);
1402 strioctl(fd
, cmd
, ptr
, ilen
, olen
)
1403 int fd
, cmd
, ilen
, olen
;
1406 struct strioctl str
;
1412 if (ioctl(fd
, I_STR
, &str
) == -1)
1414 if (str
.ic_len
!= olen
)
1415 dbglog("strioctl: expected %d bytes, got %d for cmd %x\n",
1416 olen
, str
.ic_len
, cmd
);
1421 * Use the hostid as part of the random number seed.
1431 * Code for locking/unlocking the serial device.
1432 * This code is derived from chat.c.
1435 #if !defined(HDB) && !defined(SUNOS3)
1436 #define HDB 1 /* ascii lock files are the default */
1442 # define LOCK_PREFIX "/usr/spool/locks/LCK.."
1444 # define LOCK_PREFIX "/usr/spool/uucp/LCK.."
1446 #endif /* LOCK_DIR */
1448 static char *lock_file
; /* name of lock file created */
1451 * lock - create a lock file for the named device.
1457 char hdb_lock_buffer
[12];
1462 if ((p
= strrchr(dev
, '/')) != NULL
)
1464 l
= strlen(LOCK_PREFIX
) + strlen(dev
) + 1;
1465 lock_file
= malloc(l
);
1466 if (lock_file
== NULL
)
1467 novm("lock file name");
1468 slprintf(lock_file
, l
, "%s%s", LOCK_PREFIX
, dev
);
1470 while ((fd
= open(lock_file
, O_EXCL
| O_CREAT
| O_RDWR
, 0644)) < 0) {
1472 && (fd
= open(lock_file
, O_RDONLY
, 0)) >= 0) {
1473 /* Read the lock file to find out who has the device locked */
1475 n
= read(fd
, hdb_lock_buffer
, 11);
1477 hdb_lock_buffer
[n
] = 0;
1478 pid
= atoi(hdb_lock_buffer
);
1481 n
= read(fd
, &pid
, sizeof(pid
));
1484 error("Can't read pid from lock file %s", lock_file
);
1487 if (kill(pid
, 0) == -1 && errno
== ESRCH
) {
1488 /* pid no longer exists - remove the lock file */
1489 if (unlink(lock_file
) == 0) {
1491 notice("Removed stale lock on %s (pid %d)",
1495 warn("Couldn't remove stale lock on %s",
1498 notice("Device %s is locked by pid %d",
1503 error("Can't create lock file %s: %m", lock_file
);
1510 slprintf(hdb_lock_buffer
, sizeof(hdb_lock_buffer
), "%10d\n", getpid());
1511 write(fd
, hdb_lock_buffer
, 11);
1514 write(fd
, &pid
, sizeof pid
);
1522 * unlock - remove our lockfile
1533 #endif /* lock stuff removed */
1536 * get_pty - get a pty master/slave pair and chown the slave side
1537 * to the uid given. Assumes slave_name points to >= 12 bytes of space.
1540 get_pty(master_fdp
, slave_fdp
, slave_name
, uid
)
1548 struct termios tios
;
1551 for (i
= 0; i
< 64; ++i
) {
1552 slprintf(pty_name
, sizeof(pty_name
), "/dev/pty%c%x",
1553 'p' + i
/ 16, i
% 16);
1554 mfd
= open(pty_name
, O_RDWR
, 0);
1557 sfd
= open(pty_name
, O_RDWR
| O_NOCTTY
, 0);
1566 strlcpy(slave_name
, pty_name
, 12);
1569 fchown(sfd
, uid
, -1);
1570 fchmod(sfd
, S_IRUSR
| S_IWUSR
);
1571 if (tcgetattr(sfd
, &tios
) == 0) {
1572 tios
.c_cflag
&= ~(CSIZE
| CSTOPB
| PARENB
);
1573 tios
.c_cflag
|= CS8
| CREAD
;
1574 tios
.c_iflag
= IGNPAR
| CLOCAL
;
1577 if (tcsetattr(sfd
, TCSAFLUSH
, &tios
) < 0)
1578 warn("couldn't set attributes on pty: %m");
1580 warn("couldn't get attributes on pty: %m");
1586 * SunOS doesn't have strtoul :-(
1589 strtoul(str
, ptr
, base
)
1593 return (unsigned long) strtol(str
, ptr
, base
);
1599 extern char *sys_errlist
[];
1600 extern int sys_nerr
;
1606 static char unknown
[32];
1608 if (n
> 0 && n
< sys_nerr
)
1609 return sys_errlist
[n
];
1610 slprintf(unknown
, sizeof(unknown
), "Error %d", n
);