📄 sys-linux.c
字号:
/* * sys-linux.c - System-dependent procedures for setting up * PPP interfaces on Linux systems * * Copyright (c) 1994-2004 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. 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. * * 3. 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>#include <sys/types.h>#include <sys/socket.h>#include <sys/time.h>#include <sys/errno.h>#include <sys/file.h>#include <sys/stat.h>#include <sys/utsname.h>#include <sys/sysmacros.h>#include <stdio.h>#include <stdlib.h>#include <syslog.h>#include <string.h>#include <time.h>#include <memory.h>#include <utmp.h>#include <mntent.h>#include <signal.h>#include <fcntl.h>#include <ctype.h>#include <termios.h>#include <unistd.h>/* This is in netdevice.h. However, this compile will fail miserably if you attempt to include netdevice.h because it has so many references to __memcpy functions which it should not attempt to do. So, since I really don't use it, but it must be defined, define it now. */#ifndef MAX_ADDR_LEN#define MAX_ADDR_LEN 7#endif#if __GLIBC__ >= 2#include <asm/types.h> /* glibc 2 conflicts with linux/types.h */#include <net/if.h>#include <net/if_arp.h>#include <net/route.h>#include <netinet/if_ether.h>#else#include <linux/types.h>#include <linux/if.h>#include <linux/if_arp.h>#include <linux/route.h>#include <linux/if_ether.h>#endif#include <netinet/in.h>#include <arpa/inet.h>#include <linux/ppp_defs.h>#include <linux/if_ppp.h>#include "pppd.h"#include "fsm.h"#include "ipcp.h"#ifdef IPX_CHANGE#include "ipxcp.h"#if __GLIBC__ >= 2 && \ !(defined(__powerpc__) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 0)#include <netipx/ipx.h>#else#include <linux/ipx.h>#endif#endif /* IPX_CHANGE */#ifdef PPP_FILTER#include <pcap-bpf.h>#include <linux/filter.h>#endif /* PPP_FILTER */#ifdef LOCKLIB#include <sys/locks.h>#endif#ifdef INET6#ifndef _LINUX_IN6_H/* * This is in linux/include/net/ipv6.h. */struct in6_ifreq { struct in6_addr ifr6_addr; __u32 ifr6_prefixlen; unsigned int ifr6_ifindex;};#endif#define IN6_LLADDR_FROM_EUI64(sin6, eui64) do { \ memset(&sin6.s6_addr, 0, sizeof(struct in6_addr)); \ sin6.s6_addr16[0] = htons(0xfe80); \ eui64_copy(eui64, sin6.s6_addr32[2]); \ } while (0)#endif /* INET6 *//* We can get an EIO error on an ioctl if the modem has hung up */#define ok_error(num) ((num)==EIO)static int tty_disc = N_TTY; /* The TTY discipline */static int ppp_disc = N_PPP; /* The PPP discpline */static int initfdflags = -1; /* Initial file descriptor flags for fd */static int ppp_fd = -1; /* fd which is set to PPP discipline */static int sock_fd = -1; /* socket for doing interface ioctls */static int slave_fd = -1; /* pty for old-style demand mode, slave */static int master_fd = -1; /* pty for old-style demand mode, master */#ifdef INET6static int sock6_fd = -1;#endif /* INET6 *//* * 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 */static int max_in_fd; /* highest fd set in in_fds */static int has_proxy_arp = 0;static int driver_version = 0;static int driver_modification = 0;static int driver_patch = 0;static int driver_is_old = 0;static int restore_term = 0; /* 1 => we've munged the terminal */static struct termios inittermios; /* Initial TTY termios */int new_style_driver = 0;static char loop_name[20];static unsigned char inbuf[512]; /* buffer for chars read from loopback */static int if_is_up; /* Interface has been marked up */static int have_default_route; /* Gateway for default route added */static u_int32_t proxy_arp_addr; /* Addr for proxy arp entry added */static char proxy_arp_dev[16]; /* Device for proxy arp entry */static u_int32_t our_old_addr; /* for detecting address changes */static int dynaddr_set; /* 1 if ip_dynaddr set */static int looped; /* 1 if using loop */static int link_mtu; /* mtu for the link (not bundle) */static struct utsname utsname; /* for the kernel version */static int kernel_version;#define KVERSION(j,n,p) ((j)*1000000 + (n)*1000 + (p))#define MAX_IFS 100#define FLAGS_GOOD (IFF_UP | IFF_BROADCAST)#define FLAGS_MASK (IFF_UP | IFF_BROADCAST | \ IFF_POINTOPOINT | IFF_LOOPBACK | IFF_NOARP)#define SIN_ADDR(x) (((struct sockaddr_in *) (&(x)))->sin_addr.s_addr)/* Prototypes for procedures local to this file. */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);static int open_route_table (void);static int read_route_table (struct rtentry *rt);static int defaultroute_exists (struct rtentry *rt);static int get_ether_addr (u_int32_t ipaddr, struct sockaddr *hwaddr, char *name, int namelen);static void decode_version (char *buf, int *version, int *mod, int *patch);static int set_kdebugflag(int level);static int ppp_registered(void);static int make_ppp_unit(void);extern u_char inpacket_buf[]; /* borrowed from main.c *//* * SET_SA_FAMILY - set the sa_family field of a struct sockaddr, * if it exists. */#define SET_SA_FAMILY(addr, family) \ memset ((char *) &(addr), '\0', sizeof(addr)); \ addr.sa_family = (family);/* * Determine if the PPP connection should still be present. */extern int hungup;/* new_fd is the fd of a tty */static void set_ppp_fd (int new_fd){ ppp_fd = new_fd; if (!new_style_driver) ppp_dev_fd = new_fd;}static int still_ppp(void){ if (new_style_driver) return !hungup && ppp_fd >= 0; if (!hungup || ppp_fd == slave_fd) return 1; if (slave_fd >= 0) { set_ppp_fd(slave_fd); return 1; } return 0;}/* * 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; if (ioctl(fd, PPPIOCGFLAGS, &flags) == -1) goto err; flags = (flags & ~clear_bits) | set_bits; if (ioctl(fd, PPPIOCSFLAGS, &flags) == -1) goto err; return 0; err: if (errno != EIO) error("Failed to set PPP kernel option flags: %m"); return -1;}/******************************************************************** * * sys_init - System-dependent initialization. */void sys_init(void){ /* Get an internet socket for doing socket ioctls. */ sock_fd = socket(AF_INET, SOCK_DGRAM, 0); if (sock_fd < 0) fatal("Couldn't create IP socket: %m(%d)", errno);#ifdef INET6 sock6_fd = socket(AF_INET6, SOCK_DGRAM, 0); if (sock6_fd < 0) sock6_fd = -errno; /* save errno for later */#endif 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 shouldn't call die() because it's called from die(). */void sys_cleanup(void){/* * Take down the device */ if (if_is_up) { if_is_up = 0; sifdown(0); }/* * Delete any routes through the device. */ if (have_default_route) cifdefaultroute(0, 0, 0); if (has_proxy_arp) cifproxyarp(0, proxy_arp_addr);}/******************************************************************** * * sys_close - Clean up in a child process before execing. */voidsys_close(void){ 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);}/******************************************************************** * * set_kdebugflag - Define the debugging level for the kernel */static int set_kdebugflag (int requested_level){ if (ppp_dev_fd < 0) return 1; if (ioctl(ppp_dev_fd, PPPIOCSDEBUG, &requested_level) < 0) { if ( ! ok_error (errno) ) error("ioctl(PPPIOCSDEBUG): %m (line %d)", __LINE__); return (0); } return (1);}/******************************************************************** * * tty_establish_ppp - Turn the serial port into a ppp interface. */int tty_establish_ppp (int tty_fd){ int ret_fd;/* * Ensure that the tty device is in exclusive mode. */ if (ioctl(tty_fd, TIOCEXCL, 0) < 0) { if ( ! ok_error ( errno )) warn("Couldn't make tty exclusive: %m"); }/* * Demand mode - prime the old ppp device to relinquish the unit. */ if (!new_style_driver && looped && ioctl(slave_fd, PPPIOCXFERUNIT, 0) < 0) { error("ioctl(transfer ppp unit): %m, line %d", __LINE__); return -1; }/* * Set the current tty to the PPP discpline */#ifndef N_SYNC_PPP#define N_SYNC_PPP 14#endif ppp_disc = (new_style_driver && sync_serial)? N_SYNC_PPP: N_PPP; if (ioctl(tty_fd, TIOCSETD, &ppp_disc) < 0) { if ( ! ok_error (errno) ) { error("Couldn't set tty to PPP discipline: %m"); return -1; } } ret_fd = generic_establish_ppp(tty_fd);#define SC_RCVB (SC_RCV_B7_0 | SC_RCV_B7_1 | SC_RCV_EVNP | SC_RCV_ODDP)#define SC_LOGB (SC_DEBUG | SC_LOG_INPKT | SC_LOG_OUTPKT | SC_LOG_RAWIN \ | SC_LOG_FLUSH) if (ret_fd >= 0) { 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"); } return ret_fd;}/******************************************************************** * * generic_establish_ppp - Turn the fd into a ppp interface. */int generic_establish_ppp (int fd){ int x; if (new_style_driver) { 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; } dbglog("using channel %d", chindex); fd = open("/dev/ppp", O_RDWR); if (fd < 0) { 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; } flags = fcntl(fd, F_GETFL); if (flags == -1 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) warn("Couldn't set /dev/ppp (channel) to nonblock: %m"); set_ppp_fd(fd); if (!looped) ifunit = -1; if (!looped && !multilink) { /* * Create a new PPP unit. */ if (make_ppp_unit() < 0) goto err_close; } if (looped) modify_flags(ppp_dev_fd, SC_LOOP_TRAFFIC, 0); if (!multilink) { add_fd(ppp_dev_fd); if (ioctl(fd, PPPIOCCONNECT, &ifunit) < 0) { error("Couldn't attach to PPP unit %d: %m", ifunit); goto err_close; } } } else { /* * Old-style driver: find out which interface we were given. */ set_ppp_fd (fd); if (ioctl(fd, PPPIOCGUNIT, &x) < 0) { if (ok_error (errno)) goto err; fatal("ioctl(PPPIOCGUNIT): %m (line %d)", __LINE__); } /* Check that we got the same unit again. */ if (looped && x != ifunit) fatal("transfer_ppp failed: wanted unit %d, got %d", ifunit, x); ifunit = x; /* * Fetch the initial file flags and reset blocking mode on the file. */ initfdflags = fcntl(fd, F_GETFL); if (initfdflags == -1 || fcntl(fd, F_SETFL, initfdflags | O_NONBLOCK) == -1) { if ( ! ok_error (errno)) warn("Couldn't set device to non-blocking mode: %m"); } } /* * Enable debug in the driver if requested. */ if (!looped)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -