- added instructions how to update the online documentation
[bochs-mirror.git] / iodev / eth_win32.cc
blobcc5537c4e13f9f3e4228f8060a305d0fb38e1d8e
1 /////////////////////////////////////////////////////////////////////////
2 // $Id: eth_win32.cc,v 1.28 2008/12/11 18:01:56 vruppert Exp $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (C) 2001 MandrakeSoft S.A.
6 //
7 // MandrakeSoft S.A.
8 // 43, rue d'Aboukir
9 // 75002 Paris - France
10 // http://www.linux-mandrake.com/
11 // http://www.mandrakesoft.com/
13 // This library is free software; you can redistribute it and/or
14 // modify it under the terms of the GNU Lesser General Public
15 // License as published by the Free Software Foundation; either
16 // version 2 of the License, or (at your option) any later version.
18 // This library is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 // Lesser General Public License for more details.
23 // You should have received a copy of the GNU Lesser General Public
24 // License along with this library; if not, write to the Free Software
25 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 // eth_win32.cc - packet mover for win32
28 // All win32 coding by Don Becker <x-odus@iname.com>
29 // with patches from various sources
31 // Various networking docs:
32 // http://www.graphcomp.com/info/rfc/
33 // rfc0826: arp
34 // rfc0903: rarp
36 // For ethernet support under win32 to work, you must install WinPCap.
37 // Download it from http://netgroup-serv.polito.it/winpcap
39 // Define BX_PLUGGABLE in files that can be compiled into plugins. For
40 // platforms that require a special tag on exported symbols, BX_PLUGGABLE
41 // is used to know when we are exporting symbols and when we are importing.
42 #define BX_PLUGGABLE
44 #define NO_DEVICE_INCLUDES
45 #include "iodev.h"
47 #if BX_NETWORKING && defined(ETH_WIN32)
49 #include "eth.h"
51 // windows.h included by bochs.h
52 #define LOG_THIS bx_devices.pluginNE2kDevice->
54 #define BX_ETH_WIN32_LOGGING 0
56 #define NDIS_PACKET_TYPE_PROMISCUOUS 0x0020
57 #define Packet_ALIGNMENT sizeof(int)
58 #define Packet_WORDALIGN(x) (((x)+(Packet_ALIGNMENT-1))&~(Packet_ALIGNMENT-1))
60 typedef int bpf_int32;
61 typedef u_int bpf_u_int32;
64 * The instruction encondings.
67 /* instruction classes */
69 #define BPF_CLASS(code) ((code) & 0x07)
70 #define BPF_LD 0x00
71 #define BPF_LDX 0x01
72 #define BPF_ST 0x02
73 #define BPF_STX 0x03
74 #define BPF_ALU 0x04
75 #define BPF_JMP 0x05
76 #define BPF_RET 0x06
77 #define BPF_MISC 0x07
79 /* ld/ldx fields */
80 #define BPF_SIZE(code) ((code) & 0x18)
81 #define BPF_W 0x00
82 #define BPF_H 0x08
83 #define BPF_B 0x10
84 #define BPF_MODE(code) ((code) & 0xe0)
85 #define BPF_IMM 0x00
86 #define BPF_ABS 0x20
87 #define BPF_IND 0x40
88 #define BPF_MEM 0x60
89 #define BPF_LEN 0x80
90 #define BPF_MSH 0xa0
92 /* alu/jmp fields */
93 #define BPF_OP(code) ((code) & 0xf0)
94 #define BPF_ADD 0x00
95 #define BPF_SUB 0x10
96 #define BPF_MUL 0x20
97 #define BPF_DIV 0x30
98 #define BPF_OR 0x40
99 #define BPF_AND 0x50
100 #define BPF_LSH 0x60
101 #define BPF_RSH 0x70
102 #define BPF_NEG 0x80
103 #define BPF_JA 0x00
104 #define BPF_JEQ 0x10
105 #define BPF_JGT 0x20
106 #define BPF_JGE 0x30
107 #define BPF_JSET 0x40
108 #define BPF_SRC(code) ((code) & 0x08)
109 #define BPF_K 0x00
110 #define BPF_X 0x08
112 /* ret - BPF_K and BPF_X also apply */
113 #define BPF_RVAL(code) ((code) & 0x18)
114 #define BPF_A 0x10
116 /* misc */
117 #define BPF_MISCOP(code) ((code) & 0xf8)
118 #define BPF_TAX 0x00
119 #define BPF_TXA 0x80
121 #define BPF_STMT(code, k) { (u_short)(code), 0, 0, k }
122 #define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k }
125 * The instruction data structure.
127 struct bpf_insn {
128 u_short code;
129 u_char jt;
130 u_char jf;
131 bpf_int32 k;
134 struct bpf_program {
135 u_int bf_len;
136 struct bpf_insn *bf_insns;
139 struct bpf_hdr {
140 struct timeval bh_tstamp; /* time stamp */
141 UINT bh_caplen; /* length of captured portion */
142 UINT bh_datalen; /* original length of packet */
143 USHORT bh_hdrlen; /* length of bpf header (this struct
144 plus alignment padding) */
147 #define MAX_LINK_NAME_LENGTH 64
149 // Why don't these definitions come from including winpcap.h or something?
150 // -Bryce
151 typedef struct _ADAPTER {
152 HANDLE hFile;
153 TCHAR SymbolicLink[MAX_LINK_NAME_LENGTH];
154 int NumWrites;
155 HANDLE ReadEvent;
156 UINT ReadTimeOut; // WARNING: maybe invalid before winpcap 2.2
157 } ADAPTER, *LPADAPTER;
159 typedef struct _PACKET {
160 HANDLE hEvent;
161 OVERLAPPED OverLapped;
162 PVOID Buffer;
163 UINT Length;
164 UINT ulBytesReceived;
165 BOOLEAN bIoComplete;
166 } PACKET, *LPPACKET;
168 HINSTANCE hPacket;
169 LPADAPTER lpAdapter = 0;
170 LPPACKET pkSend;
171 LPPACKET pkRecv;
172 char buffer[256000];
173 DWORD dwVersion, dwMajorVersion;
174 char AdapterList[10][1024];
175 char cMacAddr[6];
176 void *rx_Arg;
177 char netdev[512];
178 BOOL IsNT = FALSE;
180 eth_rx_handler_t rx_handler;
182 LPADAPTER (*PacketOpenAdapter) (LPTSTR);
183 VOID (*PacketCloseAdapter) (LPADAPTER);
184 BOOLEAN (*PacketSetHwFilter) (LPADAPTER, ULONG);
185 BOOLEAN (*PacketSetBpf) (LPADAPTER, struct bpf_program *);
186 BOOLEAN (*PacketGetAdapterNames) (PTSTR, PULONG);
187 BOOLEAN (*PacketSendPacket) (LPADAPTER, LPPACKET, BOOLEAN);
188 BOOLEAN (*PacketReceivePacket) (LPADAPTER, LPPACKET, BOOLEAN);
189 BOOLEAN (*PacketSetBuff) (LPADAPTER, int);
190 BOOLEAN (*PacketSetReadTimeout) (LPADAPTER, int);
191 LPPACKET (*PacketAllocatePacket) (void);
192 VOID (*PacketInitPacket) (LPPACKET, PVOID, UINT);
193 VOID (*PacketFreePacket) (LPPACKET);
195 // template filter for a unicast mac address and all
196 // multicast/broadcast frames
197 static const struct bpf_insn macfilter[] = {
198 BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 2),
199 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0xaaaaaaaa, 0, 2),
200 BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 0),
201 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0x0000aaaa, 2, 0),
202 BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 0),
203 BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x01, 0, 1),
204 BPF_STMT(BPF_RET, 1514),
205 BPF_STMT(BPF_RET, 0),
209 // Define the class. This is private to this module
211 class bx_win32_pktmover_c : public eth_pktmover_c {
212 public:
213 bx_win32_pktmover_c(const char *netif, const char *macaddr,
214 eth_rx_handler_t rxh, void *rxarg, const char *script);
215 void sendpkt(void *buf, unsigned io_len);
216 private:
217 struct bpf_insn filter[8];
218 int rx_timer_index;
219 static void rx_timer_handler(void *);
220 void rx_timer(void);
221 #if BX_ETH_WIN32_LOGGING
222 FILE *pktlog_txt;
223 #endif
227 // Define the static class that registers the derived pktmover class,
228 // and allocates one on request.
230 class bx_win32_locator_c : public eth_locator_c {
231 public:
232 bx_win32_locator_c(void) : eth_locator_c("win32") {}
233 protected:
234 eth_pktmover_c *allocate(const char *netif, const char *macaddr,
235 eth_rx_handler_t rxh,
236 void *rxarg, const char *script) {
237 return (new bx_win32_pktmover_c(netif, macaddr, rxh, rxarg, script));
239 } bx_win32_match;
242 // Define the methods for the bx_win32_pktmover derived class
245 // the constructor
246 bx_win32_pktmover_c::bx_win32_pktmover_c(
247 const char *netif, const char *macaddr,
248 eth_rx_handler_t rxh, void *rxarg, const char *script)
250 // Open Packet Driver Here.
251 DWORD dwVersion;
252 DWORD dwWindowsMajorVersion;
254 BX_INFO(("bx_win32_pktmover_c"));
255 rx_Arg = rxarg;
256 rx_handler = rxh;
258 hPacket = LoadLibrary("PACKET.DLL");
259 memcpy(cMacAddr, macaddr, 6);
260 if (hPacket) {
261 PacketOpenAdapter = (LPADAPTER (*)(LPTSTR)) GetProcAddress(hPacket, "PacketOpenAdapter");
262 PacketCloseAdapter = (VOID (*)(LPADAPTER)) GetProcAddress(hPacket, "PacketCloseAdapter");
263 PacketSetHwFilter = (BOOLEAN (*)(LPADAPTER, ULONG)) GetProcAddress(hPacket, "PacketSetHwFilter");
264 PacketSetBpf = (BOOLEAN (*)(LPADAPTER, struct bpf_program *)) GetProcAddress(hPacket, "PacketSetBpf");
265 PacketGetAdapterNames = (BOOLEAN (*)(PTSTR, PULONG)) GetProcAddress(hPacket, "PacketGetAdapterNames");
266 PacketSendPacket = (BOOLEAN (*)(LPADAPTER, LPPACKET, BOOLEAN)) GetProcAddress(hPacket, "PacketSendPacket");
267 PacketReceivePacket = (BOOLEAN (*)(LPADAPTER, LPPACKET, BOOLEAN)) GetProcAddress(hPacket, "PacketReceivePacket");
268 PacketSetBuff = (BOOLEAN (*)(LPADAPTER, int)) GetProcAddress(hPacket, "PacketSetBuff");
269 PacketSetReadTimeout = (BOOLEAN (*)(LPADAPTER, int)) GetProcAddress(hPacket, "PacketSetReadTimeout");
270 PacketAllocatePacket = (LPPACKET (*)(void)) GetProcAddress(hPacket, "PacketAllocatePacket");
271 PacketInitPacket = (VOID (*)(LPPACKET, PVOID, UINT)) GetProcAddress(hPacket, "PacketInitPacket");
272 PacketFreePacket = (VOID (*)(LPPACKET)) GetProcAddress(hPacket, "PacketFreePacket");
273 } else {
274 BX_PANIC(("Could not load WPCap Drivers for ethernet support!"));
277 memset(&netdev, 0, sizeof(netdev));
278 dwVersion=GetVersion();
279 dwWindowsMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
280 if (!(dwVersion >= 0x80000000 && dwWindowsMajorVersion >= 4))
281 { // Windows NT/2k
282 int nLen = MultiByteToWideChar(CP_ACP, 0, netif, -1, NULL, 0);
283 MultiByteToWideChar(CP_ACP, 0, netif, -1, (WCHAR *)netdev, nLen);
284 IsNT = TRUE;
285 } else { // Win9x
286 strcpy(netdev, netif);
289 lpAdapter = PacketOpenAdapter(netdev);
290 if (!lpAdapter || (lpAdapter->hFile == INVALID_HANDLE_VALUE)) {
291 BX_PANIC(("Could not open adapter for ethernet reception"));
292 return;
294 PacketSetHwFilter(lpAdapter, NDIS_PACKET_TYPE_PROMISCUOUS);
296 /* The code below sets a BPF mac address filter
297 that seems to really kill performance, for now
298 im just using code to filter, and it works
299 better
302 // memcpy(&this->filter, macfilter, sizeof(macfilter));
303 // this->filter[1].k = (macaddr[2] & 0xff) << 24 | (macaddr[3] & 0xff) << 16 | (macaddr[4] & 0xff) << 8 | (macaddr[5] & 0xff);
304 // this->filter[3].k = (macaddr[0] & 0xff) << 8 | (macaddr[1] & 0xff);
305 // bp.bf_len = 8;
306 // bp.bf_insns = &this->filter[0];
307 // if (!PacketSetBpf(lpAdapter, &bp)) {
308 // BX_PANIC(("Could not set mac address BPF filter"));
309 // }
311 PacketSetBuff(lpAdapter, 512000);
312 PacketSetReadTimeout(lpAdapter, -1);
314 if ((pkSend = PacketAllocatePacket()) == NULL) {
315 BX_PANIC(("Could not allocate a send packet"));
318 if ((pkRecv = PacketAllocatePacket()) == NULL) {
319 BX_PANIC(("Could not allocate a recv packet"));
321 rx_timer_index =
322 bx_pc_system.register_timer(this, this->rx_timer_handler, 10000, 1, 1, "eth_win32");
324 #if BX_ETH_WIN32_LOGGING
325 pktlog_txt = fopen ("ne2k-pktlog.txt", "wb");
326 if (!pktlog_txt) BX_PANIC (("ne2k-pktlog.txt failed"));
327 fprintf (pktlog_txt, "win32 packetmover readable log file\n");
328 fprintf (pktlog_txt, "host adapter = %s\n", netif);
329 fprintf (pktlog_txt, "guest MAC address = ");
330 int i;
331 for (i=0; i<6; i++)
332 fprintf (pktlog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : "\n");
333 fprintf (pktlog_txt, "--\n");
334 fflush (pktlog_txt);
335 #endif
338 void
339 bx_win32_pktmover_c::sendpkt(void *buf, unsigned io_len)
341 #if BX_ETH_WIN32_LOGGING
342 fprintf (pktlog_txt, "a packet from guest to host, length %u\n", io_len);
343 Bit8u *charbuf = (Bit8u *)buf;
344 unsigned n;
345 for (n=0; n<io_len; n++) {
346 if (((n % 16) == 0) && n>0)
347 fprintf (pktlog_txt, "\n");
348 fprintf (pktlog_txt, "%02x ", (unsigned)charbuf[n]);
350 fprintf (pktlog_txt, "\n--\n");
351 fflush (pktlog_txt);
352 #endif
354 // SendPacket Here.
355 PacketInitPacket(pkSend, (char *)buf, io_len);
357 if (!PacketSendPacket(lpAdapter, pkSend, TRUE)) {
358 fprintf(stderr, "[ETH-WIN32] Error sending packet: %lu\n", GetLastError());
362 void bx_win32_pktmover_c::rx_timer_handler (void *this_ptr)
364 bx_win32_pktmover_c *class_ptr = (bx_win32_pktmover_c *) this_ptr;
366 class_ptr->rx_timer();
369 void bx_win32_pktmover_c::rx_timer(void)
371 // Recieve Packet ????
372 char *pBuf;
373 unsigned char *pPacket;
374 unsigned int iOffset = 0;
375 struct bpf_hdr *hdr;
376 int pktlen;
378 PacketInitPacket(pkRecv, (char *)buffer, 256000);
379 if (WaitForSingleObject(lpAdapter->ReadEvent,0) == WAIT_OBJECT_0 || IsNT) {
380 PacketReceivePacket(lpAdapter, pkRecv, TRUE);
381 pBuf = (char *)pkRecv->Buffer;
382 iOffset = 0;
383 while(iOffset < pkRecv->ulBytesReceived)
385 hdr = (struct bpf_hdr *)(pBuf + iOffset);
386 pPacket = (unsigned char *)(pBuf + iOffset + hdr->bh_hdrlen);
387 if (memcmp(pPacket + 6, cMacAddr, 6) != 0) // src field != ours
389 if(memcmp(pPacket, cMacAddr, 6) == 0 || memcmp(pPacket, broadcast_macaddr, 6) == 0)
391 pktlen = hdr->bh_caplen;
392 if (pktlen < 60) pktlen = 60;
393 #if BX_ETH_WIN32_LOGGING
394 fprintf (pktlog_txt, "a packet from host to guest, length %u\n", pktlen);
395 Bit8u *charbuf = (Bit8u *)pPacket;
396 int n;
397 for (n=0; n<pktlen; n++) {
398 if (((n % 16) == 0) && n>0)
399 fprintf (pktlog_txt, "\n");
400 fprintf (pktlog_txt, "%02x ", (unsigned)charbuf[n]);
402 fprintf (pktlog_txt, "\n--\n");
403 fflush (pktlog_txt);
404 #endif
405 (*rx_handler)(rx_Arg, pPacket, pktlen);
408 iOffset = Packet_WORDALIGN(iOffset + (hdr->bh_hdrlen + hdr->bh_caplen));
412 #endif /* if BX_NETWORKING && defined ETH_WIN32 */