* 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>
#ifdef INET6
static int sock6_fd = -1;
#endif /* INET6 */
-static int ppp_dev_fd = -1; /* fd for /dev/ppp (new style driver) */
+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 */
/* Prototypes for procedures local to this file. */
static int get_flags (int fd);
-static void set_flags (int fd, int flags);
+static int set_flags (int fd, int flags);
static int translate_speed (int bps);
static int baud_rate_of (int speed);
static void close_route_table (void);
/********************************************************************/
-static void set_flags (int fd, int flags)
+static int set_flags (int fd, int flags)
{
SYSDEBUG ((LOG_DEBUG, "set flags = %x\n", flags));
if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &flags) < 0) {
if (! ok_error (errno) )
- fatal("ioctl(PPPIOCSFLAGS, %x): %m (line %d)", flags, errno, __LINE__);
+ error("Failed to set PPP kernel option flags: %m", flags);
+ return -1;
}
+ return 0;
}
/********************************************************************
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)
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();
}
/********************************************************************
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;
* 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
*/
warn("Couldn't restore device fd flags: %m");
}
}
+flushfailed:
initfdflags = -1;
generic_disestablish_ppp(tty_fd);
if (demand) {
set_flags(ppp_dev_fd, get_flags(ppp_dev_fd) | 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 (ifunit >= 0) {
+ close(ppp_dev_fd);
remove_fd(ppp_dev_fd);
+ ppp_dev_fd = -1;
+ }
} else {
/* old-style driver */
if (demand)
*/
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);
}
*/
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);
+ set_flags(master_fd, get_flags(master_fd) | SC_MULTILINK);
+ close(master_fd);
ifunit = ifnum;
return 1;
int proto;
dump_packet("sent", p, len);
+ if (snoop_send_hook) snoop_send_hook(p, len);
if (len < PPP_HDRLEN)
return;
*/
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;
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)
+int tty_send_config (int mtu,u_int32_t asyncmap,int pcomp,int accomp)
{
u_int x;
* Set the asyncmap and other parameters for the ppp device
*/
if (!still_ppp())
- return;
+ return 0;
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;
+ if (errno != EIO && errno != ENOTTY)
+ error("Couldn't set transmit async character map: %m");
+ else if (debug)
+ dbglog("PPPIOCSASYNCMAP: %m");
+ return -1;
}
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);
+ return set_flags(ppp_fd, x);
}
/********************************************************************
* the ppp interface.
*/
-void tty_recv_config (int mru,u_int32_t asyncmap,int pcomp,int accomp)
+int tty_recv_config (int mru,u_int32_t asyncmap,int pcomp,int accomp)
{
+ int ret = 0;
+
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;
+ return 0;
/*
* 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 (errno != EIO && errno != ENOTTY)
+ error("Couldn't set channel receive MRU: %m");
+ else if (debug)
+ dbglog("PPPIOCSMRU: %m");
+ ret = -1;
}
if (new_style_driver && ifunit >= 0
- && ioctl(ppp_dev_fd, PPPIOCSMRU, (caddr_t) &mru) < 0)
+ && ioctl(ppp_dev_fd, PPPIOCSMRU, (caddr_t) &mru) < 0) {
error("Couldn't set MRU in generic PPP layer: %m");
+ ret = -1;
+ }
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 (errno != EIO && errno != ENOTTY)
+ error("Couldn't set channel receive asyncmap: %m");
+ else if (debug)
+ dbglog("PPPIOCSRASYNCMAP: %m");
+ ret = -1;
}
+ return ret;
}
/********************************************************************
* 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;
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;
}
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