* sys-linux.c - System-dependent procedures for setting up
* PPP interfaces on Linux systems
*
- * Copyright (c) 1989 Carnegie Mellon 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.
+ * Copyright (c) 1994-2002 Paul Mackerras. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name(s) of the authors of this software must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Paul Mackerras
+ * <paulus@samba.org>".
+ *
+ * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Derived from main.c and pppd.h, which are:
+ *
+ * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any legal
+ * details, please contact
+ * Office of Technology Transfer
+ * Carnegie Mellon University
+ * 5000 Forbes Avenue
+ * Pittsburgh, PA 15213-3890
+ * (412) 268-4387, fax: (412) 268-7395
+ * tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/ioctl.h>
#define IN6_LLADDR_FROM_EUI64(sin6, eui64) do { \
memset(&sin6.s6_addr, 0, sizeof(struct in6_addr)); \
- sin6.s6_addr16[0] = htons(0xfe80); \
+ sin6.s6_addr16[0] = htons(0xfe80); \
eui64_copy(eui64, sin6.s6_addr32[2]); \
} while (0)
#ifdef INET6
static int sock6_fd = -1;
#endif /* INET6 */
-static int ppp_dev_fd = -1; /* fd for /dev/ppp (new style driver) */
+
+/*
+ * For the old-style kernel driver, this is the same as ppp_fd.
+ * For the new-style driver, it is the fd of an instance of /dev/ppp
+ * which is attached to the ppp unit and is used for controlling it.
+ */
+int ppp_dev_fd = -1; /* fd for /dev/ppp (new style driver) */
+
static int chindex; /* channel index (new style driver) */
static fd_set in_fds; /* set of fds that wait_input waits for */
#define SIN_ADDR(x) (((struct sockaddr_in *) (&(x)))->sin_addr.s_addr)
/* Prototypes for procedures local to this file. */
-static int get_flags (int fd);
-static void set_flags (int fd, int flags);
+static int modify_flags(int fd, int clear_bits, int set_bits);
static int translate_speed (int bps);
static int baud_rate_of (int speed);
static void close_route_table (void);
return 0;
}
-/********************************************************************
- *
- * Functions to read and set the flags value in the device driver
+/*
+ * modify_flags - set and clear flag bits controlling the kernel
+ * PPP driver.
*/
+static int modify_flags(int fd, int clear_bits, int set_bits)
+{
+ int flags;
-static int get_flags (int fd)
-{
- int flags;
-
- if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &flags) < 0) {
- if ( ok_error (errno) )
- flags = 0;
- else
- fatal("ioctl(PPPIOCGFLAGS): %m (line %d)", __LINE__);
- }
-
- SYSDEBUG ((LOG_DEBUG, "get flags = %x\n", flags));
- return flags;
-}
-
-/********************************************************************/
+ if (ioctl(fd, PPPIOCGFLAGS, &flags) == -1)
+ goto err;
+ flags = (flags & ~clear_bits) | set_bits;
+ if (ioctl(fd, PPPIOCSFLAGS, &flags) == -1)
+ goto err;
-static void set_flags (int fd, int flags)
-{
- SYSDEBUG ((LOG_DEBUG, "set flags = %x\n", flags));
+ return 0;
- if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &flags) < 0) {
- if (! ok_error (errno) )
- fatal("ioctl(PPPIOCSFLAGS, %x): %m (line %d)", flags, errno, __LINE__);
- }
+ err:
+ if (errno != EIO)
+ error("Failed to set PPP kernel option flags: %m");
+ return -1;
}
/********************************************************************
void sys_init(void)
{
- int flags;
-
- if (new_style_driver) {
- ppp_dev_fd = open("/dev/ppp", O_RDWR);
- if (ppp_dev_fd < 0)
- fatal("Couldn't open /dev/ppp: %m");
- flags = fcntl(ppp_dev_fd, F_GETFL);
- if (flags == -1
- || fcntl(ppp_dev_fd, F_SETFL, flags | O_NONBLOCK) == -1)
- warn("Couldn't set /dev/ppp to nonblock: %m");
- }
-
/* Get an internet socket for doing socket ioctls. */
sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (sock_fd < 0)
void
sys_close(void)
{
- if (new_style_driver)
+ if (new_style_driver && ppp_dev_fd >= 0)
close(ppp_dev_fd);
if (sock_fd >= 0)
close(sock_fd);
+#ifdef INET6
+ if (sock6_fd >= 0)
+ close(sock6_fd);
+#endif
if (slave_fd >= 0)
close(slave_fd);
if (master_fd >= 0)
close(master_fd);
- closelog();
}
/********************************************************************
static int set_kdebugflag (int requested_level)
{
- if (new_style_driver && ifunit < 0)
+ if (ppp_dev_fd < 0)
return 1;
if (ioctl(ppp_dev_fd, PPPIOCSDEBUG, &requested_level) < 0) {
if ( ! ok_error (errno) )
| SC_LOG_FLUSH)
if (ret_fd >= 0) {
- set_flags(ppp_fd, ((get_flags(ppp_fd) & ~(SC_RCVB | SC_LOGB))
- | ((kdebugflag * SC_DEBUG) & SC_LOGB)));
+ modify_flags(ppp_fd, SC_RCVB | SC_LOGB,
+ (kdebugflag * SC_DEBUG) & SC_LOGB);
} else {
if (ioctl(tty_fd, TIOCSETD, &tty_disc) < 0 && !ok_error(errno))
warn("Couldn't reset tty to normal line discipline: %m");
int x;
if (new_style_driver) {
- /* Open another instance of /dev/ppp and connect the channel to it */
int flags;
+ /* Open an instance of /dev/ppp and connect the channel to it */
if (ioctl(fd, PPPIOCGCHAN, &chindex) == -1) {
error("Couldn't get channel number: %m");
goto err;
error("Couldn't reopen /dev/ppp: %m");
goto err;
}
+ (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
if (ioctl(fd, PPPIOCATTCHAN, &chindex) < 0) {
error("Couldn't attach to channel %d: %m", chindex);
goto err_close;
}
if (looped)
- set_flags(ppp_dev_fd, get_flags(ppp_dev_fd) & ~SC_LOOP_TRAFFIC);
+ modify_flags(ppp_dev_fd, SC_LOOP_TRAFFIC, 0);
if (!multilink) {
add_fd(ppp_dev_fd);
}
}
- looped = 0;
-
/*
* Enable debug in the driver if requested.
*/
if (!looped)
set_kdebugflag (kdebugflag);
+ looped = 0;
+
SYSDEBUG ((LOG_NOTICE, "Using version %d.%d.%d of PPP driver",
driver_version, driver_modification, driver_patch));
* Flush the tty output buffer so that the TIOCSETD doesn't hang.
*/
if (tcflush(tty_fd, TCIOFLUSH) < 0)
+ {
warn("tcflush failed: %m");
+ goto flushfailed;
+ }
/*
* Restore the previous line discipline
*/
if ( ! ok_error (errno))
error("ioctl(TIOCSETD, N_TTY): %m (line %d)", __LINE__);
}
-
+
if (ioctl(tty_fd, TIOCNXCL, 0) < 0) {
if ( ! ok_error (errno))
warn("ioctl(TIOCNXCL): %m (line %d)", __LINE__);
warn("Couldn't restore device fd flags: %m");
}
}
+flushfailed:
initfdflags = -1;
generic_disestablish_ppp(tty_fd);
close(ppp_fd);
ppp_fd = -1;
if (demand) {
- set_flags(ppp_dev_fd, get_flags(ppp_dev_fd) | SC_LOOP_TRAFFIC);
+ modify_flags(ppp_dev_fd, 0, SC_LOOP_TRAFFIC);
looped = 1;
- } else if (ifunit >= 0 && ioctl(ppp_dev_fd, PPPIOCDETACH) < 0)
- error("Couldn't release PPP unit: %m");
- if (!multilink)
+ } else if (ppp_dev_fd >= 0) {
+ close(ppp_dev_fd);
remove_fd(ppp_dev_fd);
+ ppp_dev_fd = -1;
+ }
} else {
/* old-style driver */
if (demand)
set_ppp_fd(slave_fd);
+ else
+ ppp_dev_fd = -1;
}
}
*/
static int make_ppp_unit()
{
- int x;
+ int x, flags;
+
+ if (ppp_dev_fd >= 0) {
+ dbglog("in make_ppp_unit, already had /dev/ppp open?");
+ close(ppp_dev_fd);
+ }
+ ppp_dev_fd = open("/dev/ppp", O_RDWR);
+ if (ppp_dev_fd < 0)
+ fatal("Couldn't open /dev/ppp: %m");
+ flags = fcntl(ppp_dev_fd, F_GETFL);
+ if (flags == -1
+ || fcntl(ppp_dev_fd, F_SETFL, flags | O_NONBLOCK) == -1)
+ warn("Couldn't set /dev/ppp to nonblock: %m");
ifunit = req_unit;
x = ioctl(ppp_dev_fd, PPPIOCNEWUNIT, &ifunit);
if (x < 0 && req_unit >= 0 && errno == EEXIST) {
- warn("Couldn't allocate PPP unit %d as it is already in use");
+ warn("Couldn't allocate PPP unit %d as it is already in use", req_unit);
ifunit = -1;
x = ioctl(ppp_dev_fd, PPPIOCNEWUNIT, &ifunit);
}
*/
void cfg_bundle(int mrru, int mtru, int rssn, int tssn)
{
- int flags;
-
if (!new_style_driver)
return;
/* set the mrru, mtu and flags */
if (ioctl(ppp_dev_fd, PPPIOCSMRRU, &mrru) < 0)
error("Couldn't set MRRU: %m");
- flags = get_flags(ppp_dev_fd);
- flags &= ~(SC_MP_SHORTSEQ | SC_MP_XSHORTSEQ);
- flags |= (rssn? SC_MP_SHORTSEQ: 0) | (tssn? SC_MP_XSHORTSEQ: 0)
- | (mrru? SC_MULTILINK: 0);
- set_flags(ppp_dev_fd, flags);
+ modify_flags(ppp_dev_fd, SC_MP_SHORTSEQ|SC_MP_XSHORTSEQ|SC_MULTILINK,
+ ((rssn? SC_MP_SHORTSEQ: 0) | (tssn? SC_MP_XSHORTSEQ: 0)
+ | (mrru? SC_MULTILINK: 0)));
/* connect up the channel */
if (ioctl(ppp_fd, PPPIOCCONNECT, &ifunit) < 0)
*/
int bundle_attach(int ifnum)
{
+ int master_fd;
+
if (!new_style_driver)
return -1;
- if (ioctl(ppp_dev_fd, PPPIOCATTACH, &ifnum) < 0) {
- if (errno == ENXIO)
+ master_fd = open("/dev/ppp", O_RDWR);
+ if (master_fd < 0)
+ fatal("Couldn't open /dev/ppp: %m");
+ if (ioctl(master_fd, PPPIOCATTACH, &ifnum) < 0) {
+ if (errno == ENXIO) {
+ close(master_fd);
return 0; /* doesn't still exist */
+ }
fatal("Couldn't attach to interface unit %d: %m\n", ifnum);
}
if (ioctl(ppp_fd, PPPIOCCONNECT, &ifnum) < 0)
fatal("Couldn't connect to interface unit %d: %m", ifnum);
- set_flags(ppp_dev_fd, get_flags(ppp_dev_fd) | SC_MULTILINK);
+ modify_flags(master_fd, 0, SC_MULTILINK);
+ close(master_fd);
ifunit = ifnum;
return 1;
case SC_RCV_B7_0:
s = "all had bit 7 set to 1";
break;
-
+
case SC_RCV_B7_1:
s = "all had bit 7 set to 0";
break;
-
+
case SC_RCV_EVNP:
s = "all had odd parity";
break;
-
+
case SC_RCV_ODDP:
s = "all had even parity";
break;
}
-
+
if (s != NULL) {
warn("Receive serial link is not 8-bit clean:");
warn("Problem: %s", s);
}
}
}
-
+
/*
* List of valid speeds.
static int baud_rate_of (int speed)
{
struct speed *speedp;
-
+
if (speed != 0) {
for (speedp = speeds; speedp->speed_int; speedp++) {
if (speed == speedp->speed_val)
fatal("tcgetattr: %m (line %d)", __LINE__);
return;
}
-
+
if (!restore_term)
inittermios = tios;
-
+
tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
tios.c_cflag |= CS8 | CREAD | HUPCL;
tios.c_lflag = 0;
tios.c_cc[VMIN] = 1;
tios.c_cc[VTIME] = 0;
-
+
if (local || !modem)
tios.c_cflag ^= (CLOCAL | HUPCL);
default:
break;
}
-
+
speed = translate_speed(inspeed);
if (speed) {
cfsetospeed (&tios, speed);
if (tcsetattr(tty_fd, TCSAFLUSH, &tios) < 0)
if (!ok_error(errno))
fatal("tcsetattr: %m (line %d)", __LINE__);
-
+
baud_rate = baud_rate_of(speed);
restore_term = 1;
}
*/
if (!default_device)
inittermios.c_lflag &= ~(ECHO | ECHONL);
-
+
if (tcsetattr(tty_fd, TCSAFLUSH, &inittermios) < 0) {
if (! ok_error (errno))
warn("tcsetattr: %m (line %d)", __LINE__);
int fd = ppp_fd;
int proto;
- if (debug)
- dbglog("sent %P", p, len);
+ dump_packet("sent", p, len);
+ if (snoop_send_hook) snoop_send_hook(p, len);
if (len < PPP_HDRLEN)
return;
p += 2;
len -= 2;
proto = (p[0] << 8) + p[1];
- if (ifunit >= 0 && !(proto >= 0xc000 || proto == PPP_CCPFRAG))
+ if (ppp_dev_fd >= 0 && !(proto >= 0xc000 || proto == PPP_CCPFRAG))
fd = ppp_dev_fd;
}
if (write(fd, p, len) < 0) {
- if (errno == EWOULDBLOCK || errno == ENOBUFS
+ if (errno == EWOULDBLOCK || errno == EAGAIN || errno == ENOBUFS
|| errno == ENXIO || errno == EIO || errno == EINTR)
warn("write: warning: %m (%d)", errno);
else
*/
void add_fd(int fd)
{
+ if (fd >= FD_SETSIZE)
+ fatal("internal error: file descriptor too large (%d)", fd);
FD_SET(fd, &in_fds);
if (fd > max_in_fd)
max_in_fd = fd;
nr = -1;
if (ppp_fd >= 0) {
nr = read(ppp_fd, buf, len);
- if (nr < 0 && errno != EWOULDBLOCK && errno != EIO && errno != EINTR)
+ if (nr < 0 && errno != EWOULDBLOCK && errno != EAGAIN
+ && errno != EIO && errno != EINTR)
error("read: %m");
if (nr < 0 && errno == ENXIO)
return 0;
}
- if (nr < 0 && new_style_driver && ifunit >= 0) {
+ if (nr < 0 && new_style_driver && ppp_dev_fd >= 0) {
/* N.B. we read ppp_fd first since LCP packets come in there. */
nr = read(ppp_dev_fd, buf, len);
- if (nr < 0 && errno != EWOULDBLOCK && errno != EIO && errno != EINTR)
+ if (nr < 0 && errno != EWOULDBLOCK && errno != EAGAIN
+ && errno != EIO && errno != EINTR)
error("read /dev/ppp: %m");
if (nr < 0 && errno == ENXIO)
return 0;
if (n == 0)
fatal("eof on loopback");
- if (errno != EWOULDBLOCK)
+ if (errno != EWOULDBLOCK && errno != EAGAIN)
fatal("read from loopback: %m(%d)", errno);
return rv;
memset (&ifr, '\0', sizeof (ifr));
strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
ifr.ifr_mtu = mtu;
-
+
if (ifunit >= 0 && ioctl(sock_fd, SIOCSIFMTU, (caddr_t) &ifr) < 0)
error("ioctl(SIOCSIFMTU): %m (line %d)", __LINE__);
}
+/*
+ * netif_get_mtu - get the MTU on the PPP network interface.
+ */
+int
+netif_get_mtu(int unit)
+{
+ struct ifreq ifr;
+
+ memset (&ifr, '\0', sizeof (ifr));
+ strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+
+ if (ifunit >= 0 && ioctl(sock_fd, SIOCGIFMTU, (caddr_t) &ifr) < 0) {
+ error("ioctl(SIOCGIFMTU): %m (line %d)", __LINE__);
+ return 0;
+ }
+ return ifr.ifr_mtu;
+}
+
/********************************************************************
*
* tty_send_config - configure the transmit characteristics of
* the ppp interface.
*/
-void tty_send_config (int mtu,u_int32_t asyncmap,int pcomp,int accomp)
+void tty_send_config(int mtu, u_int32_t asyncmap, int pcomp, int accomp)
{
- u_int x;
+ int x;
-/*
- * Set the asyncmap and other parameters for the ppp device
- */
- if (!still_ppp())
- return;
- link_mtu = mtu;
- SYSDEBUG ((LOG_DEBUG, "send_config: asyncmap = %lx\n", asyncmap));
- if (ioctl(ppp_fd, PPPIOCSASYNCMAP, (caddr_t) &asyncmap) < 0) {
- if (!ok_error(errno))
- fatal("ioctl(PPPIOCSASYNCMAP): %m (line %d)", __LINE__);
- return;
- }
-
- x = get_flags(ppp_fd);
- x = pcomp ? x | SC_COMP_PROT : x & ~SC_COMP_PROT;
- x = accomp ? x | SC_COMP_AC : x & ~SC_COMP_AC;
- x = sync_serial ? x | SC_SYNC : x & ~SC_SYNC;
- set_flags(ppp_fd, x);
+ if (!still_ppp())
+ return;
+ link_mtu = mtu;
+ if (ioctl(ppp_fd, PPPIOCSASYNCMAP, (caddr_t) &asyncmap) < 0) {
+ if (errno != EIO && errno != ENOTTY)
+ error("Couldn't set transmit async character map: %m");
+ ++error_count;
+ return;
+ }
+
+ x = (pcomp? SC_COMP_PROT: 0) | (accomp? SC_COMP_AC: 0)
+ | (sync_serial? SC_SYNC: 0);
+ modify_flags(ppp_fd, SC_COMP_PROT|SC_COMP_AC|SC_SYNC, x);
}
/********************************************************************
* the ppp interface.
*/
-void tty_recv_config (int mru,u_int32_t asyncmap,int pcomp,int accomp)
+void tty_recv_config(int mru, u_int32_t asyncmap, int pcomp, int accomp)
{
- SYSDEBUG ((LOG_DEBUG, "recv_config: mru = %d\n", mru));
/*
* If we were called because the link has gone down then there is nothing
* which may be done. Just return without incident.
*/
- if (!still_ppp())
- return;
+ if (!still_ppp())
+ return;
/*
* Set the receiver parameters
*/
- if (ioctl(ppp_fd, PPPIOCSMRU, (caddr_t) &mru) < 0) {
- if ( ! ok_error (errno))
- error("ioctl(PPPIOCSMRU): %m (line %d)", __LINE__);
- }
- if (new_style_driver && ifunit >= 0
- && ioctl(ppp_dev_fd, PPPIOCSMRU, (caddr_t) &mru) < 0)
- error("Couldn't set MRU in generic PPP layer: %m");
+ if (ioctl(ppp_fd, PPPIOCSMRU, (caddr_t) &mru) < 0) {
+ if (errno != EIO && errno != ENOTTY)
+ error("Couldn't set channel receive MRU: %m");
+ }
+ if (new_style_driver && ppp_dev_fd >= 0
+ && ioctl(ppp_dev_fd, PPPIOCSMRU, (caddr_t) &mru) < 0)
+ error("Couldn't set MRU in generic PPP layer: %m");
- SYSDEBUG ((LOG_DEBUG, "recv_config: asyncmap = %lx\n", asyncmap));
- if (ioctl(ppp_fd, PPPIOCSRASYNCMAP, (caddr_t) &asyncmap) < 0) {
- if (!ok_error(errno))
- error("ioctl(PPPIOCSRASYNCMAP): %m (line %d)", __LINE__);
- }
+ if (ioctl(ppp_fd, PPPIOCSRASYNCMAP, (caddr_t) &asyncmap) < 0) {
+ if (errno != EIO && errno != ENOTTY)
+ error("Couldn't set channel receive asyncmap: %m");
+ }
}
/********************************************************************
* is acceptable for use.
*/
-int ccp_test (int unit, u_char *opt_ptr, int opt_len, int for_transmit)
+int
+ccp_test(int unit, u_char *opt_ptr, int opt_len, int for_transmit)
{
struct ppp_option_data data;
void ccp_flags_set (int unit, int isopen, int isup)
{
- if (still_ppp() && ifunit >= 0) {
- int x = get_flags(ppp_dev_fd);
- x = isopen? x | SC_CCP_OPEN : x &~ SC_CCP_OPEN;
- x = isup? x | SC_CCP_UP : x &~ SC_CCP_UP;
- set_flags (ppp_dev_fd, x);
- }
+ int x;
+
+ x = (isopen? SC_CCP_OPEN: 0) | (isup? SC_CCP_UP: 0);
+ if (still_ppp() && ppp_dev_fd >= 0)
+ modify_flags(ppp_dev_fd, SC_CCP_OPEN|SC_CCP_UP, x);
}
#ifdef PPP_FILTER
struct ppp_idle *ip;
{
return ioctl(ppp_dev_fd, PPPIOCGIDLE, ip) >= 0;
-}
+}
/********************************************************************
*
int ccp_fatal_error (int unit)
{
- int x = get_flags(ppp_dev_fd);
+ int flags;
- return x & SC_DC_FERROR;
+ if (ioctl(ppp_dev_fd, PPPIOCGFLAGS, &flags) < 0) {
+ error("Couldn't read compression error flags: %m");
+ flags = 0;
+ }
+ return flags & SC_DC_FERROR;
}
/********************************************************************
static void close_route_table (void)
{
if (route_fd != (FILE *) 0) {
- fclose (route_fd);
- route_fd = (FILE *) 0;
+ fclose (route_fd);
+ route_fd = (FILE *) 0;
}
}
path = path_to_procfs("/net/route");
route_fd = fopen (path, "r");
if (route_fd == NULL) {
- error("can't open routing table %s: %m", path);
- return 0;
+ error("can't open routing table %s: %m", path);
+ return 0;
}
route_dev_col = 0; /* default to usual columns */
{
char *cols[ROUTE_MAX_COLS], *p;
int col;
-
+
memset (rt, '\0', sizeof (struct rtentry));
if (fgets (route_buffer, sizeof (route_buffer), route_fd) == (char *) 0)
int result = 0;
if (!open_route_table())
- return 0;
+ return 0;
while (read_route_table(rt) != 0) {
- if ((rt->rt_flags & RTF_UP) == 0)
+ if ((rt->rt_flags & RTF_UP) == 0)
continue;
if (kernel_version > KVERSION(2,1,0) && SIN_ADDR(rt->rt_genmask) != 0)
continue;
- if (SIN_ADDR(rt->rt_dst) == 0L) {
+ if (SIN_ADDR(rt->rt_dst) == 0L) {
result = 1;
break;
}
SET_SA_FAMILY (rt.rt_dst, AF_INET);
SET_SA_FAMILY (rt.rt_gateway, AF_INET);
+ rt.rt_dev = ifname;
+
if (kernel_version > KVERSION(2,1,0)) {
SET_SA_FAMILY (rt.rt_genmask, AF_INET);
SIN_ADDR(rt.rt_genmask) = 0L;
}
SIN_ADDR(rt.rt_gateway) = gateway;
-
+
rt.rt_flags = RTF_UP | RTF_GATEWAY;
if (ioctl(sock_fd, SIOCADDRT, &rt) < 0) {
if ( ! ok_error ( errno ))
}
SIN_ADDR(rt.rt_gateway) = gateway;
-
+
rt.rt_flags = RTF_UP | RTF_GATEWAY;
if (ioctl(sock_fd, SIOCDELRT, &rt) < 0 && errno != ESRCH) {
if (still_ppp()) {
if (has_proxy_arp == 0) {
memset (&arpreq, '\0', sizeof(arpreq));
-
+
SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
SIN_ADDR(arpreq.arp_pa) = his_adr;
arpreq.arp_flags = ATF_PERM | ATF_PUBL;
}
return 1;
}
-
+
/********************************************************************
*
* get_ether_addr - get the hardware address of an interface on the
struct ifreq *ifr, *ifend;
u_int32_t ina, mask;
char *aliasp;
- struct ifreq ifreq;
+ struct ifreq ifreq, bestifreq;
struct ifconf ifc;
struct ifreq ifs[MAX_IFS];
-
+
+ u_int32_t bestmask=0;
+ int found_interface = 0;
+
ifc.ifc_len = sizeof(ifs);
ifc.ifc_req = ifs;
if (ioctl(sock_fd, SIOCGIFCONF, &ifc) < 0) {
if (ifr->ifr_addr.sa_family == AF_INET) {
ina = SIN_ADDR(ifr->ifr_addr);
strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
- SYSDEBUG ((LOG_DEBUG, "proxy arp: examining interface %s",
+ SYSDEBUG ((LOG_DEBUG, "proxy arp: examining interface %s",
ifreq.ifr_name));
/*
* Check that the interface is up, and not point-to-point
* Get its netmask and check that it's on the right subnet.
*/
if (ioctl(sock_fd, SIOCGIFNETMASK, &ifreq) < 0)
- continue;
+ continue;
mask = SIN_ADDR(ifreq.ifr_addr);
SYSDEBUG ((LOG_DEBUG, "proxy arp: interface addr %s mask %lx",
- ip_ntoa(ina), ntohl(mask)));
+ ip_ntoa(ina), ntohl(mask)));
if (((ipaddr ^ ina) & mask) != 0)
- continue;
- break;
+ continue; /* no match */
+ /* matched */
+ if (mask >= bestmask) {
+ /* Compare using >= instead of > -- it is possible for
+ an interface to have a netmask of 0.0.0.0 */
+ found_interface = 1;
+ bestifreq = ifreq;
+ bestmask = mask;
+ }
}
}
-
- if (ifr >= ifend)
- return 0;
- strlcpy(name, ifreq.ifr_name, namelen);
+ if (!found_interface) return 0;
+
+ strlcpy(name, bestifreq.ifr_name, namelen);
/* trim off the :1 in eth0:1 */
aliasp = strchr(name, ':');
/*
* Now get the hardware address.
*/
- memset (&ifreq.ifr_hwaddr, 0, sizeof (struct sockaddr));
- if (ioctl (sock_fd, SIOCGIFHWADDR, &ifreq) < 0) {
- error("SIOCGIFHWADDR(%s): %m", ifreq.ifr_name);
- return 0;
+ memset (&bestifreq.ifr_hwaddr, 0, sizeof (struct sockaddr));
+ if (ioctl (sock_fd, SIOCGIFHWADDR, &bestifreq) < 0) {
+ error("SIOCGIFHWADDR(%s): %m", bestifreq.ifr_name);
+ return 0;
}
memcpy (hwaddr,
- &ifreq.ifr_hwaddr,
+ &bestifreq.ifr_hwaddr,
sizeof (struct sockaddr));
SYSDEBUG ((LOG_DEBUG,
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);
/*
warn("ioctl(SIOCGIFCONF): %m (line %d)", __LINE__);
return mask;
}
-
+
ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
for (ifr = ifc.ifc_req; ifr < ifend; ifr++) {
/*
strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
if (ioctl(sock_fd, SIOCGIFFLAGS, &ifreq) < 0)
continue;
-
+
if (((ifreq.ifr_flags ^ FLAGS_GOOD) & FLAGS_MASK) != 0)
continue;
/*
*version = (int) strtoul (buf, &endp, 10);
*modification = 0;
*patch = 0;
-
+
if (endp != buf && *endp == '.') {
buf = endp + 1;
*modification = (int) strtoul (buf, &endp, 10);
error("ioctl(TIOCSETD(PPP)): %m (line %d)", __LINE__);
} else
ret = 1;
-
+
close(local_fd);
close(mfd);
return ret;
int my_version, my_modification, my_patch;
int osmaj, osmin, ospatch;
- no_ppp_msg =
+ no_ppp_msg =
"This system lacks kernel support for PPP. This could be because\n"
"the PPP kernel module could not be loaded, or because PPP was not\n"
"included in the kernel configuration. If PPP was included as a\n"
/*
* Open a socket for doing the ioctl operations.
- */
+ */
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0)
return 0;
-
+
strlcpy (ifr.ifr_name, "ppp0", sizeof (ifr.ifr_name));
ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 0;
/*
* Ensure that the hardware address is for PPP and not something else
*/
if (ok)
- ok = ioctl (s, SIOCGIFHWADDR, (caddr_t) &ifr) >= 0;
+ ok = ioctl (s, SIOCGIFHWADDR, (caddr_t) &ifr) >= 0;
if (ok && ((ifr.ifr_hwaddr.sa_family & ~0xFF) != ARPHRD_PPP))
- ok = 0;
+ ok = 0;
/*
* This is the PPP device. Validate the version of the driver at this
/* The version numbers must match */
if (driver_version != my_version)
ok = 0;
-
+
/* The modification levels must be legal */
if (driver_modification < 3) {
if (driver_modification >= 2) {
utmpname(_PATH_UTMP);
setutent();
while ((utp = getutent()) && (utp->ut_pid != mypid))
- /* nothing */;
+ /* nothing */;
- /* Is this call really necessary? There is another one after the 'put' */
- endutent();
-
if (utp)
memcpy(&ut, utp, sizeof(ut));
else
if (ut.ut_id[0] == 0)
strncpy(ut.ut_id, line + 3, sizeof(ut.ut_id));
-
+
strncpy(ut.ut_user, name, sizeof(ut.ut_user));
strncpy(ut.ut_line, line, sizeof(ut.ut_line));
if (ipcp_protent.enabled_flag && ipcp_hisoptions[0].neg_addr)
memcpy(&ut.ut_addr, (char *) &ipcp_hisoptions[0].hisaddr,
sizeof(ut.ut_addr));
-
+
/* CL: Makes sure that the logout works */
if (*host == 0 && *name==0)
ut.ut_host[0]=0;
int sifvjcomp (int u, int vjcomp, int cidcomp, int maxcid)
{
- u_int x = get_flags(ppp_dev_fd);
+ u_int x;
- if (vjcomp) {
- if (ioctl (ppp_dev_fd, PPPIOCSMAXCID, (caddr_t) &maxcid) < 0) {
- if (! ok_error (errno))
- error("ioctl(PPPIOCSMAXCID): %m (line %d)", __LINE__);
- vjcomp = 0;
+ if (vjcomp) {
+ if (ioctl(ppp_dev_fd, PPPIOCSMAXCID, (caddr_t) &maxcid) < 0)
+ error("Couldn't set up TCP header compression: %m");
+ vjcomp = 0;
}
- }
- x = vjcomp ? x | SC_COMP_TCP : x &~ SC_COMP_TCP;
- x = cidcomp ? x & ~SC_NO_TCP_CCID : x | SC_NO_TCP_CCID;
- set_flags (ppp_dev_fd, x);
+ x = (vjcomp? SC_COMP_TCP: 0) | (cidcomp? 0: SC_NO_TCP_CCID);
+ modify_flags(ppp_dev_fd, SC_COMP_TCP|SC_NO_TCP_CCID, x);
- return 1;
+ return 1;
}
/********************************************************************
int sifaddr (int unit, u_int32_t our_adr, u_int32_t his_adr,
u_int32_t net_mask)
{
- struct ifreq ifr;
+ struct ifreq ifr;
struct rtentry rt;
-
+
memset (&ifr, '\0', sizeof (ifr));
memset (&rt, '\0', sizeof (rt));
-
- SET_SA_FAMILY (ifr.ifr_addr, AF_INET);
- SET_SA_FAMILY (ifr.ifr_dstaddr, AF_INET);
- SET_SA_FAMILY (ifr.ifr_netmask, AF_INET);
+
+ SET_SA_FAMILY (ifr.ifr_addr, AF_INET);
+ SET_SA_FAMILY (ifr.ifr_dstaddr, AF_INET);
+ SET_SA_FAMILY (ifr.ifr_netmask, AF_INET);
strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
/*
if (! ok_error (errno))
error("ioctl(SIOCSIFADDR): %m (line %d)", __LINE__);
}
- else {
+ else {
warn("ioctl(SIOCSIFADDR): Address already exists");
}
- return (0);
+ return (0);
}
/*
* Set the gateway address
SIN_ADDR(ifr.ifr_dstaddr) = his_adr;
if (ioctl(sock_fd, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) {
if (! ok_error (errno))
- error("ioctl(SIOCSIFDSTADDR): %m (line %d)", __LINE__);
+ error("ioctl(SIOCSIFDSTADDR): %m (line %d)", __LINE__);
return (0);
- }
+ }
/*
* Set the netmask.
* For recent kernels, force the netmask to 255.255.255.255.
SIN_ADDR(ifr.ifr_netmask) = net_mask;
if (ioctl(sock_fd, SIOCSIFNETMASK, (caddr_t) &ifr) < 0) {
if (! ok_error (errno))
- error("ioctl(SIOCSIFNETMASK): %m (line %d)", __LINE__);
+ error("ioctl(SIOCSIFNETMASK): %m (line %d)", __LINE__);
return (0);
- }
+ }
}
/*
* Add the device route
memset(&ifr, 0, sizeof(ifr));
SET_SA_FAMILY(ifr.ifr_addr, AF_INET);
strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
-
+
if (ioctl(sock_fd, SIOCSIFADDR, (caddr_t) &ifr) < 0) {
if (! ok_error (errno)) {
error("ioctl(SIOCSIFADDR): %m (line %d)", __LINE__);
#ifdef INET6
/********************************************************************
- *
+ *
* sif6addr - Config the interface with an IPv6 link-local address
*/
int sif6addr (int unit, eui64_t our_eui64, eui64_t his_eui64)
error("sif6addr: ioctl(SIOCGIFINDEX): %m (line %d)", __LINE__);
return 0;
}
-
+
/* Local interface */
memset(&ifr6, 0, sizeof(ifr6));
IN6_LLADDR_FROM_EUI64(ifr6.ifr6_addr, our_eui64);
error("sif6addr: ioctl(SIOCSIFADDR): %m (line %d)", __LINE__);
return 0;
}
-
+
/* Route to remote host */
memset(&rt6, 0, sizeof(rt6));
IN6_LLADDR_FROM_EUI64(rt6.rtmsg_dst, his_eui64);
rt6.rtmsg_dst_len = 10;
rt6.rtmsg_ifindex = ifr.ifr_ifindex;
rt6.rtmsg_metric = 1;
-
+
if (ioctl(sock6_fd, SIOCADDRT, &rt6) < 0) {
error("sif6addr: ioctl(SIOCADDRT): %m (line %d)", __LINE__);
return 0;
error("cif6addr: ioctl(SIOCGIFINDEX): %m (line %d)", __LINE__);
return 0;
}
-
+
memset(&ifr6, 0, sizeof(ifr6));
IN6_LLADDR_FROM_EUI64(ifr6.ifr6_addr, our_eui64);
ifr6.ifr6_ifindex = ifr.ifr_ifindex;
if (! ok_error (errno))
error("cif6addr: ioctl(SIOCDIFADDR): %m (line %d)", __LINE__);
}
- else {
+ else {
warn("cif6addr: ioctl(SIOCDIFADDR): No such address");
}
- return (0);
+ return (0);
}
return 1;
}
/* allocate ourselves a ppp unit */
if (make_ppp_unit() < 0)
die(1);
- set_flags(ppp_dev_fd, SC_LOOP_TRAFFIC);
+ modify_flags(ppp_dev_fd, 0, SC_LOOP_TRAFFIC);
set_kdebugflag(kdebugflag);
ppp_fd = -1;
return ppp_dev_fd;
int result = 1;
#ifdef IPX_CHANGE
- int skfd;
+ int skfd;
struct ifreq ifr;
struct sockaddr_ipx *sipx = (struct sockaddr_ipx *) &ifr.ifr_addr;
skfd = socket (AF_IPX, SOCK_DGRAM, 0);
- if (skfd < 0) {
+ if (skfd < 0) {
if (! ok_error (errno))
dbglog("socket(AF_IPX): %m (line %d)", __LINE__);
result = 0;
int result = 1;
#ifdef IPX_CHANGE
- int skfd;
+ int skfd;
struct ifreq ifr;
struct sockaddr_ipx *sipx = (struct sockaddr_ipx *) &ifr.ifr_addr;
skfd = socket (AF_IPX, SOCK_DGRAM, 0);
- if (skfd < 0) {
+ if (skfd < 0) {
if (! ok_error (errno))
dbglog("socket(AF_IPX): %m (line %d)", __LINE__);
result = 0;
if (ipxcp_protent.enabled_flag) {
struct stat stat_buf;
- if ((path = path_to_procfs("/net/ipx_interface")) == 0
+ if ((path = path_to_procfs("/net/ipx_interface")) == 0
|| lstat(path, &stat_buf) < 0) {
error("IPX support is not present in the kernel\n");
ipxcp_protent.enabled_flag = 0;
}
return 1;
}
+
+#ifdef INET6
+/*
+ * ether_to_eui64 - Convert 48-bit Ethernet address into 64-bit EUI
+ *
+ * convert the 48-bit MAC address of eth0 into EUI 64. caller also assumes
+ * that the system has a properly configured Ethernet interface for this
+ * function to return non-zero.
+ */
+int
+ether_to_eui64(eui64_t *p_eui64)
+{
+ struct ifreq ifr;
+ int skfd;
+ const unsigned char *ptr;
+
+ skfd = socket(PF_INET6, SOCK_DGRAM, 0);
+ if(skfd == -1)
+ {
+ warn("could not open IPv6 socket");
+ return 0;
+ }
+
+ strcpy(ifr.ifr_name, "eth0");
+ if(ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0)
+ {
+ close(skfd);
+ warn("could not obtain hardware address for eth0");
+ return 0;
+ }
+ close(skfd);
+
+ /*
+ * And convert the EUI-48 into EUI-64, per RFC 2472 [sec 4.1]
+ */
+ ptr = ifr.ifr_hwaddr.sa_data;
+ p_eui64->e8[0] = ptr[0] | 0x02;
+ p_eui64->e8[1] = ptr[1];
+ p_eui64->e8[2] = ptr[2];
+ p_eui64->e8[3] = 0xFF;
+ p_eui64->e8[4] = 0xFE;
+ p_eui64->e8[5] = ptr[3];
+ p_eui64->e8[6] = ptr[4];
+ p_eui64->e8[7] = ptr[5];
+
+ return 1;
+}
+#endif