summaryrefslogtreecommitdiffstats
path: root/libdnet-stripped/src/eth-win32.c
blob: fc6aed1c935185e29d27e87b8d9cd7b6e25acc1a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/*
 * 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];

	if (eth_get_pcap_devname(device, pcapdev, sizeof(pcapdev)) != 0)
		return (NULL);

	if ((eth = calloc(1, sizeof(*eth))) == NULL)
		return (NULL);
	eth->lpa = PacketOpenAdapter(pcapdev);
	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)
{
	if (eth != NULL) {
		if (eth->pkt != NULL)
			PacketFreePacket(eth->pkt);
		if (eth->lpa != NULL)
			PacketCloseAdapter(eth->lpa);
		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);
}