summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2018-04-29 15:02:09 -0700
committerGuy Harris <guy@alum.mit.edu>2018-04-29 15:02:09 -0700
commit38fe5d4033c4e49b414617473aa581a75873fc89 (patch)
treef87da023892e1eb2d06cbe981a2e473fc3f82ddd
parente3a28bfcb200115ef541c0eda3d9b3ae2136e4c5 (diff)
downloadlibpcap-38fe5d4033c4e49b414617473aa581a75873fc89.tar.gz
Add more interface flags to pcap_findalldevs().
We add: PCAP_IF_WIRELESS, which indicates whether the interface is "wireless" or not. PCAP_IF_CONNECTION_STATUS, which is a bitmask for a two-bit field that can have one of the values: PCAP_IF_CONNECTION_STATUS_UNKNOWN if the status of whether the interface is "connected" or "disconnected" is unknown; PCAP_IF_CONNECTION_STATUS_CONNECTED if the interface is "connected"; PCAP_IF_CONNECTION_STATUS_DISCONNECTED if the interface is "disconnected"; PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE if the notion of "connected" or "disconnected" doesn't apply to this interface. Take that into account when sorting interfaces in the interface list, penalizing "disconnected" interfaces, as you won't see traffic on them if they're not wireless and you'd have to be in some form of "monitor mode" to see traffic on them if they're wireless. This should address GitHub issue #700.
-rw-r--r--pcap-bpf.c85
-rw-r--r--pcap-bt-linux.c11
-rw-r--r--pcap-dag.c18
-rw-r--r--pcap-dbus.c12
-rw-r--r--pcap-dlpi.c16
-rw-r--r--pcap-dos.c3
-rw-r--r--pcap-int.h4
-rw-r--r--pcap-libdlpi.c11
-rw-r--r--pcap-linux.c157
-rw-r--r--pcap-netfilter-linux.c12
-rw-r--r--pcap-nit.c11
-rw-r--r--pcap-npf.c273
-rw-r--r--pcap-null.c11
-rw-r--r--pcap-pf.c11
-rw-r--r--pcap-rdmasniff.c4
-rw-r--r--pcap-septel.c3
-rw-r--r--pcap-snf.c19
-rw-r--r--pcap-snit.c11
-rw-r--r--pcap-snoop.c11
-rw-r--r--pcap-usb-linux.c28
-rw-r--r--pcap.c41
-rw-r--r--pcap/pcap.h13
-rw-r--r--pcap_findalldevs.3pcap24
-rw-r--r--testprogs/findalldevstest.c39
24 files changed, 764 insertions, 64 deletions
diff --git a/pcap-bpf.c b/pcap-bpf.c
index bb2cbd15..eb2b4a74 100644
--- a/pcap-bpf.c
+++ b/pcap-bpf.c
@@ -124,7 +124,7 @@ static int bpf_load(char *errbuf);
#include <string.h>
#include <unistd.h>
-#ifdef HAVE_NET_IF_MEDIA_H
+#ifdef SIOCGIFMEDIA
# include <net/if_media.h>
#endif
@@ -2715,6 +2715,89 @@ finddevs_usb(pcap_if_list_t *devlistp, char *errbuf)
}
#endif
+/*
+ * Get additional flags for a device, using SIOCGIFMEDIA.
+ */
+#ifdef SIOCGIFMEDIA
+int
+get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf)
+{
+ int sock;
+ struct ifmediareq req;
+
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock == -1) {
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno,
+ "Can't create socket to get media information for %s",
+ name);
+ return (-1);
+ }
+ memset(&req, 0, sizeof(req));
+ strncpy(req.ifm_name, name, sizeof(req.ifm_name));
+ if (ioctl(sock, SIOCGIFMEDIA, &req) < 0) {
+ if (errno == EOPNOTSUPP) {
+ /*
+ * Not supported, so we can't provide any
+ * additional information. Assume that
+ * this means that "connected" vs.
+ * "disconnected" doesn't apply.
+ */
+ *flags |= PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE;
+ close(sock);
+ return (0);
+ }
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno,
+ "SIOCGIFMEDIA on %s failed", name);
+ close(sock);
+ return (-1);
+ }
+ close(sock);
+
+ /*
+ * OK, what type of network is this?
+ */
+ switch (IFM_TYPE(req.ifm_active)) {
+
+ case IFM_IEEE80211:
+ /*
+ * Wireless.
+ */
+ *flags |= PCAP_IF_WIRELESS;
+ break;
+ }
+
+ /*
+ * Do we know whether it's connected?
+ */
+ if (req.ifm_status & IFM_AVALID) {
+ /*
+ * Yes.
+ */
+ if (req.ifm_status & IFM_ACTIVE) {
+ /*
+ * It's connected.
+ */
+ *flags |= PCAP_IF_CONNECTION_STATUS_CONNECTED;
+ } else {
+ /*
+ * It's disconnected.
+ */
+ *flags |= PCAP_IF_CONNECTION_STATUS_DISCONNECTED;
+ }
+ }
+ return (0);
+}
+#else
+int
+get_if_flags(const char *name _U_, bpf_u_int32 flags _U_, char *errbuf _U_)
+{
+ /*
+ * Nothing we can do.
+ */
+ return (0);
+}
+#endif
+
int
pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf)
{
diff --git a/pcap-bt-linux.c b/pcap-bt-linux.c
index 3cd4f500..07ed1c73 100644
--- a/pcap-bt-linux.c
+++ b/pcap-bt-linux.c
@@ -114,12 +114,19 @@ bt_findalldevs(pcap_if_list_t *devlistp, char *err_str)
pcap_snprintf(dev_name, 20, BT_IFACE"%d", dev_req->dev_id);
pcap_snprintf(dev_descr, 30, "Bluetooth adapter number %d", i);
- if (add_dev(devlistp, dev_name, 0, dev_descr, err_str) == NULL)
+ /*
+ * Bluetooth is a wireless technology.
+ * XXX - if there's the notion of associating with a
+ * network, and we can determine whether the interface
+ * is associated with a network, check that and set
+ * the status to PCAP_IF_CONNECTION_STATUS_CONNECTED
+ * or PCAP_IF_CONNECTION_STATUS_DISCONNECTED.
+ */
+ if (add_dev(devlistp, dev_name, PCAP_IF_WIRELESS, dev_descr, err_str) == NULL)
{
ret = -1;
break;
}
-
}
free:
diff --git a/pcap-dag.c b/pcap-dag.c
index ae37b10c..931f2f3a 100644
--- a/pcap-dag.c
+++ b/pcap-dag.c
@@ -1070,7 +1070,6 @@ int
dag_findalldevs(pcap_if_list_t *devlistp, char *errbuf)
{
char name[12]; /* XXX - pick a size */
- int ret = 0;
int c;
char dagname[DAGNAME_BUFSIZE];
int dagstream;
@@ -1086,17 +1085,26 @@ dag_findalldevs(pcap_if_list_t *devlistp, char *errbuf)
{
(void) pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
"dag: device name %s can't be parsed", name);
- return -1;
+ return (-1);
}
if ( (dagfd = dag_open(dagname)) >= 0 ) {
description = NULL;
if ((inf = dag_pciinfo(dagfd)))
description = dag_device_name(inf->device_code, 1);
+ /*
+ * XXX - is there a way to determine whether
+ * the card is plugged into a network or not?
+ * If so, we should check that and set
+ * PCAP_IF_CONNECTION_STATUS_CONNECTED or
+ * PCAP_IF_CONNECTION_STATUS_DISCONNECTED.
+ *
+ * Also, are there notions of "up" and "running"?
+ */
if (add_dev(devlistp, name, 0, description, errbuf) == NULL) {
/*
* Failure.
*/
- ret = -1;
+ return (-1);
}
rxstreams = dag_rx_get_stream_count(dagfd);
for(stream=0;stream<DAG_STREAM_MAX;stream+=2) {
@@ -1108,7 +1116,7 @@ dag_findalldevs(pcap_if_list_t *devlistp, char *errbuf)
/*
* Failure.
*/
- ret = -1;
+ return (-1);
}
rxstreams--;
@@ -1121,7 +1129,7 @@ dag_findalldevs(pcap_if_list_t *devlistp, char *errbuf)
}
}
- return (ret);
+ return (0);
}
/*
diff --git a/pcap-dbus.c b/pcap-dbus.c
index c2364053..1252975e 100644
--- a/pcap-dbus.c
+++ b/pcap-dbus.c
@@ -334,9 +334,17 @@ dbus_create(const char *device, char *ebuf, int *is_ours)
int
dbus_findalldevs(pcap_if_list_t *devlistp, char *err_str)
{
- if (add_dev(devlistp, "dbus-system", 0, "D-Bus system bus", err_str) == NULL)
+ /*
+ * The notion of "connected" vs. "disconnected" doesn't apply.
+ * XXX - what about the notions of "up" and "running"?
+ */
+ if (add_dev(devlistp, "dbus-system",
+ PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE, "D-Bus system bus",
+ err_str) == NULL)
return -1;
- if (add_dev(devlistp, "dbus-session", 0, "D-Bus session bus", err_str) == NULL)
+ if (add_dev(devlistp, "dbus-session",
+ PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE, "D-Bus session bus",
+ err_str) == NULL)
return -1;
return 0;
}
diff --git a/pcap-dlpi.c b/pcap-dlpi.c
index bbf75b96..abf72f2c 100644
--- a/pcap-dlpi.c
+++ b/pcap-dlpi.c
@@ -1050,6 +1050,17 @@ is_dlpi_interface(const char *name)
}
int
+get_if_flags(const char *name _U_, bpf_u_int32 flags _U_, char *errbuf _U_)
+{
+ /*
+ * Nothing we can do.
+ * XXX - is there a way to find out whether an adapter has
+ * something plugged into it?
+ */
+ return (0);
+}
+
+int
pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf)
{
#ifdef HAVE_SOLARIS
@@ -1092,6 +1103,11 @@ pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf)
}
for (i = 0; i < buf.nunits; i++) {
pcap_snprintf(baname, sizeof baname, "ba%u", i);
+ /*
+ * XXX - is there a notion of "up" and "running"?
+ * And is there a way to determine whether the
+ * interface is plugged into a network?
+ */
if (add_dev(devlistp, baname, 0, NULL, errbuf) == NULL)
return (-1);
}
diff --git a/pcap-dos.c b/pcap-dos.c
index 54690d2a..b1b9ecd7 100644
--- a/pcap-dos.c
+++ b/pcap-dos.c
@@ -579,6 +579,9 @@ int pcap_platform_finddevs (pcap_if_list_t *devlistp, char *errbuf)
/*
* XXX - find out whether it's up or running? Does that apply here?
+ * Can we find out if anything's plugged into the adapter, if it's
+ * a wired device, and set PCAP_IF_CONNECTION_STATUS_CONNECTED
+ * or PCAP_IF_CONNECTION_STATUS_DISCONNECTED?
*/
if ((curdev = add_dev(devlistp, dev->name, 0,
dev->long_name, errbuf)) == NULL)
diff --git a/pcap-int.h b/pcap-int.h
index 7877b607..6cd8740e 100644
--- a/pcap-int.h
+++ b/pcap-int.h
@@ -437,10 +437,14 @@ int pcap_check_activated(pcap_t *);
*
* "find_or_add_dev()" checks whether a device is already in a pcap_if_list_t
* and, if not, adds an entry for it.
+ *
+ * "get_if_flags()" is the platform-dependent routine to get additional
+ * pcap flags for an interface.
*/
struct pcap_if_list;
typedef struct pcap_if_list pcap_if_list_t;
int pcap_platform_finddevs(pcap_if_list_t *, char *);
+int get_if_flags(const char *name, bpf_u_int32 *, char *);
#if !defined(_WIN32) && !defined(MSDOS)
int pcap_findalldevs_interfaces(pcap_if_list_t *, char *,
int (*)(const char *));
diff --git a/pcap-libdlpi.c b/pcap-libdlpi.c
index 99ca9be7..2d1b58f3 100644
--- a/pcap-libdlpi.c
+++ b/pcap-libdlpi.c
@@ -287,6 +287,17 @@ is_dlpi_interface(const char *name _U_)
return (1);
}
+int
+get_if_flags(const char *name _U_, bpf_u_int32 flags _U_, char *errbuf _U_)
+{
+ /*
+ * Nothing we can do.
+ * XXX - is there a way to find out whether an adapter has
+ * something plugged into it?
+ */
+ return (0);
+}
+
/*
* In Solaris, the "standard" mechanism" i.e SIOCGLIFCONF will only find
* network links that are plumbed and are up. dlpi_walk(3DLPI) will find
diff --git a/pcap-linux.c b/pcap-linux.c
index a33f9977..5deff8c1 100644
--- a/pcap-linux.c
+++ b/pcap-linux.c
@@ -2601,6 +2601,157 @@ can_be_bound(const char *name _U_)
return (1);
}
+/*
+ * Get additional flags for a device, using SIOCGIFMEDIA.
+ */
+int
+get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf)
+{
+ int sock;
+ char *pathstr;
+ FILE *fh;
+ unsigned int arptype;
+ struct ifreq ifr;
+ struct ethtool_value info;
+
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock == -1) {
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno,
+ "Can't create socket to get ethtool information for %s",
+ name);
+ return -1;
+ }
+
+ /*
+ * OK, what type of network is this?
+ * In particular, is it wired or wireless?
+ */
+ if (is_wifi(sock, name)) {
+ /*
+ * Wi-Fi, hence wireless.
+ */
+ *flags |= PCAP_IF_WIRELESS;
+ } else {
+ /*
+ * OK, what does /sys/class/net/{if}/type contain?
+ * (We don't use that for Wi-Fi, as it'll report
+ * "Ethernet", i.e. ARPHRD_ETHER, for non-monitor-
+ * mode devices.)
+ */
+ if (asprintf(&pathstr, "/sys/class/net/%s/type", name) == -1) {
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "%s: Can't generate path name string for /sys/class/net device",
+ device);
+ close(sock);
+ return -1;
+ }
+ fh = fopen(pathstr, "r");
+ if (fh != NULL) {
+ if (scanf(fh, "%u", &arptype) == 1) {
+ /*
+ * OK, we got an ARPHRD_ type; what is it?
+ */
+ switch (arptype) {
+
+ case ARPHRD_LOOPBACK;
+ /*
+ * These are types to which
+ * "connected" and "disconnected"
+ * don't apply, so don't bother
+ * asking about it.
+ *
+ * XXX - add other types?
+ */
+ close(sock);
+ return 0;
+
+ case ARPHRD_IRDA:
+ case ARPHRD_IEEE80211:
+ case ARPHRD_IEEE80211_PRISM:
+ case ARPHRD_IEEE80211_RADIOTAP:
+ case ARPHRD_IEEE802154:
+ case ARPHRD_IEEE802154_MONITOR:
+ case ARPHRD_6LOWPAN:
+ /*
+ * Various wireless types.
+ */
+ *flags |= PCAP_IF_WIRELESS;
+ break;
+ }
+ }
+ fclose(fh);
+ }
+ }
+ free(pathstr);
+
+#ifdef ETHTOOL_GLINK
+ memset(&ifr, 0, sizeof(ifr));
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ info.cmd = ETHTOOL_GLINK;
+ ifr.ifr_data = (caddr_t)&info;
+ if (ioctl(sock, SIOCETHTOOL, &ifr) == -1) {
+ int save_errno = errno;
+
+ switch (save_errno) {
+
+ case EOPNOTSUPP:
+ case EINVAL:
+ /*
+ * OK, this OS version or driver doesn't support
+ * asking for this information.
+ * XXX - distinguish between "this doesn't
+ * support ethtool at all because it's not
+ * that type of device" vs. "this doesn't
+ * support ethtool even though it's that
+ * type of device", and return "unknown".
+ */
+ *flags |= PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE;
+ close(sock);
+ return 0;
+
+ case ENODEV:
+ /*
+ * OK, no such device.
+ * The user will find that out when they try to
+ * activate the device; just say "OK" and
+ * don't set anything.
+ */
+ close(sock);
+ return 0;
+
+ default:
+ /*
+ * Other error.
+ */
+ pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+ save_errno,
+ "%s: SIOCETHTOOL(ETHTOOL_GLINK) ioctl failed",
+ device);
+ close(sock);
+ return -1;
+ }
+ }
+
+ /*
+ * Is it connected?
+ */
+ if (info.data) {
+ /*
+ * It's connected.
+ */
+ *flags |= PCAP_IF_CONNECTION_STATUS_CONNECTED;
+ } else {
+ /*
+ * It's disconnected.
+ */
+ *flags |= PCAP_IF_CONNECTION_STATUS_DISCONNECTED;
+ }
+#endif
+
+ close(sock);
+ return 0;
+}
+
int
pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf)
{
@@ -2633,8 +2784,12 @@ pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf)
/*
* Add the "any" device.
+ * As it refers to all network devices, not to any particular
+ * network device, the notion of "connected" vs. "disconnected"
+ * doesn't apply.
*/
- if (add_dev(devlistp, "any", PCAP_IF_UP|PCAP_IF_RUNNING,
+ if (add_dev(devlistp, "any",
+ PCAP_IF_UP|PCAP_IF_RUNNING|PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE,
any_descr, errbuf) == NULL)
return (-1);
diff --git a/pcap-netfilter-linux.c b/pcap-netfilter-linux.c
index ee4f0188..d5c5dcdc 100644
--- a/pcap-netfilter-linux.c
+++ b/pcap-netfilter-linux.c
@@ -743,9 +743,17 @@ netfilter_findalldevs(pcap_if_list_t *devlistp, char *err_str)
}
close(sock);
- if (add_dev(devlistp, NFLOG_IFACE, 0, "Linux netfilter log (NFLOG) interface", err_str) == NULL)
+ /*
+ * The notion of "connected" vs. "disconnected" doesn't apply.
+ * XXX - what about "up" and "running"?
+ */
+ if (add_dev(devlistp, NFLOG_IFACE,
+ PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE,
+ "Linux netfilter log (NFLOG) interface", err_str) == NULL)
return -1;
- if (add_dev(devlistp, NFQUEUE_IFACE, 0, "Linux netfilter queue (NFQUEUE) interface", err_str) == NULL)
+ if (add_dev(devlistp, NFQUEUE_IFACE,
+ PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE,
+ "Linux netfilter queue (NFQUEUE) interface", err_str) == NULL)
return -1;
return 0;
}
diff --git a/pcap-nit.c b/pcap-nit.c
index 41b550de..f41b8edc 100644
--- a/pcap-nit.c
+++ b/pcap-nit.c
@@ -390,6 +390,17 @@ can_be_bound(const char *name _U_)
}
int
+get_if_flags(const char *name _U_, bpf_u_int32 flags _U_, char *errbuf _U_)
+{
+ /*
+ * Nothing we can do.
+ * XXX - is there a way to find out whether an adapter has
+ * something plugged into it?
+ */
+ return (0);
+}
+
+int
pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf)
{
return (pcap_findalldevs_interfaces(devlistp, errbuf, can_be_bound));
diff --git a/pcap-npf.c b/pcap-npf.c
index 1419470b..f41f956f 100644
--- a/pcap-npf.c
+++ b/pcap-npf.c
@@ -127,6 +127,63 @@ PacketGetMonitorMode(PCHAR AdapterName _U_)
#endif
static int
+oid_get_request(ADAPTER *adapter, bpf_u_int32 oid, void *data, size_t *lenp,
+ char *errbuf)
+{
+ PACKET_OID_DATA *oid_data_arg;
+ char errbuf[PCAP_ERRBUF_SIZE+1];
+
+ /*
+ * Allocate a PACKET_OID_DATA structure to hand to PacketRequest().
+ * It should be big enough to hold "*lenp" bytes of data; it
+ * will actually be slightly larger, as PACKET_OID_DATA has a
+ * 1-byte data array at the end, standing in for the variable-length
+ * data that's actually there.
+ */
+ oid_data_arg = malloc(sizeof (PACKET_OID_DATA) + *lenp);
+ if (oid_data_arg == NULL) {
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "Couldn't allocate argument buffer for PacketRequest");
+ return (PCAP_ERROR);
+ }
+
+ /*
+ * No need to copy the data - we're doing a fetch.
+ */
+ oid_data_arg->Oid = oid;
+ oid_data_arg->Length = (ULONG)(*lenp); /* XXX - check for ridiculously large value? */
+ if (!PacketRequest(adapter, FALSE, oid_data_arg)) {
+ int status;
+ DWORD request_error;
+
+ request_error = GetLastError();
+ if (request_error == NDIS_STATUS_INVALID_OID ||
+ request_error == NDIS_STATUS_NOT_SUPPORTED ||
+ request_error == NDIS_STATUS_NOT_RECOGNIZED)
+ status = PCAP_ERROR_OPERATION_NOTSUP;
+ else
+ status = PCAP_ERROR;
+ pcap_win32_err_to_str(request_error, errbuf);
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "Error calling PacketRequest: %s", errbuf);
+ free(oid_data_arg);
+ return (status);
+ }
+
+ /*
+ * Get the length actually supplied.
+ */
+ *lenp = oid_data_arg->Length;
+
+ /*
+ * Copy back the data we fetched.
+ */
+ memcpy(data, oid_data_arg->Data, *lenp);
+ free(oid_data_arg);
+ return (0);
+}
+
+static int
pcap_stats_win32(pcap_t *p, struct pcap_stat *ps)
{
struct pcap_win *pw = p->priv;
@@ -275,47 +332,8 @@ static int
pcap_oid_get_request_win32(pcap_t *p, bpf_u_int32 oid, void *data, size_t *lenp)
{
struct pcap_win *pw = p->priv;
- PACKET_OID_DATA *oid_data_arg;
- char errbuf[PCAP_ERRBUF_SIZE+1];
- /*
- * Allocate a PACKET_OID_DATA structure to hand to PacketRequest().
- * It should be big enough to hold "*lenp" bytes of data; it
- * will actually be slightly larger, as PACKET_OID_DATA has a
- * 1-byte data array at the end, standing in for the variable-length
- * data that's actually there.
- */
- oid_data_arg = malloc(sizeof (PACKET_OID_DATA) + *lenp);
- if (oid_data_arg == NULL) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "Couldn't allocate argument buffer for PacketRequest");
- return (PCAP_ERROR);
- }
-
- /*
- * No need to copy the data - we're doing a fetch.
- */
- oid_data_arg->Oid = oid;
- oid_data_arg->Length = (ULONG)(*lenp); /* XXX - check for ridiculously large value? */
- if (!PacketRequest(pw->adapter, FALSE, oid_data_arg)) {
- pcap_win32_err_to_str(GetLastError(), errbuf);
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "Error calling PacketRequest: %s", errbuf);
- free(oid_data_arg);
- return (PCAP_ERROR);
- }
-
- /*
- * Get the length actually supplied.
- */
- *lenp = oid_data_arg->Length;
-
- /*
- * Copy back the data we fetched.
- */
- memcpy(data, oid_data_arg->Data, *lenp);
- free(oid_data_arg);
- return (0);
+ return (oid_get_request(pw->adapter, oid, data, lenp, p->errbuf));
}
static int
@@ -1409,6 +1427,173 @@ pcap_add_if_win32(pcap_if_list_t *devlistp, char *name, bpf_u_int32 flags,
}
int
+get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf)
+{
+ ADAPTER *adapter;
+ int status;
+#ifdef OID_GEN_PHYSICAL_MEDIUM
+ NDIS_PHYSICAL_MEDIUM phys_medium;
+ bpf_u_int32 gen_physical_medium_oids[] = {
+ #ifdef OID_GEN_PHYSICAL_MEDIUM_EX
+ OID_GEN_PHYSICAL_MEDIUM_EX,
+ #endif
+ OID_GEN_PHYSICAL_MEDIUM
+ };
+#define N_GEN_PHYSICAL_MEDIUM_OIDS (sizeof gen_physical_medium_oids / sizeof gen_physical_medium_oids[0])
+#endif /* OID_GEN_PHYSICAL_MEDIUM */
+#ifdef OID_GEN_MEDIA_CONNECT_STATUS_EX
+ NET_IF_MEDIA_CONNECT_STATE connect_state_ex;
+#endif
+ int connect_state;
+
+ if (*flags & PCAP_IF_LOOPBACK) {
+ /*
+ * Loopback interface, so the connection status doesn't
+ * apply. and it's not wireless (or wired, for that
+ * matter...).
+ */
+ *flags |= PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE;
+ return (0);
+ }
+
+ /*
+ * We need to open the adapter to get this information.
+ */
+ adapter = PacketOpenAdapter(name);
+ if (adapter == NULL) {
+ /*
+ * Give up; if they try to open this device, it'll fail.
+ */
+ return (0);
+ }
+
+ /*
+ * Get the network type.
+ */
+#ifdef OID_GEN_PHYSICAL_MEDIUM
+ /*
+ * Try the OIDs we have for this, in order.
+ */
+ for (i = 0; i < N_GEN_PHYSICAL_MEDIUM_OIDS; i++) {
+ len = sizeof (phys_medium);
+ status = oid_get_request(adapter, gen_physical_medium_oids[i],
+ &phys_medium, &len, errbuf);
+ if (status == PCAP_ERROR) {
+ /*
+ * Failed with a hard error.
+ */
+ PacketCloseAdapter(adapter);
+ return (-1);
+ }
+ if (status == 0) {
+ /*
+ * Success.
+ */
+ break;
+ }
+ /*
+ * Failed with "I don't support that OID", so try the
+ * next one, if we have a next one.
+ */
+ }
+ if (status == 0) {
+ /*
+ * We got the physical medium.
+ */
+ switch (phys_medium) {
+
+ case NdisPhysicalMediumWirelessLan:
+ case NdisPhysicalMediumWirelessWan:
+ case NdisPhysicalMediumNative802_11:
+ case NdisPhysicalMediumBluetooth:
+ case NdisPhysicalMediumUWB:
+ case NdisPhysicalMediumIrda:
+ /*
+ * Wireless.
+ */
+ *flags |= PCAP_IF_WIRELESS;
+ break;
+ }
+ }
+#endif
+
+ /*
+ * Get the connection status.
+ */
+#ifdef OID_GEN_MEDIA_CONNECT_STATUS_EX
+ len = sizeof(connect_state_ex);
+ status = oid_get_request(adapter, OID_GEN_MEDIA_CONNECT_STATUS_EX,
+ &connect_state_ex, &len, errbuf);
+ if (status == PCAP_ERROR) {
+ /*
+ * Fatal error.
+ */
+ PacketCloseAdapter(adapter);
+ return (-1);
+ }
+ if (status == 0) {
+ switch (connect_state_ex) {
+
+ case MediaConnectStateConnected:
+ /*
+ * It's connected.
+ */
+ *flags |= PCAP_IF_CONNECTION_STATUS_CONNECTED;
+ break;
+
+ case MediaConnectStateDisconnected:
+ /*
+ * It's disconnected.
+ */
+ *flags |= PCAP_IF_CONNECTION_STATUS_DISCONNECTED;
+ break;
+ }
+ }
+#else
+ /*
+ * OID_GEN_MEDIA_CONNECT_STATUS_EX isn't supported because it's
+ * not in our SDK.
+ */
+ status = PCAP_ERROR_OPERATION_NOTSUP;
+#endif
+ if (status == PCAP_ERROR_OPERATION_NOTSUP) {
+ /*
+ * OK, OID_GEN_MEDIA_CONNECT_STATUS_EX isn't supported,
+ * try OID_GEN_MEDIA_CONNECT_STATUS.
+ */
+ status = oid_get_request(adapter, OID_GEN_MEDIA_CONNECT_STATUS,
+ &connect_state, &len, errbuf);
+ if (status == PCAP_ERROR) {
+ /*
+ * Fatal error.
+ */
+ PacketCloseAdapter(adapter);
+ return (-1);
+ }
+ if (status == 0) {
+ switch (connect_state) {
+
+ case NdisMediaStateConnected:
+ /*
+ * It's connected.
+ */
+ *flags |= PCAP_IF_CONNECTION_STATUS_CONNECTED;
+ break;
+
+ case NdisMediaStateDisconnected:
+ /*
+ * It's disconnected.
+ */
+ *flags |= PCAP_IF_CONNECTION_STATUS_DISCONNECTED;
+ break;
+ }
+ }
+ }
+ PacketCloseAdapter(adapter);
+ return (0);
+}
+
+int
pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf)
{
int ret = 0;
@@ -1507,6 +1692,14 @@ pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf)
#endif
/*
+ * XXX - get the link state here.
+ * Does the OID we want depend on NDIS 5 vs. NDIS 6?
+ * If so, that means that there should be a packet.dll
+ * API for this.
+ * Set the appropriate bits in flags.
+ */
+
+ /*
* Add an entry for this interface.
*/
if (pcap_add_if_win32(devlistp, name, flags, desc,
diff --git a/pcap-null.c b/pcap-null.c
index 92a5e2d8..2f614837 100644
--- a/pcap-null.c
+++ b/pcap-null.c
@@ -37,6 +37,17 @@ pcap_create_interface(const char *device _U_, char *ebuf)
}
int
+get_if_flags(const char *name _U_, bpf_u_int32 flags _U_, char *errbuf _U_)
+{
+ /*
+ * Nothing we can do.
+ * XXX - is there a way to find out whether an adapter has
+ * something plugged into it?
+ */
+ return (0);
+}
+
+int
pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf)
{
/*
diff --git a/pcap-pf.c b/pcap-pf.c
index f01de258..c3c8db94 100644
--- a/pcap-pf.c
+++ b/pcap-pf.c
@@ -559,6 +559,17 @@ can_be_bound(const char *name _U_)
}
int
+get_if_flags(const char *name _U_, bpf_u_int32 flags _U_, char *errbuf _U_)
+{
+ /*
+ * Nothing we can do.
+ * XXX - is there a way to find out whether an adapter has
+ * something plugged into it?
+ */
+ return (0);
+}
+
+int
pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf)
{
return (pcap_findalldevs_interfaces(devlistp, errbuf, can_be_bound));
diff --git a/pcap-rdmasniff.c b/pcap-rdmasniff.c
index 512d8431..c50fe3fd 100644
--- a/pcap-rdmasniff.c
+++ b/pcap-rdmasniff.c
@@ -420,6 +420,10 @@ rdmasniff_findalldevs(pcap_if_list_t *devlistp, char *err_str)
}
for (i = 0; i < numdev; ++i) {
+ /*
+ * XXX - do the notions of "up", "running", or
+ * "connected" apply here?
+ */
if (!add_dev(devlistp, dev_list[i]->name, 0, "RDMA sniffer", err_str)) {
ret = -1;
goto out;
diff --git a/pcap-septel.c b/pcap-septel.c
index f812154c..0471153f 100644
--- a/pcap-septel.c
+++ b/pcap-septel.c
@@ -275,6 +275,9 @@ static int septel_stats(pcap_t *p, struct pcap_stat *ps) {
int
septel_findalldevs(pcap_if_list_t *devlistp, char *errbuf)
{
+ /*
+ * XXX - do the notions of "up", "running", or "connected" apply here?
+ */
if (add_dev(devlistp,"septel",0,"Intel/Septel device",errbuf) == NULL)
return -1;
return 0;
diff --git a/pcap-snf.c b/pcap-snf.c
index 7bc8d5fd..4eae0b39 100644
--- a/pcap-snf.c
+++ b/pcap-snf.c
@@ -439,6 +439,12 @@ snf_findalldevs(pcap_if_list_t *devlistp, char *errbuf)
} else {
/*
* No. Add an entry for it.
+ *
+ * XXX - is there a notion of "up" or "running",
+ * and can we determine whether something's
+ * plugged into the adapter and set
+ * PCAP_IF_CONNECTION_STATUS_CONNECTED or
+ * PCAP_IF_CONNECTION_STATUS_DISCONNECTED?
*/
dev = add_dev(devlistp, ifa->snf_ifa_name, 0, desc,
errbuf);
@@ -481,7 +487,18 @@ snf_findalldevs(pcap_if_list_t *devlistp, char *errbuf)
(void)pcap_snprintf(name,MAX_DESC_LENGTH,"snf%d",allports);
(void)pcap_snprintf(desc,MAX_DESC_LENGTH,"Myricom Merge Bitmask All Ports snf%d",
allports);
- if (add_dev(devlistp, name, 0, desc, errbuf) == NULL)
+ /*
+ * XXX - is there any notion of "up" and "running" that
+ * would apply to this device, given that it handles
+ * multiple ports?
+ *
+ * Presumably, there's no notion of "connected" vs.
+ * "disconnected", as "is this plugged into a network?"
+ * would be a per-port property.
+ */
+ if (add_dev(devlistp, name,
+ PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE, desc,
+ errbuf) == NULL)
return (-1);
/*
* XXX - should we give it a list of addresses with all
diff --git a/pcap-snit.c b/pcap-snit.c
index 9da8573d..2fa809aa 100644
--- a/pcap-snit.c
+++ b/pcap-snit.c
@@ -479,6 +479,17 @@ can_be_bound(const char *name _U_)
}
int
+get_if_flags(const char *name _U_, bpf_u_int32 flags _U_, char *errbuf _U_)
+{
+ /*
+ * Nothing we can do.
+ * XXX - is there a way to find out whether an adapter has
+ * something plugged into it?
+ */
+ return (0);
+}
+
+int
pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf)
{
return (pcap_findalldevs_interfaces(devlistp, errbuf, can_be_bound));
diff --git a/pcap-snoop.c b/pcap-snoop.c
index 2fe7715b..aa84b27c 100644
--- a/pcap-snoop.c
+++ b/pcap-snoop.c
@@ -440,6 +440,17 @@ can_be_bound(const char *name _U_)
}
int
+get_if_flags(const char *name _U_, bpf_u_int32 flags _U_, char *errbuf _U_)
+{
+ /*
+ * Nothing we can do.
+ * XXX - is there a way to find out whether an adapter has
+ * something plugged into it?
+ */
+ return (0);
+}
+
+int
pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf)
{
return (pcap_findalldevs_interfaces(devlistp, errbuf, can_be_bound));
diff --git a/pcap-usb-linux.c b/pcap-usb-linux.c
index 6e0e3b14..6f8adf65 100644
--- a/pcap-usb-linux.c
+++ b/pcap-usb-linux.c
@@ -230,13 +230,31 @@ usb_dev_add(pcap_if_list_t *devlistp, int n, char *err_str)
char dev_name[10];
char dev_descr[30];
pcap_snprintf(dev_name, 10, USB_IFACE"%d", n);
- if (n == 0)
- pcap_snprintf(dev_descr, 30, "All USB buses");
- else
+ /*
+ * XXX - is there any notion of "up" and "running"?
+ */
+ if (n == 0) {
+ /*
+ * As this refers to all buses, there's no notion of
+ * "connected" vs. "disconnected", as that's a property
+ * that would apply to a particular USB interface.
+ */
+ if (add_dev(devlistp, dev_name,
+ PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE,
+ "All USB buses", err_str) == NULL)
+ return -1;
+ } else {
+ /*
+ * XXX - is there a way to determine whether anything's
+ * plugged into this bus interface or not, and set
+ * PCAP_IF_CONNECTION_STATUS_CONNECTED or
+ * PCAP_IF_CONNECTION_STATUS_DISCONNECTED?
+ */
pcap_snprintf(dev_descr, 30, "USB bus number %d", n);
+ if (add_dev(devlistp, dev_name, 0, dev_descr, err_str) == NULL)
+ return -1;
+ }
- if (add_dev(devlistp, dev_name, 0, dev_descr, err_str) == NULL)
- return -1;
return 0;
}
diff --git a/pcap.c b/pcap.c
index 64d64ed7..b2c27909 100644
--- a/pcap.c
+++ b/pcap.c
@@ -567,8 +567,28 @@ get_figure_of_merit(pcap_if_t *dev)
n |= 0x80000000;
if (!(dev->flags & PCAP_IF_UP))
n |= 0x40000000;
- if (dev->flags & PCAP_IF_LOOPBACK)
+
+ /*
+ * Give non-wireless interfaces that aren't disconnected a better
+ * figure of merit than interfaces that are disconnected, as
+ * "disconnected" should indicate that the interface isn't
+ * plugged into a network and thus won't give you any traffic.
+ *
+ * For wireless interfaces, it means "associated with a network",
+ * which we presume not to necessarily prevent capture, as you
+ * might run the adapter in some flavor of monitor mode.
+ */
+ if (!(dev->flags & PCAP_IF_WIRELESS) &&
+ (dev->flags & PCAP_IF_CONNECTION_STATUS) == PCAP_IF_CONNECTION_STATUS_DISCONNECTED)
n |= 0x20000000;
+
+ /*
+ * Sort loopback devices after non-loopback devices, *except* for
+ * disconnected devices.
+ */
+ if (dev->flags & PCAP_IF_LOOPBACK)
+ n |= 0x10000000;
+
return (n);
}
@@ -992,7 +1012,21 @@ find_or_add_dev(pcap_if_list_t *devlistp, const char *name, bpf_u_int32 flags,
}
/*
- * No, we didn't find it. Try to add it to the list of devices.
+ * No, we didn't find it.
+ */
+
+ /*
+ * Try to get additional flags for the device.
+ */
+ if (get_if_flags(name, &flags, errbuf) == -1) {
+ /*
+ * Failed.
+ */
+ return (NULL);
+ }
+
+ /*
+ * Now, try to add it to the list of devices.
*/
return (add_dev(devlistp, name, flags, description, errbuf));
}
@@ -3278,6 +3312,9 @@ pcap_statustostr(int errnum)
case PCAP_ERROR_TSTAMP_PRECISION_NOTSUP:
return ("That device doesn't support that time stamp precision");
+
+ case PCAP_ERROR_OPERATION_NOTSUP:
+ return ("That device doesn't support that operation");
}
(void)pcap_snprintf(ebuf, sizeof ebuf, "Unknown error: %d", errnum);
return(ebuf);
diff --git a/pcap/pcap.h b/pcap/pcap.h
index 94ca2114..4ea9592f 100644
--- a/pcap/pcap.h
+++ b/pcap/pcap.h
@@ -260,9 +260,15 @@ struct pcap_if {
bpf_u_int32 flags; /* PCAP_IF_ interface flags */
};
-#define PCAP_IF_LOOPBACK 0x00000001 /* interface is loopback */
-#define PCAP_IF_UP 0x00000002 /* interface is up */
-#define PCAP_IF_RUNNING 0x00000004 /* interface is running */
+#define PCAP_IF_LOOPBACK 0x00000001 /* interface is loopback */
+#define PCAP_IF_UP 0x00000002 /* interface is up */
+#define PCAP_IF_RUNNING 0x00000004 /* interface is running */
+#define PCAP_IF_WIRELESS 0x00000008 /* interface is wireless (*NOT* necessarily Wi-Fi!) */
+#define PCAP_IF_CONNECTION_STATUS 0x00000030 /* connection status: */
+#define PCAP_IF_CONNECTION_STATUS_UNKNOWN 0x00000000 /* unknown */
+#define PCAP_IF_CONNECTION_STATUS_CONNECTED 0x00000010 /* connected */
+#define PCAP_IF_CONNECTION_STATUS_DISCONNECTED 0x00000020 /* disconnected */
+#define PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE 0x00000030 /* not applicable */
/*
* Representation of an interface address.
@@ -296,6 +302,7 @@ typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *,
#define PCAP_ERROR_CANTSET_TSTAMP_TYPE -10 /* this device doesn't support setting the time stamp type */
#define PCAP_ERROR_PROMISC_PERM_DENIED -11 /* you don't have permission to capture in promiscuous mode */
#define PCAP_ERROR_TSTAMP_PRECISION_NOTSUP -12 /* the requested time stamp precision is not supported */
+#define PCAP_ERROR_OPERATION_NOTSUP -13 /* OID operation not supported by adapter */
/*
* Warning codes for the pcap API.
diff --git a/pcap_findalldevs.3pcap b/pcap_findalldevs.3pcap
index 2dd3e59b..9523e008 100644
--- a/pcap_findalldevs.3pcap
+++ b/pcap_findalldevs.3pcap
@@ -98,6 +98,30 @@ set if the device is up
.TP
.B PCAP_IF_RUNNING
set if the device is running
+.TP
+.B PCAP_IF_WIRELESS
+set if the device is a wireless interface; this includes IrDA as well as
+radio-based networks such as IEEE 802.15.4 and IEEE 802.11, so it
+doesn't just mean Wi-Fi
+.TP
+.B PCAP_IF_CONNECTION_STATUS
+a bitmask for an indication of whether the adapter is connected or not;
+for wireless interfaces, "connected" means "associated with a network"
+.TP
+The possible values for the connection status bits are:
+.TP
+.B PCAP_IF_CONNECTION_STATUS_UNKNOWN
+it's unknown whether the adapter is connected or not
+.TP
+.B PCAP_IF_CONNECTION_STATUS_CONNECTED
+the adapter is connected
+.TP
+.B PCAP_IF_CONNECTION_STATUS_DISCONNECTED
+the adapter is disconnected
+.TP
+.B PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE
+the notion of "connected" and "disconnected" don't apply to this
+interface; for example, it doesn't apply to a loopback device
.RE
.RE
.PP
diff --git a/testprogs/findalldevstest.c b/testprogs/findalldevstest.c
index 6a221f25..4e085f8c 100644
--- a/testprogs/findalldevstest.c
+++ b/testprogs/findalldevstest.c
@@ -190,6 +190,45 @@ static int ifprint(pcap_if_t *d)
printf("%sLOOPBACK", sep);
sep = ", ";
}
+ if (d->flags & PCAP_IF_WIRELESS) {
+ printf("%sWIRELESS", sep);
+ switch (d->flags & PCAP_IF_CONNECTION_STATUS) {
+
+ case PCAP_IF_CONNECTION_STATUS_UNKNOWN:
+ printf(" (association unknown)");
+ break;
+
+ case PCAP_IF_CONNECTION_STATUS_CONNECTED:
+ printf(" (associated)");
+ break;
+
+ case PCAP_IF_CONNECTION_STATUS_DISCONNECTED:
+ printf(" (not associated)");
+ break;
+
+ case PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE:
+ break;
+ }
+ } else {
+ switch (d->flags & PCAP_IF_CONNECTION_STATUS) {
+
+ case PCAP_IF_CONNECTION_STATUS_UNKNOWN:
+ printf(" (connection status unknown)");
+ break;
+
+ case PCAP_IF_CONNECTION_STATUS_CONNECTED:
+ printf(" (connected)");
+ break;
+
+ case PCAP_IF_CONNECTION_STATUS_DISCONNECTED:
+ printf(" (disconnectted)");
+ break;
+
+ case PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE:
+ break;
+ }
+ }
+ sep = ", ";
printf("\n");
for(a=d->addresses;a;a=a->next) {