/********************************************************************** *%FUNCTION: openInterface *%ARGUMENTS: * ifname -- name of interface * type -- Ethernet frame type (0 for any frame type) * hwaddr -- if non-NULL, set to the hardware address *%RETURNS: * A file descriptor for talking with the Ethernet card. Exits on error. * Note that the Linux version of this routine returns a socket instead. *%DESCRIPTION: * Opens a BPF on an interface for all PPPoE traffic (discovery and * session). If 'type' is 0, uses promiscuous mode to watch any PPPoE * traffic on this network. ***********************************************************************/ int openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr) { static int fd = -1; char bpfName[32]; u_int optval; struct bpf_version bpf_ver; struct ifreq ifr; int sock; int i; /* BSD only opens one socket for both Discovery and Session packets */ if (fd >= 0) { return fd; } /* Find a free BPF device */ for (i = 0; i < 256; i++) { sprintf(bpfName, "/dev/bpf%d", i); if (((fd = open(bpfName, O_RDWR, 0)) >= 0) || (errno != EBUSY)) { break; } } if (fd < 0) { switch (errno) { case EACCES: /* permission denied */ { char buffer[256]; sprintf(buffer, "Cannot open %.32s -- pppoe must be run as root.", bpfName); rp_fatal(buffer); } break; case EBUSY: case ENOENT: /* no such file */ if (i == 0) { rp_fatal("No /dev/bpf* devices (check your kernel configuration for BPF support)"); } else { rp_fatal("All /dev/bpf* devices are in use"); } break; } fatalSys(bpfName); } if ((sock = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0) { fatalSys("socket"); } /* Check that the interface is up */ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) { fatalSys("ioctl(SIOCGIFFLAGS)"); } if ((ifr.ifr_flags & IFF_UP) == 0) { char buffer[256]; sprintf(buffer, "Interface %.16s is not up\n", ifname); rp_fatal(buffer); } /* Fill in hardware address and initialize the packet filter rules */ if (hwaddr == NULL) { rp_fatal("openInterface: no hwaddr arg."); } getHWaddr(sock, ifname, hwaddr); initFilter(fd, type, hwaddr); /* Sanity check on MTU -- apparently does not work on OpenBSD */ #if !defined(__OpenBSD__) strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if (ioctl(sock, SIOCGIFMTU, &ifr) < 0) { fatalSys("ioctl(SIOCGIFMTU)"); } if (ifr.ifr_mtu < ETH_DATA_LEN) { char buffer[256]; sprintf(buffer, "Interface %.16s has MTU of %d -- should be %d. You may have serious connection problems.", ifname, ifr.ifr_mtu, ETH_DATA_LEN); printErr(buffer); } #endif /* done with the socket */ if (close(sock) < 0) { fatalSys("close"); } /* Check the BPF version number */ if (ioctl(fd, BIOCVERSION, &bpf_ver) < 0) { fatalSys("ioctl(BIOCVERSION)"); } if ((bpf_ver.bv_major != BPF_MAJOR_VERSION) || (bpf_ver.bv_minor < BPF_MINOR_VERSION)) { char buffer[256]; sprintf(buffer, "Unsupported BPF version: %d.%d (kernel: %d.%d)", BPF_MAJOR_VERSION, BPF_MINOR_VERSION, bpf_ver.bv_major, bpf_ver.bv_minor); rp_fatal(buffer); } /* allocate a receive packet buffer */ if (ioctl(fd, BIOCGBLEN, &bpfLength) < 0) { fatalSys("ioctl(BIOCGBLEN)"); } if (!(bpfBuffer = (unsigned char *) malloc(bpfLength))) { rp_fatal("malloc"); } /* reads should return as soon as there is a packet available */ optval = 1; if (ioctl(fd, BIOCIMMEDIATE, &optval) < 0) { fatalSys("ioctl(BIOCIMMEDIATE)"); } /* Bind the interface to the filter */ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if (ioctl(fd, BIOCSETIF, &ifr) < 0) { char buffer[256]; sprintf(buffer, "ioctl(BIOCSETIF) can't select interface %.16s", ifname); rp_fatal(buffer); } syslog(LOG_INFO, "Interface=%.16s HWaddr=%02X:%02X:%02X:%02X:%02X:%02X Device=%.32s Buffer size=%d", ifname, hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5], bpfName, bpfLength); return fd; }
int openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr) { static int fd = -1; char bpfName[32]; u_int optval; struct bpf_version bpf_ver; struct ifreq ifr; int sock; int i; if (fd >= 0) { return fd; } for (i = 0; i < 256; i++) { sprintf(bpfName, "/dev/bpf%d", i); if (((fd = open(bpfName, O_RDWR, 0)) >= 0) || (errno != EBUSY)) { break; } } if (fd < 0) { switch (errno) { case EACCES: { char buffer[256]; sprintf(buffer, "Cannot open %.32s -- pppoe must be run as root.", bpfName); rp_fatal(buffer); } break; case EBUSY: case ENOENT: if (i == 0) { rp_fatal("No /dev/bpf* devices (check your kernel configuration for BPF support)"); } else { rp_fatal("All /dev/bpf* devices are in use"); } break; } fatalSys(bpfName); } if ((sock = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0) { fatalSys("socket"); } strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) { fatalSys("ioctl(SIOCGIFFLAGS)"); } if ((ifr.ifr_flags & IFF_UP) == 0) { char buffer[256]; sprintf(buffer, "Interface %.16s is not up", ifname); rp_fatal(buffer); } if (hwaddr == NULL) { rp_fatal("openInterface: no hwaddr arg."); } getHWaddr(sock, ifname, hwaddr); initFilter(fd, type, hwaddr); #if !defined(__OpenBSD__) strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if (ioctl(sock, SIOCGIFMTU, &ifr) < 0) { fatalSys("ioctl(SIOCGIFMTU)"); } if (ifr.ifr_mtu < ETH_DATA_LEN) { char buffer[256]; sprintf(buffer, "Interface %.16s has MTU of %d -- should be %d. You may have serious connection problems.", ifname, ifr.ifr_mtu, ETH_DATA_LEN); printErr(buffer); } #endif if (close(sock) < 0) { fatalSys("close"); } if (ioctl(fd, BIOCVERSION, &bpf_ver) < 0) { fatalSys("ioctl(BIOCVERSION)"); } if ((bpf_ver.bv_major != BPF_MAJOR_VERSION) || (bpf_ver.bv_minor < BPF_MINOR_VERSION)) { char buffer[256]; sprintf(buffer, "Unsupported BPF version: %d.%d (kernel: %d.%d)", BPF_MAJOR_VERSION, BPF_MINOR_VERSION, bpf_ver.bv_major, bpf_ver.bv_minor); rp_fatal(buffer); } if (ioctl(fd, BIOCGBLEN, &bpfLength) < 0) { fatalSys("ioctl(BIOCGBLEN)"); } if (!(bpfBuffer = (unsigned char *) malloc(bpfLength))) { rp_fatal("malloc"); } optval = 1; if (ioctl(fd, BIOCIMMEDIATE, &optval) < 0) { fatalSys("ioctl(BIOCIMMEDIATE)"); } strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if (ioctl(fd, BIOCSETIF, &ifr) < 0) { char buffer[256]; sprintf(buffer, "ioctl(BIOCSETIF) can't select interface %.16s", ifname); rp_fatal(buffer); } syslog(LOG_INFO, "Interface=%.16s HWaddr=%02X:%02X:%02X:%02X:%02X:%02X Device=%.32s Buffer size=%d", ifname, hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5], bpfName, bpfLength); return fd; }