*/
#ifndef lint
-static char rcsid[] = "$Id: sys-ultrix.c,v 1.8 1995/04/24 05:35:27 paulus Exp $";
+static char rcsid[] = "$Id: sys-ultrix.c,v 1.15 1995/10/27 03:51:52 paulus Exp $";
#endif
/*
#include "pppd.h"
static int initdisc = -1; /* Initial TTY discipline */
+static int initfdflags = -1; /* Initial file descriptor flags for fd */
-static int restore_term; /* 1 => we've munged the terminal */
+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 char *lock_file;
+static char *lock_file; /* name of lock file created */
+
+static int sockfd; /* socket for doing interface ioctls */
+
+static int if_is_up; /* the interface is currently up */
+static u_int32_t default_route_gateway; /* gateway addr for default route */
+static u_int32_t proxy_arp_addr; /* remote addr for proxy arp */
+
+/* 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 *));
-int sockfd; /* socket for doing interface ioctls */
/*
* sys_init - System-dependent initialization.
}
}
+/*
+ * 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().
+ */
+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 (default_route_gateway)
+ cifdefaultroute(0, default_route_gateway);
+ if (proxy_arp_addr)
+ cifproxyarp(0, proxy_arp_addr);
+}
+
/*
* note_debug_level - note a change in the debug level.
*/
return 0;
}
-
/*
* ppp_available - check whether the system has any ppp interfaces
* (in fact we check whether we can do an ioctl on ppp0).
*/
-
int
ppp_available()
{
int s, ok;
struct ifreq ifr;
+ extern char *no_ppp_msg;
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
- return 1; /* can't tell - maybe we're not root */
+ return 1; /* can't tell */
strncpy(ifr.ifr_name, "ppp0", sizeof (ifr.ifr_name));
ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 0;
close(s);
+ no_ppp_msg = "\
+This system lacks kernel support for PPP. To include PPP support\n\
+in the kernel, please follow the steps detailed in the README.ultrix\n\
+file in the ppp-2.2 distribution.\n";
return ok;
}
-
/*
* establish_ppp - Turn the serial port into a ppp interface.
*/
syslog(LOG_WARNING, "ioctl(PPPIOCSFLAGS): %m");
}
}
+
+ /*
+ * Set device for non-blocking reads.
+ */
+ 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");
+ }
}
int x;
char *s;
+ /* Reset non-blocking mode on the file descriptor. */
+ if (initfdflags != -1 && fcntl(fd, F_SETFL, initfdflags) < 0)
+ syslog(LOG_WARNING, "Couldn't restore device fd flags: %m");
+ initfdflags = -1;
+
if (initdisc >= 0) {
/*
* Check whether the link seems not to be 8-bit clean.
* at the requested speed, etc. If `local' is true, set CLOCAL
* regardless of whether the modem option was specified.
*/
+void
set_up_tty(fd, local)
int fd, local;
{
die(1);
}
- if (!restore_term)
+ if (!restore_term) {
inittermios = tios;
+ ioctl(fd, TIOCGWINSZ, &wsinfo);
+ }
tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
#ifdef CRTSCTS
- if (crtscts > 0)
+ if (crtscts > 0 && !local)
tios.c_cflag |= CRTSCTS;
else if (crtscts < 0)
tios.c_cflag &= ~CRTSCTS;
tios.c_cc[VMIN] = 1;
tios.c_cc[VTIME] = 0;
- if (crtscts == 2) {
- tios.c_iflag |= IXOFF;
+ if (crtscts == -2) {
+ tios.c_iflag |= IXON | IXOFF;
tios.c_cc[VSTOP] = 0x13; /* DC3 = XOFF = ^S */
tios.c_cc[VSTART] = 0x11; /* DC1 = XON = ^Q */
}
}
x = 0;
- if (ioctl(fd, (crtscts || modem)? TIOCMODEM: TIOCNMODEM, &x) < 0)
+ if (ioctl(fd, (crtscts > 0 || modem)? TIOCMODEM: TIOCNMODEM, &x) < 0)
syslog(LOG_WARNING, "TIOC(N)MODEM: %m");
if (ioctl(fd, (local || !modem)? TIOCNCAR: TIOCCAR) < 0)
syslog(LOG_WARNING, "TIOC(N)CAR: %m");
restore_tty()
{
if (restore_term) {
+ if (!default_device) {
+ /*
+ * Turn off echoing, because otherwise we can get into
+ * a loop with the tty and the modem echoing to each other.
+ * We presume we are the sole user of this tty device, so
+ * when we close it, it will revert to its defaults anyway.
+ */
+ inittermios.c_lflag &= ~(ECHO | ECHONL);
+ }
if (tcsetattr(fd, TCSAFLUSH, &inittermios) < 0)
if (errno != ENXIO)
syslog(LOG_WARNING, "tcsetattr: %m");
+ ioctl(fd, TIOCSWINSZ, &wsinfo);
restore_term = FALSE;
}
}
* setdtr - control the DTR line on the serial port.
* This is called from die(), so it shouldn't call die().
*/
+void
setdtr(fd, on)
int fd, on;
{
u_char *p;
int len;
{
- if (unit != 0)
- MAINDEBUG((LOG_WARNING, "output: unit != 0!"));
if (debug)
log_packet(p, len, "sent ");
if (write(fd, p, len) < 0) {
- syslog(LOG_ERR, "write: %m");
- die(1);
+ if (errno != EIO)
+ syslog(LOG_ERR, "write: %m");
}
}
* for the length of time specified by *timo (indefinite
* if timo is NULL).
*/
+void
wait_input(timo)
struct timeval *timo;
{
int len;
if ((len = read(fd, buf, PPP_MTU + PPP_HDRLEN)) < 0) {
- if (errno == EWOULDBLOCK || errno == EINTR) {
- MAINDEBUG((LOG_DEBUG, "read(fd): %m"));
+ if (errno == EWOULDBLOCK || errno == EINTR)
return -1;
- }
syslog(LOG_ERR, "read(fd): %m");
die(1);
}
/*
* ccp_test - ask kernel whether a given compression method
- * is acceptable for use.
+ * is acceptable for use. Returns 1 if the method and parameters
+ * are OK, 0 if the method is known but the parameters are not OK
+ * (e.g. code size should be reduced), or -1 if the method is unknown.
*/
+int
ccp_test(unit, opt_ptr, opt_len, for_transmit)
int unit, opt_len, for_transmit;
u_char *opt_ptr;
data.ptr = opt_ptr;
data.length = opt_len;
data.transmit = for_transmit;
- return ioctl(fd, PPPIOCSCOMPRESS, (caddr_t) &data) >= 0;
+ if (ioctl(fd, PPPIOCSCOMPRESS, (caddr_t) &data) >= 0)
+ return 1;
+ return (errno == ENOBUFS)? 0: -1;
}
/*
syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
return 0;
}
+ if_is_up = 1;
npi.protocol = PPP_IP;
npi.mode = NPMODE_PASS;
if (ioctl(fd, PPPIOCSNPMODE, &npi) < 0) {
if (ioctl(sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
rv = 0;
- }
+ } else
+ if_is_up = 0;
}
return rv;
}
syslog(LOG_ERR, "default route ioctl(SIOCADDRT): %m");
return 0;
}
+ default_route_gateway = g;
return 1;
}
rt.rt_flags = RTF_GATEWAY;
if (ioctl(sockfd, SIOCDELRT, &rt) < 0)
syslog(LOG_WARNING, "default route ioctl(SIOCDELRT): %m");
+ default_route_gateway = 0;
+ return 1;
}
/*
((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
arpreq.arp_flags = ATF_PERM | ATF_PUBL;
if (ioctl(sockfd, SIOCSARP, (caddr_t)&arpreq) < 0) {
- syslog(LOG_ERR, "ioctl(SIOCSARP): %m");
+ syslog(LOG_ERR, "Couldn't add proxy arp entry: %m");
return 0;
}
+ proxy_arp_addr = hisaddr;
return 1;
}
SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
if (ioctl(sockfd, SIOCDARP, (caddr_t)&arpreq) < 0) {
- syslog(LOG_WARNING, "ioctl(SIOCDARP): %m");
+ syslog(LOG_WARNING, "Couldn't delete proxy arp entry: %m");
return 0;
}
+ proxy_arp_addr = 0;
return 1;
}
*/
#define MAX_IFS 32
-int
+static int
get_ether_addr(ipaddr, hwaddr)
u_int32_t ipaddr;
struct sockaddr *hwaddr;
{
- struct ifreq *ifr, *ifend, *ifp;
+ struct ifreq *ifr, *ifend;
u_int32_t ina, mask;
- struct sockaddr_dl *dla;
struct ifreq ifreq;
struct ifconf ifc;
struct ifreq ifs[MAX_IFS];
+ struct ifdevea ifdevea;
ifc.ifc_len = sizeof(ifs);
ifc.ifc_req = ifs;
*/
if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0)
continue;
- mask = ((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;
- }
+ break;
+ }
}
if (ifr >= ifend)
syslog(LOG_INFO, "found interface %s for proxy arp", ifr->ifr_name);
/*
- * Now scan through again looking for a link-level address
- * for this interface.
+ * Grab the physical address for this interface.
*/
- ifp = ifr;
- for (ifr = ifc.ifc_req; ifr < ifend; ) {
- if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0
- && ifr->ifr_addr.sa_family == AF_DLI) {
-/* && ifr->ifr_addr.sa_family == AF_LINK) { Per! Kolla !!! ROHACK */
- /*
- * Found the link-level address - copy it out
- */
- dla = (struct sockaddr_dl *)&ifr->ifr_addr;
- hwaddr->sa_family = AF_UNSPEC;
- BCOPY(dla, hwaddr->sa_data, sizeof(hwaddr->sa_data));
- return 1;
- }
- ifr = (struct ifreq *) ((char *)&ifr->ifr_addr + sizeof(struct sockaddr)
-);
+ strncpy(ifdevea.ifr_name, ifr->ifr_name, sizeof(ifdevea.ifr_name));
+ if (ioctl(sockfd, SIOCRPHYSADDR, &ifdevea) < 0) {
+ syslog(LOG_ERR, "Couldn't get h/w address for %s: %m", ifr->ifr_name);
+ return 0;
}
- return 0;
+ hwaddr->sa_family = AF_UNSPEC;
+ BCOPY(ifdevea.current_pa, hwaddr->sa_data, 6);
+ return 1;
+}
+
+/*
+ * Return user specified netmask, modified by any mask we might determine
+ * for address `addr' (in network byte order).
+ * Here we scan through the system's list of interfaces, looking for
+ * any non-point-to-point interfaces which might appear to be on the same
+ * network as `addr'. If we find any, we OR in their netmask to the
+ * user-specified netmask.
+ */
+u_int32_t
+GetMask(addr)
+ u_int32_t 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 */
+ nmask = IN_CLASSA_NET;
+ else if (IN_CLASSB(addr))
+ nmask = IN_CLASSB_NET;
+ else
+ nmask = IN_CLASSC_NET;
+ /* class D nets are disallowed by bad_ip_adrs */
+ mask = netmask | htonl(nmask);
+
+ /*
+ * Scan through the system's network interfaces.
+ */
+ ifc.ifc_len = sizeof(ifs);
+ ifc.ifc_req = ifs;
+ if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
+ syslog(LOG_WARNING, "ioctl(SIOCGIFCONF): %m");
+ return mask;
+ }
+ ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
+ for (ifr = ifc.ifc_req; ifr < ifend; ifr = (struct ifreq *)
+ ((char *)&ifr->ifr_addr + sizeof(struct sockaddr))) {
+ /*
+ * 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;
+ }
+
+ return mask;
}