From 5d86a7c3b271e42374e5d9817838d491b7ba6681 Mon Sep 17 00:00:00 2001 From: Guy Harris Date: Mon, 1 Jun 2009 13:04:55 -0700 Subject: Move some more stuff up before the first use. --- pcap-linux.c | 390 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 193 insertions(+), 197 deletions(-) (limited to 'pcap-linux.c') diff --git a/pcap-linux.c b/pcap-linux.c index 455077b..0e23fd0 100644 --- a/pcap-linux.c +++ b/pcap-linux.c @@ -469,203 +469,6 @@ get_mac80211_phydev(pcap_t *handle, const char *device, char *phydev_path, return 1; } -static int -enter_rfmon_mode_mac80211(pcap_t *handle, int sock_fd, const char *device) -{ - int ret; - char phydev_path[PATH_MAX+1]; - struct nl80211_state nlstate; - struct ifreq ifr; - u_int n; - - /* - * Is this a mac80211 device? - */ - ret = get_mac80211_phydev(handle, device, phydev_path, PATH_MAX); - if (ret < 0) - return ret; /* error */ - if (ret == 0) - return 0; /* no error, but not mac80211 device */ - - /* - * XXX - is this already a monN device? - * If so, we're done. - * Is that determined by old Wireless Extensions ioctls? - */ - - /* - * OK, it's apparently a mac80211 device. - * Try to find an unused monN device for it. - */ - ret = nl80211_init(handle, &nlstate, device); - if (ret != 0) - return ret; - for (n = 0; n < UINT_MAX; n++) { - /* - * Try mon{n}. - */ - char mondevice[3+10+1]; /* mon{UINT_MAX}\0 */ - - snprintf(mondevice, sizeof mondevice, "mon%u", n); - ret = add_mon_if(handle, sock_fd, &nlstate, device, mondevice); - if (ret == 1) { - handle->md.mondevice = strdup(mondevice); - goto added; - } - if (ret < 0) { - /* - * Hard failure. Just return ret; handle->errbuf - * has already been set. - */ - nl80211_cleanup(&nlstate); - return ret; - } - } - - snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, - "%s: No free monN interfaces", device); - nl80211_cleanup(&nlstate); - return PCAP_ERROR; - -added: - -#if 0 - /* - * Sleep for .1 seconds. - */ - delay.tv_sec = 0; - delay.tv_nsec = 500000000; - nanosleep(&delay, NULL); -#endif - - /* - * Now configure the monitor interface up. - */ - memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, handle->md.mondevice, sizeof(ifr.ifr_name)); - if (ioctl(sock_fd, SIOCGIFFLAGS, &ifr) == -1) { - snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, - "%s: Can't get flags for %s: %s", device, - handle->md.mondevice, strerror(errno)); - del_mon_if(handle, sock_fd, &nlstate, device, - handle->md.mondevice); - nl80211_cleanup(&nlstate); - return PCAP_ERROR; - } - ifr.ifr_flags |= IFF_UP|IFF_RUNNING; - if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr) == -1) { - snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, - "%s: Can't set flags for %s: %s", device, - handle->md.mondevice, strerror(errno)); - del_mon_if(handle, sock_fd, &nlstate, device, - handle->md.mondevice); - nl80211_cleanup(&nlstate); - return PCAP_ERROR; - } - - /* - * Success. Clean up the libnl state. - */ - nl80211_cleanup(&nlstate); - - /* - * Note that we have to delete the monitor device when we close - * the handle. - */ - handle->md.must_do_on_close |= MUST_DELETE_MONIF; - - /* - * Add this to the list of pcaps to close when we exit. - */ - pcap_add_to_pcaps_to_close(handle); - - return 1; -} -#endif /* HAVE_LIBNL */ - -static int -pcap_can_set_rfmon_linux(pcap_t *handle) -{ -#ifdef HAVE_LIBNL - char phydev_path[PATH_MAX+1]; - int ret; -#endif -#ifdef IW_MODE_MONITOR - int sock_fd; - struct iwreq ireq; -#endif - - if (strcmp(handle->opt.source, "any") == 0) { - /* - * Monitor mode makes no sense on the "any" device. - */ - return 0; - } - -#ifdef HAVE_LIBNL - /* - * Bleah. There doesn't seem to be a way to ask a mac80211 - * device, through libnl, whether it supports monitor mode; - * we'll just check whether the device appears to be a - * mac80211 device and, if so, assume the device supports - * monitor mode. - * - * wmaster devices don't appear to support the Wireless - * Extensions, but we can create a mon device for a - * wmaster device, so we don't bother checking whether - * a mac80211 device supports the Wireless Extensions. - */ - ret = get_mac80211_phydev(handle, handle->opt.source, phydev_path, - PATH_MAX); - if (ret < 0) - return ret; /* error */ - if (ret == 1) - return 1; /* mac80211 device */ -#endif - -#ifdef IW_MODE_MONITOR - /* - * Bleah. There doesn't appear to be an ioctl to use to ask - * whether a device supports monitor mode; we'll just do - * SIOCGIWMODE and, if it succeeds, assume the device supports - * monitor mode. - * - * Open a socket on which to attempt to get the mode. - * (We assume that if we have Wireless Extensions support - * we also have PF_PACKET support.) - */ - sock_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); - if (sock_fd == -1) { - (void)snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, - "socket: %s", pcap_strerror(errno)); - return PCAP_ERROR; - } - - /* - * Attempt to get the current mode. - */ - strncpy(ireq.ifr_ifrn.ifrn_name, handle->opt.source, - sizeof ireq.ifr_ifrn.ifrn_name); - ireq.ifr_ifrn.ifrn_name[sizeof ireq.ifr_ifrn.ifrn_name - 1] = 0; - if (ioctl(sock_fd, SIOCGIWMODE, &ireq) != -1) { - /* - * Well, we got the mode; assume we can set it. - */ - close(sock_fd); - return 1; - } - if (errno == ENODEV) { - /* The device doesn't even exist. */ - close(sock_fd); - return PCAP_ERROR_NO_SUCH_DEVICE; - } - close(sock_fd); -#endif - return 0; -} - -#ifdef HAVE_LIBNL - struct nl80211_state { struct nl_handle *nl_handle; struct nl_cache *nl_cache; @@ -881,8 +684,201 @@ nla_put_failure: return PCAP_ERROR; } +static int +enter_rfmon_mode_mac80211(pcap_t *handle, int sock_fd, const char *device) +{ + int ret; + char phydev_path[PATH_MAX+1]; + struct nl80211_state nlstate; + struct ifreq ifr; + u_int n; + + /* + * Is this a mac80211 device? + */ + ret = get_mac80211_phydev(handle, device, phydev_path, PATH_MAX); + if (ret < 0) + return ret; /* error */ + if (ret == 0) + return 0; /* no error, but not mac80211 device */ + + /* + * XXX - is this already a monN device? + * If so, we're done. + * Is that determined by old Wireless Extensions ioctls? + */ + + /* + * OK, it's apparently a mac80211 device. + * Try to find an unused monN device for it. + */ + ret = nl80211_init(handle, &nlstate, device); + if (ret != 0) + return ret; + for (n = 0; n < UINT_MAX; n++) { + /* + * Try mon{n}. + */ + char mondevice[3+10+1]; /* mon{UINT_MAX}\0 */ + + snprintf(mondevice, sizeof mondevice, "mon%u", n); + ret = add_mon_if(handle, sock_fd, &nlstate, device, mondevice); + if (ret == 1) { + handle->md.mondevice = strdup(mondevice); + goto added; + } + if (ret < 0) { + /* + * Hard failure. Just return ret; handle->errbuf + * has already been set. + */ + nl80211_cleanup(&nlstate); + return ret; + } + } + + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: No free monN interfaces", device); + nl80211_cleanup(&nlstate); + return PCAP_ERROR; + +added: + +#if 0 + /* + * Sleep for .1 seconds. + */ + delay.tv_sec = 0; + delay.tv_nsec = 500000000; + nanosleep(&delay, NULL); +#endif + + /* + * Now configure the monitor interface up. + */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, handle->md.mondevice, sizeof(ifr.ifr_name)); + if (ioctl(sock_fd, SIOCGIFFLAGS, &ifr) == -1) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: Can't get flags for %s: %s", device, + handle->md.mondevice, strerror(errno)); + del_mon_if(handle, sock_fd, &nlstate, device, + handle->md.mondevice); + nl80211_cleanup(&nlstate); + return PCAP_ERROR; + } + ifr.ifr_flags |= IFF_UP|IFF_RUNNING; + if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr) == -1) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: Can't set flags for %s: %s", device, + handle->md.mondevice, strerror(errno)); + del_mon_if(handle, sock_fd, &nlstate, device, + handle->md.mondevice); + nl80211_cleanup(&nlstate); + return PCAP_ERROR; + } + + /* + * Success. Clean up the libnl state. + */ + nl80211_cleanup(&nlstate); + + /* + * Note that we have to delete the monitor device when we close + * the handle. + */ + handle->md.must_do_on_close |= MUST_DELETE_MONIF; + + /* + * Add this to the list of pcaps to close when we exit. + */ + pcap_add_to_pcaps_to_close(handle); + + return 1; +} #endif /* HAVE_LIBNL */ +static int +pcap_can_set_rfmon_linux(pcap_t *handle) +{ +#ifdef HAVE_LIBNL + char phydev_path[PATH_MAX+1]; + int ret; +#endif +#ifdef IW_MODE_MONITOR + int sock_fd; + struct iwreq ireq; +#endif + + if (strcmp(handle->opt.source, "any") == 0) { + /* + * Monitor mode makes no sense on the "any" device. + */ + return 0; + } + +#ifdef HAVE_LIBNL + /* + * Bleah. There doesn't seem to be a way to ask a mac80211 + * device, through libnl, whether it supports monitor mode; + * we'll just check whether the device appears to be a + * mac80211 device and, if so, assume the device supports + * monitor mode. + * + * wmaster devices don't appear to support the Wireless + * Extensions, but we can create a mon device for a + * wmaster device, so we don't bother checking whether + * a mac80211 device supports the Wireless Extensions. + */ + ret = get_mac80211_phydev(handle, handle->opt.source, phydev_path, + PATH_MAX); + if (ret < 0) + return ret; /* error */ + if (ret == 1) + return 1; /* mac80211 device */ +#endif + +#ifdef IW_MODE_MONITOR + /* + * Bleah. There doesn't appear to be an ioctl to use to ask + * whether a device supports monitor mode; we'll just do + * SIOCGIWMODE and, if it succeeds, assume the device supports + * monitor mode. + * + * Open a socket on which to attempt to get the mode. + * (We assume that if we have Wireless Extensions support + * we also have PF_PACKET support.) + */ + sock_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + if (sock_fd == -1) { + (void)snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "socket: %s", pcap_strerror(errno)); + return PCAP_ERROR; + } + + /* + * Attempt to get the current mode. + */ + strncpy(ireq.ifr_ifrn.ifrn_name, handle->opt.source, + sizeof ireq.ifr_ifrn.ifrn_name); + ireq.ifr_ifrn.ifrn_name[sizeof ireq.ifr_ifrn.ifrn_name - 1] = 0; + if (ioctl(sock_fd, SIOCGIWMODE, &ireq) != -1) { + /* + * Well, we got the mode; assume we can set it. + */ + close(sock_fd); + return 1; + } + if (errno == ENODEV) { + /* The device doesn't even exist. */ + close(sock_fd); + return PCAP_ERROR_NO_SUCH_DEVICE; + } + close(sock_fd); +#endif + return 0; +} + /* * With older kernels promiscuous mode is kind of interesting because we * have to reset the interface before exiting. The problem can't really -- cgit v1.2.3