]> The Tcpdump Group git mirrors - libpcap/commitdiff
Add more interface flags to pcap_findalldevs().
authorGuy Harris <[email protected]>
Sun, 29 Apr 2018 22:02:09 +0000 (15:02 -0700)
committerGuy Harris <[email protected]>
Sun, 29 Apr 2018 22:02:09 +0000 (15:02 -0700)
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.

24 files changed:
pcap-bpf.c
pcap-bt-linux.c
pcap-dag.c
pcap-dbus.c
pcap-dlpi.c
pcap-dos.c
pcap-int.h
pcap-libdlpi.c
pcap-linux.c
pcap-netfilter-linux.c
pcap-nit.c
pcap-npf.c
pcap-null.c
pcap-pf.c
pcap-rdmasniff.c
pcap-septel.c
pcap-snf.c
pcap-snit.c
pcap-snoop.c
pcap-usb-linux.c
pcap.c
pcap/pcap.h
pcap_findalldevs.3pcap
testprogs/findalldevstest.c

index bb2cbd152fe53ec7bc56b52acd6788b3df591e38..eb2b4a747e301903775d5bd97f29a4c80e1937bb 100644 (file)
@@ -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)
 {
index 3cd4f5000f11d14886a205e3ac1ca74e7a5492f0..07ed1c73de5a47cdec8601c5116641a3b0d2c208 100644 (file)
@@ -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:
index ae37b10c21494e5832306977b4d2fb48e0c2cf33..931f2f3ae795e5b11a25bd48c934c78be45549d0 100644 (file)
@@ -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);
 }
 
 /*
index c23640539b65a1ba70d1d5448a68dce52493088c..1252975e9ac7b31d71cf6270b98fcd8a25cbf8b6 100644 (file)
@@ -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;
 }
index bbf75b966de3c17ac1a1c8a43b7d74d613b8bc9a..abf72f2cf0509b03b02a7f0f11dbf27f9e01684f 100644 (file)
@@ -1049,6 +1049,17 @@ is_dlpi_interface(const char *name)
        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);
+}
+
 int
 pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf)
 {
@@ -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);
        }
index 54690d2af7885024a0946e2e0b59bf48cc9196a3..b1b9ecd72b16ef5967d3b42769fb7a1452768174 100644 (file)
@@ -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)
index 7877b6076511d7534a47b246cda9bcef0bfd4293..6cd8740ee95353bdd6b9a5a449328343c600ea7a 100644 (file)
@@ -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 *));
index 99ca9be7d7dab3e8f1c0928090bc689663147817..2d1b58f387c860830a95212c021aacab1bb608c3 100644 (file)
@@ -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
index a33f9977a91f5c728b94ecbdb5ac0045999fbb1a..5deff8c1090b2a717bb57c1d277c44a0eafe0ac7 100644 (file)
@@ -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);
 
index ee4f01883b9ab748e35f9f2713eca222e8993765..d5c5dcdc485040adcbdf85805e600801e7092a6d 100644 (file)
@@ -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;
 }
index 41b550deadbf80a3886f5d70d28fd7115189db81..f41b8edc583bf0ab65976d52269dbd4ae73c76a4 100644 (file)
@@ -389,6 +389,17 @@ can_be_bound(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);
+}
+
 int
 pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf)
 {
index 1419470b4a077dbd48a24b99a1e5e158de2db302..f41f956f05515b5a4e6b03caebcf1c92d4ebed81 100644 (file)
@@ -126,6 +126,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)
 {
@@ -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
@@ -1408,6 +1426,173 @@ pcap_add_if_win32(pcap_if_list_t *devlistp, char *name, bpf_u_int32 flags,
        return (res);
 }
 
+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)
 {
@@ -1506,6 +1691,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.
                 */
index 92a5e2d8649b657bfbd8ce8eeb12b8eb4e9b2ec8..2f614837ed3bf172e3588c4f43c35dc06b6119a9 100644 (file)
@@ -36,6 +36,17 @@ pcap_create_interface(const char *device _U_, char *ebuf)
        return (NULL);
 }
 
+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)
 {
index f01de258cb5cac4aaa221994f5b85af7e4b193f5..c3c8db9470db3c13d5a58d6efac92fdb34a9ef77 100644 (file)
--- a/pcap-pf.c
+++ b/pcap-pf.c
@@ -558,6 +558,17 @@ can_be_bound(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);
+}
+
 int
 pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf)
 {
index 512d843158bbbbe8dda6fd858d693dfe6ef2a7e6..c50fe3fd693f0e2cf6458bf2b0db05b5af12af1b 100644 (file)
@@ -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;
index f812154cf57d54bbdd4829c05755d862ae2ed95d..0471153fdc7a6a667fbad8667ecfe50ed9a9cc27 100644 (file)
@@ -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;
index 7bc8d5fdb15089e56ddb05363528bf536a9ba8b4..4eae0b3993161ab6ef6d593010c1125864e44e1d 100644 (file)
@@ -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
index 9da8573d96fd55cd0c3af33c07a7ae8d58f8faeb..2fa809aaee5f3cbe30be9e70155cd0119d8f2e6e 100644 (file)
@@ -478,6 +478,17 @@ can_be_bound(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);
+}
+
 int
 pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf)
 {
index 2fe7715bc14686e87f9e409c9c024d7515c4591b..aa84b27ca4dfb32e34b80477a443a940bf20ac76 100644 (file)
@@ -439,6 +439,17 @@ can_be_bound(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);
+}
+
 int
 pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf)
 {
index 6e0e3b1486999e3d0a17c508fda6b34e07037659..6f8adf65eab579e43b699786b31700b72b127347 100644 (file)
@@ -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 64d64ed75d455fb23880153e8d33a6e227b9ffbe..b2c2790968c8b74d6a673f56f3bfddd618b9160f 100644 (file)
--- 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);
index 94ca2114d81ca9b2c271ef4eab593bacb2878a53..4ea9592f484025e5c8389894015592b9121a8449 100644 (file)
@@ -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.
index 2dd3e59b9c9314551aee0df6efb2a847d0aebbf2..9523e008a69c34f12667b14ae04195465a2bb3a2 100644 (file)
@@ -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
index 6a221f2599f75e31c4c2a7910b6ec4b9df2d061d..4e085f8c62e3dfdb972b29da96e8c382bb2b0fc3 100644 (file)
@@ -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) {