+#ifdef HAVE_PCAP_FINDALLDEVS
+static long
+parse_interface_number(const char *device)
+{
+ const char *p;
+ long devnum;
+ char *end;
+
+ /*
+ * Search for a colon, terminating any scheme at the beginning
+ * of the device.
+ */
+ p = strchr(device, ':');
+ if (p != NULL) {
+ /*
+ * We found it. Is it followed by "//"?
+ */
+ p++; /* skip the : */
+ if (strncmp(p, "//", 2) == 0) {
+ /*
+ * Yes. Search for the next /, at the end of the
+ * authority part of the URL.
+ */
+ p += 2; /* skip the // */
+ p = strchr(p, '/');
+ if (p != NULL) {
+ /*
+ * OK, past the / is the path.
+ */
+ device = p + 1;
+ }
+ }
+ }
+ devnum = strtol(device, &end, 10);
+ if (device != end && *end == '\0') {
+ /*
+ * It's all-numeric, but is it a valid number?
+ */
+ if (devnum <= 0) {
+ /*
+ * No, it's not an ordinal.
+ */
+ error("Invalid adapter index");
+ }
+ return (devnum);
+ } else {
+ /*
+ * It's not all-numeric; return -1, so our caller
+ * knows that.
+ */
+ return (-1);
+ }
+}
+
+static char *
+find_interface_by_number(const char *url
+#ifndef HAVE_PCAP_FINDALLDEVS_EX
+_U_
+#endif
+, long devnum)
+{
+ pcap_if_t *dev, *devlist;
+ long i;
+ char ebuf[PCAP_ERRBUF_SIZE];
+ char *device;
+#ifdef HAVE_PCAP_FINDALLDEVS_EX
+ const char *endp;
+ char *host_url;
+#endif
+ int status;
+
+#ifdef HAVE_PCAP_FINDALLDEVS_EX
+ /*
+ * Search for a colon, terminating any scheme at the beginning
+ * of the URL.
+ */
+ endp = strchr(url, ':');
+ if (endp != NULL) {
+ /*
+ * We found it. Is it followed by "//"?
+ */
+ endp++; /* skip the : */
+ if (strncmp(endp, "//", 2) == 0) {
+ /*
+ * Yes. Search for the next /, at the end of the
+ * authority part of the URL.
+ */
+ endp += 2; /* skip the // */
+ endp = strchr(endp, '/');
+ } else
+ endp = NULL;
+ }
+ if (endp != NULL) {
+ /*
+ * OK, everything from device to endp is a URL to hand
+ * to pcap_findalldevs_ex().
+ */
+ endp++; /* Include the trailing / in the URL; pcap_findalldevs_ex() requires it */
+ host_url = malloc(endp - url + 1);
+ if (host_url == NULL && (endp - url + 1) > 0)
+ error("Invalid allocation for host");
+
+ memcpy(host_url, url, endp - url);
+ host_url[endp - url] = '\0';
+ status = pcap_findalldevs_ex(host_url, NULL, &devlist, ebuf);
+ free(host_url);
+ } else
+#endif
+ status = pcap_findalldevs(&devlist, ebuf);
+ if (status < 0)
+ error("%s", ebuf);
+ /*
+ * Look for the devnum-th entry in the list of devices (1-based).
+ */
+ for (i = 0, dev = devlist; i < devnum-1 && dev != NULL;
+ i++, dev = dev->next)
+ ;
+ if (dev == NULL)
+ error("Invalid adapter index");
+ device = strdup(dev->name);
+ pcap_freealldevs(devlist);
+ return (device);
+}
+#endif
+
+#ifdef HAVE_PCAP_OPEN
+/*
+ * Prefixes for rpcap URLs.
+ */
+static char rpcap_prefix[] = "rpcap://";
+static char rpcap_ssl_prefix[] = "rpcaps://";
+#endif
+
+static pcap_t *
+open_interface(const char *device, netdissect_options *ndo, char *ebuf)
+{
+ pcap_t *pc;
+#ifdef HAVE_PCAP_CREATE
+ int status;
+ char *cp;
+#endif
+
+#ifdef HAVE_PCAP_OPEN
+ /*
+ * Is this an rpcap URL?
+ */
+ if (strncmp(device, rpcap_prefix, sizeof(rpcap_prefix) - 1) == 0 ||
+ strncmp(device, rpcap_ssl_prefix, sizeof(rpcap_ssl_prefix) - 1) == 0) {
+ /*
+ * Yes. Open it with pcap_open().
+ */
+ *ebuf = '\0';
+ pc = pcap_open(device, ndo->ndo_snaplen,
+ pflag ? 0 : PCAP_OPENFLAG_PROMISCUOUS, timeout, NULL,
+ ebuf);
+ if (pc == NULL) {
+ /*
+ * If this failed with "No such device" or "The system
+ * cannot find the device specified", that means
+ * the interface doesn't exist; return NULL, so that
+ * the caller can see whether the device name is
+ * actually an interface index.
+ */
+ if (strstr(ebuf, "No such device") != NULL ||
+ strstr(ebuf, "The system cannot find the device specified") != NULL)
+ return (NULL);
+ error("%s", ebuf);
+ }
+ if (*ebuf)
+ warning("%s", ebuf);
+ return (pc);
+ }
+#endif /* HAVE_PCAP_OPEN */
+
+#ifdef HAVE_PCAP_CREATE
+ pc = pcap_create(device, ebuf);
+ if (pc == NULL) {
+ /*
+ * If this failed with "No such device", that means
+ * the interface doesn't exist; return NULL, so that
+ * the caller can see whether the device name is
+ * actually an interface index.
+ */
+ if (strstr(ebuf, "No such device") != NULL)
+ return (NULL);
+ error("%s", ebuf);
+ }
+#ifdef HAVE_PCAP_SET_TSTAMP_TYPE
+ if (Jflag)
+ show_tstamp_types_and_exit(pc, device);
+#endif
+#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
+ status = pcap_set_tstamp_precision(pc, ndo->ndo_tstamp_precision);
+ if (status != 0)
+ error("%s: Can't set %ssecond time stamp precision: %s",
+ device,
+ tstamp_precision_to_string(ndo->ndo_tstamp_precision),
+ pcap_statustostr(status));
+#endif
+
+#ifdef HAVE_PCAP_SET_IMMEDIATE_MODE
+ if (immediate_mode) {
+ status = pcap_set_immediate_mode(pc, 1);
+ if (status != 0)
+ error("%s: Can't set immediate mode: %s",
+ device, pcap_statustostr(status));
+ }
+#endif
+ /*
+ * Is this an interface that supports monitor mode?
+ */
+ if (pcap_can_set_rfmon(pc) == 1)
+ supports_monitor_mode = 1;
+ else
+ supports_monitor_mode = 0;
+ if (ndo->ndo_snaplen != 0) {
+ /*
+ * A snapshot length was explicitly specified;
+ * use it.
+ */
+ status = pcap_set_snaplen(pc, ndo->ndo_snaplen);
+ if (status != 0)
+ error("%s: Can't set snapshot length: %s",
+ device, pcap_statustostr(status));
+ }
+ status = pcap_set_promisc(pc, !pflag);
+ if (status != 0)
+ error("%s: Can't set promiscuous mode: %s",
+ device, pcap_statustostr(status));
+ if (Iflag) {
+ status = pcap_set_rfmon(pc, 1);
+ if (status != 0)
+ error("%s: Can't set monitor mode: %s",
+ device, pcap_statustostr(status));
+ }
+ status = pcap_set_timeout(pc, timeout);
+ if (status != 0)
+ error("%s: pcap_set_timeout failed: %s",
+ device, pcap_statustostr(status));
+ if (Bflag != 0) {
+ status = pcap_set_buffer_size(pc, Bflag);
+ if (status != 0)
+ error("%s: Can't set buffer size: %s",
+ device, pcap_statustostr(status));
+ }
+#ifdef HAVE_PCAP_SET_TSTAMP_TYPE
+ if (jflag != -1) {
+ status = pcap_set_tstamp_type(pc, jflag);
+ if (status < 0)
+ error("%s: Can't set time stamp type: %s",
+ device, pcap_statustostr(status));
+ else if (status > 0)
+ warning("When trying to set timestamp type '%s' on %s: %s",
+ pcap_tstamp_type_val_to_name(jflag), device,
+ pcap_statustostr(status));
+ }
+#endif
+ status = pcap_activate(pc);
+ if (status < 0) {
+ /*
+ * pcap_activate() failed.
+ */
+ cp = pcap_geterr(pc);
+ if (status == PCAP_ERROR)
+ error("%s", cp);
+ else if (status == PCAP_ERROR_NO_SUCH_DEVICE) {
+ /*
+ * Return an error for our caller to handle.
+ */
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s\n(%s)",
+ device, pcap_statustostr(status), cp);
+ } else if (status == PCAP_ERROR_PERM_DENIED && *cp != '\0')
+ error("%s: %s\n(%s)", device,
+ pcap_statustostr(status), cp);
+#ifdef __FreeBSD__
+ else if (status == PCAP_ERROR_RFMON_NOTSUP &&
+ strncmp(device, "wlan", 4) == 0) {
+ char parent[8], newdev[8];
+ char sysctl[32];
+ size_t s = sizeof(parent);
+
+ snprintf(sysctl, sizeof(sysctl),
+ "net.wlan.%d.%%parent", atoi(device + 4));
+ sysctlbyname(sysctl, parent, &s, NULL, 0);
+ strlcpy(newdev, device, sizeof(newdev));
+ /* Suggest a new wlan device. */
+ /* FIXME: incrementing the index this way is not going to work well
+ * when the index is 9 or greater but the only consequence in this
+ * specific case would be an error message that looks a bit odd.
+ */
+ newdev[strlen(newdev)-1]++;
+ error("%s is not a monitor mode VAP\n"
+ "To create a new monitor mode VAP use:\n"
+ " ifconfig %s create wlandev %s wlanmode monitor\n"
+ "and use %s as the tcpdump interface",
+ device, newdev, parent, newdev);
+ }
+#endif
+ else
+ error("%s: %s", device,
+ pcap_statustostr(status));
+ pcap_close(pc);
+ return (NULL);
+ } else if (status > 0) {
+ /*
+ * pcap_activate() succeeded, but it's warning us
+ * of a problem it had.
+ */
+ cp = pcap_geterr(pc);
+ if (status == PCAP_WARNING)
+ warning("%s", cp);
+ else if (status == PCAP_WARNING_PROMISC_NOTSUP &&
+ *cp != '\0')
+ warning("%s: %s\n(%s)", device,
+ pcap_statustostr(status), cp);
+ else
+ warning("%s: %s", device,
+ pcap_statustostr(status));
+ }
+#ifdef HAVE_PCAP_SETDIRECTION
+ if (Qflag != -1) {
+ status = pcap_setdirection(pc, Qflag);
+ if (status != 0)
+ error("%s: pcap_setdirection() failed: %s",
+ device, pcap_geterr(pc));
+ }
+#endif /* HAVE_PCAP_SETDIRECTION */
+#else /* HAVE_PCAP_CREATE */
+ *ebuf = '\0';
+ /*
+ * If no snapshot length was specified, or a length of 0 was
+ * specified, default to 256KB.
+ */
+ if (ndo->ndo_snaplen == 0)
+ ndo->ndo_snaplen = MAXIMUM_SNAPLEN;
+ pc = pcap_open_live(device, ndo->ndo_snaplen, !pflag, timeout, ebuf);
+ if (pc == NULL) {
+ /*
+ * If this failed with "No such device", that means
+ * the interface doesn't exist; return NULL, so that
+ * the caller can see whether the device name is
+ * actually an interface index.
+ */
+ if (strstr(ebuf, "No such device") != NULL)
+ return (NULL);
+ error("%s", ebuf);
+ }
+ if (*ebuf)
+ warning("%s", ebuf);
+#endif /* HAVE_PCAP_CREATE */
+
+ return (pc);
+}
+