text: /* capture_if_details_dlg.c
   * Routines for capture interface details window (only Win32!)
   *
   * Wireshark - Network traffic analyzer
   * By Gerald Combs <gerald@wireshark.org>
   * Copyright 1998 Gerald Combs
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License
   * as published by the Free Software Foundation; either version 2
   * of the License, or (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
   */
  
  #include "config.h"
  
  
  #if defined HAVE_LIBPCAP && defined _WIN32
  
  #include <time.h>
  #include <string.h>
  
  #include <gtk/gtk.h>
  
  #include "epan/value_string.h"
  #include "epan/addr_resolv.h"
  
  #include "wsutil/str_util.h"
  
  #include "../file.h"
  #include "ui/capture.h"
  
  #include "simple_dialog.h"
  
  #include "ui/gtk/main.h"
  #include "ui/gtk/dlg_utils.h"
  #include "ui/gtk/gui_utils.h"
  #include "ui/gtk/help_dlg.h"
  #include "ui/gtk/capture_if_details_dlg_win32.h"
  
  #include <winsock2.h>    /* Needed here to force a definition of WINVER           */
                           /* for some (all ?) Microsoft compilers newer than vc6.  */
                           /* (If windows.h were used instead, there might be       */
                           /*  issues re winsock.h included before winsock2.h )     */
  #include <windowsx.h>
  
  #ifdef HAVE_NTDDNDIS_H
  #include <Ntddndis.h>
  #endif
  
  #include "caputils/capture_win_ifnames.h"
  
  #include "caputils/capture_wpcap_packet.h"
  
  /* packet32.h requires sockaddr_storage
   * whether sockaddr_storage is defined or not depends on the Platform SDK
   * version installed. The only one not defining it is the SDK that comes
   * with MSVC 6.0 (WINVER 0x0400).
   *
   * copied from RFC2553 (and slightly modified because of datatypes) ...
   * XXX - defined more than once, move this to a header file */
  #ifndef WINVER
  #error WINVER not defined ...
  #endif
  #if (WINVER <= 0x0400) && defined(_MSC_VER)
  typedef unsigned short eth_sa_family_t;
  
  /*
   * Desired design of maximum size and alignment
   */
  #define ETH_SS_MAXSIZE    128  /* Implementation specific max size */
  #define ETH_SS_ALIGNSIZE  (sizeof (gint64 /*int64_t*/))
                           /* Implementation specific desired alignment */
  /*
   * Definitions used for sockaddr_storage structure paddings design.
   */
  #define ETH_SS_PAD1SIZE   (ETH_SS_ALIGNSIZE - sizeof (eth_sa_family_t))
  #define ETH_SS_PAD2SIZE   (ETH_SS_MAXSIZE - (sizeof (eth_sa_family_t) + \
                                ETH_SS_PAD1SIZE + ETH_SS_ALIGNSIZE))
  
  struct sockaddr_storage {
      eth_sa_family_t  __ss_family;     /* address family */
      /* Following fields are implementation specific */
      char      __ss_pad1[ETH_SS_PAD1SIZE];
                /* 6 byte pad, this is to make implementation */
                /* specific pad up to alignment field that */
                /* follows explicit in the data structure */
      gint64 /*int64_t*/   __ss_align;     /* field to force desired structure */
                 /* storage alignment */
      char      __ss_pad2[ETH_SS_PAD2SIZE];
                /* 112 byte pad to achieve desired size, */
                /* _SS_MAXSIZE value minus size of ss_family */
                /* __ss_pad1, __ss_align fields is 112 */
  };
  /* ... copied from RFC2553 */
  #endif /* WINVER */
  
  #include <Packet32.h>
  
  #define DETAILS_STR_MAX     1024
  
  
  /* The informations and definitions used here are coming from various places on the web:
   *
   * ndiswrapper (various NDIS related definitions)
   *  http://cvs.sourceforge.net/viewcvs.py/ndiswrapper/ndiswrapper/driver/
   *
   * ReactOS (various NDIS related definitions)
   *  http://www.reactos.org/generated/doxygen/d2/d6d/ndis_8h-source.html
   *
   * IEEE802.11 "Detailed NDIS OID Log for a 802.11b Miniport"
   *  http://www.ndis.com/papers/ieee802_11_log.htm
   *
   * FreeBSD (various NDIS related definitions)
   *  http://lists.freebsd.org/pipermail/p4-projects/2004-January/003433.html
   *
   * MS WHDC "Network Drivers and Windows"
   *  http://www.microsoft.com/whdc/archive/netdrv_up.mspx
   *
   * IEEE "Get IEEE 802" (the various 802.11 docs)
   *  http://standards.ieee.org/getieee802/802.11.html
   *
   * MS MSDN "Network Devices: Windows Driver Kit"
   *  http://msdn.microsoft.com/library/default.asp?url=/library/en-us/NetXP_r/hh/NetXP_r/netref_4c297a96-2ba5-41ed-ab21-b7a9cfaa9b4d.xml.asp
   *
   * MS MSDN "Microsoft Windows CE .NET 4.2 Network Driver Reference"
   *  http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wceddk40/html/cxgrfNetworkDriverReference.asp
   *
   * MS MSDN (some explanations of a special MS 802.11 Information Element)
   *  http://msdn.microsoft.com/library/default.asp?url=/library/en-us/randz/protocol/securing_public_wi-fi_hotspots.asp
   *
   * "WLANINFO fuer Windows XP"
   *  http://www-pc.uni-regensburg.de/systemsw/TOOLS/wlaninfo.htm
   */
  
  /********************************************************************************/
  /* definitions that would usually come from the windows DDK (device driver kit) */
  /* and are not part of the ntddndis.h file delivered with WinPcap */
  
  /* Required OIDs */
  #define OID_GEN_VLAN_ID                 0x0001021C
  
  /* Optional OIDs */
  #define OID_GEN_MEDIA_CAPABILITIES      0x00010201
  #define OID_GEN_PHYSICAL_MEDIUM         0x00010202
  
  /* Optional OIDs */
  #define OID_GEN_NETWORK_LAYER_ADDRESSES 0x00010118
  #define OID_GEN_TRANSPORT_HEADER_OFFSET 0x00010119
  
  /* Currently associated SSID (OID_802_11_SSID) */
  #define NDIS_ESSID_MAX_SIZE 32
  struct ndis_essid {
      ULONG length;
      UCHAR essid[NDIS_ESSID_MAX_SIZE+1];
  };
  
  
  /* some definitions needed for the following structs */
  #define NDIS_MAX_RATES_EX 16
  typedef UCHAR mac_address[/* ETH_ALEN */ 6];
  typedef UCHAR ndis_rates[NDIS_MAX_RATES_EX];
  
  /* configuration, e.g. frequency (OID_802_11_CONFIGURATION / OID_802_11_BSSID_LIST) */
  struct /*packed*/ ndis_configuration {
      ULONG length;
      ULONG beacon_period;
      ULONG atim_window;
      ULONG ds_config;
      struct ndis_configuration_fh {
          ULONG length;
          ULONG hop_pattern;
          ULONG hop_set;
          ULONG dwell_time;
      } fh_config;
  };
  
  /* bssid list item (OID_802_11_BSSID_LIST) */
  struct ndis_ssid_item {
      ULONG                     length;
      mac_address               mac;
      UCHAR                     reserved[2];
      struct ndis_essid         ssid;
      ULONG                     privacy;
      LONG                      rssi;
      UINT                      net_type;
      struct ndis_configuration config;
      UINT                      mode;
      ndis_rates                rates;
      ULONG                     ie_length;
      UCHAR                     ies[1];
  };
  
  
  /* bssid list (OID_802_11_BSSID_LIST) */
  struct ndis_bssid_list {
      ULONG                 num_items;
      struct ndis_ssid_item items[1];
  };
  
  
  /******************************************************************************/
  /* OID_TCP_TASK_OFFLOAD specific definitions that would usually come from the */
  /* windows DDK (device driver kit) and are not part of the ntddndis.h file */
  /* delivered with WinPcap */
  
  /* optional OID */
  #define OID_TCP_TASK_OFFLOAD    0xFC010201
  
  /* task id's */
  typedef enum _NDIS_TASK {
      TcpIpChecksumNdisTask,
      IpSecNdisTask,
      TcpLargeSendNdisTask,
      MaxNdisTask
  } NDIS_TASK, *PNDIS_TASK;
  
  /* TaskBuffer content on TcpIpChecksumNdisTask */
  typedef struct _NDIS_TASK_TCP_IP_CHECKSUM
  {
      struct
      {
          ULONG    IpOptionsSupported:1;
          ULONG    TcpOptionsSupported:1;
          ULONG    TcpChecksum:1;
          ULONG    UdpChecksum:1;
          ULONG    IpChecksum:1;
      } V4Transmit;
  
      struct
      {
          ULONG    IpOptionsSupported:1;
          ULONG    TcpOptionsSupported:1;
          ULONG    TcpChecksum:1;
          ULONG    UdpChecksum:1;
          ULONG    IpChecksum:1;
      } V4Receive;
  
      struct
      {
          ULONG    IpOptionsSupported:1;
          ULONG    TcpOptionsSupported:1;
          ULONG    TcpChecksum:1;
          ULONG    UdpChecksum:1;
      } V6Transmit;
  
      struct
      {
          ULONG    IpOptionsSupported:1;
          ULONG    TcpOptionsSupported:1;
          ULONG    TcpChecksum:1;
          ULONG    UdpChecksum:1;
      } V6Receive;
  } NDIS_TASK_TCP_IP_CHECKSUM, *PNDIS_TASK_TCP_IP_CHECKSUM;
  
  /* TaskBuffer content on TcpLargeSendNdisTask */
  typedef struct _NDIS_TASK_TCP_LARGE_SEND
  {
      ULONG     Version;
      ULONG     MaxOffLoadSize;
      ULONG     MinSegmentCount;
      BOOLEAN   TcpOptions;
      BOOLEAN   IpOptions;
  } NDIS_TASK_TCP_LARGE_SEND, *PNDIS_TASK_TCP_LARGE_SEND;
  
  /* Encapsulations */
  typedef enum _NDIS_ENCAPSULATION {
      UNSPECIFIED_Encapsulation,
      NULL_Encapsulation,
      IEEE_802_3_Encapsulation,
      IEEE_802_5_Encapsulation,
      LLC_SNAP_ROUTED_Encapsulation,
      LLC_SNAP_BRIDGED_Encapsulation
  } NDIS_ENCAPSULATION;
  
  /* Encapsulation format */
  typedef struct _NDIS_ENCAPSULATION_FORMAT {
      NDIS_ENCAPSULATION  Encapsulation;
      struct {
          ULONG  FixedHeaderSize : 1;
          ULONG  Reserved : 31;
      } Flags;
      ULONG  EncapsulationHeaderSize;
  } NDIS_ENCAPSULATION_FORMAT, *PNDIS_ENCAPSULATION_FORMAT;
  
  /* request struct */
  typedef struct _NDIS_TASK_OFFLOAD_HEADER
  {
      ULONG  Version;
      ULONG  Size;
      ULONG  Reserved;
      UCHAR  OffsetFirstTask;
      NDIS_ENCAPSULATION_FORMAT  EncapsulationFormat;
  } NDIS_TASK_OFFLOAD_HEADER, *PNDIS_TASK_OFFLOAD_HEADER;
  
  /* response struct */
  #define NDIS_TASK_OFFLOAD_VERSION 1
  typedef struct _NDIS_TASK_OFFLOAD
  {
      ULONG     Version;
      ULONG     Size;
      NDIS_TASK Task;
      ULONG     OffsetNextTask;
      ULONG     TaskBufferLength;
      UCHAR     TaskBuffer[1];
  } NDIS_TASK_OFFLOAD, *PNDIS_TASK_OFFLOAD;
  
  
  /***********************************************************************/
  /* value_string's for info functions */
  
  
  /* NDIS driver medium (OID_GEN_MEDIA_SUPPORTED / OID_GEN_MEDIA_IN_USE) */
  /* Do not use NdisMediumXXX to avoid any dependency on the SDK version installed */
  static const value_string win32_802_3_medium_vals[] = {
      { -6 /*WinPcap NdisMediumPpi*/,        "AirPcap 802.11 + PPI" },
      { -5 /*WinPcap NdisMediumRadio80211*/, "AirPcap 802.11 + Radio" },
      { -4 /*WinPcap NdisMediumBare80211*/,  "AirPcap 802.11" },
      { -3 /*WinPcap NdisMediumPPPSerial*/,  "PPP Serial" },
      { -2 /*WinPcap NdisMediumCHDLC*/,      "CHDLC" },
      { -1 /*WinPcap NdisMediumNull*/,       "Null/Loopback" },
      {  0 /*NdisMedium802_3*/,        "802.3 (Ethernet)" },
      {  1 /*NdisMedium802_5*/,        "802.5 (Token Ring)" },
      {  2 /*NdisMediumFddi*/,         "FDDI" },
      {  3 /*NdisMediumWan*/,          "WAN" },
      {  4 /*NdisMediumLocalTalk*/,    "Local Talk" },
      {  5 /*NdisMediumDix*/,          "DIX" },
      {  6 /*NdisMediumArcnetRaw*/,    "Arcnet Raw" },
      {  7 /*NdisMediumArcnet878_2*/,  "Arcnet 878.2" },
      {  8 /*NdisMediumAtm*/,          "ATM" },
      {  9 /*NdisMediumWirelessWan*/,  "Wireless WAN" },
      { 10 /*NdisMediumIrda*/,         "IrDA" },
      { 11 /*NdisMediumBpc*/,          "Broadcast PC" },
      { 12 /*NdisMediumCoWan*/,        "CoWAN" },
      { 13 /*NdisMedium1394*/,         "IEEE 1394" },
      { 14 /*NdisMediumInfiniBand*/,   "Infiniband" },
      { 15 /*NdisMediumTunnel*/,       "Tunnel" },
      { 16 /*NdisMediumNative802_11*/, "Native 802.11" },
      { 17 /*NdisMediumLoopback*/,     "Loopback" },
      { 18 /*NdisMediumWiMAX*/,        "WiMAX" },
      { 19 /*NdisMediumIP*/,           "IP" },
      { 0, NULL }
  };
  
  /* NDIS physical driver medium (OID_GEN_PHYSICAL_MEDIUM) */
  /* Do not use NdisPhysicalMediumXXX to avoid any dependency on the SDK version installed */
  static const value_string win32_802_3_physical_medium_vals[] = {
      {  0 /*NdisPhysicalMediumUnspecified*/,  "Unspecified" },
      {  1 /*NdisPhysicalMediumWirelessLan*/,  "Wireless LAN" },
      {  2 /*NdisPhysicalMediumCableModem*/,   "Cable Modem (DOCSIS)" },
      {  3 /*NdisPhysicalMediumPhoneLine*/,    "Phone Line" },
      {  4 /*NdisPhysicalMediumPowerLine*/,    "Power Line" },
      {  5 /*NdisPhysicalMediumDSL*/,          "DSL" },
      {  6 /*NdisPhysicalMediumFibreChannel*/, "Fibre Channel" },
      {  7 /*NdisPhysicalMedium1394*/,         "IEEE 1394" },
      {  8 /*NdisPhysicalMediumWirelessWan*/,  "Wireless WAN" },
      {  9 /*NdisPhysicalMediumNative802_11*/, "Native 802.11" },
      { 10 /*NdisPhysicalMediumBluetooth*/,    "Bluetooth" },
      { 11 /*NdisPhysicalMediumInfiniband*/,   "Infiniband" },
      { 12 /*NdisPhysicalMediumWiMax*/,        "WiMAX" },
      { 13 /*NdisPhysicalMediumUWB*/,          "Ultra Wideband (UWB)" },
      { 14 /*NdisPhysicalMedium802_3*/,        "802.3 (Ethernet)" },
      { 15 /*NdisPhysicalMedium802_5*/,        "802.5 (Token Ring)" },
      { 16 /*NdisPhysicalMediumIrda*/,         "IrDA" },
      { 17 /*NdisPhysicalMediumWiredWAN*/,     "Wired WAN" },
      { 18 /*NdisPhysicalMediumWiredCoWan*/,   "Wired CoWAN" },
      { 19 /*NdisPhysicalMediumOther*/,        "Other" },
      { 0, NULL }
  };
  
  static const value_string win32_802_11_infra_mode_vals[] = {
      { Ndis802_11IBSS,                   "Ad Hoc" },
      { Ndis802_11Infrastructure,         "Access Point" },
      { Ndis802_11AutoUnknown,            "Auto or unknown" },
      { 0, NULL }
  };
  
  static const value_string win32_802_11_auth_mode_vals[] = {
      { Ndis802_11AuthModeOpen,           "Open System" },
      { Ndis802_11AuthModeShared,         "Shared Key" },
      { Ndis802_11AuthModeAutoSwitch,     "Auto Switch" },
      { Ndis802_11AuthModeWPA,            "WPA" },
      { Ndis802_11AuthModeWPAPSK,         "WPA-PSK (pre shared key)" },
      { Ndis802_11AuthModeWPANone,        "WPA (ad hoc)" },
  #if (_MSC_VER != 1400) /* These are not defined in Ntddndis.h in MSVC2005/MSVC2005EE PSDK */
      { Ndis802_11AuthModeWPA2,           "WPA2" },
      { Ndis802_11AuthModeWPA2PSK,        "WPA2-PSK (pre shared key)" },
  #endif
      { 0, NULL }
  };
  
  static const value_string win32_802_11_network_type_vals[] = {
      { Ndis802_11FH,                     "FH (frequency-hopping spread-spectrum)" },
      { Ndis802_11DS,                     "DS (direct-sequence spread-spectrum)" },
      { Ndis802_11OFDM5,                  "5-GHz OFDM" },
      { Ndis802_11OFDM24,                 "2.4-GHz OFDM" },
  #if (_MSC_VER != 1400) /* These are not defined in Ntddndis.h in MSVC2005/MSVC2005EE PSDK */
      { Ndis802_11Automode,               "Auto" },
  #endif
      { 0, NULL }
  };
  
  static const value_string win32_802_11_encryption_status_vals[] = {
      { Ndis802_11Encryption1Enabled,     "WEP enabled, TKIP & AES disabled, transmit key available" },
      { Ndis802_11EncryptionDisabled,     "WEP & TKIP & AES disabled, transmit key available" },
      { Ndis802_11Encryption1KeyAbsent,   "WEP enabled, TKIP & AES disabled, transmit key unavailable" },
      { Ndis802_11EncryptionNotSupported, "WEP & TKIP & AES not supported" },
      { Ndis802_11Encryption2Enabled,     "WEP & TKIP enabled, AES disabled, transmit key available" },
      { Ndis802_11Encryption2KeyAbsent,   "WEP & TKIP enabled, AES disabled, transmit key unavailable" },
      { Ndis802_11Encryption3Enabled,     "WEP & TKIP & AES enabled, transmit key available" },
      { Ndis802_11Encryption3KeyAbsent,   "WEP & TKIP & AES enabled, transmit key unavailable" },
      { 0, NULL }
  };
  
  /* frequency to channel mapping (OID_802_11_CONFIGURATION) */
  static const value_string win32_802_11_channel_freq_vals[] = {
      { 2412000, "1 (2412 MHz)" },
      { 2417000, "2 (2417 MHz)" },
      { 2422000, "3 (2422 MHz)" },
      { 2427000, "4 (2427 MHz)" },
      { 2432000, "5 (2432 MHz)" },
      { 2437000, "6 (2437 MHz)" },
      { 2442000, "7 (2442 MHz)" },
      { 2447000, "8 (2447 MHz)" },
      { 2452000, "9 (2452 MHz)" },
      { 2457000, "10 (2457 MHz)" },
      { 2462000, "11 (2462 MHz)" },
      { 2467000, "12 (2467 MHz)" },
      { 2472000, "13 (2472 MHz)" },
      { 2484000, "14 (2484 MHz)" },
      { 0, NULL }
  };
  
  /* frequency to channel mapping (OID_802_11_CONFIGURATION) */
  static const value_string win32_802_11_channel_vals[] = {
      { 2412000, "1" },
      { 2417000, "2" },
      { 2422000, "3" },
      { 2427000, "4" },
      { 2432000, "5" },
      { 2437000, "6" },
      { 2442000, "7" },
      { 2447000, "8" },
      { 2452000, "9" },
      { 2457000, "10" },
      { 2462000, "11" },
      { 2467000, "12" },
      { 2472000, "13" },
      { 2484000, "14" },
      { 0, NULL }
  };
  
  
  /* Information Element IDs (802.11 Spec: "7.3.2 Information elements") */
  #define IE_ID_SSID                      0
  #define IE_ID_SUPPORTED_RATES           1
  #define IE_ID_DS_PARAMETER_SET          3
  #define IE_ID_TIM                       5
  #define IE_ID_COUNTRY                   7
  #define IE_ID_ERP_INFORMATION          42
  #define IE_ID_WPA2                     48
  #define IE_ID_EXTENDED_SUPPORT_RATES   50
  #define IE_ID_VENDOR_SPECIFIC         221
  
  #ifdef DEBUG_IE
  /* ElementID in NDIS_802_11_VARIABLE_IEs */
  static const value_string ie_id_vals[] = {
      { IE_ID_SSID,                   "SSID, 802.11" },
      { IE_ID_SUPPORTED_RATES,        "Supported Rates, 802.11" },
      { 2,                            "FH Parameter Set, 802.11" },
      { IE_ID_DS_PARAMETER_SET,       "DS Parameter Set, 802.11" },
      { 4,                            "CF Parameter Set, 802.11" },
      { IE_ID_TIM,                    "TIM, 802.11" },
      { 6,                            "IBSS Parameter Set, 802.11" },
      { IE_ID_COUNTRY,                "Country, 802.11d" },
      { 8,                            "Hopping Pattern Parameters, 802.11d" },
      { 9,                            "Hopping Pattern Table, 802.11d" },
      { 10,                           "Request, 802.11d" },
      /* 11-15 reserved, 802.11d */
      { 16,                           "Challenge text, 802.11" },
      /* 17-31 reserved, 802.11h */
      { 32,                           "Power Constraint, 802.11h" },
      { 33,                           "Power Capability, 802.11h" },
      { 34,                           "TPC Request, 802.11h" },
      { 35,                           "TPC Report, 802.11h" },
      { 36,                           "Supported Channels, 802.11h" },
      { 37,                           "Channel Switch Announcement, 802.11h" },
      { 38,                           "Measurement Request, 802.11h" },
      { 39,                           "Measurement Report, 802.11h" },
      { 40,                           "Quiet, 802.11h" },
      { 41,                           "IBSS DFS, 802.11h" },
      { IE_ID_ERP_INFORMATION,        "ERP information, 802.11g" },
      /* 43-47 reserved, 802.11i */
      { IE_ID_WPA2,                   "WPA2/RSN (Robust Secure Network), 802.11i" },
      /* 49 reserved, 802.11i */
      { IE_ID_EXTENDED_SUPPORT_RATES, "Extended Supported Rates, 802.11g" },
      /* 51-255 reserved, 802.11g */
      { IE_ID_VENDOR_SPECIFIC,        "WPA, (not 802.11!)" },
      { 0, NULL }
  };
  #endif
  
  #if 0
  static const value_string oid_vals[] = {
      { OID_GEN_SUPPORTED_LIST,             "OID_GEN_SUPPORTED_LIST" },
      { OID_GEN_HARDWARE_STATUS,            "OID_GEN_HARDWARE_STATUS (only internally interesting)" },
      { OID_GEN_MEDIA_SUPPORTED,            "OID_GEN_MEDIA_SUPPORTED" },
      { OID_GEN_MEDIA_IN_USE,               "OID_GEN_MEDIA_IN_USE" },
      { OID_GEN_MAXIMUM_LOOKAHEAD,          "OID_GEN_MAXIMUM_LOOKAHEAD (unused)" },
      { OID_GEN_MAXIMUM_FRAME_SIZE,         "OID_GEN_MAXIMUM_FRAME_SIZE (unused)" },
      { OID_GEN_LINK_SPEED,                 "OID_GEN_LINK_SPEED" },
      { OID_GEN_TRANSMIT_BUFFER_SPACE,      "OID_GEN_TRANSMIT_BUFFER_SPACE" },
      { OID_GEN_RECEIVE_BUFFER_SPACE,       "OID_GEN_RECEIVE_BUFFER_SPACE" },
      { OID_GEN_TRANSMIT_BLOCK_SIZE,        "OID_GEN_TRANSMIT_BLOCK_SIZE" },
      { OID_GEN_RECEIVE_BLOCK_SIZE,         "OID_GEN_RECEIVE_BLOCK_SIZE" },
      { OID_GEN_VENDOR_ID,                  "OID_GEN_VENDOR_ID" },
      { OID_GEN_VENDOR_DESCRIPTION,         "OID_GEN_VENDOR_DESCRIPTION" },
      { OID_GEN_CURRENT_PACKET_FILTER,      "OID_GEN_CURRENT_PACKET_FILTER (info seems to be constant)" },
      { OID_GEN_CURRENT_LOOKAHEAD,          "OID_GEN_CURRENT_LOOKAHEAD (only internally interesting)" },
      { OID_GEN_DRIVER_VERSION,             "OID_GEN_DRIVER_VERSION" },
      { OID_GEN_MAXIMUM_TOTAL_SIZE,         "OID_GEN_MAXIMUM_TOTAL_SIZE" },
      { OID_GEN_PROTOCOL_OPTIONS,           "OID_GEN_PROTOCOL_OPTIONS (info not interesting)" },
      { OID_GEN_MAC_OPTIONS,                "OID_GEN_MAC_OPTIONS" },
      { OID_GEN_MEDIA_CONNECT_STATUS,       "OID_GEN_MEDIA_CONNECT_STATUS" },
      { OID_GEN_MAXIMUM_SEND_PACKETS,       "OID_GEN_MAXIMUM_SEND_PACKETS (only internally interesting)" },
      { OID_GEN_VENDOR_DRIVER_VERSION,      "OID_GEN_VENDOR_DRIVER_VERSION" },
      { OID_GEN_XMIT_OK,                    "OID_GEN_XMIT_OK" },
      { OID_GEN_RCV_OK,                     "OID_GEN_RCV_OK" },
      { OID_GEN_XMIT_ERROR,                 "OID_GEN_XMIT_ERROR" },
      { OID_GEN_RCV_ERROR,                  "OID_GEN_RCV_ERROR" },
      { OID_GEN_RCV_NO_BUFFER,              "OID_GEN_RCV_NO_BUFFER" },
      { OID_GEN_DIRECTED_BYTES_XMIT,        "OID_GEN_DIRECTED_BYTES_XMIT" },
      { OID_GEN_DIRECTED_FRAMES_XMIT,       "OID_GEN_DIRECTED_FRAMES_XMIT" },
      { OID_GEN_MULTICAST_BYTES_XMIT,       "OID_GEN_MULTICAST_BYTES_XMIT" },
      { OID_GEN_MULTICAST_FRAMES_XMIT,      "OID_GEN_MULTICAST_FRAMES_XMIT" },
      { OID_GEN_BROADCAST_BYTES_XMIT,       "OID_GEN_BROADCAST_BYTES_XMIT" },
      { OID_GEN_BROADCAST_FRAMES_XMIT,      "OID_GEN_BROADCAST_FRAMES_XMIT" },
      { OID_GEN_DIRECTED_BYTES_RCV,         "OID_GEN_DIRECTED_BYTES_RCV" },
      { OID_GEN_DIRECTED_FRAMES_RCV,        "OID_GEN_DIRECTED_FRAMES_RCV" },
      { OID_GEN_MULTICAST_BYTES_RCV,        "OID_GEN_MULTICAST_BYTES_RCV" },
      { OID_GEN_MULTICAST_FRAMES_RCV,       "OID_GEN_MULTICAST_FRAMES_RCV" },
      { OID_GEN_BROADCAST_BYTES_RCV,        "OID_GEN_BROADCAST_BYTES_RCV" },
      { OID_GEN_BROADCAST_FRAMES_RCV,       "OID_GEN_BROADCAST_FRAMES_RCV" },
      { OID_GEN_RCV_CRC_ERROR,              "OID_GEN_RCV_CRC_ERROR" },
      { OID_GEN_TRANSMIT_QUEUE_LENGTH,      "OID_GEN_TRANSMIT_QUEUE_LENGTH" },
      { OID_GEN_GET_TIME_CAPS,              "OID_GEN_GET_TIME_CAPS (unsupp, unused)" },
      { OID_GEN_GET_NETCARD_TIME,           "OID_GEN_GET_NETCARD_TIME (unsupp, unused)" },
  
      { OID_GEN_PHYSICAL_MEDIUM,            "OID_GEN_PHYSICAL_MEDIUM" },
      /*{ OID_GEN_MACHINE_NAME,             "OID_GEN_MACHINE_NAME (unsupp, unused)" },*/
      { OID_GEN_VLAN_ID,                    "OID_GEN_VLAN_ID" },
      { OID_GEN_MEDIA_CAPABILITIES,         "OID_GEN_MEDIA_CAPABILITIES (unsupp, unused)" },
  
      { OID_GEN_NETWORK_LAYER_ADDRESSES,    "OID_GEN_NETWORK_LAYER_ADDRESSES (write only)" },
      { OID_GEN_TRANSPORT_HEADER_OFFSET,    "OID_GEN_TRANSPORT_HEADER_OFFSET (write only)" },
  
      { OID_802_3_PERMANENT_ADDRESS,        "OID_802_3_PERMANENT_ADDRESS" },
      { OID_802_3_CURRENT_ADDRESS,          "OID_802_3_CURRENT_ADDRESS" },
      { OID_802_3_MAXIMUM_LIST_SIZE,        "OID_802_3_MAXIMUM_LIST_SIZE (unused)" },
      { OID_802_3_MULTICAST_LIST,           "OID_802_3_MULTICAST_LIST (unused)" }, /* XXX */
      { OID_802_3_MAC_OPTIONS,              "OID_802_3_MAC_OPTIONS (unsupp, unused)" },
  
      { OID_802_3_RCV_ERROR_ALIGNMENT,      "OID_802_3_RCV_ERROR_ALIGNMENT" },
      { OID_802_3_XMIT_ONE_COLLISION,       "OID_802_3_XMIT_ONE_COLLISION" },
      { OID_802_3_XMIT_MORE_COLLISIONS,     "OID_802_3_XMIT_MORE_COLLISIONS" },
      { OID_802_3_XMIT_DEFERRED,            "OID_802_3_XMIT_DEFERRED" },
      { OID_802_3_XMIT_MAX_COLLISIONS,      "OID_802_3_XMIT_MAX_COLLISIONS" },
      { OID_802_3_RCV_OVERRUN,              "OID_802_3_RCV_OVERRUN" },
      { OID_802_3_XMIT_UNDERRUN,            "OID_802_3_XMIT_UNDERRUN" },
      { OID_802_3_XMIT_HEARTBEAT_FAILURE,   "OID_802_3_XMIT_HEARTBEAT_FAILURE (unsupp, used)" },
      { OID_802_3_XMIT_TIMES_CRS_LOST,      "OID_802_3_XMIT_TIMES_CRS_LOST (unsupp, used)" },
      { OID_802_3_XMIT_LATE_COLLISIONS,     "OID_802_3_XMIT_LATE_COLLISIONS" },
  
      { OID_802_11_BSSID,                   "OID_802_11_BSSID" },
      { OID_802_11_SSID,                    "OID_802_11_SSID" },
      { OID_802_11_NETWORK_TYPES_SUPPORTED, "OID_802_11_NETWORK_TYPES_SUPPORTED (info not interesting)" },
      { OID_802_11_NETWORK_TYPE_IN_USE,     "OID_802_11_NETWORK_TYPE_IN_USE" },
      { OID_802_11_TX_POWER_LEVEL,          "OID_802_11_TX_POWER_LEVEL (unsupp, used)" },
      { OID_802_11_RSSI,                    "OID_802_11_RSSI" },
      { OID_802_11_RSSI_TRIGGER,            "OID_802_11_RSSI_TRIGGER (unsupp, unused)" },
      { OID_802_11_INFRASTRUCTURE_MODE,     "OID_802_11_INFRASTRUCTURE_MODE" },
      { OID_802_11_FRAGMENTATION_THRESHOLD, "OID_802_11_FRAGMENTATION_THRESHOLD (unused)" },
      { OID_802_11_RTS_THRESHOLD,           "OID_802_11_RTS_THRESHOLD (unused)" },
      { OID_802_11_NUMBER_OF_ANTENNAS,      "OID_802_11_NUMBER_OF_ANTENNAS (unsupp, unused)" },
      { OID_802_11_RX_ANTENNA_SELECTED,     "OID_802_11_RX_ANTENNA_SELECTED (unsupp, unused)" },
      { OID_802_11_TX_ANTENNA_SELECTED,     "OID_802_11_TX_ANTENNA_SELECTED (unsupp, unused)" },
      { OID_802_11_SUPPORTED_RATES,         "OID_802_11_SUPPORTED_RATES" },
      { OID_802_11_DESIRED_RATES,           "OID_802_11_DESIRED_RATES (unsupp, used)" },
      { OID_802_11_CONFIGURATION,           "OID_802_11_CONFIGURATION" },
      { OID_802_11_STATISTICS,              "OID_802_11_STATISTICS (unsupp, unused)" },
      { OID_802_11_ADD_WEP,                 "OID_802_11_ADD_WEP (write only)" },
      { OID_802_11_REMOVE_WEP,              "OID_802_11_REMOVE_WEP (write only)" },
      { OID_802_11_DISASSOCIATE,            "OID_802_11_DISASSOCIATE (write only)" },
      { OID_802_11_POWER_MODE,              "OID_802_11_POWER_MODE (info not interesting)" },
      { OID_802_11_BSSID_LIST,              "OID_802_11_BSSID_LIST" },
      { OID_802_11_AUTHENTICATION_MODE,     "OID_802_11_AUTHENTICATION_MODE" },
      { OID_802_11_PRIVACY_FILTER,          "OID_802_11_PRIVACY_FILTER (info not interesting)" },
      { OID_802_11_BSSID_LIST_SCAN,         "OID_802_11_BSSID_LIST_SCAN" },
      { OID_802_11_WEP_STATUS,              "OID_802_11_WEP_STATUS (info not interesting?)" },
      { OID_802_11_ENCRYPTION_STATUS,       "OID_802_11_ENCRYPTION_STATUS (unsupp, used)" },
      { OID_802_11_RELOAD_DEFAULTS,         "OID_802_11_RELOAD_DEFAULTS (write only)" },
      { OID_802_11_ADD_KEY,                 "OID_802_11_ADD_KEY (write only)" },
      { OID_802_11_REMOVE_KEY,              "OID_802_11_REMOVE_KEY (write only)" },
      { OID_802_11_ASSOCIATION_INFORMATION, "OID_802_11_ASSOCIATION_INFORMATION (unused)" }, /* XXX */
      { OID_802_11_TEST,                    "OID_802_11_TEST (write only)" },
  #if (_MSC_VER != 1400) /* These are not defined in Ntddndis.h in MSVC2005/MSVC2005EE PSDK */
      { OID_802_11_CAPABILITY,              "OID_802_11_CAPABILITY (unsupp, unused)" },
      { OID_802_11_PMKID,                   "OID_802_11_PMKID (unsupp, unused)" },
  #endif
  
      /* Token-Ring list is utterly incomplete (contains only the values for MS Loopback Driver) */
      { OID_802_5_PERMANENT_ADDRESS,        "OID_802_5_PERMANENT_ADDRESS (unused)" },
      { OID_802_5_CURRENT_ADDRESS,          "OID_802_5_CURRENT_ADDRESS (unused)" },
      { OID_802_5_CURRENT_FUNCTIONAL,       "OID_802_5_CURRENT_FUNCTIONAL (unused)" },
      { OID_802_5_CURRENT_GROUP,            "OID_802_5_CURRENT_GROUP (unused)" },
      { OID_802_5_LAST_OPEN_STATUS,         "OID_802_5_LAST_OPEN_STATUS (unused)" },
      { OID_802_5_CURRENT_RING_STATUS,      "OID_802_5_CURRENT_RING_STATUS (unused)" },
      { OID_802_5_CURRENT_RING_STATE,       "OID_802_5_CURRENT_RING_STATE (unused)" },
      { OID_802_5_LINE_ERRORS,              "OID_802_5_LINE_ERRORS (unused)" },
      { OID_802_5_LOST_FRAMES,              "OID_802_5_LOST_FRAMES (unused)" },
  
      /* FDDI list is utterly incomplete (contains only the values for MS Loopback Driver) */
      { OID_FDDI_LONG_PERMANENT_ADDR,       "OID_FDDI_LONG_PERMANENT_ADDR (unused)" },
      { OID_FDDI_LONG_CURRENT_ADDR,         "OID_FDDI_LONG_CURRENT_ADDR (unused)" },
      { OID_FDDI_LONG_MULTICAST_LIST,       "OID_FDDI_LONG_MULTICAST_LIST (unused)" },
      { OID_FDDI_LONG_MAX_LIST_SIZE,        "OID_FDDI_LONG_MAX_LIST_SIZE (unused)" },
      { OID_FDDI_SHORT_PERMANENT_ADDR,      "OID_FDDI_SHORT_PERMANENT_ADDR (unused)" },
      { OID_FDDI_SHORT_CURRENT_ADDR,        "OID_FDDI_SHORT_CURRENT_ADDR (unused)" },
      { OID_FDDI_SHORT_MULTICAST_LIST,      "OID_FDDI_SHORT_MULTICAST_LIST (unused)" },
      { OID_FDDI_SHORT_MAX_LIST_SIZE,       "OID_FDDI_SHORT_MAX_LIST_SIZE (unused)" },
  
      /* LocalTalk list is utterly incomplete (contains only the values for MS Loopback Driver) */
      { OID_LTALK_CURRENT_NODE_ID,          "OID_LTALK_CURRENT_NODE_ID (unused)" },
  
      /* Arcnet list is utterly incomplete (contains only the values for MS Loopback Driver) */
      { OID_ARCNET_PERMANENT_ADDRESS,       "OID_ARCNET_PERMANENT_ADDRESS (unused)" },
      { OID_ARCNET_CURRENT_ADDRESS,         "OID_ARCNET_CURRENT_ADDRESS (unused)" },
  
      { OID_TCP_TASK_OFFLOAD,               "OID_TCP_TASK_OFFLOAD" },
  
      /* PnP and power management OIDs */
      { OID_PNP_CAPABILITIES,               "OID_PNP_CAPABILITIES (unused)" },
      { OID_PNP_SET_POWER,                  "OID_PNP_SET_POWER (write only)" },
      { OID_PNP_QUERY_POWER,                "OID_PNP_QUERY_POWER (unused)" },
      { OID_PNP_ADD_WAKE_UP_PATTERN,        "OID_PNP_ADD_WAKE_UP_PATTERN (write only)" },
      { OID_PNP_REMOVE_WAKE_UP_PATTERN,     "OID_PNP_REMOVE_WAKE_UP_PATTERN (write only)" },
      { OID_PNP_WAKE_UP_PATTERN_LIST,       "OID_PNP_WAKE_UP_PATTERN_LIST (unused)" },
      { OID_PNP_ENABLE_WAKE_UP,             "OID_PNP_ENABLE_WAKE_UP (unused)" },
  
      /* Unknown OID's (seen on an          "Intel(R) PRO/Wireless 2200BG" 802.11 interface) */
      { 0xFF100000,                         "Unknown 0xFF100000 (unused)" },
      { 0xFF100002,                         "Unknown 0xFF100002 (unused)" },
      { 0xFF100003,                         "Unknown 0xFF100003 (unused)" },
      { 0xFF100004,                         "Unknown 0xFF100004 (unused)" },
      { 0xFF100005,                         "Unknown 0xFF100005 (unused)" },
      { 0xFF100006,                         "Unknown 0xFF100006 (unused)" },
      { 0xFF100007,                         "Unknown 0xFF100007 (unused)" },
      { 0xFF100009,                         "Unknown 0xFF100009 (unused)" },
      { 0xFF10000b,                         "Unknown 0xFF10000b (unused)" },
      { 0xFF10000c,                         "Unknown 0xFF10000c (unused)" },
      { 0xFF10000e,                         "Unknown 0xFF10000e (unused)" },
      { 0xFF10000f,                         "Unknown 0xFF10000f (unused)" },
      /* continued by a lot more 0xFF... values */
  
      { 0, NULL }
  };
  #endif
  
  /***************************************************************************/
  /* debug functions, query or list supported NDIS OID's */
  
  #if 0
  static void
  supported_list(LPADAPTER adapter)
  {
      unsigned char values[10000];
      int           length;
      gchar* tmp_str;
  
      g_warning("supported_list_unhandled");
      length = sizeof(values);
      if (wpcap_packet_request(adapter, OID_GEN_SUPPORTED_LIST, FALSE /* !set */, values, &length)) {
          guint32 *value = (guint32 *)values;
  
          while (length >= 4) {
              tmp_str = val_to_str_wmem(NULL, *value, oid_vals, "unknown (%d)");
              printf("OID: 0x%08X %s\n", *value, tmp_str);
              wmem_free(NULL, tmp_str);
  
              value++;
              length -= 4;
          }
      }
  }
  
  
  static gboolean
  supported_query_oid(LPADAPTER adapter, guint32 oid)
  {
      unsigned char values[10000];
      int           length;
  
  
      length = sizeof(values);
      if (wpcap_packet_request(adapter, OID_GEN_SUPPORTED_LIST, FALSE /* !set */, values, &length)) {
          guint32 *value = (guint32 *) values;
  
          while (length >= 4) {
              if (*value == oid) {
                  return TRUE;
              }
              value++;
              length -= 4;
          }
      }
  
      return FALSE;
  }
  #endif
  
  /******************************************************************************/
  /* info functions, get and display various NDIS driver values */
  
  
  #if 0
      GtkWidget *meter;
      GtkWidget *val_lb;
  
  static GtkWidget *
  add_meter_to_grid(GtkWidget *grid, guint *row, gchar *title,
                   int value, gchar *value_title,
                   int min, int max,
                   int yellow_level,
                   GList *scale)
  {
      GtkWidget *label;
      gchar     *indent;
      GtkWidget *main_hb;
  
  
      /* the label */
      indent = g_strdup_printf("   %s", title);
      label = gtk_label_new(indent);
      g_free(indent);
      gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
      ws_gtk_grid_attach_extended(GTK_GRID(grid), label, 0, *row, 1, 1, GTK_EXPAND|GTK_FILL, 0, 0,0);
  
      /* the level meter */
      main_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6, FALSE);
  
      meter = gtk_vumeter_new ();
  
      gtk_vumeter_set_orientation(GTK_VUMETER(meter), GTK_VUMETER_LEFT_TO_RIGHT);
  
      gtk_vumeter_set_min_max(GTK_VUMETER(meter), &min, &max);
      gtk_vumeter_set_yellow_level (GTK_VUMETER(meter), yellow_level);
      gtk_vumeter_set_thickness (GTK_VUMETER(meter), 10);
      gtk_vumeter_set_thickness_reduction (GTK_VUMETER(meter), 2);
      gtk_vumeter_set_scale_hole_size (GTK_VUMETER(meter), 2);
      gtk_vumeter_set_colors_inverted (GTK_VUMETER(meter), TRUE);
  
      if (scale) {
          gtk_vumeter_set_scale_items(GTK_VUMETER(meter), scale);
      }
  
      gtk_vumeter_set_level(GTK_VUMETER(meter), value);
  
      gtk_box_pack_start                (GTK_BOX(main_hb),
                                               meter,
                                               TRUE /*expand*/,
                                               TRUE /*fill*/,
                                               0 /* padding */);
  
      val_lb = gtk_label_new(value_title);
      gtk_widget_set_size_request(val_lb, 50, -1);
      gtk_misc_set_alignment(GTK_MISC(val_lb), 1.0, 0.5);
  
      gtk_box_pack_start                (GTK_BOX(main_hb),
                                               val_lb,
                                               FALSE /*expand*/,
                                               FALSE /*fill*/,
                                               0 /* padding */);
  
      ws_gtk_grid_attach_extended(GTK_GRID(grid), main_hb, 1, *row, 1, 1, GTK_EXPAND|GTK_FILL, 0, 0,0);
  
      *row += 1;
  
      return meter;
  }
  
  #endif
  
  static void
  add_row_to_grid(GtkWidget *grid, guint *row, gchar *title, const gchar *value, gboolean sensitive)
  {
      GtkWidget *label;
      gchar     *indent;
  
      if (strlen(value) != 0) {
          indent = g_strdup_printf("   %s", title);
      } else {
          indent = g_strdup(title);
      }
      label = gtk_label_new(indent);
      g_free(indent);
      gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
      gtk_widget_set_sensitive(label, sensitive);
      ws_gtk_grid_attach_extended(GTK_GRID(grid), label, 0, *row, 1, 1, GTK_EXPAND | GTK_FILL, 0, 0,0);
  
      label = gtk_label_new(value);
      gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
      gtk_widget_set_sensitive(label, sensitive);
      ws_gtk_grid_attach_extended(GTK_GRID(grid), label, 1, *row, 1, 1, GTK_EXPAND | GTK_FILL, 0, 0,0);
  
      *row += 1;
  }
  
  
  #if 0
  static void
  add_string_to_grid_sensitive(GtkWidget *grid, guint *row, gchar *title, gchar *value, gboolean sensitive)
  {
      add_row_to_grid(grid, row, title, value, sensitive);
  }
  #endif
  
  static void
  add_string_to_grid(GtkWidget *grid, guint *row, gchar *title, const gchar *value)
  {
      add_row_to_grid(grid, row, title, value, TRUE);
  }
  
  
  static void
  ssid_details(GtkWidget *grid, guint *row, struct ndis_essid *ssid_in) {
      struct ndis_essid   ssid[2]; /* prevent an off by one error */
  
      ssid[0] = *ssid_in;
      g_assert(ssid->length <= NDIS_ESSID_MAX_SIZE);
  
      if (ssid->length != 0) {
          ssid->essid[ssid->length] = '\0';
          add_string_to_grid(grid, row, "SSID (Service Set IDentifier)", ssid->essid);
      } else {
          add_string_to_grid(grid, row, "SSID (Service Set IDentifier)", "(currently not associated with an SSID)");
      }
  }
  
  
  static GString *
  rates_details(unsigned char *values, int length) {
      int      i;
      GString *Rates;
      float    float_value;
      int      int_value;
  
  
      Rates = g_string_new("");
  
      if (length != 0) {
          i = 0;
          while (length--) {
              if (values[i]) {
                  if (i != 0) {
                      g_string_append(Rates, "/");
                  }
  
                  float_value = ((float) (values[i] & 0x7F)) / 2;
  
                  /* reduce the screen estate by showing fractions only where required */
                  int_value = (int)float_value;
                  if (float_value == (float)int_value) {
                      g_string_append_printf(Rates, "%.0f", float_value);
                  } else {
                      g_string_append_printf(Rates, "%.1f", float_value);
                  }
              }
              i++;
          }
          Rates = g_string_append(Rates, " MBits/s");
      } else {
          Rates = g_string_append(Rates, "-");
      }
  
      return Rates;
  }
  
  
  #if 0
  static GList *
  rates_vu_list(unsigned char *values, int length, int *max)
  {
      int                  i;
      GList               *Rates = NULL;
      GtkVUMeterScaleItem *item;
  
      *max = 0;
  
      if (length == 0) {
          return NULL;
      }
  
      /* add a zero scale point */
      item = g_malloc(sizeof(GtkVUMeterScaleItem));
      item->level = 0;
      item->large = TRUE;
      item->label = "0";
      Rates = g_list_append(Rates, item);
  
      /* get the maximum rate */
      for(i=0; i<length; i++) {
          gint level;
  
          if (values[i]) {
              level = (values[i] & 0x7F) / 2;
  
              if (level > *max) {
                  *max = level;
              }
          }
      }
  
      /* debug: fake the 108MBit entry (I don't own one :-) */
      *max = 108;
  
      item = g_malloc(sizeof(GtkVUMeterScaleItem));
      item->level = 108;
      item->large = TRUE;
      item->label = "108";
      Rates = g_list_append(Rates, item);
  
      for(i=0; i<length; i++) {
          if (values[i]) {
              /* reduce the screen estate by showing fractions only where required */
              item = g_malloc(sizeof(GtkVUMeterScaleItem));
  
              item->level = (values[i] & 0x7F) / 2;
  
              /* common data rates: */
              /* 802.11  (15.1)  : mandatory: 2, 1 */
              /* 802.11a (17.1)  : mandatory: 24, 12, 6 optional: 54, 48, 36, 18, 9 */
              /* 802.11b (18.1)  : mandatory: 11, 5.5 (+ 2, 1) */
              /* 802.11g (19.1.1): mandatory: 24, 12, 11, 6, 5.5, 2, 1 optional: 54, 48, 36, 33, 22, 18, 9 */
              /* 802.11n: ? */
              /* proprietary: 108 */
  
              switch (item->level) {
                  case 2:
                      if (*max >= 108) {
                          item->large = FALSE;
                          item->label = NULL;
                      } else {
                          item->large = TRUE;
                          item->label = "2";
                      }
                      break;
                  case 5:
                      item->large = TRUE;
                      item->label = "5.5";
                      break;
                  case 11:
                      item->large = TRUE;
                      item->label = "11";
                      break;
                  case 18:
                      item->large = TRUE;
                      item->label = "18";
                      break;
                  case 24:
                      item->large = TRUE;
                      item->label = "24";
                      break;
                  case 36:
                      item->large = TRUE;
                      item->label = "36";
                      break;
                  case 48:
                      item->large = TRUE;
                      item->label = "48";
                      break;
                  case 54:
                      item->large = TRUE;
                      item->label = "54";
                      break;
                  case 72: /* XXX */
                      item->large = TRUE;
                      item->label = "72";
                      break;
                  case 96: /* XXX */
                      item->large = TRUE;
                      item->label = "96";
                      break;
                  case 108:
                      item->large = TRUE;
                      item->label = "108";
                      break;
                  default:
                      item->large = FALSE;
                      item->label = NULL;
              }
  
              Rates = g_list_append(Rates, item);
          }
      }
  
      return Rates;
  }
  #endif
  
  
  /* debugging only */
  static void
  hex(unsigned char *p, int len) {
      int i = 0;
  
      while (len) {
          g_warning("%u: 0x%x (%u) '%c'", i, *p, *p,
              g_ascii_isprint(*p) ? *p : '.');
  
          i++;
          p++;
          len--;
      }
  }
  
  
  static void
  capture_if_details_802_11_bssid_list(GtkWidget *main_vb, struct ndis_bssid_list *bssid_list)
  {
      struct ndis_ssid_item *bssid_item;
      unsigned char          mac[6];
      const gchar           *manuf_name;
      GString               *Rates;
      gchar                 *tmp_str;
  
  
      if (bssid_list->num_items != 0) {
          static const char *titles[] = { "SSID", "MAC", "Vendor", "Privacy", "RSSI" , "Network Type" ,
                                          "Infra. Mode" , "Ch." , "Rates", "Country" };
          GtkWidget *list;
          gboolean   privacy_required;
          gboolean   privacy_wpa;
          gboolean   privacy_wpa2;
  
          gchar      ssid_buff    [DETAILS_STR_MAX];
          gchar      mac_buff     [DETAILS_STR_MAX];
          gchar      vendor_buff  [DETAILS_STR_MAX];
          gchar      privacy_buff [DETAILS_STR_MAX];
          gchar      rssi_buff    [DETAILS_STR_MAX];
          gchar      nettype_buff [DETAILS_STR_MAX];
          gchar      infra_buff   [DETAILS_STR_MAX];
          gchar      freq_buff    [DETAILS_STR_MAX];
          gchar      country_buff [DETAILS_STR_MAX] = "";
  
          list = simple_list_new(10, titles);
          gtk_box_pack_start(GTK_BOX(main_vb), list, TRUE /*expand*/, TRUE /*fill*/, 0 /* padding */);
  
          bssid_item = &bssid_list->items[0];
  
          while (bssid_list->num_items--) {
              privacy_required = FALSE;
              privacy_wpa = FALSE;
              privacy_wpa2 = FALSE;
  
              /* SSID */
              if (bssid_item->ssid.length > DETAILS_STR_MAX-1) {
                  bssid_item->ssid.length = DETAILS_STR_MAX-1;
              }
              memcpy(ssid_buff, bssid_item->ssid.essid, bssid_item->ssid.length);
              ssid_buff[bssid_item->ssid.length] = '\0';
  
              /* MAC */
              memcpy(mac, &bssid_item->mac, sizeof(mac));
              g_snprintf(mac_buff, DETAILS_STR_MAX, "%02X:%02X:%02X:%02X:%02X:%02X",
                  mac[0], mac[1], mac[2],
                  mac[3], mac[4], mac[5]);
  
              /* Vendor */
              manuf_name = get_manuf_name_if_known(mac);
              if (manuf_name != NULL) {
                  g_strlcpy(vendor_buff, manuf_name, DETAILS_STR_MAX);
              } else {
                  vendor_buff[0] = '\0';
              }
  
              /* Supported Rates */
              Rates = rates_details(bssid_item->rates, NDIS_MAX_RATES_EX);
  
              /* RSSI */
              g_snprintf(rssi_buff, DETAILS_STR_MAX, "%d dBm", bssid_item->rssi);
  
              /* Privacy */
              /* (flag is set, if WEP (or higher) privacy is required) */
              if (bssid_item->privacy) {
                  privacy_required = TRUE;
              }
  
              /* Network Type */
              tmp_str = val_to_str_wmem(NULL, bssid_item->net_type, win32_802_11_network_type_vals, "(0x%x)");
              g_snprintf(nettype_buff, sizeof(nettype_buff), "%s", tmp_str);
              wmem_free(NULL, tmp_str);
  
              /* Infrastructure Mode */
              tmp_str = val_to_str_wmem(NULL, bssid_item->mode, win32_802_11_infra_mode_vals, "(0x%x)");
              g_snprintf(infra_buff, sizeof(infra_buff), "%s", tmp_str);
              wmem_free(NULL, tmp_str);
  
              /* Channel */
              tmp_str = val_to_str_wmem(NULL, bssid_item->config.ds_config, win32_802_11_channel_vals, "(%u kHz)");
              g_snprintf(freq_buff, sizeof(freq_buff), "%s", tmp_str);
              wmem_free(NULL, tmp_str);
  
              /* XXX - IE Length is currently not really supported here */
              {
                  int len = bssid_item->ie_length;
                  unsigned char *iep = bssid_item->ies;
                  unsigned char  id;
                  guint el_len;
                  NDIS_802_11_FIXED_IEs *fixed_ies;
  /*#define DEBUG_IE*/
  #ifdef DEBUG_IE
                  const gchar    *manuf_name;
                  gchar           string_buff[DETAILS_STR_MAX];
  #endif
  
  
                  fixed_ies = (NDIS_802_11_FIXED_IEs *)iep;
  
  /**
             UCHAR   Timestamp[8];
             USHORT  BeaconInterval;
             USHORT  Capabilities;
         } NDIS_802_11_FIXED_IEs, *PNDIS_802_11_FIXED_IEs;
  **/
  
                  iep += sizeof(NDIS_802_11_FIXED_IEs);
                  len = bssid_item->ie_length - sizeof(NDIS_802_11_FIXED_IEs);
  
                  while (len >= 2) {
                      id = *iep;
                      iep++;
                      el_len = *iep;
                      iep++;
                      len -= 2;
  
  #ifdef DEBUG_IE
                      tmp_str = val_to_str_wmem(NULL, id, ie_id_vals, "0x%x");
                      g_warning("ID: %s (%u) Len: %u", tmp_str, id, el_len);
                      wmem_free(NULL, tmp_str);
  #endif
  
                      switch (id) {
                          case(IE_ID_COUNTRY):
                              if (el_len >= 6)
                                  g_snprintf(country_buff, sizeof(country_buff), "%c%c: Ch: %u-%u Max: %ddBm",
                                             iep[0], iep[1], iep[3], iep[4], iep[5]);
                              break;
                          case(IE_ID_WPA2):
                              privacy_wpa2 = TRUE;
                              break;
                          case(IE_ID_VENDOR_SPECIFIC):    /* WPA */
                              privacy_wpa = TRUE;
  
  #ifdef DEBUG_IE
                              /* include information from epan/packet-ieee80211.c dissect_vendor_ie_wpawme() */
                              manuf_name = get_manuf_name_if_known(iep);
                              if (manuf_name != NULL) {
                                  g_snprintf(string_buff, DETAILS_STR_MAX, "%02X:%02X:%02X (%s) Type: %02X",
                                             *(iep), *(iep+1), *(iep+2), manuf_name, *(iep+3));
                              } else {
                                  g_snprintf(string_buff, DETAILS_STR_MAX, "%02X:%02X:%02X Type: %02X",
                                             *(iep), *(iep+1), *(iep+2), *(iep+3));
                              }
  
                              g_warning("%s", string_buff);
                              iep += 4;
                              el_len-= 4;
                              len -= 4;
  
                              g_warning("WPA IE: %u", id);
                              hex(iep, el_len);
  #endif
                              break;
  
                          case(IE_ID_SSID):
                          case(IE_ID_SUPPORTED_RATES):
                          case(IE_ID_DS_PARAMETER_SET):
                          case(IE_ID_TIM):
                          case(IE_ID_ERP_INFORMATION):
                          case(IE_ID_EXTENDED_SUPPORT_RATES):
                              /* we already have that data, do nothing */
                              break;
                          default:
                              /* unexpected IE_ID, print out hexdump */
                              g_warning("Unknown IE ID: %u Len: %u", id, el_len);
                              hex(iep, el_len);
                      }
  
                      iep += el_len;
                      len -= el_len;
                  }
              }
  
              if (privacy_required) {
                  if (privacy_wpa2) {
                      /* XXX - how to detect data encryption (TKIP and AES)? */
                      /* XXX - how to detect authentication (PSK or not)? */
                      g_snprintf(privacy_buff, DETAILS_STR_MAX, "WPA2");
                  } else {
                      if (privacy_wpa) {
                          /* XXX - how to detect data encryption (TKIP and AES)? */
                          /* XXX - how to detect authentication (PSK or not)? */
                          g_snprintf(privacy_buff, DETAILS_STR_MAX, "WPA");
                      } else {
                          /* XXX - how to detect authentication (Open System and Shared Key)? */
                          g_snprintf(privacy_buff, DETAILS_STR_MAX, "WEP");
                      }
                  }
              } else {
                  g_snprintf(privacy_buff, DETAILS_STR_MAX, "None");
              }
  
              simple_list_append(list,
                  0, ssid_buff,
                  1, mac_buff,
                  2, vendor_buff,
                  3, privacy_buff,
                  4, rssi_buff,
                  5, nettype_buff,
                  6, infra_buff,
                  7, freq_buff,
                  8, Rates->str,
                  9, country_buff,
                  -1);
  
              g_string_free(Rates, TRUE /* free_segment */);
  
              /* the bssid_list isn't an array, but a sequence of variable length items */
              bssid_item = (struct ndis_ssid_item *) (((char *) bssid_item) + bssid_item->length);
          }
      }
  }
  
  static int
  capture_if_details_802_11(GtkWidget *grid, GtkWidget *main_vb, guint *row, LPADAPTER adapter) {
      ULONG              ulong_value;
      LONG               rssi    = -100;
      unsigned int       uint_value;
      unsigned char      values[100];
      struct ndis_essid  ssid;
      int                length;
      gchar              string_buff[DETAILS_STR_MAX];
      GString           *Rates;
      int                entries = 0;
      const gchar       *manuf_name;
      struct ndis_bssid_list    *bssid_list;
      struct ndis_configuration *configuration;
      gchar* tmp_str;
  
      add_string_to_grid(grid, row, "Current network", "");
  
      /* SSID */
      length = sizeof(struct ndis_essid);
      memset(&ssid, 0, length);
      if (wpcap_packet_request(adapter, OID_802_11_SSID, FALSE /* !set */, (char *) &ssid, &length)) {
          ssid_details(grid, row, &ssid);
          entries++;
      } else {
          add_string_to_grid(grid, row, "SSID (Service Set IDentifier)", "-");
      }
  
      /* BSSID */
      length = sizeof(values);
      memset(values, 0, 6);
      if (wpcap_packet_request(adapter, OID_802_11_BSSID, FALSE /* !set */, values, &length)) {
          manuf_name = get_manuf_name_if_known(values);
          if (manuf_name != NULL) {
              g_snprintf(string_buff, DETAILS_STR_MAX, "%02X:%02X:%02X:%02X:%02X:%02X (%s)",
                  values[0], values[1], values[2],
                  values[3], values[4], values[5],
                  manuf_name);
          } else {
              g_snprintf(string_buff, DETAILS_STR_MAX, "%02X:%02X:%02X:%02X:%02X:%02X",
                  values[0], values[1], values[2],
                  values[3], values[4], values[5]);
          }
          entries++;
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(grid, row, "BSSID (Basic Service Set IDentifier)", string_buff);
  
      /* Network type in use */
      if (wpcap_packet_request_uint(adapter, OID_802_11_NETWORK_TYPE_IN_USE, &uint_value)) {
          tmp_str = val_to_str_wmem(NULL, uint_value, win32_802_11_network_type_vals, "(0x%x)");
          add_string_to_grid(grid, row, "Network type used", tmp_str);
          wmem_free(NULL, tmp_str);
          entries++;
      } else {
          add_string_to_grid(grid, row, "Network type used", "-");
      }
  
      /* Infrastructure mode */
      if (wpcap_packet_request_ulong(adapter, OID_802_11_INFRASTRUCTURE_MODE, &uint_value)) {
          tmp_str = val_to_str_wmem(NULL, uint_value, win32_802_11_infra_mode_vals, "(0x%x)");
          add_string_to_grid(grid, row, "Infrastructure mode", tmp_str);
          wmem_free(NULL, tmp_str);
          entries++;
      } else {
          add_string_to_grid(grid, row, "Infrastructure mode", "-");
      }
  
      /* Authentication mode */
      if (wpcap_packet_request_ulong(adapter, OID_802_11_AUTHENTICATION_MODE, &uint_value)) {
          tmp_str = val_to_str_wmem(NULL, uint_value, win32_802_11_auth_mode_vals, "(0x%x)");
          add_string_to_grid(grid, row, "Authentication mode", tmp_str);
          wmem_free(NULL, tmp_str);
          entries++;
      } else {
          add_string_to_grid(grid, row, "Authentication mode", "-");
      }
  
      /* Encryption (WEP) status */
      if (wpcap_packet_request_ulong(adapter, OID_802_11_ENCRYPTION_STATUS, &uint_value)) {
          tmp_str = val_to_str_wmem(NULL, uint_value, win32_802_11_encryption_status_vals, "(0x%x)");
          add_string_to_grid(grid, row, "Encryption status", tmp_str);
          wmem_free(NULL, tmp_str);
          entries++;
      } else {
          add_string_to_grid(grid, row, "Encryption status", "-");
      }
  
      /* TX power */
      if (wpcap_packet_request_ulong(adapter, OID_802_11_TX_POWER_LEVEL, &ulong_value)) {
          g_snprintf(string_buff, DETAILS_STR_MAX, "%ld mW", ulong_value);
          add_string_to_grid(grid, row, "TX power", string_buff);
          entries++;
      } else {
          add_string_to_grid(grid, row, "TX power", "-");
      }
  
      /* RSSI */
      if (wpcap_packet_request_ulong(adapter, OID_802_11_RSSI, &rssi)) {
  #if 0
          int i;
          GList * scale_items = NULL;
          GList * current;
          GtkVUMeterScaleItem *item;
  
  
          for (i = 0; i <= 100; i++) {
              item = g_malloc(sizeof(GtkVUMeterScaleItem));
  
              item->level = i;
              item->large = !(i%5);
              item->label = NULL;
  
              switch (item->level) {
                  case 0:
                      item->label = "-100 ";
                      break;
                  case 20:
                      item->label = "-80 ";
                      break;
                  case 40:
                      item->label = "-60 ";
                      break;
                  case 60:
                      item->label = "-40 ";
                      break;
                  case 80:
                      item->label = "-20 ";
                      break;
                  case 100:
                      item->label = "0";
                      break;
                  default:
                      item->label = NULL;
              }
  
              scale_items = g_list_append(scale_items, item);
          }
  
          if (rssi < -100) {
              rssi = -100;
          }
          g_snprintf(string_buff, DETAILS_STR_MAX, "%ld dBm", rssi);
  
          add_meter_to_grid(grid, row, "RSSI (Received Signal Strength Indication)",
              rssi+100 , string_buff, -100+100, 0+100, -80+100, scale_items);
          current = scale_items;
          while (current != NULL) {
              g_free(current->data);
  
              current = g_list_next(current);
          }
          g_list_free(scale_items);
          entries++;
  #endif
      } else {
          add_string_to_grid(grid, row, "RSSI (Received Signal Strength Indication)", "-");
      }
  
      /* Supported Rates */
      length = sizeof(values);
      if (!wpcap_packet_request(adapter, OID_802_11_SUPPORTED_RATES, FALSE /* !set */, values, &length)) {
          length = 0;
      } else {
          entries++;
      }
  
      /* if we can get the link speed, show Supported Rates in level meter format */
      if (length != 0 && wpcap_packet_request_uint(adapter, OID_GEN_LINK_SPEED, &uint_value)) {
  #if 0
          int max;
          int yellow;
          GList *rates_list;
  
          GList * current;
  
  
          rates_list = rates_vu_list(values, length, &max);
  
          /* if we don't have a signal, we might not have a valid link speed */
          if (rssi == -100) {
              uint_value = 0;
          }
  
          uint_value /= 10 * 1000;
          g_snprintf(string_buff, DETAILS_STR_MAX, "%u MBits/s", uint_value);
  
          if (max >= 54) {
              yellow = 2;
          } else {
              yellow = 1;
          }
  
          add_meter_to_grid(grid, row, "Link Speed",
                  uint_value, string_buff, 0, max, yellow, rates_list);
          current = rates_list;
          while (current != NULL) {
              g_free(current->data);
  
              current = g_list_next(current);
          }
          g_list_free(rates_list);
  #endif
      }
  
      /* Supported Rates in String format */
      Rates = rates_details(values, length);
      add_string_to_grid(grid, row, "Supported Rates", Rates->str);
      g_string_free(Rates, TRUE /* free_segment */);
  
      /* Desired Rates */
      length = sizeof(values);
      if (!wpcap_packet_request(adapter, OID_802_11_DESIRED_RATES, FALSE /* !set */, values, &length)) {
          length = 0;
      } else {
          entries++;
      }
  
      Rates = rates_details(values, length);
      add_string_to_grid(grid, row, "Desired Rates", Rates->str);
      g_string_free(Rates, TRUE /* free_segment */);
  
      /* Configuration (e.g. frequency) */
      length = sizeof(values);
      if (wpcap_packet_request(adapter, OID_802_11_CONFIGURATION, FALSE /* !set */, (char *) values, &length)) {
          configuration = (struct ndis_configuration *) values;
  
          tmp_str = val_to_str_wmem(NULL, configuration->ds_config, win32_802_11_channel_freq_vals, "(%u kHz)");
          add_string_to_grid(grid, row, "Channel", tmp_str);
          wmem_free(NULL, tmp_str);
          entries++;
      } else {
          add_string_to_grid(grid, row, "Channel", "-");
      }
  
      /* BSSID list: first trigger a scan */
      length = sizeof(uint_value);
      if (wpcap_packet_request(adapter, OID_802_11_BSSID_LIST_SCAN, TRUE /* set */, (char *) &uint_value, &length)) {
  #if 0
          g_warning("BSSID list scan done");
      } else {
          g_warning("BSSID list scan failed");
  #endif
      }
  
      /* BSSID list: get scan results */
      /* XXX - we might have to wait up to 7 seconds! */
      length = sizeof(ULONG) + sizeof(struct ndis_ssid_item) * 16;
      bssid_list = g_malloc(length);
      /* some drivers don't set bssid_list->num_items to 0 if
         OID_802_11_BSSID_LIST returns no items (prism54 driver, e.g.,) */
      memset(bssid_list, 0, length);
  
      if (wpcap_packet_request(adapter, OID_802_11_BSSID_LIST, FALSE /* !set */, (char *) bssid_list, &length)) {
          add_string_to_grid(grid, row, "", "");
          add_string_to_grid(grid, row, "Available networks (BSSID list)", "");
  
          capture_if_details_802_11_bssid_list(main_vb, bssid_list);
          entries += bssid_list->num_items;
      } else {
          add_string_to_grid(grid, row, "Available networks (BSSID list)", "-");
      }
  
      g_free(bssid_list);
  
      return entries;
  }
  
  
  static int
  capture_if_details_802_3(GtkWidget *grid, GtkWidget *main_vb, guint *row, LPADAPTER adapter) {
      unsigned int   uint_value;
      unsigned char  values[100];
      int            length;
      gchar          string_buff[DETAILS_STR_MAX];
      const gchar   *manuf_name;
      int            entries = 0;
  
  
      add_string_to_grid(grid, row, "Characteristics", "");
  
      length = sizeof(values);
      if (wpcap_packet_request(adapter, OID_802_3_PERMANENT_ADDRESS, FALSE /* !set */, values, &length)) {
          manuf_name = get_manuf_name_if_known(values);
          if (manuf_name != NULL) {
              g_snprintf(string_buff, DETAILS_STR_MAX, "%02X:%02X:%02X:%02X:%02X:%02X (%s)",
                  values[0], values[1], values[2],
                  values[3], values[4], values[5],
                  manuf_name);
          } else {
              g_snprintf(string_buff, DETAILS_STR_MAX, "%02X:%02X:%02X:%02X:%02X:%02X",
                  values[0], values[1], values[2],
                  values[3], values[4], values[5]);
          }
          entries++;
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(grid, row, "Permanent station address", string_buff);
  
      length = sizeof(values);
      if (wpcap_packet_request(adapter, OID_802_3_CURRENT_ADDRESS, FALSE /* !set */, values, &length)) {
          manuf_name = get_manuf_name_if_known(values);
          if (manuf_name != NULL) {
              g_snprintf(string_buff, DETAILS_STR_MAX, "%02X:%02X:%02X:%02X:%02X:%02X (%s)",
                  values[0], values[1], values[2],
                  values[3], values[4], values[5],
                  manuf_name);
          } else {
              g_snprintf(string_buff, DETAILS_STR_MAX, "%02X:%02X:%02X:%02X:%02X:%02X",
                  values[0], values[1], values[2],
                  values[3], values[4], values[5]);
          }
          entries++;
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(grid, row, "Current station address", string_buff);
  
  
      add_string_to_grid(grid, row, "", "");
      add_string_to_grid(grid, row, "Statistics", "");
  
      if (wpcap_packet_request_uint(adapter, OID_802_3_RCV_ERROR_ALIGNMENT, &uint_value)) {
          g_snprintf(string_buff, DETAILS_STR_MAX, "%d", uint_value);
          entries++;
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(grid, row, "Packets received with alignment error", string_buff);
  
      if (wpcap_packet_request_uint(adapter, OID_802_3_XMIT_ONE_COLLISION, &uint_value)) {
          g_snprintf(string_buff, DETAILS_STR_MAX, "%d", uint_value);
          entries++;
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(grid, row, "Packets transmitted with one collision", string_buff);
  
      if (wpcap_packet_request_uint(adapter, OID_802_3_XMIT_MORE_COLLISIONS, &uint_value)) {
          g_snprintf(string_buff, DETAILS_STR_MAX, "%d", uint_value);
          entries++;
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(grid, row, "Packets transmitted with more than one collision", string_buff);
  
      if (wpcap_packet_request_uint(adapter, OID_802_3_RCV_OVERRUN, &uint_value)) {
          g_snprintf(string_buff, DETAILS_STR_MAX, "%d", uint_value);
          entries++;
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(grid, row, "Packets not received due to overrun", string_buff);
  
      if (wpcap_packet_request_uint(adapter, OID_802_3_XMIT_DEFERRED, &uint_value)) {
          g_snprintf(string_buff, DETAILS_STR_MAX, "%d", uint_value);
          entries++;
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(grid, row, "Packets transmitted after deferred", string_buff);
  
      if (wpcap_packet_request_uint(adapter, OID_802_3_XMIT_MAX_COLLISIONS, &uint_value)) {
          g_snprintf(string_buff, DETAILS_STR_MAX, "%d", uint_value);
          entries++;
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(grid, row, "Packets not transmitted due to collisions", string_buff);
  
      if (wpcap_packet_request_uint(adapter, OID_802_3_XMIT_UNDERRUN, &uint_value)) {
          g_snprintf(string_buff, DETAILS_STR_MAX, "%d", uint_value);
          entries++;
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(grid, row, "Packets not transmitted due to underrun", string_buff);
  
      if (wpcap_packet_request_uint(adapter, OID_802_3_XMIT_HEARTBEAT_FAILURE, &uint_value)) {
          g_snprintf(string_buff, DETAILS_STR_MAX, "%d", uint_value);
          entries++;
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(grid, row, "Packets transmitted with heartbeat failure", string_buff);
  
      if (wpcap_packet_request_uint(adapter, OID_802_3_XMIT_TIMES_CRS_LOST, &uint_value)) {
          g_snprintf(string_buff, DETAILS_STR_MAX, "%d", uint_value);
          entries++;
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(grid, row, "Times carrier sense signal lost during transmission", string_buff);
  
      if (wpcap_packet_request_uint(adapter, OID_802_3_XMIT_LATE_COLLISIONS, &uint_value)) {
          g_snprintf(string_buff, DETAILS_STR_MAX, "%d", uint_value);
          entries++;
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(grid, row, "Times late collisions detected", string_buff);
  
      return entries;
  }
  
  static int
  capture_if_details_task_offload(GtkWidget *table, GtkWidget *main_vb, guint *row, LPADAPTER adapter) {
      NDIS_TASK_OFFLOAD_HEADER *offload;
      unsigned char values[10000];
      int           length;
      gchar         string_buff[DETAILS_STR_MAX];
      int           entries                = 0;
      int           TcpIpChecksumSupported = 0;
      int           IpSecSupported         = 0;
      int           TcpLargeSendSupported  = 0;
  
  
      /* Task Offload */
      offload = (NDIS_TASK_OFFLOAD_HEADER *) values;
      offload->Version = NDIS_TASK_OFFLOAD_VERSION;
      offload->Size = sizeof(NDIS_TASK_OFFLOAD_HEADER);
      offload->Reserved = 0;
      offload->OffsetFirstTask = 0;
      /* the EncapsulationFormat seems to be ignored on a query (using Ethernet values) */
      offload->EncapsulationFormat.Encapsulation = IEEE_802_3_Encapsulation;
      offload->EncapsulationFormat.Flags.FixedHeaderSize = 1;
      offload->EncapsulationFormat.Flags.Reserved = 0;
      offload->EncapsulationFormat.EncapsulationHeaderSize = 14; /* sizeof(struct ether_header) */;
  
      length = sizeof(values);
      if (wpcap_packet_request(adapter, OID_TCP_TASK_OFFLOAD, FALSE /* !set */, values, &length)) {
          NDIS_TASK_OFFLOAD *of;
          /* XXX - hmmm, using a tvb for this? */
          unsigned char *valuep = values + offload->OffsetFirstTask;
          length -= offload->OffsetFirstTask;
  
          do {
              of = (NDIS_TASK_OFFLOAD *) valuep;
  
              switch (of->Task) {
                  case TcpIpChecksumNdisTask:
                  {
                      NDIS_TASK_TCP_IP_CHECKSUM *tic = (NDIS_TASK_TCP_IP_CHECKSUM *) (of->TaskBuffer);
  
                      entries++;
                      TcpIpChecksumSupported++;
  
                      add_string_to_grid(table, row, "TCP/IP Checksum", "");
  
                      g_snprintf(string_buff, DETAILS_STR_MAX, "");
                      add_string_to_grid(table, row, "V4 transmit checksum", "");
  
                      g_snprintf(string_buff, DETAILS_STR_MAX, "TCP: %s, UDP: %s, IP: %s",
                                 tic->V4Transmit.TcpChecksum ? "Yes" : "No",
                                 tic->V4Transmit.UdpChecksum ? "Yes" : "No",
                                 tic->V4Transmit.IpChecksum ? "Yes" : "No");
                      add_string_to_grid(table, row, "Calculation supported", string_buff);
  
                      g_snprintf(string_buff, DETAILS_STR_MAX, "TCP: %s, IP: %s",
                                 tic->V4Transmit.TcpOptionsSupported ? "Yes" : "No",
                                 tic->V4Transmit.IpOptionsSupported ? "Yes" : "No");
                      add_string_to_grid(table, row, "Options fields supported", string_buff);
  
                      g_snprintf(string_buff, DETAILS_STR_MAX, "");
                      add_string_to_grid(table, row, "V4 receive checksum", "");
  
                      g_snprintf(string_buff, DETAILS_STR_MAX, "TCP: %s, UDP: %s, IP: %s",
                                 tic->V4Receive.TcpChecksum ? "Yes" : "No",
                                 tic->V4Receive.UdpChecksum ? "Yes" : "No",
                                 tic->V4Receive.IpChecksum ? "Yes" : "No");
                      add_string_to_grid(table, row, "Validation supported", string_buff);
  
                      g_snprintf(string_buff, DETAILS_STR_MAX, "TCP: %s, IP: %s",
                                 tic->V4Receive.TcpOptionsSupported ? "Yes" : "No",
                                 tic->V4Receive.IpOptionsSupported ? "Yes" : "No");
                      add_string_to_grid(table, row, "Options fields supported", string_buff);
  
                      g_snprintf(string_buff, DETAILS_STR_MAX, "");
                      add_string_to_grid(table, row, "V6 transmit checksum", "");
  
                      g_snprintf(string_buff, DETAILS_STR_MAX, "TCP: %s, UDP: %s",
                                 tic->V6Transmit.TcpChecksum ? "Yes" : "No",
                                 tic->V6Transmit.UdpChecksum ? "Yes" : "No");
                      add_string_to_grid(table, row, "Calculation supported", string_buff);
  
                      g_snprintf(string_buff, DETAILS_STR_MAX, "TCP: %s, IP: %s",
                                 tic->V6Transmit.TcpOptionsSupported ? "Yes" : "No",
                                 tic->V6Transmit.IpOptionsSupported ? "Yes" : "No");
                      add_string_to_grid(table, row, "Options fields supported", string_buff);
  
                      g_snprintf(string_buff, DETAILS_STR_MAX, "");
                      add_string_to_grid(table, row, "V6 receive checksum", "");
  
                      g_snprintf(string_buff, DETAILS_STR_MAX, "TCP: %s, UDP: %s",
                                 tic->V6Receive.TcpChecksum ? "Yes" : "No",
                                 tic->V6Receive.UdpChecksum ? "Yes" : "No");
                      add_string_to_grid(table, row, "Validation supported", string_buff);
  
                      g_snprintf(string_buff, DETAILS_STR_MAX, "TCP: %s, IP: %s",
                                 tic->V6Receive.TcpOptionsSupported ? "Yes" : "No",
                                 tic->V6Receive.IpOptionsSupported ? "Yes" : "No");
                      add_string_to_grid(table, row, "Options fields supported", string_buff);
                  }
                  break;
                  case IpSecNdisTask:
                      entries++;
                      IpSecSupported++;
  
                      add_string_to_grid(table, row, "IPSEC", "");
                      g_snprintf(string_buff, DETAILS_STR_MAX, "IPSEC (TaskID 1) not decoded yet");
                      add_string_to_grid(table, row, "Task", string_buff);
                      break;
                  case TcpLargeSendNdisTask:
                  {
                      NDIS_TASK_TCP_LARGE_SEND *tls = (NDIS_TASK_TCP_LARGE_SEND *) (of->TaskBuffer);
  
                      entries++;
                      TcpLargeSendSupported++;
  
                      add_string_to_grid(table, row, "TCP large send", "");
                      /* XXX - while MSDN tells about version 0, we see version 1?!? */
                      if (tls->Version == 1) {
                          g_snprintf(string_buff, DETAILS_STR_MAX, "%u", tls->MaxOffLoadSize);
                          add_string_to_grid(table, row, "Max Offload Size", string_buff);
                          g_snprintf(string_buff, DETAILS_STR_MAX, "%u", tls->MinSegmentCount);
                          add_string_to_grid(table, row, "Min Segment Count", string_buff);
                          g_snprintf(string_buff, DETAILS_STR_MAX, "%s", tls->TcpOptions ? "Yes" : "No");
                          add_string_to_grid(table, row, "TCP option fields", string_buff);
                          g_snprintf(string_buff, DETAILS_STR_MAX, "%s", tls->IpOptions ? "Yes" : "No");
                          add_string_to_grid(table, row, "IP option fields", string_buff);
                      } else {
                          g_snprintf(string_buff, DETAILS_STR_MAX, "%u (unknown)", tls->Version);
                          add_string_to_grid(table, row, "Version", string_buff);
                      }
                  }
                  break;
                  default:
                      g_snprintf(string_buff, DETAILS_STR_MAX, "Unknown task %u", of->Task);
                      add_string_to_grid(table, row, "Task", string_buff);
  
              }
  
              add_string_to_grid(table, row, "", "");
  
              valuep += of->OffsetNextTask;
              length -= of->OffsetNextTask;
          } while (of->OffsetNextTask != 0);
      }
  
      if (TcpIpChecksumSupported == 0) {
          add_string_to_grid(table, row, "TCP/IP Checksum", "");
          add_string_to_grid(table, row, "Offload not supported", "-");
      }
  
      if (IpSecSupported == 0) {
          add_string_to_grid(table, row, "IpSec", "");
          add_string_to_grid(table, row, "Offload not supported", "-");
      }
  
      if (TcpLargeSendSupported == 0) {
          add_string_to_grid(table, row, "TCP Large Send", "");
          add_string_to_grid(table, row, "Offload not supported", "-");
      }
  
      return entries;
  }
  
  static int
  capture_if_details_general(GtkWidget *grid, GtkWidget *main_vb, guint *row, LPADAPTER adapter, gchar *iface) {
      gchar          *interface_friendly_name;
      gchar           string_buff[DETAILS_STR_MAX];
      const gchar    *manuf_name;
      unsigned int    uint_value;
      unsigned int    uint_array[50];
      int             uint_array_size;
      unsigned int    physical_medium;
      int             i;
      unsigned char   values[100];
      guint16         wvalues[100];
      char           *utf8value;
      int             length;
      unsigned short  ushort_value;
      int             entries = 0;
      gchar          *size_str, *tmp_str;
  
  
      /* general */
      add_string_to_grid(grid, row, "Characteristics", "");
  
      /* OS friendly name - look it up from iface ("\Device\NPF_{11111111-2222-3333-4444-555555555555}") */
      interface_friendly_name = get_windows_interface_friendly_name(/* IN */ iface);
      if (interface_friendly_name != NULL){
          add_string_to_grid(grid, row, "OS Friendly name", interface_friendly_name);
          g_free(interface_friendly_name);
      }
  
      /* Vendor description */
      length = sizeof(values);
      if (wpcap_packet_request(adapter, OID_GEN_VENDOR_DESCRIPTION, FALSE /* !set */, values, &length)) {
          g_snprintf(string_buff, DETAILS_STR_MAX, "%s", values);
          entries++;
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(grid, row, "Vendor description", string_buff);
  
      /* NDIS's "Friendly name" */
      length = sizeof(wvalues);
      if (wpcap_packet_request(adapter, OID_GEN_FRIENDLY_NAME, FALSE /* !set */, (char *)wvalues, &length)) {
          utf8value = g_utf16_to_utf8(wvalues, -1, NULL, NULL, NULL);
          g_snprintf(string_buff, DETAILS_STR_MAX, "%s", utf8value);
          g_free(utf8value);
          entries++;
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(grid, row, "NDIS Friendly name", string_buff);
  
      /* Interface */
      add_string_to_grid(grid, row, "Interface", iface);
  
      /* link status (connected/disconnected) */
      if (wpcap_packet_request_uint(adapter, OID_GEN_MEDIA_CONNECT_STATUS, &uint_value)) {
          entries++;
          if (uint_value == 0) {
              add_string_to_grid(grid, row, "Link status", "Connected");
          } else {
              add_string_to_grid(grid, row, "Link status", "Disconnected");
          }
      } else {
          add_string_to_grid(grid, row, "Link status", "-");
      }
  
      /* link speed */
      if (wpcap_packet_request_uint(adapter, OID_GEN_LINK_SPEED, &uint_value)) {
          entries++;
          uint_value *= 100;
          size_str    = format_size(uint_value, format_size_unit_bits_s|format_size_prefix_si);
          g_strlcpy(string_buff, size_str, DETAILS_STR_MAX);
          g_free(size_str);
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(grid, row, "Link speed", string_buff);
  
      uint_array_size = sizeof(uint_array);
      if (wpcap_packet_request(adapter, OID_GEN_MEDIA_SUPPORTED, FALSE /* !set */, (char *) uint_array, &uint_array_size)) {
          entries++;
          uint_array_size /= sizeof(unsigned int);
          i = 0;
          while (uint_array_size--) {
              tmp_str = val_to_str_wmem(NULL, uint_array[i], win32_802_3_medium_vals, "(0x%x)");
              add_string_to_grid(grid, row, "Media supported", tmp_str);
              wmem_free(NULL, tmp_str);
              i++;
          }
      } else {
          add_string_to_grid(grid, row, "Media supported", "-");
      }
  
      uint_array_size = sizeof(uint_array);
      if (wpcap_packet_request(adapter, OID_GEN_MEDIA_IN_USE, FALSE /* !set */, (char *) uint_array, &uint_array_size)) {
          entries++;
          uint_array_size /= sizeof(unsigned int);
          i = 0;
          while (uint_array_size--) {
              tmp_str = val_to_str_wmem(NULL, uint_array[i], win32_802_3_medium_vals, "(0x%x)");
              add_string_to_grid(grid, row, "Media in use", tmp_str);
              wmem_free(NULL, tmp_str);
              i++;
          }
      } else {
          add_string_to_grid(grid, row, "Media in use", "-");
      }
  
      if (wpcap_packet_request_uint(adapter, OID_GEN_PHYSICAL_MEDIUM, &physical_medium)) {
          entries++;
          tmp_str = val_to_str_wmem(NULL, physical_medium, win32_802_3_physical_medium_vals, "(0x%x)");
          add_string_to_grid(grid, row, "Physical medium", tmp_str);
          wmem_free(NULL, tmp_str);
      } else {
          add_string_to_grid(grid, row, "Physical medium", "-");
      }
  
      length = sizeof(ushort_value);
      if (wpcap_packet_request(adapter, OID_GEN_DRIVER_VERSION, FALSE /* !set */, (char *) &ushort_value, &length)) {
          entries++;
          g_snprintf(string_buff, DETAILS_STR_MAX, "%u.%u", ushort_value / 0x100, ushort_value % 0x100);
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(grid, row, "NDIS Driver Version", string_buff);
  
      length = sizeof(uint_value);
      if (wpcap_packet_request(adapter, OID_GEN_VENDOR_DRIVER_VERSION, FALSE /* !set */, (char *) &uint_value, &length)) {
          entries++;
          /* XXX - what's the correct output format? */
          g_snprintf(string_buff, DETAILS_STR_MAX, "%u.%u (Hex: %X.%X)",
              (uint_value / 0x10000  ) % 0x10000,
               uint_value              % 0x10000,
              (uint_value / 0x10000  ) % 0x10000,
               uint_value              % 0x10000);
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(grid, row, "Vendor Driver Version", string_buff);
  
      length = sizeof(values);
      if (wpcap_packet_request(adapter, OID_GEN_VENDOR_ID, FALSE /* !set */, values, &length)) {
          entries++;
          manuf_name = get_manuf_name_if_known(values);
          if (manuf_name != NULL) {
              g_snprintf(string_buff, DETAILS_STR_MAX, "%02X:%02X:%02X (%s) NIC: %02X",
                  values[0], values[1], values[2], manuf_name, values[3]);
          } else {
              g_snprintf(string_buff, DETAILS_STR_MAX, "%02X:%02X:%02X NIC: %02X",
                  values[0], values[1], values[2], values[3]);
          }
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(grid, row, "Vendor ID", string_buff);
  
      if (wpcap_packet_request_uint(adapter, OID_GEN_MAC_OPTIONS, &uint_value)) {
          entries++;
          g_snprintf(string_buff, DETAILS_STR_MAX,
              "802.1P Priority: %s, 802.1Q VLAN: %s",
              (uint_value & NDIS_MAC_OPTION_8021P_PRIORITY) ? "Supported" : "Unsupported",
              (uint_value & NDIS_MAC_OPTION_8021Q_VLAN) ? "Supported" : "Unsupported" );
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(grid, row, "MAC Options", string_buff);
  
      if (wpcap_packet_request_uint(adapter, OID_GEN_VLAN_ID, &uint_value)) {
          entries++;
          g_snprintf(string_buff, DETAILS_STR_MAX, "%u", uint_value);
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(grid, row, "VLAN ID", string_buff);
  
  #if 0
      /* value seems to be constant */
      if (wpcap_packet_request_uint(adapter, OID_GEN_CURRENT_PACKET_FILTER, &uint_value)) {
          entries++;
          g_snprintf(string_buff, DETAILS_STR_MAX, "%d", uint_value);
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(grid, row, "Packet filter", string_buff);
  #endif
  
      if (wpcap_packet_request_uint(adapter, OID_GEN_TRANSMIT_BUFFER_SPACE, &uint_value)) {
          entries++;
          g_snprintf(string_buff, DETAILS_STR_MAX, "%d", uint_value);
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(grid, row, "Transmit Buffer Space", string_buff);
  
      if (wpcap_packet_request_uint(adapter, OID_GEN_RECEIVE_BUFFER_SPACE, &uint_value)) {
          entries++;
          g_snprintf(string_buff, DETAILS_STR_MAX, "%d", uint_value);
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(grid, row, "Receive Buffer Space", string_buff);
  
      if (wpcap_packet_request_uint(adapter, OID_GEN_TRANSMIT_BLOCK_SIZE , &uint_value)) {
          entries++;
          g_snprintf(string_buff, DETAILS_STR_MAX, "%d", uint_value);
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(grid, row, "Transmit Block Size", string_buff);
  
      if (wpcap_packet_request_uint(adapter, OID_GEN_RECEIVE_BLOCK_SIZE, &uint_value)) {
          entries++;
          g_snprintf(string_buff, DETAILS_STR_MAX, "%d", uint_value);
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(grid, row, "Receive Block Size", string_buff);
  
      if (wpcap_packet_request_uint(adapter, OID_GEN_MAXIMUM_TOTAL_SIZE, &uint_value)) {
          entries++;
          g_snprintf(string_buff, DETAILS_STR_MAX, "%d", uint_value);
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(grid, row, "Maximum Packet Size", string_buff);
  
      return entries;
  }
  
  
  static int
  capture_if_details_stats(GtkWidget *table, GtkWidget *main_vb, guint *row, LPADAPTER adapter) {
      gchar        string_buff[DETAILS_STR_MAX];
      unsigned int uint_value;
      int          entries = 0;
  
  
      add_string_to_grid(table, row, "Statistics", "");
  
      if (wpcap_packet_request_uint(adapter, OID_GEN_XMIT_OK, &uint_value)) {
          entries++;
          g_snprintf(string_buff, DETAILS_STR_MAX, "%d", uint_value);
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(table, row, "Transmit OK", string_buff);
  
      if (wpcap_packet_request_uint(adapter, OID_GEN_XMIT_ERROR, &uint_value)) {
          entries++;
          g_snprintf(string_buff, DETAILS_STR_MAX, "%d", uint_value);
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(table, row, "Transmit Error", string_buff);
  
  
      if (wpcap_packet_request_uint(adapter, OID_GEN_RCV_OK, &uint_value)) {
          entries++;
          g_snprintf(string_buff, DETAILS_STR_MAX, "%d", uint_value);
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(table, row, "Receive OK", string_buff);
  
      if (wpcap_packet_request_uint(adapter, OID_GEN_RCV_ERROR, &uint_value)) {
          entries++;
          g_snprintf(string_buff, DETAILS_STR_MAX, "%d", uint_value);
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(table, row, "Receive Error", string_buff);
  
      if (wpcap_packet_request_uint(adapter, OID_GEN_RCV_NO_BUFFER, &uint_value)) {
          entries++;
          g_snprintf(string_buff, DETAILS_STR_MAX, "%d", uint_value);
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(table, row, "Receive but no Buffer", string_buff);
  
      if (wpcap_packet_request_uint(adapter, OID_GEN_DIRECTED_BYTES_XMIT, &uint_value)) {
          entries++;
          g_snprintf(string_buff, DETAILS_STR_MAX, "%d", uint_value);
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(table, row, "Directed bytes transmitted w/o errors", string_buff);
  
      if (wpcap_packet_request_uint(adapter, OID_GEN_DIRECTED_FRAMES_XMIT, &uint_value)) {
          entries++;
          g_snprintf(string_buff, DETAILS_STR_MAX, "%d", uint_value);
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(table, row, "Directed packets transmitted w/o errors", string_buff);
  
      if (wpcap_packet_request_uint(adapter, OID_GEN_MULTICAST_BYTES_XMIT, &uint_value)) {
          entries++;
          g_snprintf(string_buff, DETAILS_STR_MAX, "%d", uint_value);
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(table, row, "Multicast bytes transmitted w/o errors", string_buff);
  
      if (wpcap_packet_request_uint(adapter, OID_GEN_MULTICAST_FRAMES_XMIT, &uint_value)) {
          entries++;
          g_snprintf(string_buff, DETAILS_STR_MAX, "%d", uint_value);
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(table, row, "Multicast packets transmitted w/o errors", string_buff);
  
      if (wpcap_packet_request_uint(adapter, OID_GEN_BROADCAST_BYTES_XMIT, &uint_value)) {
          entries++;
          g_snprintf(string_buff, DETAILS_STR_MAX, "%d", uint_value);
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(table, row, "Broadcast bytes transmitted w/o errors", string_buff);
  
      if (wpcap_packet_request_uint(adapter, OID_GEN_BROADCAST_FRAMES_XMIT, &uint_value)) {
          entries++;
          g_snprintf(string_buff, DETAILS_STR_MAX, "%d", uint_value);
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(table, row, "Broadcast packets transmitted w/o errors", string_buff);
  
      if (wpcap_packet_request_uint(adapter, OID_GEN_DIRECTED_BYTES_RCV, &uint_value)) {
          entries++;
          g_snprintf(string_buff, DETAILS_STR_MAX, "%d", uint_value);
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(table, row, "Directed bytes received w/o errors", string_buff);
  
      if (wpcap_packet_request_uint(adapter, OID_GEN_DIRECTED_FRAMES_RCV, &uint_value)) {
          entries++;
          g_snprintf(string_buff, DETAILS_STR_MAX, "%d", uint_value);
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(table, row, "Directed packets received w/o errors", string_buff);
  
      if (wpcap_packet_request_uint(adapter, OID_GEN_MULTICAST_BYTES_RCV, &uint_value)) {
          entries++;
          g_snprintf(string_buff, DETAILS_STR_MAX, "%d", uint_value);
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(table, row, "Multicast bytes received w/o errors", string_buff);
  
      if (wpcap_packet_request_uint(adapter, OID_GEN_MULTICAST_FRAMES_RCV, &uint_value)) {
          entries++;
          g_snprintf(string_buff, DETAILS_STR_MAX, "%d", uint_value);
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(table, row, "Multicast packets received w/o errors", string_buff);
  
      if (wpcap_packet_request_uint(adapter, OID_GEN_BROADCAST_BYTES_RCV, &uint_value)) {
          entries++;
          g_snprintf(string_buff, DETAILS_STR_MAX, "%d", uint_value);
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(table, row, "Broadcast bytes received w/o errors", string_buff);
  
      if (wpcap_packet_request_uint(adapter, OID_GEN_BROADCAST_FRAMES_RCV, &uint_value)) {
          entries++;
          g_snprintf(string_buff, DETAILS_STR_MAX, "%d", uint_value);
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(table, row, "Broadcast packets received w/o errors", string_buff);
  
      if (wpcap_packet_request_uint(adapter, OID_GEN_RCV_CRC_ERROR, &uint_value)) {
          entries++;
          g_snprintf(string_buff, DETAILS_STR_MAX, "%d", uint_value);
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(table, row, "Packets received with CRC or FCS errors", string_buff);
  
      if (wpcap_packet_request_uint(adapter, OID_GEN_TRANSMIT_QUEUE_LENGTH, &uint_value)) {
          entries++;
          g_snprintf(string_buff, DETAILS_STR_MAX, "%d", uint_value);
      } else {
          g_snprintf(string_buff, DETAILS_STR_MAX, "-");
      }
      add_string_to_grid(table, row, "Packets queued for transmission", string_buff);
  
      return entries;
  }
  
  
  static GtkWidget *
  capture_if_details_page_new(GtkWidget **grid)
  {
      GtkWidget *main_vb;
  
      main_vb =  ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 6, FALSE);
      gtk_container_set_border_width(GTK_CONTAINER(main_vb), 12);
  
      /* grid */
      *grid = ws_gtk_grid_new();
      ws_gtk_grid_set_column_spacing(GTK_GRID(*grid), 6);
      ws_gtk_grid_set_row_spacing(GTK_GRID(*grid), 3);
      gtk_box_pack_start(GTK_BOX (main_vb),  *grid, TRUE, TRUE, 0);
      return main_vb;
  }
  
  
  static void
  capture_if_details_open_win(char *iface)
  {
      GtkWidget *details_open_w,
                *main_vb, *bbox, *close_bt, *help_bt;
      GtkWidget *page_general, *page_stats, *page_802_3, *page_802_11, *page_task_offload;
      GtkWidget *page_lb;
      GtkWidget *grid, *notebook, *label;
      guint      row;
      LPADAPTER  adapter;
      int        entries;
  
  
      /* open the network adapter */
      adapter = wpcap_packet_open(iface);
      if (adapter == NULL) {
          /*
           * We have an adapter that is not exposed through normal APIs (e.g. TurboCap)
           * or an adapter that isn't plugged in.
           *
           * XXX - We should use the TurboCap API to get info about TurboCap adapters.
           */
          simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
              "%sCould not open adapter %s!%s"
              "\n\nHas it been unplugged?",
              simple_dialog_primary_start(), iface, simple_dialog_primary_end());
          return;
      }
  
      /* open a new window */
      details_open_w = dlg_window_new("Wireshark: Interface Details");  /* transient_for top_level */
      gtk_window_set_destroy_with_parent (GTK_WINDOW(details_open_w), TRUE);
  
      /* Container for the window contents */
      main_vb =  ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 12, FALSE);
      gtk_container_set_border_width(GTK_CONTAINER(main_vb), 12);
      gtk_container_add(GTK_CONTAINER(details_open_w), main_vb);
  
      /* notebook */
      notebook = gtk_notebook_new();
      gtk_box_pack_start(GTK_BOX(main_vb), notebook, TRUE /*expand*/, TRUE /*fill*/, 0 /*padding*/);
  
      /* General page */
      page_general = capture_if_details_page_new(&grid);
      page_lb = gtk_label_new("Characteristics");
      gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page_general, page_lb);
      row = 0;
      entries = capture_if_details_general(grid, page_general, &row, adapter, iface);
      if (entries == 0) {
          gtk_widget_set_sensitive(page_lb, FALSE);
      }
  
      /* Statistics page */
      page_stats = capture_if_details_page_new(&grid);
      page_lb = gtk_label_new("Statistics");
      gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page_stats, page_lb);
      row = 0;
      entries = capture_if_details_stats(grid, page_stats, &row, adapter);
      if (entries == 0) {
          gtk_widget_set_sensitive(page_lb, FALSE);
      }
  
      /* 802.3 (Ethernet) page */
      page_802_3 = capture_if_details_page_new(&grid);
      page_lb = gtk_label_new("802.3 (Ethernet)");
      gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page_802_3, page_lb);
      row = 0;
      entries = capture_if_details_802_3(grid, page_802_3, &row, adapter);
      if (entries == 0) {
          gtk_widget_set_sensitive(page_lb, FALSE);
      }
  
      /* 802_11 (WI-FI) page */
      page_802_11 = capture_if_details_page_new(&grid);
      page_lb = gtk_label_new("802.11 (WLAN)");
      gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page_802_11, page_lb);
      row = 0;
      entries = capture_if_details_802_11(grid, page_802_11, &row, adapter);
      if (entries == 0) {
          gtk_widget_set_sensitive(page_lb, FALSE);
      }
  
      /* Task offload page */
      page_task_offload = capture_if_details_page_new(&grid);
      page_lb = gtk_label_new("Task Offload");
      gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page_task_offload, page_lb);
      row = 0;
      entries = capture_if_details_task_offload(grid, page_task_offload, &row, adapter);
      if (entries == 0) {
          gtk_widget_set_sensitive(page_lb, FALSE);
      }
  
      wpcap_packet_close(adapter);
  
      label = gtk_label_new("Some drivers may not provide accurate values.");
      gtk_box_pack_start(GTK_BOX(main_vb), label, FALSE /*expand*/, FALSE /*fill*/, 0 /*padding*/);
  
      /* Button row. */
      bbox = dlg_button_row_new(GTK_STOCK_CLOSE, GTK_STOCK_HELP, NULL);
      gtk_box_pack_start(GTK_BOX(main_vb), bbox, FALSE /*expand*/, FALSE /*fill*/, 0 /*padding*/);
  
      close_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CLOSE);
      window_set_cancel_button(details_open_w, close_bt, window_cancel_button_cb);
  
      help_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_HELP);
      g_signal_connect(help_bt, "clicked", G_CALLBACK(topic_cb), (gpointer) (HELP_CAPTURE_INTERFACES_DETAILS_DIALOG));
  
      gtk_widget_grab_focus(close_bt);
  
      g_signal_connect(details_open_w, "delete_event", G_CALLBACK(window_delete_event_cb), NULL);
  
      gtk_widget_show_all(details_open_w);
      window_present(details_open_w);
  }
  
  
  static void
  capture_if_details_open_answered_cb(gpointer dialog _U_, gint btn, gpointer data)
  {
      switch (btn) {
          case(ESD_BTN_OK):
              capture_if_details_open_win(data);
              break;
          case(ESD_BTN_CANCEL):
              break;
          default:
              g_assert_not_reached();
      }
  }
  
  
  void
  capture_if_details_open(char *iface)
  {
      char     *version;
      gboolean  version_ok = FALSE;
      gpointer  dialog;
  
  
      /* check packet.dll version */
      version = wpcap_packet_get_version();
  
      if (version == NULL) {
          /* couldn't even get the packet.dll version, must be a very old one or just not existing -> give up */
          /* (this seems to be the case for 2.3 beta and all previous releases) */
          simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
              "%sCouldn't obtain WinPcap packet.dll version.%s"
              "\n\nThe WinPcap packet.dll is not installed or the version you use seems to be very old."
              "\n\nPlease update or install WinPcap.",
              simple_dialog_primary_start(), simple_dialog_primary_end());
          return;
      }
  
      /* XXX - add more known DLL versions here */
      /* (all versions since the 2.3 release seems to be working (although the 2.3 beta did not) */
      if (
          /*
           * 4.0 version strings:
           * 4.0.0.703:  4.0 beta 3
           * 4.0.0.655:  4.0 beta 2
           * 4.0.0.592:  4.0 beta 1
           */
          (strcmp(version, "3"          ) >  0) ||       /* 4.0 and above (including betas) */
          (strcmp(version, "3, 2, 0, 29") == 0) ||       /* 3.2 beta 1 */
          (strcmp(version, "3, 1, 0, 27") == 0) ||       /* 3.1 release */
          (strcmp(version, "3, 1, 0, 24") == 0) ||       /* 3.1 beta 4 */
          (strcmp(version, "3, 1, 0, 23") == 0) ||       /* 3.1 beta 3 */
          (strcmp(version, "3, 1, 0, 22") == 0) ||       /* 3.1 beta 2 */
          (strcmp(version, "3, 1, 0, 20") == 0) ||       /* 3.1 beta */
          (strcmp(version, "3.0 alpha3" ) == 0) ||       /* 3.0 release or 3.0 beta (yes, both versions report alpha3!) */
          (strcmp(version, "2.3"        ) == 0)          /* 2.3 release */
          ) {
          version_ok = TRUE;
      }
  
      if (!version_ok) {
          /* packet.dll version not known to us, warn user but try to continue */
          dialog = simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK | ESD_BTN_CANCEL,
              "%sUnknown WinPcap version.%s"
              "\n\nThe WinPcap packet.dll version \"%s\" is unknown. It may not"
              "\nprovide functions that we need and might even crash."
              "\n\nContinue anyway?",
              simple_dialog_primary_start(), simple_dialog_primary_end(), version);
          simple_dialog_set_cb(dialog, capture_if_details_open_answered_cb, iface);
      } else {
          capture_if_details_open_win(iface);
      }
  }
  
  gboolean
  capture_if_has_details(char *iface) {
      LPADAPTER   adapter;
  
      if (!iface) {
          return FALSE;
      }
  
      adapter = wpcap_packet_open(iface);
      if (adapter) {
          wpcap_packet_close(adapter);
          return TRUE;
      }
  
      return FALSE;
  }
  
  #endif /* HAVE_LIBPCAP && _WIN32 */
  
  /*
   * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
   *
   * Local variables:
   * c-basic-offset: 4
   * tab-width: 8
   * indent-tabs-mode: nil
   * End:
   *
   * vi: set shiftwidth=4 tabstop=8 expandtab:
   * :indentSize=4:tabSize=8:noTabs=true:
   */
  