X-Git-Url: http://git.ozlabs.org/?p=ppp.git;a=blobdiff_plain;f=pppd%2Fsys-osf.c;h=45e176f788caabc4fbf8ea8aef7cd376e8eac227;hp=261019820f3dc6d450e380ee3963d391860eb2c9;hb=093489a1ce40a2075b1c5c9feb03c7ab1659d884;hpb=46a48de885209b5982fc8e55efb62ec3c8c9655d diff --git a/pppd/sys-osf.c b/pppd/sys-osf.c index 2610198..45e176f 100644 --- a/pppd/sys-osf.c +++ b/pppd/sys-osf.c @@ -1,86 +1,102 @@ /* - * sys-osf.c - System-dependent procedures for setting up - * PPP interfaces on OSF/1 systems which use the STREAMS ppp interface. + * System-dependent procedures for pppd under Digital UNIX (OSF/1). * - * Copyright (c) 1989 Carnegie Mellon University. + * Copyright (c) 1994 The Australian National University. * All rights reserved. * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by Carnegie Mellon University. The name of the - * University may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * Permission to use, copy, modify, and distribute this software and its + * documentation is hereby granted, provided that the above copyright + * notice appears in all copies. This software is provided without any + * warranty, express or implied. The Australian National University + * makes no representations about the suitability of this software for + * any purpose. + * + * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY + * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF + * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO + * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, + * OR MODIFICATIONS. */ #ifndef lint -static char rcsid[] = "$Id: sys-osf.c,v 1.5 1995/10/27 03:47:32 paulus Exp $"; +static char rcsid[] = "$Id: sys-osf.c,v 1.24 1999/04/01 07:20:10 paulus Exp $"; #endif -/* - * TODO: - */ - #include +#include #include +#include +#include #include -#include -#include #include -#include -#include -#include -#include +#include +#include #include +#include +#include #include +#include #include -#include #include #include - +#include +#include +#include +#include #include -#include -#include -#include +#include #include +#include +#include +#include #include +#include #include "pppd.h" -#ifndef ifr_mtu -#define ifr_mtu ifr_metric -#endif +static int pppfd; +static int fdmuxid = -1; +static int iffd; +static int sockfd; + +static int restore_term; +static struct termios inittermios; +static struct winsize wsinfo; /* Initial window size info */ +static pid_t tty_sid; /* PID of our session leader */ -#define MAXMODULES 10 /* max number of module names to save */ -static struct modlist { - char modname[FMNAMESZ+1]; -} str_modules[MAXMODULES]; -static int str_module_count = 0; -static int pushed_ppp; -static int closed_stdio; +extern u_char inpacket_buf[]; /* borrowed from main.c */ -static int restore_term; /* 1 => we've munged the terminal */ -static struct termios inittermios; /* Initial TTY termios */ -static struct winsize wsinfo; /* Initial window size info */ -static int initfdflags = -1; /* Initial file descriptor flags for fd */ +static int link_mtu, link_mru; -static int sockfd; /* socket for doing interface ioctls */ +#define NMODULES 32 +static int tty_nmodules; +static char tty_modules[NMODULES][FMNAMESZ+1]; -int ttyfd = -1; /* Original ttyfd if we did a streamify() */ +static int closed_stdio; +static int initfdflags = -1; +static int orig_ttyfd = -1; static int if_is_up; /* Interface has been marked up */ +static u_int32_t ifaddrs[2]; /* local and remote addresses */ static u_int32_t default_route_gateway; /* Gateway for default route added */ static u_int32_t proxy_arp_addr; /* Addr for proxy arp entry added */ +#define MAX_POLLFDS 32 +static struct pollfd pollfds[MAX_POLLFDS]; +static int n_pollfds; + /* Prototypes for procedures local to this file. */ static int translate_speed __P((int)); static int baud_rate_of __P((int)); static int get_ether_addr __P((u_int32_t, struct sockaddr *)); +static int strioctl __P((int, int, void *, int, int)); /* @@ -89,59 +105,104 @@ static int get_ether_addr __P((u_int32_t, struct sockaddr *)); void sys_init() { + int x; + openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP); setlogmask(LOG_UPTO(LOG_INFO)); if (debug) setlogmask(LOG_UPTO(LOG_DEBUG)); /* Get an internet socket for doing socket ioctl's on. */ - if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - syslog(LOG_ERR, "Couldn't create IP socket: %m"); - die(1); + if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + fatal("Couldn't create IP socket: %m"); + + if (default_device) + tty_sid = getsid((pid_t)0); + + /* + * Open the ppp device. + */ + pppfd = open("/dev/streams/ppp", O_RDWR | O_NONBLOCK, 0); + if (pppfd < 0) + fatal("Can't open /dev/streams/ppp: %m"); + if (kdebugflag) { + x = PPPDBG_LOG + PPPDBG_DRIVER; + strioctl(pppfd, PPPIO_DEBUG, &x, sizeof(int), 0); } + + /* Assign a new PPA and get its unit number. */ + if (strioctl(pppfd, PPPIO_NEWPPA, &ifunit, 0, sizeof(int)) < 0) + fatal("Can't create new PPP interface: %m"); + + /* + * Open the ppp device again and push the if_ppp module on it. + */ + iffd = open("/dev/streams/ppp", O_RDWR, 0); + if (iffd < 0) + fatal("Can't open /dev/streams/ppp (2): %m"); + if (kdebugflag) { + x = PPPDBG_LOG + PPPDBG_DRIVER; + strioctl(iffd, PPPIO_DEBUG, &x, sizeof(int), 0); + } + if (strioctl(iffd, PPPIO_ATTACH, &ifunit, sizeof(int), 0) < 0) + fatal("Couldn't attach ppp interface to device: %m"); + if (ioctl(iffd, I_PUSH, "if_ppp") < 0) + fatal("Can't push ppp interface module: %m"); + if (kdebugflag) { + x = PPPDBG_LOG + PPPDBG_IF; + strioctl(iffd, PPPIO_DEBUG, &x, sizeof(int), 0); + } + if (strioctl(iffd, PPPIO_NEWPPA, &ifunit, sizeof(int), 0) < 0) + fatal("Couldn't create ppp interface unit: %m"); + x = PPP_IP; + if (strioctl(iffd, PPPIO_BIND, &x, sizeof(int), 0) < 0) + fatal("Couldn't bind ppp interface to IP SAP: %m"); + + n_pollfds = 0; } /* * sys_cleanup - restore any system state we modified before exiting: * mark the interface down, delete default route and/or proxy arp entry. - * This should call die() because it's called from die(). + * This shouldn't call die() because it's called from die(). */ void sys_cleanup() { - struct ifreq ifr; - - if (if_is_up) { - strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); - if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) >= 0 - && ((ifr.ifr_flags & IFF_UP) != 0)) { - ifr.ifr_flags &= ~IFF_UP; - ioctl(sockfd, SIOCSIFFLAGS, &ifr); - } - } - + if (if_is_up) + sifdown(0); + if (ifaddrs[0]) + cifaddr(0, ifaddrs[0], ifaddrs[1]); if (default_route_gateway) - cifdefaultroute(0, default_route_gateway); + cifdefaultroute(0, 0, default_route_gateway); if (proxy_arp_addr) cifproxyarp(0, proxy_arp_addr); } /* - * note_debug_level - note a change in the debug level. + * sys_close - Clean up in a child process before execing. */ void -note_debug_level() +sys_close() { - if (debug) { - syslog(LOG_INFO, "Debug turned ON, Level %d", debug); - setlogmask(LOG_UPTO(LOG_DEBUG)); - } else { - setlogmask(LOG_UPTO(LOG_WARNING)); - } + close(iffd); + close(pppfd); + close(sockfd); + closelog(); } /* - * daemon - Detach us from the terminal session. + * sys_check_options - check the options that the user specified + */ +int +sys_check_options() +{ + return 1; +} + + +/* + * daemon - Detach us from controlling terminal session. */ int daemon(nochdir, noclose) @@ -164,25 +225,18 @@ daemon(nochdir, noclose) return 0; } - -char pipename[] = "/dev/streams/pipe"; - /* - * ppp_available - check if this kernel supports PPP. + * ppp_available - check whether the system has any ppp interfaces */ int ppp_available() { - int fd, ret; + struct stat buf; - fd = open(pipename, O_RDONLY, 0); - if (fd < 0) - return 0; /* can't find out - assume we don't have ppp */ - ret = ioctl(fd, I_FIND, "pppasync") >= 0; - close(fd); - return ret; + return stat("/dev/streams/ppp", &buf) >= 0; } +char pipename[] = "/dev/streams/pipe"; /* * streampipe -- Opens a STREAMS based pipe. Used by streamify(). @@ -206,7 +260,7 @@ streampipe(int fd[2]) } /* - * streamify -- Needed for DEC OSF/1, since tty devices are not STREAMS + * streamify -- Needed for Digital UNIX, since some tty devices are not STREAMS * modules (but ptys are, and pipes can be). */ @@ -222,10 +276,10 @@ streamify(int fd) struct sigaction sa; if (streampipe(fdes) != 0) - syslog(LOG_ERR, "streampipe(): %m\n"); + error("streampipe(): %m\n"); else if (isastream(fdes[0]) == 1) { if ((fret=fork()) < 0) { - syslog(LOG_ERR, "fork(): %m\n"); + error("fork(): %m\n"); } else if (fret == 0) { /* Process to forward things from pipe to tty */ sigemptyset(&(sa.sa_mask)); @@ -248,7 +302,7 @@ streamify(int fd) if (FD_ISSET(fd, &readfds)) { rret = read(fd, buffer, BUFFSIZE); if (rret == 0) { - MAINDEBUG((LOG_DEBUG, "slave died: EOF on tty.")); + SYSDEBUG(("slave died: EOF on tty.")); exit(0); } else { write(fdes[1], buffer, rret); @@ -257,7 +311,7 @@ streamify(int fd) if (FD_ISSET(fdes[1], &readfds)) { rret = read(fdes[1], buffer, BUFFSIZE); if (rret == 0) { - MAINDEBUG((LOG_DEBUG, "slave died: EOF on pipe.")); + SYSDEBUG(("slave died: EOF on pipe.")); exit(0); } else { write(fd, buffer, rret); @@ -266,7 +320,7 @@ streamify(int fd) } } else { close(fdes[1]); - ttyfd = fd; + orig_ttyfd = fd; return(fdes[0]); } } @@ -274,181 +328,159 @@ streamify(int fd) return(-1); } - /* * establish_ppp - Turn the serial port into a ppp interface. */ -void -establish_ppp() +int +establish_ppp(fd) + int fd; { - int ret; + int i; if (isastream(fd) != 1) { - if ((fd=streamify(fd)) < 0) { - syslog(LOG_ERR, "Couldn't get a STREAMS module!\n"); - die(1); - } + if ((ttyfd = fd = streamify(fd)) < 0) + fatal("Couldn't get a STREAMS module!\n"); } - /* go through and save the name of all the modules, then pop em */ - for (;;) { - if (ioctl(fd, I_LOOK, str_modules[str_module_count].modname) < 0 || - ioctl(fd, I_POP, 0) < 0) + /* Pop any existing modules off the tty stream. */ + for (i = 0;; ++i) { + if (ioctl(fd, I_LOOK, tty_modules[i]) < 0 + || ioctl(fd, I_POP, 0) < 0) break; - MAINDEBUG((LOG_DEBUG, "popped stream module : %s", - str_modules[str_module_count].modname)); - str_module_count++; + error("popping module %s\n", tty_modules[i]); } - /* now push the async/fcs module */ - if (ioctl(fd, I_PUSH, "pppasync") < 0) { - syslog(LOG_ERR, "ioctl(I_PUSH, ppp_async): %m"); - die(1); - } - /* push the compress module */ - if (ioctl(fd, I_PUSH, "pppcomp") < 0) { - syslog(LOG_WARNING, "ioctl(I_PUSH, ppp_comp): %m"); - } - /* finally, push the ppp_if module that actually handles the */ - /* network interface */ - if (ioctl(fd, I_PUSH, "pppif") < 0) { - syslog(LOG_ERR, "ioctl(I_PUSH, ppp_if): %m"); - die(1); - } - pushed_ppp = 1; + tty_nmodules = i; + + /* Push the async hdlc module and the compressor module. */ + if (ioctl(fd, I_PUSH, "ppp_ahdl") < 0) + fatal("Couldn't push PPP Async HDLC module: %m"); + if (ioctl(fd, I_PUSH, "ppp_comp") < 0) + error("Couldn't push PPP compression module: %m"); + /* read mode, message non-discard mode */ - if (ioctl(fd, I_SRDOPT, RMSGN|RPROTNORM) < 0) { - syslog(LOG_ERR, "ioctl(I_SRDOPT, RMSGN): %m"); - die(1); - } - /* - * Find out which interface we were given. - * (ppp_if handles this ioctl) - */ - if (ioctl(fd, (int)SIOCGETU, &ifunit) < 0) { - syslog(LOG_ERR, "ioctl(SIOCGETU): %m"); - die(1); - } + if (ioctl(fd, I_SRDOPT, RMSGN|RPROTNORM) < 0) + fatal("ioctl(I_SRDOPT, RMSGN): %m"); - /* Set debug flags in driver */ - if (ioctl(fd, (int)SIOCSIFDEBUG, &kdebugflag) < 0) { - syslog(LOG_ERR, "ioctl(SIOCSIFDEBUG): %m"); - } + /* Link the serial port under the PPP multiplexor. */ + if ((fdmuxid = ioctl(pppfd, I_LINK, fd)) < 0) + fatal("Can't link tty to PPP mux: %m"); /* close stdin, stdout, stderr if they might refer to the device */ if (default_device && !closed_stdio) { - int i; + int i; - for (i = 0; i <= 2; ++i) - if (i != fd && i != sockfd) - close(i); - closed_stdio = 1; + for (i = 0; i <= 2; ++i) + if (i != fd && i != sockfd) + close(i); + closed_stdio = 1; } /* * Set device for non-blocking reads. + * XXX why do we need to do this? don't we use pppfd not fd? */ if ((initfdflags = fcntl(fd, F_GETFL)) == -1 - || fcntl(fd, F_SETFL, initfdflags | O_NONBLOCK) == -1) { - syslog(LOG_WARNING, "Couldn't set device to non-blocking mode: %m"); + || fcntl(fd, F_SETFL, initfdflags | O_NONBLOCK) == -1) { + warn("Couldn't set device to non-blocking mode: %m"); } -} -/* Debugging routine.... */ + return pppfd; +} -void prstrstack(int fd) +/* + * restore_loop - reattach the ppp unit to the loopback. + * This doesn't need to do anything because disestablish_ppp does it. + */ +void +restore_loop() { - struct str_list sl; - struct str_mlist names[20]; - int ret, i; - - sl.sl_modlist = names; - - ret = ioctl(fd, I_LIST, &sl); - - if (ret >= 0) { - MAINDEBUG((LOG_DEBUG, "Current streams modules:\n")); - for (i=0; i= 0) { + if (ioctl(pppfd, I_UNLINK, fdmuxid) < 0) { + if (!hungup) + error("Can't unlink tty from PPP mux: %m"); } - - while (ioctl(fd, I_POP, 0) == 0) /* pop any we pushed */ - ; - pushed_ppp = 0; - - for (; str_module_count > 0; str_module_count--) { - if (ioctl(fd, I_PUSH, str_modules[str_module_count-1].modname)) { - if (errno != ENXIO) - syslog(LOG_WARNING, "str_restore: couldn't push module %s: %m", - str_modules[str_module_count-1].modname); - } else { - MAINDEBUG((LOG_INFO, "str_restore: pushed module %s", - str_modules[str_module_count-1].modname)); - } + fdmuxid = -1; + + /* Reset non-blocking mode on the file descriptor. */ + if (initfdflags != -1 && fcntl(fd, F_SETFL, initfdflags) < 0) + warn("Couldn't restore device fd flags: %m"); + initfdflags = -1; + + if (!hungup) { + while (ioctl(fd, I_POP, 0) >= 0) + ; + for (i = tty_nmodules - 1; i >= 0; --i) + if (ioctl(fd, I_PUSH, tty_modules[i]) < 0) + error("Couldn't restore tty module %s: %m", + tty_modules[i]); } - if (ttyfd >= 0) { + if (hungup && default_device && tty_sid > 0) { + /* + * If we have received a hangup, we need to send a SIGHUP + * to the terminal's controlling process. The reason is + * that the original stream head for the terminal hasn't + * seen the M_HANGUP message (it went up through the ppp + * driver to the stream head for our fd to /dev/ppp). + */ + dbglog("sending hangup to %d", tty_sid); + if (kill(tty_sid, SIGHUP) < 0) + error("couldn't kill pgrp: %m"); + } + if (orig_ttyfd >= 0) { close(fd); - fd = ttyfd; - ttyfd = -1; - } + (void)wait((void *)0); + ttyfd = orig_ttyfd; + orig_ttyfd = -1; + } } - } +/* + * Check whether the link seems not to be 8-bit clean. + */ +void +clean_check() +{ + int x; + char *s; + + if (strioctl(pppfd, PPPIO_GCLEAN, &x, 0, sizeof(x)) < 0) + return; + s = NULL; + switch (~x) { + case RCV_B7_0: + s = "bit 7 set to 1"; + break; + case RCV_B7_1: + s = "bit 7 set to 0"; + break; + case RCV_EVNP: + s = "odd parity"; + break; + case RCV_ODDP: + s = "even parity"; + break; + } + if (s != NULL) { + warn("Serial link is not 8-bit clean:"); + warn("All received characters had %s", s); + } +} /* * List of valid speeds. @@ -539,7 +571,7 @@ translate_speed(bps) for (speedp = speeds; speedp->speed_int; speedp++) if (bps == speedp->speed_int) return speedp->speed_val; - syslog(LOG_WARNING, "speed %d not supported", bps); + warn("speed %d not supported", bps); return 0; } @@ -572,10 +604,8 @@ set_up_tty(fd, local) int speed; struct termios tios; - if (tcgetattr(fd, &tios) < 0) { - syslog(LOG_ERR, "tcgetattr: %m"); - die(1); - } + if (tcgetattr(fd, &tios) < 0) + fatal("tcgetattr: %m"); if (!restore_term) { inittermios = tios; @@ -610,20 +640,15 @@ set_up_tty(fd, local) } else { speed = cfgetospeed(&tios); /* - * We can't proceed if the serial port speed is B0, + * We can't proceed if the serial port speed is 0, * since that implies that the serial port is disabled. */ - if (speed == B0) { - syslog(LOG_ERR, "Baud rate for %s is 0; need explicit baud rate", - devnam); - die(1); - } + if (speed == B0) + fatal("Baud rate for %s is 0; need explicit baud rate", devnam); } - if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) { - syslog(LOG_ERR, "tcsetattr: %m"); - die(1); - } + if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) + fatal("tcsetattr: %m"); baud_rate = inspeed = baud_rate_of(speed); restore_term = 1; @@ -633,7 +658,8 @@ set_up_tty(fd, local) * restore_tty - restore the terminal to the saved settings. */ void -restore_tty() +restore_tty(fd) + int fd; { if (restore_term) { if (!default_device) { @@ -646,8 +672,8 @@ restore_tty() inittermios.c_lflag &= ~(ECHO | ECHONL); } if (tcsetattr(fd, TCSAFLUSH, &inittermios) < 0) - if (errno != ENXIO) - syslog(LOG_WARNING, "tcsetattr: %m"); + if (!hungup && errno != ENXIO) + warn("tcsetattr: %m"); ioctl(fd, TIOCSWINSZ, &wsinfo); restore_term = 0; } @@ -666,6 +692,16 @@ int fd, on; ioctl(fd, (on? TIOCMBIS: TIOCMBIC), &modembits); } +/* + * open_loopback - open the device we use for getting packets + * in demand mode. Under Digital Unix, we use our existing fd + * to the ppp driver. + */ +int +open_ppp_loopback() +{ + return pppfd; +} /* * output - Output PPP packet. @@ -676,47 +712,111 @@ output(unit, p, len) u_char *p; int len; { - struct strbuf str; + struct strbuf data; int retries; struct pollfd pfd; if (debug) - log_packet(p, len, "sent "); + dbglog("sent %P", p, len); - str.len = len; - str.buf = (caddr_t) p; + data.len = len; + data.buf = (caddr_t) p; retries = 4; - while (putmsg(fd, NULL, &str, 0) < 0) { + while (putmsg(pppfd, NULL, &data, 0) < 0) { if (--retries < 0 || (errno != EWOULDBLOCK && errno != EAGAIN)) { if (errno != ENXIO) - syslog(LOG_ERR, "Couldn't send packet: %m"); + error("Couldn't send packet: %m"); break; } - pfd.fd = fd; + pfd.fd = pppfd; pfd.events = POLLOUT; poll(&pfd, 1, 250); /* wait for up to 0.25 seconds */ } } + /* - * wait_input - wait for input, for a length of time specified in *timo. + * wait_input - wait until there is data available on fd, + * for the length of time specified by *timo (indefinite + * if timo is NULL). */ void wait_input(timo) struct timeval *timo; { int t; - struct pollfd pfd; t = timo == NULL? -1: timo->tv_sec * 1000 + timo->tv_usec / 1000; - pfd.fd = fd; - pfd.events = POLLIN | POLLPRI | POLLHUP; - if (poll(&pfd, 1, t) < 0 && errno != EINTR) { - syslog(LOG_ERR, "poll: %m"); - die(1); + if (poll(pollfds, n_pollfds, t) < 0 && errno != EINTR) + fatal("poll: %m"); +} + +/* + * add_fd - add an fd to the set that wait_input waits for. + */ +void add_fd(fd) + int fd; +{ + int n; + + for (n = 0; n < n_pollfds; ++n) + if (pollfds[n].fd == fd) + return; + if (n_pollfds < MAX_POLLFDS) { + pollfds[n_pollfds].fd = fd; + pollfds[n_pollfds].events = POLLIN | POLLPRI | POLLHUP; + ++n_pollfds; + } else + error("Too many inputs!"); +} + +/* + * remove_fd - remove an fd from the set that wait_input waits for. + */ +void remove_fd(fd) + int fd; +{ + int n; + + for (n = 0; n < n_pollfds; ++n) { + if (pollfds[n].fd == fd) { + while (++n < n_pollfds) + pollfds[n-1] = pollfds[n]; + --n_pollfds; + break; + } } } +#if 0 +/* + * wait_loop_output - wait until there is data available on the + * loopback, for the length of time specified by *timo (indefinite + * if timo is NULL). + */ +void +wait_loop_output(timo) + struct timeval *timo; +{ + wait_input(timo); +} + +/* + * wait_time - wait for a given length of time or until a + * signal is received. + */ +void +wait_time(timo) + struct timeval *timo; +{ + int n; + + n = select(0, NULL, NULL, NULL, timo); + if (n < 0 && errno != EINTR) + fatal("select: %m"); +} +#endif + /* * read_packet - get a PPP packet from the serial device. */ @@ -724,37 +824,52 @@ int read_packet(buf) u_char *buf; { - struct strbuf str, ctl; - int len, i; - unsigned char ctlbuf[16]; - - str.maxlen = PPP_MTU + PPP_HDRLEN; - str.buf = (caddr_t) buf; - ctl.maxlen = sizeof(ctlbuf); - ctl.buf = (caddr_t) ctlbuf; - i = 0; - len = getmsg(fd, &ctl, &str, &i); - if (len < 0) { - if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) { - return -1; + struct strbuf ctrl, data; + int flags, len; + unsigned char ctrlbuf[64]; + + for (;;) { + data.maxlen = PPP_MRU + PPP_HDRLEN; + data.buf = (caddr_t) buf; + ctrl.maxlen = sizeof(ctrlbuf); + ctrl.buf = (caddr_t) ctrlbuf; + flags = 0; + len = getmsg(pppfd, &ctrl, &data, &flags); + if (len < 0) { + if (errno = EAGAIN || errno == EWOULDBLOCK || errno == EINTR) + return -1; + fatal("Error reading packet: %m"); } - syslog(LOG_ERR, "getmsg(fd) %m"); - die(1); - } - if (len) - MAINDEBUG((LOG_DEBUG, "getmsg returned 0x%x",len)); - if (ctl.len > 0) - syslog(LOG_NOTICE, "got ctrl msg len %d %x %x\n", ctl.len, - ctlbuf[0], ctlbuf[1]); - - if (str.len < 0) { - MAINDEBUG((LOG_DEBUG, "getmsg short return length %d", str.len)); - return -1; - } - return str.len; + if (ctrl.len <= 0) + return data.len; + + /* + * Got a M_PROTO or M_PCPROTO message. Huh? + */ + if (debug) + dbglog("got ctrl msg len=%d", ctrl.len); + + } } +/* + * get_loop_output - get outgoing packets from the ppp device, + * and detect when we want to bring the real link up. + * Return value is 1 if we need to bring up the link, 0 otherwise. + */ +int +get_loop_output() +{ + int len; + int rv = 0; + + while ((len = read_packet(inpacket_buf)) > 0) { + if (loop_frame(inpacket_buf, len)) + rv = 1; + } + return rv; +} /* * ppp_send_config - configure the transmit characteristics of @@ -766,35 +881,24 @@ ppp_send_config(unit, mtu, asyncmap, pcomp, accomp) u_int32_t asyncmap; int pcomp, accomp; { - char c; - struct ifreq ifr; + int cf[2]; - strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); - ifr.ifr_mtu = mtu; - if (ioctl(sockfd, (int)SIOCSIPMTU, (caddr_t) &ifr) < 0) { - syslog(LOG_ERR, "ioctl(SIOCSIPMTU): %m"); - quit(); + link_mtu = mtu; + if (strioctl(pppfd, PPPIO_MTU, &mtu, sizeof(mtu), 0) < 0) { + if (hungup && errno == ENXIO) + return; + error("Couldn't set MTU: %m"); } - - if(ioctl(fd, (int)SIOCSIFASYNCMAP, (caddr_t) &asyncmap) < 0) { - syslog(LOG_ERR, "ioctl(SIOCSIFASYNCMAP): %m"); - quit(); - } - - c = (pcomp? 1: 0); - if(ioctl(fd, (int)SIOCSIFCOMPPROT, &c) < 0) { - syslog(LOG_ERR, "ioctl(SIOCSIFCOMPPROT): %m"); - quit(); + if (strioctl(pppfd, PPPIO_XACCM, &asyncmap, sizeof(asyncmap), 0) < 0) { + error("Couldn't set transmit ACCM: %m"); } - - c = (accomp? 1: 0); - if(ioctl(fd, (int)SIOCSIFCOMPAC, &c) < 0) { - syslog(LOG_ERR, "ioctl(SIOCSIFCOMPAC): %m"); - quit(); + cf[0] = (pcomp? COMP_PROT: 0) + (accomp? COMP_AC: 0); + cf[1] = COMP_PROT | COMP_AC; + if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) { + error("Couldn't set prot/AC compression: %m"); } } - /* * ppp_set_xaccm - set the extended transmit ACCM for the interface. */ @@ -803,11 +907,12 @@ ppp_set_xaccm(unit, accm) int unit; ext_accm accm; { - if (ioctl(fd, (int)SIOCSIFXASYNCMAP, accm) < 0 && errno != ENOTTY) - syslog(LOG_WARNING, "ioctl(set extended ACCM): %m"); + if (strioctl(pppfd, PPPIO_XACCM, accm, sizeof(ext_accm), 0) < 0) { + if (!hungup || errno != ENXIO) + warn("Couldn't set extended ACCM: %m"); + } } - /* * ppp_recv_config - configure the receive-side characteristics of * the ppp interface. @@ -818,45 +923,63 @@ ppp_recv_config(unit, mru, asyncmap, pcomp, accomp) u_int32_t asyncmap; int pcomp, accomp; { - char c; - - if (ioctl(fd, (int)SIOCSIFMRU, &mru) < 0) { - syslog(LOG_ERR, "ioctl(SIOCSIFMRU): %m"); - } + int cf[2]; - if (ioctl(fd, (int)SIOCSIFRASYNCMAP, (caddr_t) &asyncmap) < 0) { - syslog(LOG_ERR, "ioctl(SIOCSIFRASYNCMAP): %m"); + link_mru = mru; + if (strioctl(pppfd, PPPIO_MRU, &mru, sizeof(mru), 0) < 0) { + if (hungup && errno == ENXIO) + return; + error("Couldn't set MRU: %m"); } - - c = 2 + (pcomp? 1: 0); - if(ioctl(fd, (int)SIOCSIFCOMPPROT, &c) < 0) { - syslog(LOG_ERR, "ioctl(SIOCSIFCOMPPROT): %m"); + if (strioctl(pppfd, PPPIO_RACCM, &asyncmap, sizeof(asyncmap), 0) < 0) { + error("Couldn't set receive ACCM: %m"); } - - c = 2 + (accomp? 1: 0); - if (ioctl(fd, (int)SIOCSIFCOMPAC, &c) < 0) { - syslog(LOG_ERR, "ioctl(SIOCSIFCOMPAC): %m"); + cf[0] = (pcomp? DECOMP_PROT: 0) + (accomp? DECOMP_AC: 0); + cf[1] = DECOMP_PROT | DECOMP_AC; + if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) { + error("Couldn't set prot/AC decompression: %m"); } } /* * ccp_test - ask kernel whether a given compression method * is acceptable for use. + * + * In Digital UNIX the memory buckets for chunks >16K are not + * primed when the system comes up. That means we're not + * likely to get the memory needed for the compressor on + * the first try. The way we work around this is to have + * the driver spin off a thread to go get the memory for us + * (we can't block at that point in a streams context.) + * + * This code synchronizes with the thread when it has returned + * with the memory we need. The driver will continue to return + * with EAGAIN until the thread comes back. We give up here + * if after 10 attempts in one second we still don't have memory. + * It's up to the driver to not lose track of that memory if + * thread takes too long to return. */ int ccp_test(unit, opt_ptr, opt_len, for_transmit) int unit, opt_len, for_transmit; u_char *opt_ptr; { - struct ppp_option_data data; - - if ((unsigned) opt_len > MAX_PPP_OPTION) - opt_len = MAX_PPP_OPTION; - data.length = opt_len; - data.transmit = for_transmit; - BCOPY(opt_ptr, data.opt_data, opt_len); - if (ioctl(fd, (int)SIOCSCOMPRESS, (caddr_t) &data) >= 0) - return 1; + struct timeval tval; + int i; + + tval.tv_sec = 0; + tval.tv_usec = 100000; + for (i = 0; i < 10; ++i) { + if (strioctl(pppfd, (for_transmit? PPPIO_XCOMP: PPPIO_RCOMP), + opt_ptr, opt_len, 0) >= 0) { + return 1; + } + if (errno != EAGAIN) + break; + wait_time(&tval); + } + if (errno != 0) + error("hard failure trying to get memory for a compressor: %m"); return (errno == ENOSR)? 0: -1; } @@ -867,13 +990,47 @@ void ccp_flags_set(unit, isopen, isup) int unit, isopen, isup; { - int x; + int cf[2]; - x = (isopen? 1: 0) + (isup? 2: 0); - if (ioctl(fd, (int)SIOCSIFCOMP, (caddr_t) &x) < 0 && errno != ENOTTY) - syslog(LOG_ERR, "ioctl (SIOCSIFCOMP): %m"); + cf[0] = (isopen? CCP_ISOPEN: 0) + (isup? CCP_ISUP: 0); + cf[1] = CCP_ISOPEN | CCP_ISUP | CCP_ERROR | CCP_FATALERROR; + if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) { + if (!hungup || errno != ENXIO) + error("Couldn't set kernel CCP state: %m"); + } } +/* + * get_idle_time - return how long the link has been idle. + */ +int +get_idle_time(u, ip) + int u; + struct ppp_idle *ip; +{ + return strioctl(pppfd, PPPIO_GIDLE, ip, 0, sizeof(struct ppp_idle)) >= 0; +} + +/* + * get_ppp_stats - return statistics for the link. + */ +int +get_ppp_stats(u, stats) + int u; + struct pppd_stats *stats; +{ + struct ppp_stats s; + + if (strioctl(pppfd, PPPIO_GETSTAT, &s, 0, sizeof(s)) < 0) { + error("Couldn't get link statistics: %m"); + return 0; + } + stats->bytes_in = s.p.ppp_ibytes; + stats->bytes_out = s.p.ppp_obytes; + return 1; +} + + /* * ccp_fatal_error - returns 1 if decompression was disabled as a * result of an error detected after decompression of a packet, @@ -883,29 +1040,43 @@ int ccp_fatal_error(unit) int unit; { - int x; + int cf[2]; - if (ioctl(fd, (int)SIOCGIFCOMP, (caddr_t) &x) < 0) { - syslog(LOG_ERR, "ioctl(SIOCGIFCOMP): %m"); + cf[0] = cf[1] = 0; + if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) { + if (errno != ENXIO && errno != EINVAL) + error("Couldn't get compression flags: %m"); return 0; } - return x & CCP_FATALERROR; + return cf[0] & CCP_FATALERROR; } /* * sifvjcomp - config tcp header compression */ int -sifvjcomp(u, vjcomp, cidcomp, maxcid) - int u, vjcomp, cidcomp, maxcid; +sifvjcomp(u, vjcomp, xcidcomp, xmaxcid) + int u, vjcomp, xcidcomp, xmaxcid; { - char x; + int cf[2]; + char maxcid[2]; + + if (vjcomp) { + maxcid[0] = xcidcomp; + maxcid[1] = 15; /* XXX should be rmaxcid */ + if (strioctl(pppfd, PPPIO_VJINIT, maxcid, sizeof(maxcid), 0) < 0) { + error("Couldn't initialize VJ compression: %m"); + } + } - x = (vjcomp? 1: 0) + (cidcomp? 0: 2) + (maxcid << 4); - if (ioctl(fd, (int)SIOCSIFVJCOMP, (caddr_t) &x) < 0) { - syslog(LOG_ERR, "ioctl(SIOCSIFVJCOMP): %m"); - return 0; + cf[0] = (vjcomp? COMP_VJC + DECOMP_VJC: 0) /* XXX this is wrong */ + + (xcidcomp? COMP_VJCCID + DECOMP_VJCCID: 0); + cf[1] = COMP_VJC + DECOMP_VJC + COMP_VJCCID + DECOMP_VJCCID; + if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) { + if (vjcomp) + error("Couldn't enable VJ compression: %m"); } + return 1; } @@ -917,72 +1088,75 @@ sifup(u) int u; { struct ifreq ifr; - struct npioctl npi; - strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); - if (ioctl(sockfd, (int)SIOCGIFFLAGS, (caddr_t) &ifr) < 0) { - syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m"); + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) { + error("Couldn't mark interface up (get): %m"); return 0; } ifr.ifr_flags |= IFF_UP; - if (ioctl(sockfd, (int)SIOCSIFFLAGS, (caddr_t) &ifr) < 0) { - syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m"); + if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) { + error("Couldn't mark interface up (set): %m"); return 0; } if_is_up = 1; - npi.protocol = PPP_IP; - npi.mode = NPMODE_PASS; - if (ioctl(fd, (int)SIOCSETNPMODE, &npi) < 0) { - if (errno != ENOTTY) { - syslog(LOG_ERR, "ioctl(SIOCSETNPMODE): %m"); - return 0; - } - } return 1; } /* - * sifdown - Config the interface down. + * sifdown - Config the interface down and disable IP. */ int sifdown(u) int u; { struct ifreq ifr; - int rv; - struct npioctl npi; - - rv = 1; - npi.protocol = PPP_IP; - npi.mode = NPMODE_ERROR; - if (ioctl(fd, (int)SIOCSETNPMODE, (caddr_t) &npi) < 0) { - if (errno != ENOTTY) { - syslog(LOG_ERR, "ioctl(SIOCSETNPMODE): %m"); - rv = 0; + + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) { + error("Couldn't mark interface down (get): %m"); + return 0; + } + if ((ifr.ifr_flags & IFF_UP) != 0) { + ifr.ifr_flags &= ~IFF_UP; + if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) { + error("Couldn't mark interface down (set): %m"); + return 0; } } + if_is_up = 0; + return 1; +} - strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); - if (ioctl(sockfd, (int)SIOCGIFFLAGS, (caddr_t) &ifr) < 0) { - syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m"); - rv = 0; - } else { - ifr.ifr_flags &= ~IFF_UP; - if (ioctl(sockfd, (int)SIOCSIFFLAGS, (caddr_t) &ifr) < 0) { - syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m"); - rv = 0; - } else - if_is_up = 0; +/* + * sifnpmode - Set the mode for handling packets for a given NP. + */ +int +sifnpmode(u, proto, mode) + int u; + int proto; + enum NPmode mode; +{ + int npi[2]; + + npi[0] = proto; + npi[1] = (int) mode; + if (strioctl(pppfd, PPPIO_NPMODE, npi, 2 * sizeof(int), 0) < 0) { + error("ioctl(set NP %d mode to %d): %m", proto, mode); + return 0; } - return rv; + return 1; } +#define INET_ADDR(x) (((struct sockaddr_in *) &(x))->sin_addr.s_addr) + /* * SET_SA_FAMILY - initialize a struct sockaddr, setting the sa_family field. */ -#define SET_SA_FAMILY(addr, family) \ - BZERO((char *) &(addr), sizeof(addr)); \ - addr.sa_family = (family); +#define SET_SA_FAMILY(addr, family) \ + BZERO((char *) &(addr), sizeof(addr)); \ + addr.sa_family = (family); \ + addr.sa_len = sizeof ((addr)) /* * sifaddr - Config the interface IP addresses and netmask. @@ -992,42 +1166,56 @@ sifaddr(u, o, h, m) int u; u_int32_t o, h, m; { - int ret; struct ifreq ifr; + struct ifaliasreq addreq; + int ret; ret = 1; - strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); + + /* flush old address, if any + */ + bzero(&ifr, sizeof (ifr)); + strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); SET_SA_FAMILY(ifr.ifr_addr, AF_INET); ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = o; - if (ioctl(sockfd, (int)SIOCSIFADDR, (caddr_t) &ifr) < 0) { - syslog(LOG_ERR, "ioctl(SIOCSIFADDR): %m"); - ret = 0; - } - ((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr = h; - if (ioctl(sockfd, (int)SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) { - syslog(LOG_ERR, "ioctl(SIOCSIFDSTADDR): %m"); - ret = 0; + if ((ioctl(sockfd, (int)SIOCDIFADDR, (caddr_t) &ifr) < 0) + && errno != EADDRNOTAVAIL) { + error("ioctl(SIOCDIFADDR): %m"); + ret = 0; } + + bzero(&addreq, sizeof (addreq)); + strlcpy(addreq.ifra_name, ifname, sizeof (addreq.ifra_name)); + SET_SA_FAMILY(addreq.ifra_addr, AF_INET); + SET_SA_FAMILY(addreq.ifra_broadaddr, AF_INET); + ((struct sockaddr_in *)&addreq.ifra_addr)->sin_addr.s_addr = o; + ((struct sockaddr_in *)&addreq.ifra_broadaddr)->sin_addr.s_addr = h; + if (m != 0) { - ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = m; - syslog(LOG_INFO, "Setting interface mask to %s\n", ip_ntoa(m)); - if (ioctl(sockfd, (int)SIOCSIFNETMASK, (caddr_t) &ifr) < 0) { - syslog(LOG_ERR, "ioctl(SIOCSIFNETMASK): %m"); - ret = 0; - } + ((struct sockaddr_in *)&addreq.ifra_mask)->sin_addr.s_addr = m; + addreq.ifra_mask.sa_len = sizeof (struct sockaddr); + info("Setting interface mask to %s\n", ip_ntoa(m)); } -/* Reset if address --- This is stupid, but seems to be necessary... */ + /* install new src/dst and (possibly) netmask + */ + if (ioctl(sockfd, SIOCPIFADDR, &addreq) < 0) { + error("ioctl(SIOCPIFADDR): %m"); + ret = 0; + } - ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = o; - if (ioctl(sockfd, (int)SIOCSIFADDR, (caddr_t) &ifr) < 0) { - syslog(LOG_ERR, "ioctl(SIOCSIFADDR): %m"); + ifr.ifr_metric = link_mtu; + if (ioctl(sockfd, SIOCSIPMTU, &ifr) < 0) { + error("Couldn't set IP MTU: %m"); ret = 0; } - return ret; + ifaddrs[0] = o; + ifaddrs[1] = h; + return (ret); } + /* * cifaddr - Clear the interface IP addresses, and delete routes * through the interface if possible. @@ -1037,59 +1225,64 @@ cifaddr(u, o, h) int u; u_int32_t o, h; { - struct ortentry rt; + struct ifreq ifr; - SET_SA_FAMILY(rt.rt_dst, AF_INET); - ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = h; - SET_SA_FAMILY(rt.rt_gateway, AF_INET); - ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = o; - rt.rt_flags = RTF_HOST; - if (ioctl(sockfd, (int)SIOCDELRT, (caddr_t) &rt) < 0) { - syslog(LOG_ERR, "ioctl(SIOCDELRT): %m"); - return 0; + ifaddrs[0] = 0; + ifaddrs[1] = 0; + bzero(&ifr, sizeof (ifr)); + strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); + SET_SA_FAMILY(ifr.ifr_addr, AF_INET); + ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = o; + if (ioctl(sockfd, (int)SIOCDIFADDR, (caddr_t) &ifr) < 0) { + error("ioctl(SIOCDIFADDR): %m"); + return 0; } return 1; } + /* * sifdefaultroute - assign a default route through the address given. */ int -sifdefaultroute(u, g) +sifdefaultroute(u, l, g) int u; - u_int32_t g; + u_int32_t l, g; { struct ortentry rt; + BZERO(&rt, sizeof(rt)); SET_SA_FAMILY(rt.rt_dst, AF_INET); SET_SA_FAMILY(rt.rt_gateway, AF_INET); ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g; rt.rt_flags = RTF_GATEWAY; if (ioctl(sockfd, (int)SIOCADDRT, &rt) < 0) { - syslog(LOG_ERR, "default route ioctl(SIOCADDRT): %m"); - return 0; + error("default route ioctl(SIOCADDRT): %m"); + return 0; } default_route_gateway = g; return 1; } + /* * cifdefaultroute - delete a default route through the address given. */ int -cifdefaultroute(u, g) +cifdefaultroute(u, l, g) int u; - u_int32_t g; + u_int32_t l, g; { struct ortentry rt; + BZERO(&rt, sizeof(rt)); SET_SA_FAMILY(rt.rt_dst, AF_INET); SET_SA_FAMILY(rt.rt_gateway, AF_INET); ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g; rt.rt_flags = RTF_GATEWAY; if (ioctl(sockfd, (int)SIOCDELRT, &rt) < 0) { - syslog(LOG_ERR, "default route ioctl(SIOCDELRT): %m"); - return 0; + error("default route ioctl(SIOCDELRT): %m"); + return 0; } default_route_gateway = 0; return 1; @@ -1112,22 +1305,23 @@ sifproxyarp(unit, hisaddr) * as our local address. */ if (!get_ether_addr(hisaddr, &arpreq.arp_ha)) { - syslog(LOG_WARNING, "Cannot determine ethernet address for proxy ARP"); - return 0; + warn("Cannot determine ethernet address for proxy ARP"); + return 0; } SET_SA_FAMILY(arpreq.arp_pa, AF_INET); ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr; arpreq.arp_flags = ATF_PERM | ATF_PUBL; if (ioctl(sockfd, (int)SIOCSARP, (caddr_t)&arpreq) < 0) { - syslog(LOG_ERR, "ioctl(SIOCSARP): %m"); - return 0; + error("ioctl(SIOCSARP): %m"); + return 0; } proxy_arp_addr = hisaddr; return 1; } + /* * cifproxyarp - Delete the proxy ARP entry for the peer. */ @@ -1142,8 +1336,8 @@ cifproxyarp(unit, hisaddr) SET_SA_FAMILY(arpreq.arp_pa, AF_INET); ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr; if (ioctl(sockfd, (int)SIOCDARP, (caddr_t)&arpreq) < 0) { - syslog(LOG_ERR, "ioctl(SIOCDARP): %m"); - return 0; + error("ioctl(SIOCDARP): %m"); + return 0; } proxy_arp_addr = 0; return 1; @@ -1153,18 +1347,15 @@ cifproxyarp(unit, hisaddr) * get_ether_addr - get the hardware address of an interface on the * the same subnet as ipaddr. */ -#define MAX_IFS 32 - -int s; +#define MAX_IFS 32 static int get_ether_addr(ipaddr, hwaddr) - u_int ipaddr; + u_int32_t ipaddr; struct sockaddr *hwaddr; { - struct ifreq *ifr, *ifend, *ifp; - u_int ina, mask; - struct sockaddr_dl *dla; + struct ifreq *ifr, *ifend; + u_int32_t ina, mask; struct ifreq ifreq; struct ifconf ifc; struct ifreq ifs[MAX_IFS]; @@ -1172,9 +1363,9 @@ get_ether_addr(ipaddr, hwaddr) ifc.ifc_len = sizeof(ifs); ifc.ifc_req = ifs; - if (ioctl(sockfd, (int)SIOCGIFCONF, &ifc) < 0) { - perror("ioctl(SIOCGIFCONF)"); - return 0; + if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) { + error("ioctl(SIOCGIFCONF): %m"); + return 0; } /* @@ -1182,39 +1373,43 @@ get_ether_addr(ipaddr, hwaddr) * address on the same subnet as `ipaddr'. */ ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len); - for (ifr = ifc.ifc_req; ifr < ifend; ) { + for (ifr = ifc.ifc_req; ifr < ifend; ifr++) { if (ifr->ifr_addr.sa_family == AF_INET) { - ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr; - strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name)); + /* * Check that the interface is up, and not point-to-point * or loopback. */ - if (ioctl(sockfd, (int)SIOCGIFFLAGS, &ifreq) < 0) + strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name)); + if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0) continue; if ((ifreq.ifr_flags & (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP)) != (IFF_UP|IFF_BROADCAST)) continue; + /* * Get its netmask and check that it's on the right subnet. */ - if (ioctl(sockfd, (int)SIOCGIFNETMASK, &ifreq) < 0) + if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0) continue; + ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr; mask = ((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr.s_addr; if ((ipaddr & mask) != (ina & mask)) continue; break; - } - ifr++; + } else { + if (ifr->ifr_addr.sa_len > sizeof (ifr->ifr_addr)) + ifr = (struct ifreq *)((caddr_t)ifr + (ifr->ifr_addr.sa_len - sizeof (ifr->ifr_addr))); + } } if (ifr >= ifend) - return 0; - syslog(LOG_INFO, "found interface %s for proxy arp", ifr->ifr_name); + return 0; + info("found interface %s for proxy arp", ifr->ifr_name); - strncpy(ifdevreq.ifr_name, ifr->ifr_name, sizeof(ifdevreq.ifr_name)); + strlcpy(ifdevreq.ifr_name, ifr->ifr_name, sizeof(ifdevreq.ifr_name)); if (ioctl(sockfd, (int)SIOCRPHYSADDR, &ifdevreq) < 0) { perror("ioctl(SIOCRPHYSADDR)"); @@ -1223,9 +1418,31 @@ get_ether_addr(ipaddr, hwaddr) hwaddr->sa_family = AF_UNSPEC; memcpy(hwaddr->sa_data, ifdevreq.current_pa, sizeof(ifdevreq.current_pa)); - return(1); + return 1; } +#define WTMPFILE "/usr/adm/wtmp" + +void +logwtmp(line, name, host) + const char *line, *name, *host; +{ + int fd; + struct stat buf; + struct utmp ut; + + if ((fd = open(WTMPFILE, O_WRONLY|O_APPEND, 0)) < 0) + return; + if (!fstat(fd, &buf)) { + strlcpy(ut.ut_line, line, sizeof(ut.ut_line)); + strlcpy(ut.ut_name, name, sizeof(ut.ut_name)); + strlcpy(ut.ut_host, host, sizeof(ut.ut_host)); + (void)time(&ut.ut_time); + if (write(fd, (char *)&ut, sizeof(struct utmp)) != sizeof(struct utmp)) + (void)ftruncate(fd, buf.st_size); + } + close(fd); +} /* * Return user specified netmask, modified by any mask we might determine @@ -1242,7 +1459,6 @@ GetMask(addr) u_int32_t mask, nmask, ina; struct ifreq *ifr, *ifend, ifreq; struct ifconf ifc; - struct ifreq ifs[MAX_IFS]; addr = ntohl(addr); if (IN_CLASSA(addr)) /* determine network mask for address class */ @@ -1257,65 +1473,189 @@ GetMask(addr) /* * Scan through the system's network interfaces. */ - ifc.ifc_len = sizeof(ifs); - ifc.ifc_req = ifs; + ifc.ifc_len = MAX_IFS * sizeof(struct ifreq); + ifc.ifc_req = (struct ifreq *)alloca(ifc.ifc_len); + if (ifc.ifc_req == 0) + return mask; if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) { - syslog(LOG_WARNING, "ioctl(SIOCGIFCONF): %m"); + warn("Couldn't get system interface list: %m"); return mask; } ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len); - for (ifr = ifc.ifc_req; ifr < ifend; ++ifr) { + for (ifr = ifc.ifc_req; ifr < ifend; ifr++) { /* * Check the interface's internet address. */ - if (ifr->ifr_addr.sa_family != AF_INET) - continue; - ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr; - if ((ntohl(ina) & nmask) != (addr & nmask)) - continue; - /* - * Check that the interface is up, and not point-to-point or loopback. - */ - strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name)); - if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0) - continue; - if ((ifreq.ifr_flags & (IFF_UP|IFF_POINTOPOINT|IFF_LOOPBACK)) - != IFF_UP) - continue; - /* - * Get its netmask and OR it into our mask. - */ - if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0) - continue; - mask |= ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr.s_addr; + if (ifr->ifr_addr.sa_family == AF_INET) { + ina = INET_ADDR(ifr->ifr_addr); + if ((ntohl(ina) & nmask) != (addr & nmask)) + continue; + /* + * Check that the interface is up, and not point-to-point or loopback. + */ + strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name)); + if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0) + continue; + if ((ifreq.ifr_flags & (IFF_UP|IFF_POINTOPOINT|IFF_LOOPBACK)) + != IFF_UP) + continue; + /* + * Get its netmask and OR it into our mask. + */ + if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0) + continue; + mask |= INET_ADDR(ifreq.ifr_addr); + break; + } else { + if (ifr->ifr_addr.sa_len > sizeof (ifr->ifr_addr)) + ifr = (struct ifreq *)((caddr_t)ifr + (ifr->ifr_addr.sa_len - sizeof (ifr->ifr_addr))); + } } return mask; } +/* + * have_route_to - determine if the system has any route to + * a given IP address. `addr' is in network byte order. + * For demand mode to work properly, we have to ignore routes + * through our own interface. + */ +int have_route_to(u_int32_t addr) +{ + char buf[sizeof(struct rt_msghdr) + (sizeof(struct sockaddr_in))]; + int status; + int s, n; + struct rt_msghdr *rtm; + struct sockaddr_in *sin; + int msglen = sizeof(*rtm) + (sizeof(*sin)); + char *cp; + char msg[2048]; + + rtm = (struct rt_msghdr *)buf; + memset(rtm, 0, msglen); + rtm->rtm_msglen = msglen; + rtm->rtm_version = RTM_VERSION; + rtm->rtm_type = RTM_GET; + rtm->rtm_addrs = RTA_DST; + /* rtm->rtm_addrs, rtm_flags should be set on output */ + + sin = (struct sockaddr_in *)((u_char *)rtm + sizeof(*rtm)); + sin->sin_len = sizeof(*sin); + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = addr; + + status = 0; + + if ((s = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) + return -1; + if (write(s, (char *)rtm, msglen) != msglen) { + close(s); + return status == ESRCH? 0: -1; + } -#define WTMPFILE "/usr/adm/wtmp" -#include + n = read(s, msg, 2048); + close(s); + if (n <= 0) + return -1; + + rtm = (struct rt_msghdr *) msg; + if (rtm->rtm_version != RTM_VERSION) + return -1; + + /* here we try to work out if the route is through our own interface */ + cp = (char *)(rtm + 1); + if (rtm->rtm_addrs & RTA_DST) { + struct sockaddr *sa = (struct sockaddr *) cp; + cp = (char *)(((unsigned long)cp + sa->sa_len + + sizeof(long) - 1) & ~(sizeof(long) - 1)); + } + if (rtm->rtm_addrs & RTA_GATEWAY) { + sin = (struct sockaddr_in *) cp; + if (sin->sin_addr.s_addr == ifaddrs[0] + || sin->sin_addr.s_addr == ifaddrs[1]) + return 0; /* route is through our interface */ + } -void -logwtmp(line, name, host) - char *line, *name, *host; + return 1; +} + +static int +strioctl(fd, cmd, ptr, ilen, olen) + int fd, cmd, ilen, olen; + void *ptr; { - int fd; - struct stat buf; - struct utmp ut; + struct strioctl str; - if ((fd = open(WTMPFILE, O_WRONLY|O_APPEND, 0)) < 0) - return; - if (!fstat(fd, &buf)) { - (void)strncpy(ut.ut_line, line, sizeof(ut.ut_line)); - (void)strncpy(ut.ut_name, name, sizeof(ut.ut_name)); - (void)strncpy(ut.ut_host, host, sizeof(ut.ut_host)); - (void)time(&ut.ut_time); - if (write(fd, (char *)&ut, sizeof(struct utmp)) != sizeof(struct utmp)) - (void)ftruncate(fd, buf.st_size); + str.ic_cmd = cmd; + str.ic_timout = 0; + str.ic_len = ilen; + str.ic_dp = ptr; + if (ioctl(fd, I_STR, &str) == -1) + return -1; + if (str.ic_len != olen) + dbglog("strioctl: expected %d bytes, got %d for cmd %x\n", + olen, str.ic_len, cmd); + return 0; +} + +/* + * Use the hostid as part of the random number seed. + */ +int +get_host_seed() +{ + return gethostid(); +} + +/* + * get_pty - get a pty master/slave pair and chown the slave side + * to the uid given. Assumes slave_name points to >= 12 bytes of space. + */ +int +get_pty(master_fdp, slave_fdp, slave_name, uid) + int *master_fdp; + int *slave_fdp; + char *slave_name; + int uid; +{ + int i, mfd, sfd; + char pty_name[12]; + struct termios tios; + + sfd = -1; + for (i = 0; i < 64; ++i) { + slprintf(pty_name, sizeof(pty_name), "/dev/pty%c%x", + 'p' + i / 16, i % 16); + mfd = open(pty_name, O_RDWR, 0); + if (mfd >= 0) { + pty_name[5] = 't'; + sfd = open(pty_name, O_RDWR | O_NOCTTY, 0); + if (sfd >= 0) + break; + close(mfd); + } } - close(fd); + if (sfd < 0) + return 0; + + strlcpy(slave_name, pty_name, 12); + *master_fdp = mfd; + *slave_fdp = sfd; + fchown(sfd, uid, -1); + fchmod(sfd, S_IRUSR | S_IWUSR); + if (tcgetattr(sfd, &tios) == 0) { + tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB); + tios.c_cflag |= CS8 | CREAD; + tios.c_iflag = IGNPAR | CLOCAL; + tios.c_oflag = 0; + tios.c_lflag = 0; + if (tcsetattr(sfd, TCSAFLUSH, &tios) < 0) + warn("couldn't set attributes on pty: %m"); + } else + warn("couldn't get attributes on pty: %m"); + + return 1; } /* @@ -1323,19 +1663,23 @@ logwtmp(line, name, host) * This code is derived from chat.c. */ +#if !defined(HDB) && !defined(SUNOS3) +#define HDB 1 /* ascii lock files are the default */ +#endif + #ifndef LOCK_DIR -# ifdef HDB -# define PIDSTRING -# define LOCK_PREFIX "/usr/spool/locks/LCK.." -# else /* HDB */ -# define LOCK_PREFIX "/usr/spool/uucp/LCK.." -# endif /* HDB */ +# if HDB +# define PIDSTRING +# define LOCK_PREFIX "/usr/spool/locks/LCK.." +# else /* HDB */ +# define LOCK_PREFIX "/usr/spool/uucp/LCK.." +# endif /* HDB */ #endif /* LOCK_DIR */ -static char *lock_file; +static char *lock_file; /* name of lock file created */ /* - * lock - create a lock file for the named device + * lock - create a lock file for the named device. */ int lock(dev) @@ -1344,13 +1688,15 @@ lock(dev) char hdb_lock_buffer[12]; int fd, pid, n; char *p; + size_t l; if ((p = strrchr(dev, '/')) != NULL) dev = p + 1; - lock_file = malloc(strlen(LOCK_PREFIX) + strlen(dev) + 1); + l = strlen(LOCK_PREFIX) + strlen(dev) + 1; + lock_file = malloc(l); if (lock_file == NULL) novm("lock file name"); - strcat(strcpy(lock_file, LOCK_PREFIX), dev); + slprintf(lock_file, l, "%s%s", LOCK_PREFIX, dev); while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) { if (errno == EEXIST @@ -1366,38 +1712,38 @@ lock(dev) n = read(fd, &pid, sizeof(pid)); #endif if (n <= 0) { - syslog(LOG_ERR, "Can't read pid from lock file %s", lock_file); + error("Can't read pid from lock file %s", lock_file); close(fd); } else { if (kill(pid, 0) == -1 && errno == ESRCH) { /* pid no longer exists - remove the lock file */ if (unlink(lock_file) == 0) { close(fd); - syslog(LOG_NOTICE, "Removed stale lock on %s (pid %d)", + notice("Removed stale lock on %s (pid %d)", dev, pid); continue; } else - syslog(LOG_WARNING, "Couldn't remove stale lock on %s", + warn("Couldn't remove stale lock on %s", dev); } else - syslog(LOG_NOTICE, "Device %s is locked by pid %d", + notice("Device %s is locked by pid %d", dev, pid); } close(fd); } else - syslog(LOG_ERR, "Can't create lock file %s: %m", lock_file); + error("Can't create lock file %s: %m", lock_file); free(lock_file); lock_file = NULL; return -1; } -# ifdef PIDSTRING - sprintf(hdb_lock_buffer, "%10d\n", getpid()); +#ifdef PIDSTRING + slprintf(hdb_lock_buffer, sizeof(hdb_lock_buffer), "%10d\n", getpid()); write(fd, hdb_lock_buffer, 11); -# else +#else pid = getpid(); write(fd, &pid, sizeof pid); -# endif +#endif close(fd); return 0; @@ -1416,3 +1762,34 @@ unlock() } } +int +set_filters(pass, active) + struct bpf_program *pass, *active; +{ + return 1; +} + +int +bpf_compile(program, buf, optimize) + struct bpf_program *program; + char *buf; + int optimize; +{ + return 0; +} + +char * +bpf_geterr() +{ + return 0; +} + +u_int +bpf_filter(pc, p, wirelen, buflen) + struct bpf_insn *pc; + u_char *p; + u_int wirelen; + u_int buflen; +{ + return 0; +}