X-Git-Url: http://git.ozlabs.org/?a=blobdiff_plain;f=pppd%2Fsys-linux.c;h=448d426dfdf04249fa086dec1b6496702bb60dfe;hb=26703b215b0b68d7005e6b5e41d744101471a743;hp=1e52e3bddf8ab4bd53fb26855c42c0f3c8d20c62;hpb=2c872bc67b83b91ba6390f6e5e72be08e09811a1;p=ppp.git diff --git a/pppd/sys-linux.c b/pppd/sys-linux.c index 1e52e3b..448d426 100644 --- a/pppd/sys-linux.c +++ b/pppd/sys-linux.c @@ -85,6 +85,11 @@ #endif #endif /* IPX_CHANGE */ +#ifdef PPP_FILTER +#include +#include +#endif /* PPP_FILTER */ + #ifdef LOCKLIB #include #endif @@ -149,6 +154,7 @@ 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; @@ -176,6 +182,7 @@ static int get_ether_addr (u_int32_t ipaddr, struct sockaddr *hwaddr, 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 */ @@ -280,7 +287,7 @@ void sys_init(void) #ifdef INET6 sock6_fd = socket(AF_INET6, SOCK_DGRAM, 0); if (sock6_fd < 0) - fatal("Couldn't create IPv6 socket: %m(%d)", errno); + sock6_fd = -errno; /* save errno for later */ #endif FD_ZERO(&in_fds); @@ -413,22 +420,14 @@ int establish_ppp (int tty_fd) warn("Couldn't set /dev/ppp (channel) to nonblock: %m"); set_ppp_fd(fd); - ifunit = -1; + if (!looped) + ifunit = -1; if (!looped && !multilink) { /* * Create a new PPP unit. */ - 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"); - ifunit = -1; - x = ioctl(ppp_dev_fd, PPPIOCNEWUNIT, &ifunit); - } - if (x < 0) { - error("Couldn't create new ppp unit: %m"); + if (make_ppp_unit() < 0) goto err_close; - } } if (looped) @@ -448,8 +447,9 @@ int establish_ppp (int tty_fd) */ set_ppp_fd (tty_fd); if (ioctl(tty_fd, PPPIOCGUNIT, &x) < 0) { - if ( ! ok_error (errno)) - fatal("ioctl(PPPIOCGUNIT): %m(%d)", errno); + if (ok_error (errno)) + goto err; + fatal("ioctl(PPPIOCGUNIT): %m(%d)", errno); } /* Check that we got the same unit again. */ if (looped && x != ifunit) @@ -529,7 +529,7 @@ void disestablish_ppp(int tty_fd) if (new_style_driver) { close(ppp_fd); ppp_fd = -1; - if (!looped && ioctl(ppp_dev_fd, PPPIOCDETACH) < 0) + if (!looped && ifunit >= 0 && ioctl(ppp_dev_fd, PPPIOCDETACH) < 0) error("Couldn't release PPP unit: %m"); if (!multilink) remove_fd(ppp_dev_fd); @@ -537,30 +537,101 @@ void disestablish_ppp(int tty_fd) } /* - * bundle_attach - attach our link to a given PPP unit. + * make_ppp_unit - make a new ppp unit for ppp_dev_fd. + * Assumes new_style_driver. */ -int bundle_attach(int ifnum) +static int make_ppp_unit() { - int mrru = 1500; + int x; - if (!new_style_driver) - return -1; + 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"); + ifunit = -1; + x = ioctl(ppp_dev_fd, PPPIOCNEWUNIT, &ifunit); + } + if (x < 0) + error("Couldn't create new ppp unit: %m"); + return x; +} - if (ioctl(ppp_dev_fd, PPPIOCATTACH, &ifnum) < 0) { - error("Couldn't attach to interface unit %d: %m\n", ifnum); - return -1; - } - set_flags(ppp_dev_fd, get_flags(ppp_dev_fd) | SC_MULTILINK); - if (ioctl(ppp_dev_fd, PPPIOCSMRRU, &mrru) < 0) - error("Couldn't set interface MRRU: %m"); +/* + * cfg_bundle - configure the existing bundle. + * Used in demand mode. + */ +void cfg_bundle(int mrru, int mtru, int rssn, int tssn) +{ + int flags; + struct ifreq ifr; - if (ioctl(ppp_fd, PPPIOCCONNECT, &ifnum) < 0) { - error("Couldn't connect to interface unit %d: %m", ifnum); - return -1; - } + 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); + + if (mtru > 0 && mtru != link_mtu) { + memset(&ifr, 0, sizeof(ifr)); + slprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "ppp%d", ifunit); + ifr.ifr_mtu = mtru; + if (ioctl(sock_fd, SIOCSIFMTU, &ifr) < 0) + error("Couldn't set interface MTU: %m"); + flags |= SC_MULTILINK; + } - dbglog("bundle_attach succeeded"); - return 0; + set_flags(ppp_dev_fd, flags); + + /* connect up the channel */ + if (ioctl(ppp_fd, PPPIOCCONNECT, &ifunit) < 0) + fatal("Couldn't attach to PPP unit %d: %m", ifunit); + add_fd(ppp_dev_fd); +} + +/* + * make_new_bundle - create a new PPP unit (i.e. a bundle) + * and connect our channel to it. This should only get called + * if `multilink' was set at the time establish_ppp was called. + * In demand mode this uses our existing bundle instead of making + * a new one. + */ +void make_new_bundle(int mrru, int mtru, int rssn, int tssn) +{ + if (!new_style_driver) + return; + + /* make us a ppp unit */ + if (make_ppp_unit() < 0) + die(1); + + /* set the mrru, mtu and flags */ + cfg_bundle(mrru, mtru, rssn, tssn); +} + +/* + * bundle_attach - attach our link to a given PPP unit. + * We assume the unit is controlled by another pppd. + */ +int bundle_attach(int ifnum) +{ + if (!new_style_driver) + return -1; + + if (ioctl(ppp_dev_fd, PPPIOCATTACH, &ifnum) < 0) { + if (errno == ENXIO) + 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); + + ifunit = ifnum; + return 1; } /******************************************************************** @@ -855,7 +926,7 @@ void output (int unit, unsigned char *p, int len) p += 2; len -= 2; proto = (p[0] << 8) + p[1]; - if (!multilink && proto != PPP_LCP) + if (ifunit >= 0 && !(proto >= 0xc000 || proto == PPP_CCPFRAG)) fd = ppp_dev_fd; } if (write(fd, p, len) < 0) { @@ -923,13 +994,13 @@ int read_packet (unsigned char *buf) nr = -1; if (ppp_fd >= 0) { nr = read(ppp_fd, buf, len); - if (nr < 0 && errno != EWOULDBLOCK && errno != EIO) + if (nr < 0 && errno != EWOULDBLOCK && errno != EIO && errno != EINTR) error("read: %m"); } - if (nr < 0 && new_style_driver && !multilink) { + if (nr < 0 && new_style_driver && ifunit >= 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) + if (nr < 0 && errno != EWOULDBLOCK && errno != EIO && errno != EINTR) error("read /dev/ppp: %m"); } return (new_style_driver && nr > 0)? nr+2: nr; @@ -988,7 +1059,8 @@ void ppp_send_config (int unit,int mtu,u_int32_t asyncmap,int pcomp,int accomp) if (ifunit >= 0 && ioctl(sock_fd, SIOCSIFMTU, (caddr_t) &ifr) < 0) fatal("ioctl(SIOCSIFMTU): %m(%d)", errno); - + link_mtu = mtu; + if (!still_ppp()) return; SYSDEBUG ((LOG_DEBUG, "send_config: asyncmap = %lx\n", asyncmap)); @@ -1092,6 +1164,33 @@ void ccp_flags_set (int unit, int isopen, int isup) } } +#ifdef PPP_FILTER +/* + * set_filters - set the active and pass filters in the kernel driver. + */ +int set_filters(struct bpf_program *pass, struct bpf_program *active) +{ + struct sock_fprog fp; + + fp.len = pass->bf_len; + fp.filter = (struct sock_filter *) pass->bf_insns; + if (ioctl(ppp_dev_fd, PPPIOCSPASS, &fp) < 0) { + if (errno == ENOTTY) + warn("kernel does not support PPP filtering"); + else + error("Couldn't set pass-filter in kernel: %m"); + return 0; + } + fp.len = active->bf_len; + fp.filter = (struct sock_filter *) active->bf_insns; + if (ioctl(ppp_dev_fd, PPPIOCSACTIVE, &fp) < 0) { + error("Couldn't set active-filter in kernel: %m"); + return 0; + } + return 1; +} +#endif /* PPP_FILTER */ + /******************************************************************** * * get_idle_time - return how long the link has been idle. @@ -1600,6 +1699,38 @@ static int get_ether_addr (u_int32_t ipaddr, return 1; } +/* + * get_if_hwaddr - get the hardware address for the specified + * network interface device. + */ +int +get_if_hwaddr(u_char *addr, char *name) +{ + struct ifreq ifreq; + int ret, sock_fd; + + sock_fd = socket(AF_INET, SOCK_DGRAM, 0); + if (sock_fd < 0) + return 0; + memset(&ifreq.ifr_hwaddr, 0, sizeof(struct sockaddr)); + strlcpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name)); + ret = ioctl(sock_fd, SIOCGIFHWADDR, &ifreq); + close(sock_fd); + if (ret >= 0) + memcpy(addr, ifreq.ifr_hwaddr.sa_data, 6); + return ret; +} + +/* + * get_first_ethernet - return the name of the first ethernet-style + * interface on this system. + */ +char * +get_first_ethernet() +{ + return "eth0"; +} + /******************************************************************** * * Return user specified netmask, modified by any mask we might determine @@ -1763,35 +1894,34 @@ int ppp_available(void) sscanf(utsname.release, "%d.%d.%d", &osmaj, &osmin, &ospatch); kernel_version = KVERSION(osmaj, osmin, ospatch); - if (kernel_version >= KVERSION(2,3,13)) { - fd = open("/dev/ppp", O_RDWR); + fd = open("/dev/ppp", O_RDWR); #if 0 - if (fd < 0 && errno == ENOENT) { - /* try making it and see if that helps. */ - if (mknod("/dev/ppp", S_IFCHR | S_IRUSR | S_IWUSR, - makedev(108, 0)) >= 0) { - fd = open("/dev/ppp", O_RDWR); - if (fd >= 0) - info("Created /dev/ppp device node"); - else - unlink("/dev/ppp"); /* didn't work, undo the mknod */ - } else if (errno == EEXIST) { - fd = open("/dev/ppp", O_RDWR); - } + if (fd < 0 && errno == ENOENT) { + /* try making it and see if that helps. */ + if (mknod("/dev/ppp", S_IFCHR | S_IRUSR | S_IWUSR, + makedev(108, 0)) >= 0) { + fd = open("/dev/ppp", O_RDWR); + if (fd >= 0) + info("Created /dev/ppp device node"); + else + unlink("/dev/ppp"); /* didn't work, undo the mknod */ + } else if (errno == EEXIST) { + fd = open("/dev/ppp", O_RDWR); } + } #endif /* 0 */ - if (fd >= 0) { - new_style_driver = 1; - - /* XXX should get from driver */ - driver_version = 2; - driver_modification = 4; - driver_patch = 0; - close(fd); - return 1; - } - return 0; + if (fd >= 0) { + new_style_driver = 1; + + /* XXX should get from driver */ + driver_version = 2; + driver_modification = 4; + driver_patch = 0; + close(fd); + return 1; } + if (kernel_version >= KVERSION(2,3,13)) + return 0; /* * Open a socket for doing the ioctl operations. @@ -2202,6 +2332,11 @@ int sif6addr (int unit, eui64_t our_eui64, eui64_t his_eui64) struct ifreq ifr; struct in6_rtmsg rt6; + if (sock6_fd < 0) { + errno = -sock6_fd; + error("IPv6 socket creation failed: %m"); + return 0; + } memset(&ifr, 0, sizeof (ifr)); strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if (ioctl(sock6_fd, SIOCGIFINDEX, (caddr_t) &ifr) < 0) { @@ -2246,6 +2381,11 @@ int cif6addr (int unit, eui64_t our_eui64, eui64_t his_eui64) struct ifreq ifr; struct in6_ifreq ifr6; + if (sock6_fd < 0) { + errno = -sock6_fd; + error("IPv6 socket creation failed: %m"); + return 0; + } memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if (ioctl(sock6_fd, SIOCGIFINDEX, (caddr_t) &ifr) < 0) { @@ -2355,20 +2495,13 @@ get_pty(master_fdp, slave_fdp, slave_name, uid) int open_ppp_loopback(void) { - int flags, x; + int flags; looped = 1; if (new_style_driver) { /* allocate ourselves a ppp unit */ - 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"); - ifunit = -1; - x = ioctl(ppp_dev_fd, PPPIOCNEWUNIT, &ifunit); - } - if (x < 0) - fatal("Couldn't create PPP unit: %m"); + if (make_ppp_unit() < 0) + die(1); set_flags(ppp_dev_fd, SC_LOOP_TRAFFIC); set_kdebugflag(kdebugflag); ppp_fd = -1; @@ -2595,8 +2728,8 @@ sys_check_options(void) return 0; } if (multilink && !new_style_driver) { - option_error("multilink is not supported by the kernel driver"); - return 0; + warn("Warning: multilink is not supported by the kernel driver"); + multilink = 0; } return 1; }