X-Git-Url: http://git.ozlabs.org/?a=blobdiff_plain;f=pppd%2Fsys-linux.c;h=0b6db1c8f91d0b6a1d13f73f12b4875555a7f335;hb=39c06d616dd4c9443ed390969e58cd53ca1e314d;hp=d630bca14fab4f864aa2599701bb15619a9f6c61;hpb=83cac090b7ed4088a87cd320aa2a57f18cca2839;p=ppp.git diff --git a/pppd/sys-linux.c b/pppd/sys-linux.c index d630bca..0b6db1c 100644 --- a/pppd/sys-linux.c +++ b/pppd/sys-linux.c @@ -2,20 +2,76 @@ * 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 + * ". + * + * 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 @@ -127,7 +183,7 @@ static int master_fd = -1; #ifdef INET6 static int sock6_fd = -1; #endif /* INET6 */ -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 */ @@ -169,7 +225,7 @@ static int kernel_version; /* 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); @@ -244,14 +300,16 @@ static int get_flags (int fd) /********************************************************************/ -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; } /******************************************************************** @@ -261,18 +319,6 @@ static void set_flags (int fd, int flags) 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) @@ -325,11 +371,14 @@ sys_close(void) 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(); } /******************************************************************** @@ -416,9 +465,9 @@ int generic_establish_ppp (int fd) 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; @@ -429,6 +478,7 @@ int generic_establish_ppp (int fd) 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; @@ -517,7 +567,10 @@ void tty_disestablish_ppp(int tty_fd) * 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 */ @@ -537,6 +590,7 @@ void tty_disestablish_ppp(int tty_fd) warn("Couldn't restore device fd flags: %m"); } } +flushfailed: initfdflags = -1; generic_disestablish_ppp(tty_fd); @@ -556,10 +610,11 @@ void generic_disestablish_ppp(int dev_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) @@ -573,7 +628,19 @@ void generic_disestablish_ppp(int dev_fd) */ 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); @@ -640,17 +707,25 @@ void make_new_bundle(int mrru, int mtru, int rssn, int tssn) */ 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; @@ -990,6 +1065,8 @@ void wait_input(struct timeval *timo) */ 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; @@ -1112,7 +1189,7 @@ netif_get_mtu(int unit) * 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; @@ -1120,20 +1197,22 @@ void tty_send_config (int mtu,u_int32_t asyncmap,int pcomp,int accomp) * 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); } /******************************************************************** @@ -1160,31 +1239,42 @@ void tty_set_xaccm (ext_accm accm) * 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; } /******************************************************************** @@ -2778,3 +2868,51 @@ sys_check_options(void) } 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