]> The Tcpdump Group git mirrors - libpcap/commitdiff
Merge pull request #906 from Oppen/issue_898
authorMichael Richardson <[email protected]>
Fri, 28 Aug 2020 21:19:10 +0000 (17:19 -0400)
committerGitHub <[email protected]>
Fri, 28 Aug 2020 21:19:10 +0000 (17:19 -0400)
Linux: proper memory sync for PACKET_MMAP.

1  2 
pcap-linux.c

diff --combined pcap-linux.c
index 5cfa5de55edc8c886485ffa86d14c95a25e69662,3ba8f71026212470d09108850f17c80b29e75c86..9b126a3a68ce30b639ba3902c948ce6133412a0f
  # define HAVE_TPACKET3
  #endif /* TPACKET3_HDRLEN */
  
+ #define packet_mmap_acquire(pkt) \
+       (__atomic_load_n(&pkt->tp_status, __ATOMIC_ACQUIRE) != TP_STATUS_KERNEL)
+ #define packet_mmap_release(pkt) \
+       (__atomic_store_n(&pkt->tp_status, TP_STATUS_KERNEL, __ATOMIC_RELEASE))
+ #define packet_mmap_v3_acquire(pkt) \
+       (__atomic_load_n(&pkt->hdr.bh1.block_status, __ATOMIC_ACQUIRE) != TP_STATUS_KERNEL)
+ #define packet_mmap_v3_release(pkt) \
+       (__atomic_store_n(&pkt->hdr.bh1.block_status, TP_STATUS_KERNEL, __ATOMIC_RELEASE))
  #include <linux/types.h>
  #include <linux/filter.h>
  
   */
  #include <linux/if_bonding.h>
  
 -/*
 - * Got Wireless Extensions?
 - */
 -#ifdef HAVE_LINUX_WIRELESS_H
 -#include <linux/wireless.h>
 -#endif /* HAVE_LINUX_WIRELESS_H */
 -
  /*
   * Got libnl?
   */
@@@ -197,8 -213,8 +206,8 @@@ struct pcap_linux 
   * Prototypes for internal functions and methods.
   */
  static int get_if_flags(const char *, bpf_u_int32 *, char *);
 -static int is_wifi(int, const char *);
 -static void map_arphrd_to_dlt(pcap_t *, int, int, const char *, int);
 +static int is_wifi(const char *);
 +static void map_arphrd_to_dlt(pcap_t *, int, const char *, int);
  static int pcap_activate_linux(pcap_t *);
  static int activate_pf_packet(pcap_t *, int);
  static int setup_mmapped(pcap_t *, int *);
@@@ -294,6 -310,9 +303,6 @@@ static int iface_get_id(int fd, const c
  static int    iface_get_mtu(int fd, const char *device, char *ebuf);
  static int    iface_get_arptype(int fd, const char *device, char *ebuf);
  static int    iface_bind(int fd, int ifindex, char *ebuf, int protocol);
 -#ifdef IW_MODE_MONITOR
 -static int    has_wext(int sock_fd, const char *device, char *ebuf);
 -#endif /* IW_MODE_MONITOR */
  static int    enter_rfmon_mode(pcap_t *handle, int sock_fd,
      const char *device);
  #if defined(HAVE_LINUX_NET_TSTAMP_H) && defined(PACKET_TIMESTAMP)
@@@ -319,7 -338,7 +328,7 @@@ pcap_create_interface(const char *devic
  {
        pcap_t *handle;
  
 -      handle = pcap_create_common(ebuf, sizeof (struct pcap_linux));
 +      handle = PCAP_CREATE_COMMON(ebuf, struct pcap_linux);
        if (handle == NULL)
                return NULL;
  
@@@ -670,8 -689,169 +679,8 @@@ nla_put_failure
        nlmsg_free(msg);
        return PCAP_ERROR;
  }
 -
 -static int
 -enter_rfmon_mode_mac80211(pcap_t *handle, int sock_fd, const char *device)
 -{
 -      struct pcap_linux *handlep = handle->priv;
 -      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) {
 -                      /*
 -                       * Success.  We don't clean up the libnl state
 -                       * yet, as we'll be using it later.
 -                       */
 -                      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
 -
 -      /*
 -       * If we haven't already done so, arrange to have
 -       * "pcap_close_all()" called when we exit.
 -       */
 -      if (!pcap_do_addexit(handle)) {
 -              /*
 -               * "atexit()" failed; don't put the interface
 -               * in rfmon mode, just give up.
 -               */
 -              del_mon_if(handle, sock_fd, &nlstate, device,
 -                  handlep->mondevice);
 -              nl80211_cleanup(&nlstate);
 -              return PCAP_ERROR;
 -      }
 -
 -      /*
 -       * Now configure the monitor interface up.
 -       */
 -      memset(&ifr, 0, sizeof(ifr));
 -      pcap_strlcpy(ifr.ifr_name, handlep->mondevice, sizeof(ifr.ifr_name));
 -      if (ioctl(sock_fd, SIOCGIFFLAGS, &ifr) == -1) {
 -              pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
 -                  errno, "%s: Can't get flags for %s", device,
 -                  handlep->mondevice);
 -              del_mon_if(handle, sock_fd, &nlstate, device,
 -                  handlep->mondevice);
 -              nl80211_cleanup(&nlstate);
 -              return PCAP_ERROR;
 -      }
 -      ifr.ifr_flags |= IFF_UP|IFF_RUNNING;
 -      if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr) == -1) {
 -              pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
 -                  errno, "%s: Can't set flags for %s", device,
 -                  handlep->mondevice);
 -              del_mon_if(handle, sock_fd, &nlstate, device,
 -                  handlep->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.
 -       */
 -      handlep->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 */
  
 -#ifdef IW_MODE_MONITOR
 -/*
 - * Bonding devices mishandle unknown ioctls; they fail with ENODEV
 - * rather than ENOTSUP, EOPNOTSUPP, or ENOTTY, so Wireless Extensions
 - * will fail with ENODEV if we try to do them on a bonding device,
 - * making us return a "no such device" indication rather than just
 - * saying "no Wireless Extensions".
 - *
 - * So we check for bonding devices, if we can, before trying those
 - * ioctls, by trying a bonding device information query ioctl to see
 - * whether it succeeds.
 - */
 -static int
 -is_bonding_device(int fd, const char *device)
 -{
 -      struct ifreq ifr;
 -      ifbond ifb;
 -
 -      memset(&ifr, 0, sizeof ifr);
 -      pcap_strlcpy(ifr.ifr_name, device, sizeof ifr.ifr_name);
 -      memset(&ifb, 0, sizeof ifb);
 -      ifr.ifr_data = (caddr_t)&ifb;
 -      if (ioctl(fd, SIOCBONDINFOQUERY, &ifr) == 0)
 -              return 1;       /* success, so it's a bonding device */
 -
 -      return 0;       /* no, it's not a bonding device */
 -}
 -#endif /* IW_MODE_MONITOR */
 -
  static int pcap_protocol(pcap_t *handle)
  {
        int protocol;
@@@ -690,6 -870,10 +699,6 @@@ pcap_can_set_rfmon_linux(pcap_t *handle
        char phydev_path[PATH_MAX+1];
        int ret;
  #endif
 -#ifdef IW_MODE_MONITOR
 -      int sock_fd;
 -      struct iwreq ireq;
 -#endif
  
        if (strcmp(handle->opt.device, "any") == 0) {
                /*
         * 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.device, phydev_path,
            PATH_MAX);
                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, pcap_protocol(handle));
 -      if (sock_fd == -1) {
 -              pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
 -                  errno, "socket");
 -              return PCAP_ERROR;
 -      }
 -
 -      if (is_bonding_device(sock_fd, handle->opt.device)) {
 -              /* It's a bonding device, so don't even try. */
 -              close(sock_fd);
 -              return 0;
 -      }
 -
 -      /*
 -       * Attempt to get the current mode.
 -       */
 -      pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, handle->opt.device,
 -          sizeof ireq.ifr_ifrn.ifrn_name);
 -      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. */
 -              pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
 -                  errno, "SIOCGIWMODE failed");
 -              close(sock_fd);
 -              return PCAP_ERROR_NO_SUCH_DEVICE;
 -      }
 -      close(sock_fd);
 -#endif
        return 0;
  }
  
