text: /*
   * eth-win32.c
   *
   * Copyright (c) 2000 Dug Song <dugsong@monkey.org>
   *
   * $Id: eth-win32.c 613 2005-09-26 02:46:57Z dugsong $
   */
  
  #ifdef _WIN32
  #include "dnet_winconfig.h"
  #else
  #include "config.h"
  #endif
  
  /* XXX - VC++ 6.0 bogosity */
  #define sockaddr_storage sockaddr
  #undef sockaddr_storage
  
  #include <errno.h>
  #include <stdlib.h>
  
  #include "dnet.h"
  #include <winsock2.h>
  #include "pcap.h"
  #include <Packet32.h>
  #include <Ntddndis.h>
  
  /* From Npcap's Loopback.h */
  /*
   * * Structure of a DLT_NULL header.
   * */
  typedef struct _DLT_NULL_HEADER
  {
      UINT  null_type;
  } DLT_NULL_HEADER, *PDLT_NULL_HEADER;
  
  /*
   * * The length of the combined header.
   * */
  #define DLT_NULL_HDR_LEN  sizeof(DLT_NULL_HEADER)
  
  /*
   * * Types in a DLT_NULL (Loopback) header.
   * */
  #define DLTNULLTYPE_IP    0x00000002  /* IP protocol */
  #define DLTNULLTYPE_IPV6  0x00000018 /* IPv6 */
  /* END Loopback.h */
  
  struct eth_handle {
  	LPADAPTER	 lpa;
  	LPPACKET	 pkt;
  	NetType    type;
  };
  
  eth_t *
  eth_open(const char *device)
  {
  	eth_t *eth;
  	char pcapdev[128];
    HANDLE pcapMutex;
    DWORD wait;
  
  	if (eth_get_pcap_devname(device, pcapdev, sizeof(pcapdev)) != 0)
  		return (NULL);
  
  	if ((eth = calloc(1, sizeof(*eth))) == NULL)
  		return (NULL);
    pcapMutex = CreateMutex(NULL, 0, "Global\\DnetPcapHangAvoidanceMutex");
    wait = WaitForSingleObject(pcapMutex, INFINITE);
  	eth->lpa = PacketOpenAdapter(pcapdev);
    if (wait == WAIT_ABANDONED || wait == WAIT_OBJECT_0) {
      ReleaseMutex(pcapMutex);
    }
    CloseHandle(pcapMutex);
  	if (eth->lpa == NULL) {
  		eth_close(eth);
  		return (NULL);
  	}
  	PacketSetBuff(eth->lpa, 512000);
  	eth->pkt = PacketAllocatePacket();
  	if (eth->pkt == NULL) {
  		eth_close(eth);
  		return NULL;
  	}
  	if (!PacketGetNetType(eth->lpa, &eth->type)) {
  	  eth_close(eth);
  	  return NULL;
    }
  
  	return (eth);
  }
  
  ssize_t
  eth_send(eth_t *eth, const void *buf, size_t len)
  {
    /* 14-byte Ethernet header, but DLT_NULL is a 4-byte header. Skip over the difference */
    DLT_NULL_HEADER *hdr = (DLT_NULL_HEADER *)((uint8_t *)buf + ETH_HDR_LEN - DLT_NULL_HDR_LEN);
    if (eth->type.LinkType == NdisMediumNull) {
      switch (ntohs(((struct eth_hdr *)buf)->eth_type)) {
        case ETH_TYPE_IP:
          hdr->null_type = DLTNULLTYPE_IP;
          break;
        case ETH_TYPE_IPV6:
          hdr->null_type = DLTNULLTYPE_IPV6;
          break;
        default:
          hdr->null_type = 0;
          break;
      }
      PacketInitPacket(eth->pkt, (void *)((uint8_t *)buf + ETH_HDR_LEN - DLT_NULL_HDR_LEN), (UINT) (len - ETH_HDR_LEN + DLT_NULL_HDR_LEN));
      PacketSendPacket(eth->lpa, eth->pkt, TRUE);
    }
    else {
      PacketInitPacket(eth->pkt, (void *)buf, (UINT) len);
      PacketSendPacket(eth->lpa, eth->pkt, TRUE);
    }
  	return (ssize_t)(len);
  }
  
  eth_t *
  eth_close(eth_t *eth)
  {
    HANDLE pcapMutex;
    DWORD wait;
  	if (eth != NULL) {
  		if (eth->pkt != NULL)
  			PacketFreePacket(eth->pkt);
  		if (eth->lpa != NULL)
      {
        pcapMutex = CreateMutex(NULL, 0, "Global\\DnetPcapHangAvoidanceMutex");
        wait = WaitForSingleObject(pcapMutex, INFINITE);
  			PacketCloseAdapter(eth->lpa);
        if (wait == WAIT_ABANDONED || wait == WAIT_OBJECT_0) {
          ReleaseMutex(pcapMutex);
        }
        CloseHandle(pcapMutex);
      }
  		free(eth);
  	}
  	return (NULL);
  }
  
  int
  eth_get(eth_t *eth, eth_addr_t *ea)
  {
  	PACKET_OID_DATA *data;
  	u_char buf[512];
  
  	data = (PACKET_OID_DATA *)buf;
  	data->Oid = OID_802_3_CURRENT_ADDRESS;
  	data->Length = ETH_ADDR_LEN;
  
  	if (PacketRequest(eth->lpa, FALSE, data) == TRUE) {
  		memcpy(ea, data->Data, ETH_ADDR_LEN);
  		return (0);
  	}
  	return (-1);
  }
  
  int
  eth_set(eth_t *eth, const eth_addr_t *ea)
  {
  	PACKET_OID_DATA *data;
  	u_char buf[512];
  
  	data = (PACKET_OID_DATA *)buf;
  	data->Oid = OID_802_3_CURRENT_ADDRESS;
  	memcpy(data->Data, ea, ETH_ADDR_LEN);
  	data->Length = ETH_ADDR_LEN;
  	
  	if (PacketRequest(eth->lpa, TRUE, data) == TRUE)
  		return (0);
  	
  	return (-1);
  }
  
  int
  eth_get_pcap_devname(const char *intf_name, char *pcapdev, int pcapdevlen)
  {
  	return intf_get_pcap_devname(intf_name, pcapdev, pcapdevlen);
  }
  