mirror of
https://github.com/paulusmack/ppp.git
synced 2024-11-28 05:53:51 +08:00
e8be982dbc
Unified the locking code, added relock(). Revert strlcpy to strncpy when filling in utmp structs. Fixed some bugs in DNS addr option handling. Set PPPLOGNAME with login name of user. Moved daemon() logic into detach(). Fix bug where errno was clobbered by seteuid(). Use pty in sys-linux.c when making a ppp unit.
1692 lines
37 KiB
C
1692 lines
37 KiB
C
/*
|
|
* sys-next.c - System-dependent procedures for setting up
|
|
* PPP interfaces on NeXT 3.2/3.3 systems
|
|
*
|
|
* Copyright (c) 1989 Carnegie Mellon University.
|
|
* Copyright (c) 1994 Philippe-Andre Prindeville.
|
|
* 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.
|
|
*/
|
|
|
|
#ifndef lint
|
|
static char rcsid[] = "$Id: sys-NeXT.c,v 1.18 1999/04/12 06:24:48 paulus Exp $";
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <termios.h>
|
|
#include <utmp.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <libc.h>
|
|
#include <strings.h>
|
|
#include <sys/types.h>
|
|
#include <sys/file.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/time.h>
|
|
#include <sys/errno.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/fcntl.h>
|
|
|
|
#include <net/if.h>
|
|
#include <net/ppp_defs.h>
|
|
#include <net/if_ppp.h>
|
|
#include <netdb.h>
|
|
#include <netinet/in.h>
|
|
#include <netinet/in_systm.h>
|
|
#include <netinet/in_var.h>
|
|
#if !(NS_TARGET >= 40)
|
|
/* XXX get an error "duplicate member ip_v under 4.1 GAMMA */
|
|
#include <netinet/ip.h>
|
|
#endif /* NS_TARGET */
|
|
#include <netinet/if_ether.h>
|
|
#include <net/route.h>
|
|
#include <netinet/in.h>
|
|
|
|
#include <netinfo/ni.h>
|
|
|
|
#include "pppd.h"
|
|
|
|
static int initdisc = -1; /* Initial TTY discipline */
|
|
static int initfdflags = -1; /* Initial file descriptor flags for fd */
|
|
static int ppp_fd = -1; /* fd which is set to PPP discipline */
|
|
static int loop_slave = -1;
|
|
static int loop_master;
|
|
static char loop_name[20];
|
|
|
|
static fd_set in_fds; /* set of fds that wait_input waits for */
|
|
static int max_in_fd; /* highest fd set in in_fds */
|
|
|
|
extern int errno;
|
|
|
|
static int restore_term; /* 1 => we've munged the terminal */
|
|
static struct termios inittermios; /* Initial TTY termios */
|
|
|
|
static int sockfd; /* socket for doing interface ioctls */
|
|
static int pppdev; /* +++ */
|
|
|
|
#if defined(i386) && defined(HAS_BROKEN_IOCTL)
|
|
#define ioctl myioctl
|
|
#endif
|
|
|
|
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 dodefaultroute __P((u_int32_t, int));
|
|
static int get_ether_addr __P((u_int32_t, struct sockaddr *));
|
|
static int ether_by_host __P((char *, struct ether_addr *));
|
|
|
|
|
|
/*
|
|
* sys_init - System-dependent initialization.
|
|
*/
|
|
void
|
|
sys_init()
|
|
{
|
|
openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP);
|
|
setlogmask(LOG_UPTO(LOG_INFO));
|
|
|
|
/* Get an internet socket for doing socket ioctl's on. */
|
|
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
|
|
fatal("Couldn't create IP socket: %m");
|
|
|
|
if((pppdev = open("/dev/ppp0", O_RDWR, O_NONBLOCK)) == NULL)
|
|
fatal("Couldn't open /dev/ppp0: %m");
|
|
|
|
FD_ZERO(&in_fds);
|
|
max_in_fd = 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().
|
|
*/
|
|
void
|
|
sys_cleanup()
|
|
{
|
|
struct ifreq ifr;
|
|
|
|
if (if_is_up) {
|
|
strlcpy(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, 0, default_route_gateway);
|
|
if (proxy_arp_addr)
|
|
cifproxyarp(0, proxy_arp_addr);
|
|
|
|
close(pppdev);
|
|
}
|
|
|
|
/*
|
|
* 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 */
|
|
|
|
strlcpy(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.NeXT\n\
|
|
file in the ppp-2.2 distribution.\n";
|
|
|
|
return ok;
|
|
}
|
|
|
|
/*
|
|
* establish_ppp - Turn the serial port into a ppp interface.
|
|
*/
|
|
int
|
|
establish_ppp(fd)
|
|
int fd;
|
|
{
|
|
int pppdisc = PPPDISC;
|
|
int x;
|
|
|
|
if (ioctl(fd, TIOCGETD, &initdisc) < 0)
|
|
fatal("ioctl(TIOCGETD): %m");
|
|
if (ioctl(fd, TIOCSETD, &pppdisc) < 0)
|
|
fatal("ioctl(establish TIOCSETD): %m");
|
|
|
|
/*
|
|
* Find out which interface we were given.
|
|
*/
|
|
if (ioctl(fd, PPPIOCGUNIT, &ifunit) < 0)
|
|
fatal("ioctl(PPPIOCGUNIT): %m");
|
|
|
|
/*
|
|
* Enable debug in the driver if requested.
|
|
*/
|
|
if (kdebugflag) {
|
|
if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
|
|
warn("ioctl(PPPIOCGFLAGS): %m");
|
|
} else {
|
|
x |= (kdebugflag & 0xFF) * SC_DEBUG;
|
|
if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0)
|
|
warn("ioctl(PPPIOCSFLAGS): %m");
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Set device for non-blocking reads so PPPD can poll for
|
|
* input from the kernel.
|
|
*/
|
|
if ((initfdflags = fcntl(fd, F_GETFL)) == -1
|
|
|| fcntl(fd, F_SETFL, initfdflags | O_NONBLOCK) == -1) {
|
|
warn("Couldn't set device to non-blocking mode: %m");
|
|
}
|
|
|
|
return fd;
|
|
}
|
|
|
|
|
|
/*
|
|
* disestablish_ppp - Restore the serial port to normal operation.
|
|
* This shouldn't call die() because it's called from die().
|
|
*/
|
|
void
|
|
disestablish_ppp(fd)
|
|
int fd;
|
|
{
|
|
/* Reset non-blocking mode on fd. */
|
|
if (initfdflags != -1 && fcntl(fd, F_SETFL, initfdflags) < 0)
|
|
warn("Couldn't restore device fd flags: %m");
|
|
initfdflags = -1;
|
|
|
|
/* Restore old line discipline. */
|
|
if (initdisc >= 0 && ioctl(fd, TIOCSETD, &initdisc) < 0)
|
|
error("ioctl(TIOCSETD): %m");
|
|
initdisc = -1;
|
|
}
|
|
|
|
/*
|
|
* Check whether the link seems not to be 8-bit clean.
|
|
*/
|
|
void
|
|
clean_check()
|
|
{
|
|
int x;
|
|
char *s;
|
|
|
|
if (ioctl(ttyfd, PPPIOCGFLAGS, (caddr_t) &x) == 0) {
|
|
s = NULL;
|
|
switch (~x & (SC_RCV_B7_0|SC_RCV_B7_1|SC_RCV_EVNP|SC_RCV_ODDP)) {
|
|
case SC_RCV_B7_0:
|
|
s = "bit 7 set to 1";
|
|
break;
|
|
case SC_RCV_B7_1:
|
|
s = "bit 7 set to 0";
|
|
break;
|
|
case SC_RCV_EVNP:
|
|
s = "odd parity";
|
|
break;
|
|
case SC_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.
|
|
*/
|
|
struct speed {
|
|
int speed_int, speed_val;
|
|
} speeds[] = {
|
|
#ifdef B50
|
|
{ 50, B50 },
|
|
#endif
|
|
#ifdef B75
|
|
{ 75, B75 },
|
|
#endif
|
|
#ifdef B110
|
|
{ 110, B110 },
|
|
#endif
|
|
#ifdef B134
|
|
{ 134, B134 },
|
|
#endif
|
|
#ifdef B150
|
|
{ 150, B150 },
|
|
#endif
|
|
#ifdef B200
|
|
{ 200, B200 },
|
|
#endif
|
|
#ifdef B300
|
|
{ 300, B300 },
|
|
#endif
|
|
#ifdef B600
|
|
{ 600, B600 },
|
|
#endif
|
|
#ifdef B1200
|
|
{ 1200, B1200 },
|
|
#endif
|
|
#ifdef B1800
|
|
{ 1800, B1800 },
|
|
#endif
|
|
#ifdef B2000
|
|
{ 2000, B2000 },
|
|
#endif
|
|
#ifdef B2400
|
|
{ 2400, B2400 },
|
|
#endif
|
|
#ifdef B3600
|
|
{ 3600, B3600 },
|
|
#endif
|
|
#ifdef B4800
|
|
{ 4800, B4800 },
|
|
#endif
|
|
#ifdef B7200
|
|
{ 7200, B7200 },
|
|
#endif
|
|
#ifdef B9600
|
|
{ 9600, B9600 },
|
|
#endif
|
|
#ifdef B19200
|
|
{ 19200, B19200 },
|
|
#endif
|
|
#ifdef B38400
|
|
{ 38400, B38400 },
|
|
#endif
|
|
#ifdef EXTA
|
|
{ 19200, EXTA },
|
|
#endif
|
|
#ifdef EXTB
|
|
{ 38400, EXTB },
|
|
#endif
|
|
#ifdef B14400
|
|
{ 14400, B14400 },
|
|
#endif
|
|
#ifdef B28800
|
|
{ 28800, B28800 },
|
|
#endif
|
|
#ifdef B43200
|
|
{ 43200, B43200 },
|
|
#endif
|
|
#ifdef B57600
|
|
{ 57600, B57600 },
|
|
#endif
|
|
/*
|
|
#ifndef B115200
|
|
#warning Defining B115200
|
|
#define B115200 20
|
|
#endif
|
|
*/
|
|
#ifdef B115200
|
|
{ 115200, B115200 },
|
|
#endif
|
|
{ 0, 0 }
|
|
};
|
|
|
|
/*
|
|
* Translate from bits/second to a speed_t.
|
|
*/
|
|
int
|
|
translate_speed(bps)
|
|
int bps;
|
|
{
|
|
struct speed *speedp;
|
|
|
|
if (bps == 0)
|
|
return 0;
|
|
for (speedp = speeds; speedp->speed_int; speedp++)
|
|
if (bps == speedp->speed_int)
|
|
return speedp->speed_val;
|
|
warn("speed %d not supported", bps);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Translate from a speed_t to bits/second.
|
|
*/
|
|
static int
|
|
baud_rate_of(speed)
|
|
int speed;
|
|
{
|
|
struct speed *speedp;
|
|
|
|
if (speed == 0)
|
|
return 0;
|
|
for (speedp = speeds; speedp->speed_int; speedp++)
|
|
if (speed == speedp->speed_val)
|
|
return speedp->speed_int;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* set_up_tty: Set up the serial port on `fd' for 8 bits, no parity,
|
|
* 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;
|
|
{
|
|
int speed, x, modembits;
|
|
struct termios tios;
|
|
|
|
if (tcgetattr(fd, &tios) < 0)
|
|
fatal("tcgetattr: %m");
|
|
|
|
if (!restore_term)
|
|
inittermios = tios;
|
|
|
|
tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
|
|
|
|
tios.c_cflag |= CS8 | CREAD | HUPCL;
|
|
if (local || !modem)
|
|
tios.c_cflag |= CLOCAL;
|
|
|
|
tios.c_iflag = IGNBRK | IGNPAR;
|
|
tios.c_oflag = 0;
|
|
tios.c_lflag = 0;
|
|
tios.c_cc[VMIN] = 1;
|
|
tios.c_cc[VTIME] = 0;
|
|
|
|
if (crtscts == -2) {
|
|
tios.c_iflag |= IXON | IXOFF;
|
|
tios.c_cc[VSTOP] = 0x13; /* DC3 = XOFF = ^S */
|
|
tios.c_cc[VSTART] = 0x11; /* DC1 = XON = ^Q */
|
|
}
|
|
|
|
speed = translate_speed(inspeed);
|
|
if (speed) {
|
|
cfsetospeed(&tios, speed);
|
|
cfsetispeed(&tios, speed);
|
|
} else {
|
|
speed = cfgetospeed(&tios);
|
|
/*
|
|
* We can't proceed if the serial port speed is B0,
|
|
* since that implies that the serial port is disabled.
|
|
*/
|
|
if (speed == B0)
|
|
fatal("Baud rate for %s is 0; need explicit baud rate",
|
|
devnam);
|
|
}
|
|
|
|
if (modem) {
|
|
modembits = TIOCM_RTS | TIOCM_CTS;
|
|
if (ioctl(fd, (crtscts ? TIOCMBIS : TIOCMBIC), &modembits) < 0)
|
|
error("ioctl: TIOCMBIS/BIC: %m");
|
|
}
|
|
|
|
if (tcsetattr(fd, TCSAFLUSH, &tios) < 0)
|
|
fatal("tcsetattr: %m");
|
|
|
|
baud_rate = inspeed = baud_rate_of(speed);
|
|
restore_term = 1;
|
|
}
|
|
|
|
/*
|
|
* restore_tty - restore the terminal to the saved settings.
|
|
*/
|
|
void
|
|
restore_tty(fd)
|
|
int fd;
|
|
{
|
|
if (restore_term) {
|
|
if (tcsetattr(fd, TCSAFLUSH, &inittermios) < 0)
|
|
if (errno != ENXIO)
|
|
warn("tcsetattr: %m");
|
|
restore_term = 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* setdtr - control the DTR line on the serial port.
|
|
* This is called from die(), so it shouldn't call die().
|
|
*
|
|
* The write hack is to get NXFax to recognize that there is
|
|
* activity on the port. Not using the write nukes
|
|
* NXFax's capability to determine port usage.
|
|
*
|
|
*/
|
|
void
|
|
setdtr(fd, on)
|
|
int fd, on;
|
|
{
|
|
int modembits = TIOCM_DTR;
|
|
|
|
if (!on)
|
|
{
|
|
write(fd, " ", 1);
|
|
sleep(1);
|
|
}
|
|
|
|
/* ioctl(fd, (on? TIOCMBIS: TIOCMBIC), &modembits); */
|
|
ioctl(fd, (on? TIOCSDTR: TIOCCDTR), 0);
|
|
}
|
|
|
|
|
|
/*
|
|
* output - Output PPP packet.
|
|
*/
|
|
void
|
|
output(unit, p, len)
|
|
int unit;
|
|
u_char *p;
|
|
int len;
|
|
{
|
|
if (debug)
|
|
dbglog("sent %P", p, len);
|
|
|
|
if (write(ttyfd, p, len) < 0) {
|
|
if (errno == EWOULDBLOCK || errno == ENOBUFS
|
|
|| errno == ENXIO || errno == EIO) {
|
|
warn("write: warning: %m");
|
|
} else {
|
|
fatal("write: %m");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* wait_input - wait until there is data available,
|
|
* for the length of time specified by *timo (indefinite
|
|
* if timo is NULL).
|
|
*/
|
|
void
|
|
wait_input(timo)
|
|
struct timeval *timo;
|
|
{
|
|
fd_set ready;
|
|
int n;
|
|
|
|
ready = in_fds;
|
|
n = select(max_in_fd + 1, &ready, NULL, &ready, timo);
|
|
if (n < 0 && errno != EINTR)
|
|
fatal("select: %m");
|
|
}
|
|
|
|
|
|
/*
|
|
* add_fd - add an fd to the set that wait_input waits for.
|
|
*/
|
|
void add_fd(fd)
|
|
int fd;
|
|
{
|
|
FD_SET(fd, &in_fds);
|
|
if (fd > max_in_fd)
|
|
max_in_fd = fd;
|
|
}
|
|
|
|
/*
|
|
* remove_fd - remove an fd from the set that wait_input waits for.
|
|
*/
|
|
void remove_fd(fd)
|
|
int fd;
|
|
{
|
|
FD_CLR(fd, &in_fds);
|
|
}
|
|
|
|
/*
|
|
* read_packet - get a PPP packet from the serial device.
|
|
*/
|
|
int
|
|
read_packet(buf)
|
|
u_char *buf;
|
|
{
|
|
int len;
|
|
|
|
if ((len = read(ttyfd, buf, PPP_MTU + PPP_HDRLEN)) < 0) {
|
|
if (errno == EWOULDBLOCK || errno == EINTR) {
|
|
SYSDEBUG(("read: %m"));
|
|
return -1;
|
|
}
|
|
fatal("read: %m");
|
|
}
|
|
return len;
|
|
}
|
|
|
|
|
|
/*
|
|
* ppp_send_config - configure the transmit characteristics of
|
|
* the ppp interface.
|
|
*/
|
|
void
|
|
ppp_send_config(unit, mtu, asyncmap, pcomp, accomp)
|
|
int unit, mtu;
|
|
u_int32_t asyncmap;
|
|
int pcomp, accomp;
|
|
{
|
|
u_int x;
|
|
struct ifreq ifr;
|
|
|
|
strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
|
|
ifr.ifr_mtu = mtu;
|
|
if (ioctl(sockfd, SIOCSIFMTU, (caddr_t) &ifr) < 0)
|
|
fatal("ioctl(SIOCSIFMTU): %m");
|
|
|
|
if (ioctl(ttyfd, PPPIOCSASYNCMAP, (caddr_t) &asyncmap) < 0)
|
|
fatal("ioctl(PPPIOCSASYNCMAP): %m");
|
|
|
|
if (ioctl(ttyfd, PPPIOCGFLAGS, (caddr_t) &x) < 0)
|
|
fatal("ioctl(PPPIOCGFLAGS): %m");
|
|
|
|
x = pcomp? x | SC_COMP_PROT: x &~ SC_COMP_PROT;
|
|
x = accomp? x | SC_COMP_AC: x &~ SC_COMP_AC;
|
|
if (ioctl(ttyfd, PPPIOCSFLAGS, (caddr_t) &x) < 0)
|
|
fatal("ioctl(PPPIOCSFLAGS): %m");
|
|
}
|
|
|
|
|
|
/*
|
|
* ppp_set_xaccm - set the extended transmit ACCM for the interface.
|
|
*/
|
|
void
|
|
ppp_set_xaccm(unit, accm)
|
|
int unit;
|
|
ext_accm accm;
|
|
{
|
|
if (ioctl(ttyfd, PPPIOCSXASYNCMAP, accm) < 0 && errno != ENOTTY)
|
|
warn("ioctl(PPPIOCSXASYNCMAP): %m");
|
|
}
|
|
|
|
|
|
/*
|
|
* ppp_recv_config - configure the receive-side characteristics of
|
|
* the ppp interface.
|
|
*/
|
|
void
|
|
ppp_recv_config(unit, mru, asyncmap, pcomp, accomp)
|
|
int unit, mru;
|
|
u_int32_t asyncmap;
|
|
int pcomp, accomp;
|
|
{
|
|
int x;
|
|
|
|
if (ioctl(ttyfd, PPPIOCSMRU, (caddr_t) &mru) < 0)
|
|
fatal("ioctl(PPPIOCSMRU): %m");
|
|
if (ioctl(ttyfd, PPPIOCSRASYNCMAP, (caddr_t) &asyncmap) < 0)
|
|
fatal("ioctl(PPPIOCSRASYNCMAP): %m");
|
|
if (ioctl(ttyfd, PPPIOCGFLAGS, (caddr_t) &x) < 0)
|
|
fatal("ioctl(PPPIOCGFLAGS): %m");
|
|
x = !accomp? x | SC_REJ_COMP_AC: x &~ SC_REJ_COMP_AC;
|
|
if (ioctl(ttyfd, PPPIOCSFLAGS, (caddr_t) &x) < 0)
|
|
fatal("ioctl(PPPIOCSFLAGS): %m");
|
|
}
|
|
|
|
/*
|
|
* ccp_test - ask kernel whether a given compression method
|
|
* is acceptable for use.
|
|
*/
|
|
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;
|
|
|
|
data.ptr = opt_ptr;
|
|
data.length = opt_len;
|
|
data.transmit = for_transmit;
|
|
if (ioctl(ttyfd, PPPIOCSCOMPRESS, (caddr_t) &data) >= 0)
|
|
return 1;
|
|
return (errno == ENOBUFS)? 0: -1;
|
|
}
|
|
|
|
/*
|
|
* ccp_flags_set - inform kernel about the current state of CCP.
|
|
*/
|
|
void
|
|
ccp_flags_set(unit, isopen, isup)
|
|
int unit, isopen, isup;
|
|
{
|
|
int x;
|
|
|
|
if (ioctl(ttyfd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
|
|
error("ioctl(PPPIOCGFLAGS): %m");
|
|
return;
|
|
}
|
|
x = isopen? x | SC_CCP_OPEN: x &~ SC_CCP_OPEN;
|
|
x = isup? x | SC_CCP_UP: x &~ SC_CCP_UP;
|
|
if (ioctl(ttyfd, PPPIOCSFLAGS, (caddr_t) &x) < 0)
|
|
error("ioctl(PPPIOCSFLAGS): %m");
|
|
}
|
|
|
|
/*
|
|
* ccp_fatal_error - returns 1 if decompression was disabled as a
|
|
* result of an error detected after decompression of a packet,
|
|
* 0 otherwise. This is necessary because of patent nonsense.
|
|
*/
|
|
int
|
|
ccp_fatal_error(unit)
|
|
int unit;
|
|
{
|
|
int x;
|
|
|
|
if (ioctl(ttyfd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
|
|
error("ioctl(PPPIOCGFLAGS): %m");
|
|
return 0;
|
|
}
|
|
return x & SC_DC_FERROR;
|
|
}
|
|
|
|
/*
|
|
* sifvjcomp - config tcp header compression
|
|
*/
|
|
int
|
|
sifvjcomp(u, vjcomp, cidcomp, maxcid)
|
|
int u, vjcomp, cidcomp, maxcid;
|
|
{
|
|
u_int x;
|
|
|
|
if (ioctl(ttyfd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
|
|
error("ioctl(PPIOCGFLAGS): %m");
|
|
return 0;
|
|
}
|
|
x = vjcomp ? x | SC_COMP_TCP: x &~ SC_COMP_TCP;
|
|
x = cidcomp? x & ~SC_NO_TCP_CCID: x | SC_NO_TCP_CCID;
|
|
if (ioctl(ttyfd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
|
|
error("ioctl(PPPIOCSFLAGS): %m");
|
|
return 0;
|
|
}
|
|
if (ioctl(ttyfd, PPPIOCSMAXCID, (caddr_t) &maxcid) < 0) {
|
|
error("ioctl(PPPIOCSFLAGS): %m");
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* sifup - Config the interface up and enable IP packets to pass.
|
|
*/
|
|
#ifndef SC_ENABLE_IP
|
|
#define SC_ENABLE_IP 0x100 /* compat for old versions of kernel code */
|
|
#endif
|
|
|
|
int
|
|
sifup(u)
|
|
int u;
|
|
{
|
|
struct ifreq ifr;
|
|
u_int x;
|
|
struct npioctl npi;
|
|
|
|
strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
|
|
if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
|
|
error("ioctl (SIOCGIFFLAGS): %m");
|
|
return 0;
|
|
}
|
|
ifr.ifr_flags |= IFF_UP;
|
|
if (ioctl(sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
|
|
error("ioctl(SIOCSIFFLAGS): %m");
|
|
return 0;
|
|
}
|
|
if_is_up = 1;
|
|
npi.protocol = PPP_IP;
|
|
npi.mode = NPMODE_PASS;
|
|
if (ioctl(ttyfd, PPPIOCSNPMODE, &npi) < 0) {
|
|
if (errno != ENOTTY) {
|
|
error("ioctl(PPPIOCSNPMODE): %m");
|
|
return 0;
|
|
}
|
|
/* for backwards compatibility */
|
|
if (ioctl(ttyfd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
|
|
error("ioctl (PPPIOCGFLAGS): %m");
|
|
return 0;
|
|
}
|
|
x |= SC_ENABLE_IP;
|
|
if (ioctl(ttyfd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
|
|
error("ioctl(PPPIOCSFLAGS): %m");
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* sifdown - Config the interface down and disable IP.
|
|
*/
|
|
int
|
|
sifdown(u)
|
|
int u;
|
|
{
|
|
struct ifreq ifr;
|
|
u_int x;
|
|
int rv;
|
|
struct npioctl npi;
|
|
|
|
rv = 1;
|
|
npi.protocol = PPP_IP;
|
|
npi.mode = NPMODE_ERROR;
|
|
ioctl(ttyfd, PPPIOCSNPMODE, (caddr_t) &npi);
|
|
/* ignore errors, because ttyfd might have been closed by now. */
|
|
|
|
|
|
strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
|
|
if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
|
|
error("ioctl (SIOCGIFFLAGS): %m");
|
|
rv = 0;
|
|
} else {
|
|
ifr.ifr_flags &= ~IFF_UP;
|
|
if (ioctl(sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
|
|
error("ioctl(SIOCSIFFLAGS): %m");
|
|
rv = 0;
|
|
} else
|
|
if_is_up = 0;
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
/*
|
|
* SET_SA_FAMILY - set the sa_family field of a struct sockaddr,
|
|
* if it exists.
|
|
*/
|
|
#define SET_SA_FAMILY(addr, family) \
|
|
BZERO((char *) &(addr), sizeof(addr)); \
|
|
addr.sa_family = (family);
|
|
|
|
/*
|
|
* sifaddr - Config the interface IP addresses and netmask.
|
|
*/
|
|
int
|
|
sifaddr(u, o, h, m)
|
|
int u;
|
|
u_int32_t o, h, m;
|
|
{
|
|
int ret;
|
|
struct ifreq ifr;
|
|
|
|
ret = 1;
|
|
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, SIOCSIFADDR, (caddr_t) &ifr) < 0) {
|
|
error("ioctl(SIOCAIFADDR): %m");
|
|
ret = 0;
|
|
}
|
|
((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr = h;
|
|
if (ioctl(sockfd, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) {
|
|
error("ioctl(SIOCSIFDSTADDR): %m");
|
|
ret = 0;
|
|
}
|
|
if (m != 0) {
|
|
((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = m;
|
|
info("Setting interface mask to %s\n", ip_ntoa(m));
|
|
if (ioctl(sockfd, SIOCSIFNETMASK, (caddr_t) &ifr) < 0) {
|
|
error("ioctl(SIOCSIFNETMASK): %m");
|
|
ret = 0;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* cifaddr - Clear the interface IP addresses, and delete routes
|
|
* through the interface if possible.
|
|
*
|
|
* N.B.: under NextStep, you can't *delete* an address on an interface,
|
|
* so we change it to 0.0.0.0... A real hack. But it simplifies
|
|
* reconnection on the server side.
|
|
*/
|
|
int
|
|
cifaddr(u, o, h)
|
|
int u;
|
|
u_int32_t o, h;
|
|
{
|
|
struct rtentry rt;
|
|
|
|
#if 1
|
|
h = o = 0L;
|
|
(void) sifaddr(u, o, h, 0L);
|
|
#endif
|
|
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, SIOCDELRT, (caddr_t) &rt) < 0) {
|
|
error("ioctl(SIOCDELRT): %m");
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* sifdefaultroute - assign a default route through the address given.
|
|
*/
|
|
int
|
|
sifdefaultroute(u, l, g)
|
|
int u;
|
|
u_int32_t l, g;
|
|
{
|
|
return dodefaultroute(g, 's');
|
|
}
|
|
|
|
/*
|
|
* cifdefaultroute - delete a default route through the address given.
|
|
*/
|
|
int
|
|
cifdefaultroute(u, l, g)
|
|
int u;
|
|
u_int32_t l, g;
|
|
{
|
|
return dodefaultroute(g, 'c');
|
|
}
|
|
|
|
/*
|
|
* dodefaultroute - talk to a routing socket to add/delete a default route.
|
|
*/
|
|
int
|
|
dodefaultroute(g, cmd)
|
|
u_int32_t g;
|
|
int cmd;
|
|
{
|
|
struct rtentry rt;
|
|
|
|
SET_SA_FAMILY(rt.rt_dst, AF_INET);
|
|
((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = 0L;
|
|
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, (cmd == 's') ? SIOCADDRT : SIOCDELRT, &rt) < 0) {
|
|
error("%cifdefaultroute: ioctl(%s): %m", cmd,
|
|
(cmd == 's') ? "SIOCADDRT" : "SIOCDELRT");
|
|
return 0;
|
|
}
|
|
default_route_gateway = (cmd == 's')? g: 0;
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* sifproxyarp - Make a proxy ARP entry for the peer.
|
|
*/
|
|
int
|
|
sifproxyarp(unit, hisaddr)
|
|
int unit;
|
|
u_int32_t hisaddr;
|
|
{
|
|
struct arpreq arpreq;
|
|
|
|
BZERO(&arpreq, sizeof(arpreq));
|
|
|
|
/*
|
|
* Get the hardware address of an interface on the same subnet
|
|
* as our local address.
|
|
*/
|
|
if (!get_ether_addr(hisaddr, &arpreq.arp_ha)) {
|
|
error("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, SIOCSARP, (caddr_t)&arpreq) < 0) {
|
|
error("ioctl(SIOCSARP): %m");
|
|
return 0;
|
|
}
|
|
|
|
proxy_arp_addr = hisaddr;
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* cifproxyarp - Delete the proxy ARP entry for the peer.
|
|
*/
|
|
int
|
|
cifproxyarp(unit, hisaddr)
|
|
int unit;
|
|
u_int32_t hisaddr;
|
|
{
|
|
struct arpreq arpreq;
|
|
|
|
BZERO(&arpreq, sizeof(arpreq));
|
|
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) {
|
|
warn("ioctl(SIOCDARP): %m");
|
|
return 0;
|
|
}
|
|
proxy_arp_addr = 0;
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* get_ether_addr - get the hardware address of an interface on the
|
|
* the same subnet as ipaddr.
|
|
*/
|
|
#define MAX_IFS 32
|
|
|
|
int
|
|
get_ether_addr(ipaddr, hwaddr)
|
|
u_int32_t ipaddr;
|
|
struct sockaddr *hwaddr;
|
|
{
|
|
struct ifreq *ifr, *ifend, *ifp;
|
|
u_int32_t ina, mask;
|
|
struct ether_addr dla;
|
|
struct ifreq ifreq;
|
|
struct ifconf ifc;
|
|
struct ifreq ifs[MAX_IFS];
|
|
struct hostent *hostent;
|
|
|
|
ifc.ifc_len = sizeof(ifs);
|
|
ifc.ifc_req = ifs;
|
|
if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
|
|
error("ioctl(SIOCGIFCONF): %m");
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Scan through looking for an interface with an Internet
|
|
* address on the same subnet as `ipaddr'.
|
|
*/
|
|
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))) {
|
|
if (ifr->ifr_addr.sa_family == AF_INET) {
|
|
ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
|
|
strlcpy(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, 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, SIOCGIFNETMASK, &ifreq) < 0)
|
|
continue;
|
|
mask = ((struct sockaddr_in*)&ifreq.ifr_addr)->sin_addr.s_addr;
|
|
if ((ipaddr & mask) != (ina & mask))
|
|
continue;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ifr >= ifend)
|
|
return 0;
|
|
info("found interface %s for proxy arp", ifr->ifr_name);
|
|
|
|
/*
|
|
* Get the hostname and look for an entry using the ethers database.
|
|
* Under NeXTStep this is the best we can do for now.
|
|
*/
|
|
if ((hostent = gethostbyaddr((char*)&ina, sizeof(ina), AF_INET)) == NULL)
|
|
return 0;
|
|
|
|
if (ether_by_host(hostent->h_name, &dla)) {
|
|
info("Add entry for %s in /etc/ethers", hostent->h_name);
|
|
return 0; /* it's not there */
|
|
}
|
|
hwaddr->sa_family = AF_UNSPEC;
|
|
BCOPY(&dla, hwaddr->sa_data, sizeof(dla));
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
ether_by_host(hostname, etherptr)
|
|
char *hostname;
|
|
struct ether_addr *etherptr;
|
|
{
|
|
struct ether_addr *thisptr;
|
|
void *conn;
|
|
ni_id root;
|
|
ni_namelist val;
|
|
char path[256];
|
|
|
|
if (!ether_hostton(hostname, etherptr))
|
|
return 0;
|
|
/*
|
|
* We shall now try and
|
|
* find the address in the
|
|
* top domain of netinfo.
|
|
*/
|
|
slprintf(path, sizeof(path), "/machines/%s", hostname);
|
|
|
|
if (ni_open((void *)0, "/", &conn)
|
|
|| ni_root(conn, &root)
|
|
|| ni_pathsearch(conn, &root, path)
|
|
|| ni_lookupprop(conn, &root, "en_address", &val))
|
|
return 1;
|
|
|
|
/*
|
|
* Now we can convert the returned string into an ethernet address.
|
|
*/
|
|
strlcpy(path, val.ni_namelist_val[0], sizeof(path));
|
|
ni_free(conn);
|
|
if ((thisptr = (struct ether_addr*)ether_aton(path)) == NULL)
|
|
return 1;
|
|
BCOPY(thisptr, etherptr, sizeof(struct ether_addr));
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* 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) {
|
|
warn("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.
|
|
*/
|
|
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 |= ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr.s_addr;
|
|
}
|
|
|
|
return mask;
|
|
}
|
|
|
|
/*
|
|
* have_route_to - determine if the system has any route to
|
|
* a given IP address.
|
|
* For demand mode to work properly, we have to ignore routes
|
|
* through our own interface.
|
|
*/
|
|
int have_route_to(u_int32_t addr)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
#if 0
|
|
/*
|
|
* daemon - Detach us from the terminal session.
|
|
*/
|
|
int
|
|
daemon(nochdir, noclose)
|
|
int nochdir, noclose;
|
|
{
|
|
int pid;
|
|
|
|
if ((pid = fork()) < 0)
|
|
return -1;
|
|
if (pid != 0)
|
|
exit(0); /* parent dies */
|
|
(void)setsid();
|
|
if (!nochdir)
|
|
chdir("/");
|
|
if (!noclose) {
|
|
fclose(stdin); /* don't need stdin, stdout, stderr */
|
|
fclose(stdout);
|
|
fclose(stderr);
|
|
}
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
char *
|
|
strdup(s)
|
|
const char *s;
|
|
{
|
|
char *d = malloc(strlen(s) + 1);
|
|
|
|
if (d) strcpy(d, s);
|
|
return d;
|
|
}
|
|
|
|
/*
|
|
* This logwtmp() implementation is subject to the following copyright:
|
|
*
|
|
* Copyright (c) 1988 The Regents of the University of California.
|
|
* 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 the University of California, Berkeley. 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.
|
|
*/
|
|
|
|
#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)) {
|
|
strncpy(ut.ut_line, line, sizeof(ut.ut_line));
|
|
strncpy(ut.ut_name, name, sizeof(ut.ut_name));
|
|
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);
|
|
}
|
|
close(fd);
|
|
}
|
|
|
|
#if 0
|
|
/*
|
|
* Routines for locking and unlocking the serial device, moved here
|
|
* from chat.c.
|
|
*/
|
|
|
|
#define LOCK_PREFIX "/usr/spool/uucp/LCK/LCK.."
|
|
|
|
static char *lock_file;
|
|
|
|
/*
|
|
* lock - create a lock file for the named device
|
|
*/
|
|
int
|
|
lock(dev)
|
|
char *dev;
|
|
{
|
|
int fd, pid, n;
|
|
char *p;
|
|
size_t l;
|
|
|
|
if ((p = strrchr(dev, '/')) != NULL)
|
|
dev = p + 1;
|
|
l = strlen(LOCK_PREFIX) + strlen(dev) + 1;
|
|
lock_file = malloc(l);
|
|
if (lock_file == NULL)
|
|
novm("lock file name");
|
|
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
|
|
&& (fd = open(lock_file, O_RDONLY, 0)) >= 0) {
|
|
/* Read the lock file to find out who has the device locked */
|
|
n = read(fd, &pid, sizeof(pid));
|
|
if (n <= 0) {
|
|
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);
|
|
notice("Removed stale lock on %s (pid %d)",
|
|
dev, pid);
|
|
continue;
|
|
} else
|
|
warn("Couldn't remove stale lock on %s", dev);
|
|
} else
|
|
notice("Device %s is locked by pid %d",
|
|
dev, pid);
|
|
}
|
|
close(fd);
|
|
} else
|
|
error("Can't create lock file %s: %m", lock_file);
|
|
free(lock_file);
|
|
lock_file = NULL;
|
|
return -1;
|
|
}
|
|
|
|
pid = getpid();
|
|
write(fd, &pid, sizeof pid);
|
|
|
|
close(fd);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* unlock - remove our lockfile
|
|
*/
|
|
void
|
|
unlock()
|
|
{
|
|
if (lock_file) {
|
|
unlink(lock_file);
|
|
free(lock_file);
|
|
lock_file = NULL;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined(i386) && defined(HAS_BROKEN_IOCTL)
|
|
int
|
|
ioctl(fd, cmd, c)
|
|
int fd, cmd;
|
|
caddr_t c;
|
|
{
|
|
#undef ioctl
|
|
int ret;
|
|
|
|
#ifdef DEBUGIOCTL
|
|
int serrno;
|
|
u_char let, code, size;
|
|
|
|
size = (cmd >> 16) & IOCPARM_MASK;
|
|
let = (cmd >> 8);
|
|
code = cmd;
|
|
|
|
if (let == 't' && (75 <= code && code <= 90))
|
|
info("ioctl(%d, 0x%x ('%c', %d, %d), 0x%x)\n", fd, cmd,
|
|
let, code, size, c);
|
|
#endif
|
|
|
|
ret = ioctl(fd, cmd, c);
|
|
|
|
#ifdef DEBUGIOCTL
|
|
serrno = errno;
|
|
if (ret == -1)
|
|
info("ioctl('%c', %d, %d) errno = %d (%m)\n",
|
|
let, code, size, errno);
|
|
if (let == 't' && (75 <= code && code <= 90) && (cmd & IOC_OUT)) {
|
|
int i, len = ((cmd >> 16) & IOCPARM_MASK);
|
|
for (i = 0; i < len / 4; ++i)
|
|
info("word[%d] @ 0x%06x = 0x%x\n",
|
|
i, &((int *) c)[i],((int *)c)[i]);
|
|
}
|
|
errno = serrno;
|
|
#endif
|
|
|
|
if (ret == -1 && errno == EPERM)
|
|
errno = ret = 0;
|
|
return ret;
|
|
}
|
|
#endif /* HAS_BROKEN_IOCTL */
|
|
|
|
|
|
#if defined(FIXSIGS) && (defined (hppa) || defined(sparc))
|
|
|
|
/*
|
|
* These redefinitions of Posix functions are necessary
|
|
* because HPPA systems have an OS bug that causes
|
|
* sigaction to core dump:
|
|
*
|
|
* AlainF 9-Nov-1994 HACK FOR HP-PA/NEXTSTEP
|
|
* sigaction(3) seems broken in the HP-PA NeXTSTEP 3.2
|
|
* Posix lib. This causes pppd to SIGBUS at the expiration
|
|
* of the first timeout (_sigtramp seems to invoke
|
|
* the SIGALRM handler at an unreasonably low address).
|
|
* All calls so sigaction(3) have been changed to calls
|
|
* to sigvec(2) and sigprocmask(SIG_BLOCK,...) to
|
|
* sigblock(2).
|
|
* This is kind of a hack, especially since there are
|
|
* other routines of the Posix lib still used, but
|
|
* it worked for me.
|
|
*
|
|
* Dave Hess <David-Hess@net.tamu.edu> noted that 3.3 Sparc seems to
|
|
* have the same bug. Thus this fix has been enabled for SPARC also.
|
|
*
|
|
*
|
|
*/
|
|
|
|
int sigemptyset(sigset_t *mask)
|
|
{
|
|
*mask = 0;
|
|
}
|
|
|
|
sigaddset(sigset_t *mask, int which_sig)
|
|
{
|
|
*mask |= sigmask(which_sig);
|
|
}
|
|
|
|
|
|
int sigaction(int sig, const struct sigaction *act, struct sigaction *oact)
|
|
{
|
|
struct sigvec sv;
|
|
static int in = 0;
|
|
|
|
sv.sv_handler = act->sa_handler;
|
|
sv.sv_mask = act->sa_mask;
|
|
sv.sv_flags = 0;
|
|
|
|
if (!in)
|
|
{
|
|
in = 1;
|
|
warn("PPPD: Inside modified HP and SPARC sigaction\n");
|
|
}
|
|
|
|
return sigvec(sig, &sv, NULL);
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/*
|
|
* Code following is added for 2.3 compatibility
|
|
*/
|
|
|
|
/*
|
|
* get_idle_time - return how long the link has been idle.
|
|
*/
|
|
int
|
|
get_idle_time(u, ip)
|
|
int u;
|
|
struct ppp_idle *ip;
|
|
{
|
|
return (ioctl(ttyfd, PPPIOCGIDLE, ip) >= 0);
|
|
}
|
|
|
|
/*
|
|
* get_ppp_stats - return statistics for the link.
|
|
*/
|
|
int
|
|
get_ppp_stats(u, stats)
|
|
int u;
|
|
struct pppd_stats *stats;
|
|
{
|
|
struct ifpppstatsreq req;
|
|
|
|
memset (&req, 0, sizeof (req));
|
|
strlcpy(req.ifr_name, interface, sizeof(req.ifr_name));
|
|
if (ioctl(sockfd, SIOCGPPPSTATS, &req) < 0) {
|
|
error("Couldn't get PPP statistics: %m");
|
|
return 0;
|
|
}
|
|
stats->bytes_in = req.stats.p.ppp_ibytes;
|
|
stats->bytes_out = req.stats.p.ppp_obytes;
|
|
return 1;
|
|
}
|
|
|
|
|
|
/*
|
|
* get_loop_output - read characters from the loopback, form them
|
|
* into frames, 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()
|
|
{
|
|
|
|
#if 0
|
|
int rv = 0;
|
|
int n;
|
|
|
|
while ((n = read(loop_master, inbuf, sizeof(inbuf))) >= 0) {
|
|
if (loop_chars(inbuf, n))
|
|
rv = 1;
|
|
}
|
|
|
|
if (n == 0)
|
|
fatal("eof on loopback");
|
|
if (errno != EWOULDBLOCK)
|
|
fatal("read from loopback: %m");
|
|
|
|
return rv;
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* sifnpmode - Set the mode for handling packets for a given NP.
|
|
*/
|
|
int
|
|
sifnpmode(u, proto, mode)
|
|
int u;
|
|
int proto;
|
|
enum NPmode mode;
|
|
{
|
|
struct npioctl npi;
|
|
|
|
npi.protocol = proto;
|
|
npi.mode = mode;
|
|
if (ioctl(ttyfd, PPPIOCSNPMODE, &npi) < 0) {
|
|
error("ioctl(set NP %d mode to %d): %m", proto, mode);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
|
|
/*
|
|
* open_ppp_loopback - open the device we use for getting
|
|
* packets in demand mode, and connect it to a ppp interface.
|
|
* Here we use a pty.
|
|
*/
|
|
int
|
|
open_ppp_loopback()
|
|
{
|
|
|
|
#if 0
|
|
int flags;
|
|
struct termios tios;
|
|
int pppdisc = PPPDISC;
|
|
|
|
fatal("open_ppp_loopback called!");
|
|
|
|
if (openpty(&loop_master, &loop_slave, loop_name, NULL, NULL) < 0)
|
|
fatal("No free pty for loopback");
|
|
SYSDEBUG(("using %s for loopback", loop_name));
|
|
|
|
if (tcgetattr(loop_slave, &tios) == 0) {
|
|
tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB);
|
|
tios.c_cflag |= CS8 | CREAD;
|
|
tios.c_iflag = IGNPAR;
|
|
tios.c_oflag = 0;
|
|
tios.c_lflag = 0;
|
|
if (tcsetattr(loop_slave, TCSAFLUSH, &tios) < 0)
|
|
warn("couldn't set attributes on loopback: %m");
|
|
}
|
|
|
|
if ((flags = fcntl(loop_master, F_GETFL)) != -1)
|
|
if (fcntl(loop_master, F_SETFL, flags | O_NONBLOCK) == -1)
|
|
warn("couldn't set loopback to nonblock: %m");
|
|
|
|
ttyfd = loop_slave;
|
|
if (ioctl(ttyfd, TIOCSETD, &pppdisc) < 0)
|
|
fatal("ioctl(TIOCSETD): %m");
|
|
|
|
/*
|
|
* Find out which interface we were given.
|
|
*/
|
|
if (ioctl(ttyfd, PPPIOCGUNIT, &ifunit) < 0)
|
|
fatal("ioctl(PPPIOCGUNIT): %m");
|
|
|
|
/*
|
|
* Enable debug in the driver if requested.
|
|
*/
|
|
if (kdebugflag) {
|
|
if (ioctl(ttyfd, PPPIOCGFLAGS, (caddr_t) &flags) < 0) {
|
|
warn("ioctl (PPPIOCGFLAGS): %m");
|
|
} else {
|
|
flags |= (kdebugflag & 0xFF) * SC_DEBUG;
|
|
if (ioctl(ttyfd, PPPIOCSFLAGS, (caddr_t) &flags) < 0)
|
|
warn("ioctl(PPPIOCSFLAGS): %m");
|
|
}
|
|
}
|
|
|
|
return loop_master;
|
|
#endif
|
|
|
|
}
|
|
|
|
/*
|
|
* restore_loop - reattach the ppp unit to the loopback.
|
|
*/
|
|
void
|
|
restore_loop()
|
|
{
|
|
int x;
|
|
|
|
/*
|
|
* Transfer the ppp interface back to the loopback.
|
|
*/
|
|
if (ioctl(ttyfd, PPPIOCXFERUNIT, 0) < 0)
|
|
fatal("ioctl(transfer ppp unit): %m");
|
|
x = PPPDISC;
|
|
if (ioctl(loop_slave, TIOCSETD, &x) < 0)
|
|
fatal("ioctl(TIOCSETD): %m");
|
|
|
|
/*
|
|
* Check that we got the same unit again.
|
|
*/
|
|
if (ioctl(loop_slave, PPPIOCGUNIT, &x) < 0)
|
|
fatal("ioctl(PPPIOCGUNIT): %m");
|
|
if (x != ifunit)
|
|
fatal("transfer_ppp failed: wanted unit %d, got %d",
|
|
ifunit, x);
|
|
ttyfd = loop_slave;
|
|
}
|
|
|
|
|
|
/*
|
|
* Use the hostid as part of the random number seed.
|
|
*/
|
|
int
|
|
get_host_seed()
|
|
{
|
|
return gethostid();
|
|
}
|
|
|
|
|
|
/*
|
|
* sys_check_options - check the options that the user specified
|
|
*/
|
|
int
|
|
sys_check_options()
|
|
{
|
|
/*
|
|
* We don't support demand dialing yet.
|
|
*/
|
|
if (demand)
|
|
{
|
|
option_error("PPP-2.3 for NeXTSTEP does not yet support demand dialing");
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
|
|
/*
|
|
* sys_close - Clean up in a child process before execing.
|
|
*/
|
|
void
|
|
sys_close()
|
|
{
|
|
close(sockfd);
|
|
if (loop_slave >= 0) {
|
|
close(loop_slave);
|
|
close(loop_master);
|
|
}
|
|
closelog();
|
|
}
|
|
|
|
#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;
|
|
{
|
|
fd_set ready;
|
|
int n;
|
|
|
|
FD_ZERO(&ready);
|
|
FD_SET(loop_master, &ready);
|
|
n = select(loop_master + 1, &ready, NULL, &ready, timo);
|
|
if (n < 0 && errno != EINTR)
|
|
fatal("select: %m");
|
|
}
|
|
|
|
/*
|
|
* 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
|