@@@ -767,10 -1001,15 +776,10 @@@ linux_if_drops(const char * if_name
  static void   pcap_cleanup_linux( pcap_t *handle )
  {
        struct pcap_linux *handlep = handle->priv;
 -      struct ifreq    ifr;
  #ifdef HAVE_LIBNL
        struct nl80211_state nlstate;
        int ret;
  #endif /* HAVE_LIBNL */
 -#ifdef IW_MODE_MONITOR
 -      int oldflags;
 -      struct iwreq ireq;
 -#endif /* IW_MODE_MONITOR */
  
        if (handlep->must_do_on_close != 0) {
                /*
                }
  #endif /* HAVE_LIBNL */
  
 -#ifdef IW_MODE_MONITOR
 -              if (handlep->must_do_on_close & MUST_CLEAR_RFMON) {
 -                      /*
 -                       * We put the interface into rfmon mode;
 -                       * take it out of rfmon mode.
 -                       *
 -                       * XXX - if somebody else wants it in rfmon
 -                       * mode, this code cannot know that, so it'll take
 -                       * it out of rfmon mode.
 -                       */
 -
 -                      /*
 -                       * First, take the interface down if it's up;
 -                       * otherwise, we might get EBUSY.
 -                       * If we get errors, just drive on and print
 -                       * a warning if we can't restore the mode.
 -                       */
 -                      oldflags = 0;
 -                      memset(&ifr, 0, sizeof(ifr));
 -                      pcap_strlcpy(ifr.ifr_name, handlep->device,
 -                          sizeof(ifr.ifr_name));
 -                      if (ioctl(handle->fd, SIOCGIFFLAGS, &ifr) != -1) {
 -                              if (ifr.ifr_flags & IFF_UP) {
 -                                      oldflags = ifr.ifr_flags;
 -                                      ifr.ifr_flags &= ~IFF_UP;
 -                                      if (ioctl(handle->fd, SIOCSIFFLAGS, &ifr) == -1)
 -                                              oldflags = 0;   /* didn't set, don't restore */
 -                              }
 -                      }
 -
 -                      /*
 -                       * Now restore the mode.
 -                       */
 -                      pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, handlep->device,
 -                          sizeof ireq.ifr_ifrn.ifrn_name);
 -                      ireq.u.mode = handlep->oldmode;
 -                      if (ioctl(handle->fd, SIOCSIWMODE, &ireq) == -1) {
 -                              /*
 -                               * Scientist, you've failed.
 -                               */
 -                              fprintf(stderr,
 -                                  "Can't restore interface %s wireless mode (SIOCSIWMODE failed: %s).\n"
 -                                  "Please adjust manually.\n",
 -                                  handlep->device, strerror(errno));
 -                      }
 -
 -                      /*
 -                       * Now bring the interface back up if we brought
 -                       * it down.
 -                       */
 -                      if (oldflags != 0) {
 -                              ifr.ifr_flags = oldflags;
 -                              if (ioctl(handle->fd, SIOCSIFFLAGS, &ifr) == -1) {
 -                                      fprintf(stderr,
 -                                          "Can't bring interface %s back up (SIOCSIFFLAGS failed: %s).\n"
 -                                          "Please adjust manually.\n",
 -                                          handlep->device, strerror(errno));
 -                              }
 -                      }
 -              }
 -#endif /* IW_MODE_MONITOR */
 -
                /*
                 * Take this pcap out of the list of pcaps for which we
                 * have to take the interface out of some mode.
@@@ -1516,7 -1817,7 +1525,7 @@@ get_if_flags(const char *name, bpf_u_in
         * OK, what type of network is this?
         * In particular, is it wired or wireless?
         */
 -      if (is_wifi(sock, name)) {
 +      if (is_wifi(name)) {
                /*
                 * Wi-Fi, hence wireless.
                 */
@@@ -1703,10 -2004,17 +1712,10 @@@ pcap_setdirection_linux(pcap_t *handle
  }
  
  static int
 -is_wifi(int sock_fd
 -#ifndef IW_MODE_MONITOR
 -_U_
 -#endif
 -, const char *device)
 +is_wifi(const char *device)
  {
        char *pathstr;
        struct stat statb;
 -#ifdef IW_MODE_MONITOR
 -      char errbuf[PCAP_ERRBUF_SIZE];
 -#endif
  
        /*
         * See if there's a sysfs wireless directory for it.
        }
        free(pathstr);
  
 -#ifdef IW_MODE_MONITOR
 -      /*
 -       * OK, maybe it's not wireless, or maybe this kernel doesn't
 -       * support sysfs.  Try the wireless extensions.
 -       */
 -      if (has_wext(sock_fd, device, errbuf) == 1) {
 -              /*
 -               * It supports the wireless extensions, so it's a Wi-Fi
 -               * device.
 -               */
 -              return 1;
 -      }
 -#endif
        return 0;
  }
  
   *
   *  Sets the link type to -1 if unable to map the type.
   */
 -static void map_arphrd_to_dlt(pcap_t *handle, int sock_fd, int arptype,
 +static void map_arphrd_to_dlt(pcap_t *handle, int arptype,
                              const char *device, int cooked_ok)
  {
        static const char cdma_rmnet[] = "cdma_rmnet";
                 * is_wifi() to check for 802.11 devices; are there any
                 * others?
                 */
 -              if (!is_wifi(sock_fd, device)) {
 +              if (!is_wifi(device)) {
                        int ret;
  
                        /*
@@@ -2355,7 -2676,7 +2364,7 @@@ activate_pf_packet(pcap_t *handle, int 
                        close(sock_fd);
                        return arptype;
                }
 -              map_arphrd_to_dlt(handle, sock_fd, arptype, device, 1);
 +              map_arphrd_to_dlt(handle, arptype, device, 1);
                if (handle->linktype == -1 ||
                    handle->linktype == DLT_LINUX_SLL ||
                    handle->linktype == DLT_LINUX_IRDA ||
@@@ -3368,11 -3689,11 +3377,11 @@@ pcap_get_ring_frame_status(pcap_t *hand
        h.raw = RING_GET_FRAME_AT(handle, offset);
        switch (handlep->tp_version) {
        case TPACKET_V2:
-               return (h.h2->tp_status);
+               return __atomic_load_n(&h.h2->tp_status, __ATOMIC_ACQUIRE);
                break;
  #ifdef HAVE_TPACKET3
        case TPACKET_V3:
-               return (h.h3->hdr.bh1.block_status);
+               return __atomic_load_n(&h.h3->hdr.bh1.block_status, __ATOMIC_ACQUIRE);
                break;
  #endif
        }
@@@ -3931,13 -4252,6 +3940,13 @@@ static int pcap_handle_packet_mmap
         *
         * Trim the snapshot length to be no longer than the
         * specified snapshot length.
 +       *
 +       * XXX - an alternative is to put a filter, consisting
 +       * of a "ret <snaplen>" instruction, on the socket
 +       * in the activate routine, so that the truncation is
 +       * done in the kernel even if nobody specified a filter;
 +       * that means that less buffer space is consumed in
 +       * the memory-mapped buffer.
         */
        if (pcaphdr.caplen > (bpf_u_int32)handle->snapshot)
                pcaphdr.caplen = handle->snapshot;
@@@ -3959,7 -4273,7 +3968,7 @@@ pcap_read_linux_mmap_v2(pcap_t *handle
  
        /* wait for frames availability.*/
        h.raw = RING_GET_CURRENT_FRAME(handle);
-       if (h.h2->tp_status == TP_STATUS_KERNEL) {
+       if (!packet_mmap_acquire(h.h2)) {
                /*
                 * The current frame is owned by the kernel; wait for
                 * a frame to be handed to us.
                 * it's still owned by the kernel.
                 */
                h.raw = RING_GET_CURRENT_FRAME(handle);
-               if (h.h2->tp_status == TP_STATUS_KERNEL)
+               if (!packet_mmap_acquire(h.h2))
                        break;
  
                ret = pcap_handle_packet_mmap(
                 * after having been filtered by the kernel, count
                 * the one we've just processed.
                 */
-               h.h2->tp_status = TP_STATUS_KERNEL;
+               packet_mmap_release(h.h2);
                if (handlep->blocks_to_filter_in_userland > 0) {
                        handlep->blocks_to_filter_in_userland--;
                        if (handlep->blocks_to_filter_in_userland == 0) {
@@@ -4045,7 -4359,7 +4054,7 @@@ again
        if (handlep->current_packet == NULL) {
                /* wait for frames availability.*/
                h.raw = RING_GET_CURRENT_FRAME(handle);
-               if (h.h3->hdr.bh1.block_status == TP_STATUS_KERNEL) {
+               if (!packet_mmap_v3_acquire(h.h3)) {
                        /*
                         * The current frame is owned by the kernel; wait
                         * for a frame to be handed to us.
                }
        }
        h.raw = RING_GET_CURRENT_FRAME(handle);
-       if (h.h3->hdr.bh1.block_status == TP_STATUS_KERNEL) {
+       if (!packet_mmap_v3_acquire(h.h3)) {
                if (pkts == 0 && handlep->timeout == 0) {
                        /* Block until we see a packet. */
                        goto again;
  
                if (handlep->current_packet == NULL) {
                        h.raw = RING_GET_CURRENT_FRAME(handle);
-                       if (h.h3->hdr.bh1.block_status == TP_STATUS_KERNEL)
+                       if (!packet_mmap_v3_acquire(h.h3))
                                break;
  
                        handlep->current_packet = h.raw + h.h3->hdr.bh1.offset_to_first_pkt;
                         * filtered by the kernel, count the one we've
                         * just processed.
                         */
-                       h.h3->hdr.bh1.block_status = TP_STATUS_KERNEL;
+                       packet_mmap_v3_release(h.h3);
                        if (handlep->blocks_to_filter_in_userland > 0) {
                                handlep->blocks_to_filter_in_userland--;
                                if (handlep->blocks_to_filter_in_userland == 0) {
@@@ -4468,83 -4782,394 +4477,83 @@@ iface_bind(int fd, int ifindex, char *e
        return 0;
  }
  
 -#ifdef IW_MODE_MONITOR
 -/*
 - * Check whether the device supports the Wireless Extensions.
 - * Returns 1 if it does, 0 if it doesn't, PCAP_ERROR_NO_SUCH_DEVICE
 - * if the device doesn't even exist.
 - */
 -static int
 -has_wext(int sock_fd, const char *device, char *ebuf)
 -{
 -      struct iwreq ireq;
 -      int ret;
 -
 -      if (is_bonding_device(sock_fd, device))
 -              return 0;       /* bonding device, so don't even try */
 -
 -      pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
 -          sizeof ireq.ifr_ifrn.ifrn_name);
 -      if (ioctl(sock_fd, SIOCGIWNAME, &ireq) >= 0)
 -              return 1;       /* yes */
 -      if (errno == ENODEV)
 -              ret = PCAP_ERROR_NO_SUCH_DEVICE;
 -      else
 -              ret = 0;
 -      pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno,
 -          "%s: SIOCGIWNAME", device);
 -      return ret;
 -}
 -
 -/*
 - * Per me si va ne la citta dolente,
 - * Per me si va ne l'etterno dolore,
 - *    ...
 - * Lasciate ogne speranza, voi ch'intrate.
 - *
 - * XXX - airmon-ng does special stuff with the Orinoco driver and the
 - * wlan-ng driver.
 - */
 -typedef enum {
 -      MONITOR_WEXT,
 -      MONITOR_HOSTAP,
 -      MONITOR_PRISM,
 -      MONITOR_PRISM54,
 -      MONITOR_ACX100,
 -      MONITOR_RT2500,
 -      MONITOR_RT2570,
 -      MONITOR_RT73,
 -      MONITOR_RTL8XXX
 -} monitor_type;
 -
  /*
 - * Use the Wireless Extensions, if we have them, to try to turn monitor mode
 - * on if it's not already on.
 - *
 - * Returns 1 on success, 0 if we don't support the Wireless Extensions
 - * on this device, or a PCAP_ERROR_ value if we do support them but
 - * we weren't able to turn monitor mode on.
 + * Try to enter monitor mode.
 + * If we have libnl, try to create a new monitor-mode device and
 + * capture on that; otherwise, just say "not supported".
   */
 +#ifdef HAVE_LIBNL
  static int
 -enter_rfmon_mode_wext(pcap_t *handle, int sock_fd, const char *device)
 +enter_rfmon_mode(pcap_t *handle, int sock_fd, const char *device)
  {
 -      /*
 -       * XXX - at least some adapters require non-Wireless Extensions
 -       * mechanisms to turn monitor mode on.
 -       *
 -       * Atheros cards might require that a separate "monitor virtual access
 -       * point" be created, with later versions of the madwifi driver.
 -       * airmon-ng does
 -       *
 -       *    wlanconfig ath create wlandev {if_name} wlanmode monitor -bssid
 -       *
 -       * which apparently spits out a line "athN" where "athN" is the
 -       * monitor mode device.  To leave monitor mode, it destroys the
 -       * monitor mode device.
 -       *
 -       * Some Intel Centrino adapters might require private ioctls to get
 -       * radio headers; the ipw2200 and ipw3945 drivers allow you to
 -       * configure a separate "rtapN" interface to capture in monitor
 -       * mode without preventing the adapter from operating normally.
 -       * (airmon-ng doesn't appear to use that, though.)
 -       *
 -       * It would be Truly Wonderful if mac80211 and nl80211 cleaned this
 -       * up, and if all drivers were converted to mac80211 drivers.
 -       *
 -       * If interface {if_name} is a mac80211 driver, the file
 -       * /sys/class/net/{if_name}/phy80211 is a symlink to
 -       * /sys/class/ieee80211/{phydev_name}, for some {phydev_name}.
 -       *
 -       * On Fedora 9, with a 2.6.26.3-29 kernel, my Zydas stick, at
 -       * least, has a "wmaster0" device and a "wlan0" device; the
 -       * latter is the one with the IP address.  Both show up in
 -       * "tcpdump -D" output.  Capturing on the wmaster0 device
 -       * captures with 802.11 headers.
 -       *
 -       * airmon-ng searches through /sys/class/net for devices named
 -       * monN, starting with mon0; as soon as one *doesn't* exist,
 -       * it chooses that as the monitor device name.  If the "iw"
 -       * command exists, it does
 -       *
 -       *    iw dev {if_name} interface add {monif_name} type monitor"
 -       *
 -       * where {monif_name} is the monitor device.  It then (sigh) sleeps
 -       * .1 second, and then configures the device up.  Otherwise, if
 -       * /sys/class/ieee80211/{phydev_name}/add_iface is a file, it writes
 -       * {mondev_name}, without a newline, to that file, and again (sigh)
 -       * sleeps .1 second, and then iwconfig's that device into monitor
 -       * mode and configures it up.  Otherwise, you can't do monitor mode.
 -       *
 -       * All these devices are "glued" together by having the
 -       * /sys/class/net/{device_name}/phy80211 links pointing to the same
 -       * place, so, given a wmaster, wlan, or mon device, you can
 -       * find the other devices by looking for devices with
 -       * the same phy80211 link.
 -       *
 -       * To turn monitor mode off, delete the monitor interface,
 -       * either with
 -       *
 -       *    iw dev {monif_name} interface del
 -       *
 -       * or by sending {monif_name}, with no NL, down
 -       * /sys/class/ieee80211/{phydev_name}/remove_iface
 -       *
 -       * Note: if you try to create a monitor device named "monN", and
 -       * there's already a "monN" device, it fails, as least with
 -       * the netlink interface (which is what iw uses), with a return
 -       * value of -ENFILE.  (Return values are negative errnos.)  We
 -       * could probably use that to find an unused device.
 -       */
        struct pcap_linux *handlep = handle->priv;
 -      int err;
 -      struct iwreq ireq;
 -      struct iw_priv_args *priv;
 -      monitor_type montype;
 -      int i;
 -      __u32 cmd;
 +      int ret;
 +      char phydev_path[PATH_MAX+1];
 +      struct nl80211_state nlstate;
        struct ifreq ifr;
 -      int oldflags;
 -      int args[2];
 -      int channel;
 +      u_int n;
  
        /*
 -       * Does this device *support* the Wireless Extensions?
 +       * Is this a mac80211 device?
         */
 -      err = has_wext(sock_fd, device, handle->errbuf);
 -      if (err <= 0)
 -              return err;     /* either it doesn't or the device doesn't even exist */
 +      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 */
 +
        /*
 -       * Start out assuming we have no private extensions to control
 -       * radio metadata.
 +       * XXX - is this already a monN device?
 +       * If so, we're done.
         */
 -      montype = MONITOR_WEXT;
 -      cmd = 0;
  
        /*
 -       * Try to get all the Wireless Extensions private ioctls
 -       * supported by this device.
 -       *
 -       * First, get the size of the buffer we need, by supplying no
 -       * buffer and a length of 0.  If the device supports private
 -       * ioctls, it should return E2BIG, with ireq.u.data.length set
 -       * to the length we need.  If it doesn't support them, it should
 -       * return EOPNOTSUPP.
 +       * OK, it's apparently a mac80211 device.
 +       * Try to find an unused monN device for it.
         */
 -      memset(&ireq, 0, sizeof ireq);
 -      pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
 -          sizeof ireq.ifr_ifrn.ifrn_name);
 -      ireq.u.data.pointer = (void *)args;
 -      ireq.u.data.length = 0;
 -      ireq.u.data.flags = 0;
 -      if (ioctl(sock_fd, SIOCGIWPRIV, &ireq) != -1) {
 -              snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 -                  "%s: SIOCGIWPRIV with a zero-length buffer didn't fail!",
 -                  device);
 -              return PCAP_ERROR;
 -      }
 -      if (errno != EOPNOTSUPP) {
 +      ret = nl80211_init(handle, &nlstate, device);
 +      if (ret != 0)
 +              return ret;
 +      for (n = 0; n < UINT_MAX; n++) {
                /*
 -               * OK, it's not as if there are no private ioctls.
 +               * Try mon{n}.
                 */
 -              if (errno != E2BIG) {
 +              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) {
                        /*
 -                       * Failed.
 +                       * Success.  We don't clean up the libnl state
 +                       * yet, as we'll be using it later.
                         */
 -                      pcap_fmt_errmsg_for_errno(handle->errbuf,
 -                          PCAP_ERRBUF_SIZE, errno, "%s: SIOCGIWPRIV", device);
 -                      return PCAP_ERROR;
 -              }
 -
 -              /*
 -               * OK, try to get the list of private ioctls.
 -               */
 -              priv = malloc(ireq.u.data.length * sizeof (struct iw_priv_args));
 -              if (priv == NULL) {
 -                      pcap_fmt_errmsg_for_errno(handle->errbuf,
 -                          PCAP_ERRBUF_SIZE, errno, "malloc");
 -                      return PCAP_ERROR;
 -              }
 -              ireq.u.data.pointer = (void *)priv;
 -              if (ioctl(sock_fd, SIOCGIWPRIV, &ireq) == -1) {
 -                      pcap_fmt_errmsg_for_errno(handle->errbuf,
 -                          PCAP_ERRBUF_SIZE, errno, "%s: SIOCGIWPRIV", device);
 -                      free(priv);
 -                      return PCAP_ERROR;
 +                      goto added;
                }
 -
 -              /*
 -               * Look for private ioctls to turn monitor mode on or, if
 -               * monitor mode is on, to set the header type.
 -               */
 -              for (i = 0; i < ireq.u.data.length; i++) {
 -                      if (strcmp(priv[i].name, "monitor_type") == 0) {
 -                              /*
 -                               * Hostap driver, use this one.
 -                               * Set monitor mode first.
 -                               * You can set it to 0 to get DLT_IEEE80211,
 -                               * 1 to get DLT_PRISM, 2 to get
 -                               * DLT_IEEE80211_RADIO_AVS, and, with more
 -                               * recent versions of the driver, 3 to get
 -                               * DLT_IEEE80211_RADIO.
 -                               */
 -                              if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT)
 -                                      break;
 -                              if (!(priv[i].set_args & IW_PRIV_SIZE_FIXED))
 -                                      break;
 -                              if ((priv[i].set_args & IW_PRIV_SIZE_MASK) != 1)
 -                                      break;
 -                              montype = MONITOR_HOSTAP;
 -                              cmd = priv[i].cmd;
 -                              break;
 -                      }
 -                      if (strcmp(priv[i].name, "set_prismhdr") == 0) {
 -                              /*
 -                               * Prism54 driver, use this one.
 -                               * Set monitor mode first.
 -                               * You can set it to 2 to get DLT_IEEE80211
 -                               * or 3 or get DLT_PRISM.
 -                               */
 -                              if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT)
 -                                      break;
 -                              if (!(priv[i].set_args & IW_PRIV_SIZE_FIXED))
 -                                      break;
 -                              if ((priv[i].set_args & IW_PRIV_SIZE_MASK) != 1)
 -                                      break;
 -                              montype = MONITOR_PRISM54;
 -                              cmd = priv[i].cmd;
 -                              break;
 -                      }
 -                      if (strcmp(priv[i].name, "forceprismheader") == 0) {
 -                              /*
 -                               * RT2570 driver, use this one.
 -                               * Do this after turning monitor mode on.
 -                               * You can set it to 1 to get DLT_PRISM or 2
 -                               * to get DLT_IEEE80211.
 -                               */
 -                              if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT)
 -                                      break;
 -                              if (!(priv[i].set_args & IW_PRIV_SIZE_FIXED))
 -                                      break;
 -                              if ((priv[i].set_args & IW_PRIV_SIZE_MASK) != 1)
 -                                      break;
 -                              montype = MONITOR_RT2570;
 -                              cmd = priv[i].cmd;
 -                              break;
 -                      }
 -                      if (strcmp(priv[i].name, "forceprism") == 0) {
 -                              /*
 -                               * RT73 driver, use this one.
 -                               * Do this after turning monitor mode on.
 -                               * Its argument is a *string*; you can
 -                               * set it to "1" to get DLT_PRISM or "2"
 -                               * to get DLT_IEEE80211.
 -                               */
 -                              if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_CHAR)
 -                                      break;
 -                              if (priv[i].set_args & IW_PRIV_SIZE_FIXED)
 -                                      break;
 -                              montype = MONITOR_RT73;
 -                              cmd = priv[i].cmd;
 -                              break;
 -                      }
 -                      if (strcmp(priv[i].name, "prismhdr") == 0) {
 -                              /*
 -                               * One of the RTL8xxx drivers, use this one.
 -                               * It can only be done after monitor mode
 -                               * has been turned on.  You can set it to 1
 -                               * to get DLT_PRISM or 0 to get DLT_IEEE80211.
 -                               */
 -                              if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT)
 -                                      break;
 -                              if (!(priv[i].set_args & IW_PRIV_SIZE_FIXED))
 -                                      break;
 -                              if ((priv[i].set_args & IW_PRIV_SIZE_MASK) != 1)
 -                                      break;
 -                              montype = MONITOR_RTL8XXX;
 -                              cmd = priv[i].cmd;
 -                              break;
 -                      }
 -                      if (strcmp(priv[i].name, "rfmontx") == 0) {
 -                              /*
 -                               * RT2500 or RT61 driver, use this one.
 -                               * It has one one-byte parameter; set
 -                               * u.data.length to 1 and u.data.pointer to
 -                               * point to the parameter.
 -                               * It doesn't itself turn monitor mode on.
 -                               * You can set it to 1 to allow transmitting
 -                               * in monitor mode(?) and get DLT_IEEE80211,
 -                               * or set it to 0 to disallow transmitting in
 -                               * monitor mode(?) and get DLT_PRISM.
 -                               */
 -                              if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT)
 -                                      break;
 -                              if ((priv[i].set_args & IW_PRIV_SIZE_MASK) != 2)
 -                                      break;
 -                              montype = MONITOR_RT2500;
 -                              cmd = priv[i].cmd;
 -                              break;
 -                      }
 -                      if (strcmp(priv[i].name, "monitor") == 0) {
 -                              /*
 -                               * Either ACX100 or hostap, use this one.
 -                               * It turns monitor mode on.
 -                               * If it takes two arguments, it's ACX100;
 -                               * the first argument is 1 for DLT_PRISM
 -                               * or 2 for DLT_IEEE80211, and the second
 -                               * argument is the channel on which to
 -                               * run.  If it takes one argument, it's
 -                               * HostAP, and the argument is 2 for
 -                               * DLT_IEEE80211 and 3 for DLT_PRISM.
 -                               *
 -                               * If we see this, we don't quit, as this
 -                               * might be a version of the hostap driver
 -                               * that also supports "monitor_type".
 -                               */
 -                              if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT)
 -                                      break;
 -                              if (!(priv[i].set_args & IW_PRIV_SIZE_FIXED))
 -                                      break;
 -                              switch (priv[i].set_args & IW_PRIV_SIZE_MASK) {
 -
 -                              case 1:
 -                                      montype = MONITOR_PRISM;
 -                                      cmd = priv[i].cmd;
 -                                      break;
 -
 -                              case 2:
 -                                      montype = MONITOR_ACX100;
 -                                      cmd = priv[i].cmd;
 -                                      break;
 -
 -                              default:
 -                                      break;
 -                              }
 -                      }
 +              if (ret < 0) {
 +                      /*
 +                       * Hard failure.  Just return ret; handle->errbuf
 +                       * has already been set.
 +                       */
 +                      nl80211_cleanup(&nlstate);
 +                      return ret;
                }
 -              free(priv);
        }
  
 -      /*
 -       * XXX - ipw3945?  islism?
 -       */
 +      snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 +          "%s: No free monN interfaces", device);
 +      nl80211_cleanup(&nlstate);
 +      return PCAP_ERROR;
  
 -      /*
 -       * Get the old mode.
 -       */
 -      pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
 -          sizeof ireq.ifr_ifrn.ifrn_name);
 -      if (ioctl(sock_fd, SIOCGIWMODE, &ireq) == -1) {
 -              /*
 -               * We probably won't be able to set the mode, either.
 -               */
 -              return PCAP_ERROR_RFMON_NOTSUP;
 -      }
 +added:
  
 +#if 0
        /*
 -       * Is it currently in monitor mode?
 -       */
 -      if (ireq.u.mode == IW_MODE_MONITOR) {
 -              /*
 -               * Yes.  Just leave things as they are.
 -               * We don't offer multiple link-layer types, as
 -               * changing the link-layer type out from under
 -               * somebody else capturing in monitor mode would
 -               * be considered rude.
 -               */
 -              return 1;
 -      }
 -      /*
 -       * No.  We have to put the adapter into rfmon mode.
 +       * Sleep for .1 seconds.
         */
 +      delay.tv_sec = 0;
 +      delay.tv_nsec = 500000000;
 +      nanosleep(&delay, NULL);
 +#endif
  
        /*
         * If we haven't already done so, arrange to have
                 * "atexit()" failed; don't put the interface
                 * in rfmon mode, just give up.
                 */
 -              return PCAP_ERROR_RFMON_NOTSUP;
 -      }
 -
 -      /*
 -       * Save the old mode.
 -       */
 -      handlep->oldmode = ireq.u.mode;
 -
 -      /*
 -       * Put the adapter in rfmon mode.  How we do this depends
 -       * on whether we have a special private ioctl or not.
 -       */
 -      if (montype == MONITOR_PRISM) {
 -              /*
 -               * We have the "monitor" private ioctl, but none of
 -               * the other private ioctls.  Use this, and select
 -               * the Prism header.
 -               *
 -               * If it fails, just fall back on SIOCSIWMODE.
 -               */
 -              memset(&ireq, 0, sizeof ireq);
 -              pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
 -                  sizeof ireq.ifr_ifrn.ifrn_name);
 -              ireq.u.data.length = 1; /* 1 argument */
 -              args[0] = 3;    /* request Prism header */
 -              memcpy(ireq.u.name, args, sizeof (int));
 -              if (ioctl(sock_fd, cmd, &ireq) != -1) {
 -                      /*
 -                       * Success.
 -                       * Note that we have to put the old mode back
 -                       * when we close the device.
 -                       */
 -                      handlep->must_do_on_close |= MUST_CLEAR_RFMON;
 -
 -                      /*
 -                       * Add this to the list of pcaps to close
 -                       * when we exit.
 -                       */
 -                      pcap_add_to_pcaps_to_close(handle);
 -
 -                      return 1;
 -              }
 -
 -              /*
 -               * Failure.  Fall back on SIOCSIWMODE.
 -               */
 +              del_mon_if(handle, sock_fd, &nlstate, device,
 +                  handlep->mondevice);
 +              nl80211_cleanup(&nlstate);
 +              return PCAP_ERROR;
        }
  
        /*
 -       * First, take the interface down if it's up; otherwise, we
 -       * might get EBUSY.
 +       * Now configure the monitor interface up.
         */
        memset(&ifr, 0, sizeof(ifr));
 -      pcap_strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
 +      pcap_strlcpy(ifr.ifr_name, handlep->mondevice, sizeof(ifr.ifr_name));
        if (ioctl(sock_fd, SIOCGIFFLAGS, &ifr) == -1) {
                pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
 -                  errno, "%s: Can't get flags", device);
 +                  errno, "%s: Can't get flags for %s", device,
 +                  handlep->mondevice);
 +              del_mon_if(handle, sock_fd, &nlstate, device,
 +                  handlep->mondevice);
 +              nl80211_cleanup(&nlstate);
                return PCAP_ERROR;
        }
 -      oldflags = 0;
 -      if (ifr.ifr_flags & IFF_UP) {
 -              oldflags = ifr.ifr_flags;
 -              ifr.ifr_flags &= ~IFF_UP;
 -              if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr) == -1) {
 -                      pcap_fmt_errmsg_for_errno(handle->errbuf,
 -                          PCAP_ERRBUF_SIZE, errno, "%s: Can't set flags",
 -                          device);
 -                      return PCAP_ERROR;
 -              }
 -      }
 -
 -      /*
 -       * Then turn monitor mode on.
 -       */
 -      pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
 -          sizeof ireq.ifr_ifrn.ifrn_name);
 -      ireq.u.mode = IW_MODE_MONITOR;
 -      if (ioctl(sock_fd, SIOCSIWMODE, &ireq) == -1) {
 -              /*
 -               * Scientist, you've failed.
 -               * Bring the interface back up if we shut it down.
 -               */
 -              ifr.ifr_flags = oldflags;
 -              if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr) == -1) {
 -                      pcap_fmt_errmsg_for_errno(handle->errbuf,
 -                          PCAP_ERRBUF_SIZE, errno, "%s: Can't set flags",
 -                          device);
 -                      return PCAP_ERROR;
 -              }
 -              return PCAP_ERROR_RFMON_NOTSUP;
 -      }
 -
 -      /*
 -       * XXX - airmon-ng does "iwconfig {if_name} key off" after setting
 -       * monitor mode and setting the channel, and then does
 -       * "iwconfig up".
 -       */
 -
 -      /*
 -       * Now select the appropriate radio header.
 -       */
 -      switch (montype) {
 -
 -      case MONITOR_WEXT:
 -              /*
 -               * We don't have any private ioctl to set the header.
 -               */
 -              break;
 -
 -      case MONITOR_HOSTAP:
 -              /*
 -               * Try to select the radiotap header.
 -               */
 -              memset(&ireq, 0, sizeof ireq);
 -              pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
 -                  sizeof ireq.ifr_ifrn.ifrn_name);
 -              args[0] = 3;    /* request radiotap header */
 -              memcpy(ireq.u.name, args, sizeof (int));
 -              if (ioctl(sock_fd, cmd, &ireq) != -1)
 -                      break;  /* success */
 -
 -              /*
 -               * That failed.  Try to select the AVS header.
 -               */
 -              memset(&ireq, 0, sizeof ireq);
 -              pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
 -                  sizeof ireq.ifr_ifrn.ifrn_name);
 -              args[0] = 2;    /* request AVS header */
 -              memcpy(ireq.u.name, args, sizeof (int));
 -              if (ioctl(sock_fd, cmd, &ireq) != -1)
 -                      break;  /* success */
 -
 -              /*
 -               * That failed.  Try to select the Prism header.
 -               */
 -              memset(&ireq, 0, sizeof ireq);
 -              pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
 -                  sizeof ireq.ifr_ifrn.ifrn_name);
 -              args[0] = 1;    /* request Prism header */
 -              memcpy(ireq.u.name, args, sizeof (int));
 -              ioctl(sock_fd, cmd, &ireq);
 -              break;
 -
 -      case MONITOR_PRISM:
 -              /*
 -               * The private ioctl failed.
 -               */
 -              break;
 -
 -      case MONITOR_PRISM54:
 -              /*
 -               * Select the Prism header.
 -               */
 -              memset(&ireq, 0, sizeof ireq);
 -              pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
 -                  sizeof ireq.ifr_ifrn.ifrn_name);
 -              args[0] = 3;    /* request Prism header */
 -              memcpy(ireq.u.name, args, sizeof (int));
 -              ioctl(sock_fd, cmd, &ireq);
 -              break;
 -
 -      case MONITOR_ACX100:
 -              /*
 -               * Get the current channel.
 -               */
 -              memset(&ireq, 0, sizeof ireq);
 -              pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
 -                  sizeof ireq.ifr_ifrn.ifrn_name);
 -              if (ioctl(sock_fd, SIOCGIWFREQ, &ireq) == -1) {
 -                      pcap_fmt_errmsg_for_errno(handle->errbuf,
 -                          PCAP_ERRBUF_SIZE, errno, "%s: SIOCGIWFREQ", device);
 -                      return PCAP_ERROR;
 -              }
 -              channel = ireq.u.freq.m;
 -
 -              /*
 -               * Select the Prism header, and set the channel to the
 -               * current value.
 -               */
 -              memset(&ireq, 0, sizeof ireq);
 -              pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
 -                  sizeof ireq.ifr_ifrn.ifrn_name);
 -              args[0] = 1;            /* request Prism header */
 -              args[1] = channel;      /* set channel */
 -              memcpy(ireq.u.name, args, 2*sizeof (int));
 -              ioctl(sock_fd, cmd, &ireq);
 -              break;
 -
 -      case MONITOR_RT2500:
 -              /*
 -               * Disallow transmission - that turns on the
 -               * Prism header.
 -               */
 -              memset(&ireq, 0, sizeof ireq);
 -              pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
 -                  sizeof ireq.ifr_ifrn.ifrn_name);
 -              args[0] = 0;    /* disallow transmitting */
 -              memcpy(ireq.u.name, args, sizeof (int));
 -              ioctl(sock_fd, cmd, &ireq);
 -              break;
 -
 -      case MONITOR_RT2570:
 -              /*
 -               * Force the Prism header.
 -               */
 -              memset(&ireq, 0, sizeof ireq);
 -              pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
 -                  sizeof ireq.ifr_ifrn.ifrn_name);
 -              args[0] = 1;    /* request Prism header */
 -              memcpy(ireq.u.name, args, sizeof (int));
 -              ioctl(sock_fd, cmd, &ireq);
 -              break;
 -
 -      case MONITOR_RT73:
 -              /*
 -               * Force the Prism header.
 -               */
 -              memset(&ireq, 0, sizeof ireq);
 -              pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
 -                  sizeof ireq.ifr_ifrn.ifrn_name);
 -              ireq.u.data.length = 1; /* 1 argument */
 -              ireq.u.data.pointer = "1";
 -              ireq.u.data.flags = 0;
 -              ioctl(sock_fd, cmd, &ireq);
 -              break;
 -
 -      case MONITOR_RTL8XXX:
 -              /*
 -               * Force the Prism header.
 -               */
 -              memset(&ireq, 0, sizeof ireq);
 -              pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
 -                  sizeof ireq.ifr_ifrn.ifrn_name);
 -              args[0] = 1;    /* request Prism header */
 -              memcpy(ireq.u.name, args, sizeof (int));
 -              ioctl(sock_fd, cmd, &ireq);
 -              break;
 +      ifr.ifr_flags |= IFF_UP|IFF_RUNNING;
 +      if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr) == -1) {
 +              pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
 +                  errno, "%s: Can't set flags for %s", device,
 +                  handlep->mondevice);
 +              del_mon_if(handle, sock_fd, &nlstate, device,
 +                  handlep->mondevice);
 +              nl80211_cleanup(&nlstate);
 +              return PCAP_ERROR;
        }
  
        /*
 -       * Now bring the interface back up if we brought it down.
 +       * Success.  Clean up the libnl state.
         */
 -      if (oldflags != 0) {
 -              ifr.ifr_flags = oldflags;
 -              if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr) == -1) {
 -                      pcap_fmt_errmsg_for_errno(handle->errbuf,
 -                          PCAP_ERRBUF_SIZE, errno, "%s: Can't set flags",
 -                          device);
 -
 -                      /*
 -                       * At least try to restore the old mode on the
 -                       * interface.
 -                       */
 -                      if (ioctl(handle->fd, SIOCSIWMODE, &ireq) == -1) {
 -                              /*
 -                               * Scientist, you've failed.
 -                               */
 -                              fprintf(stderr,
 -                                  "Can't restore interface wireless mode (SIOCSIWMODE failed: %s).\n"
 -                                  "Please adjust manually.\n",
 -                                  strerror(errno));
 -                      }
 -                      return PCAP_ERROR;
 -              }
 -      }
 +      nl80211_cleanup(&nlstate);
  
        /*
 -       * Note that we have to put the old mode back when we
 -       * close the device.
 +       * Note that we have to delete the monitor device when we close
 +       * the handle.
         */
 -      handlep->must_do_on_close |= MUST_CLEAR_RFMON;
 +      handlep->must_do_on_close |= MUST_DELETE_MONIF;
  
        /*
         * Add this to the list of pcaps to close when we exit.
  
        return 1;
  }
 -#endif /* IW_MODE_MONITOR */
 -
 -/*
 - * Try various mechanisms to enter monitor mode.
 - */
 +#else /* HAVE_LIBNL */
  static int
 -enter_rfmon_mode(pcap_t *handle, int sock_fd, const char *device)
 +enter_rfmon_mode(pcap_t *handle _U_, int sock_fd _U_, const char *device _U_)
  {
 -#if defined(HAVE_LIBNL) || defined(IW_MODE_MONITOR)
 -      int ret;
 -#endif
 -
 -#ifdef HAVE_LIBNL
 -      ret = enter_rfmon_mode_mac80211(handle, sock_fd, device);
 -      if (ret < 0)
 -              return ret;     /* error attempting to do so */
 -      if (ret == 1)
 -              return 1;       /* success */
 -#endif /* HAVE_LIBNL */
 -
 -#ifdef IW_MODE_MONITOR
 -      ret = enter_rfmon_mode_wext(handle, sock_fd, device);
 -      if (ret < 0)
 -              return ret;     /* error attempting to do so */
 -      if (ret == 1)
 -              return 1;       /* success */
 -#endif /* IW_MODE_MONITOR */
 -
        /*
 -       * Either none of the mechanisms we know about work or none
 -       * of those mechanisms are available, so we can't do monitor
 -       * mode.
 +       * We don't have libnl, so we can't do monitor mode.
         */
        return 0;
  }
 +#endif /* HAVE_LIBNL */
  
  #if defined(HAVE_LINUX_NET_TSTAMP_H) && defined(PACKET_TIMESTAMP)
  /*