1 /////////////////////////////////////////////////////////////////////////
2 // $Id: eth_win32.cc 14182 2021-03-12 21:31:51Z vruppert $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (C) 2001-2021 The Bochs Project
6 //
7 // This library is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU Lesser General Public
9 // License as published by the Free Software Foundation; either
10 // version 2 of the License, or (at your option) any later version.
11 //
12 // This library is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // Lesser General Public License for more details.
16 //
17 // You should have received a copy of the GNU Lesser General Public
18 // License along with this library; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 //
21 /////////////////////////////////////////////////////////////////////////
22
23 // eth_win32.cc - packet mover for win32
24 // All win32 coding by Don Becker <x-odus@iname.com>
25 // with patches from various sources
26 //
27 // Various networking docs:
28 // http://www.graphcomp.com/info/rfc/
29 // rfc0826: arp
30 // rfc0903: rarp
31 //
32 // For ethernet support under win32 to work, you must install WinPCap.
33 // Download it from http://netgroup-serv.polito.it/winpcap
34
35 // Define BX_PLUGGABLE in files that can be compiled into plugins. For
36 // platforms that require a special tag on exported symbols, BX_PLUGGABLE
37 // is used to know when we are exporting symbols and when we are importing.
38 #define BX_PLUGGABLE
39
40 #include "bochs.h"
41 #include "plugin.h"
42 #include "pc_system.h"
43 #include "netmod.h"
44
45 #if BX_NETWORKING && BX_NETMOD_WIN32
46
47 // network driver plugin entry point
48
PLUGIN_ENTRY_FOR_NET_MODULE(win32)49 PLUGIN_ENTRY_FOR_NET_MODULE(win32)
50 {
51 if (mode == PLUGIN_PROBE) {
52 return (int)PLUGTYPE_NET;
53 }
54 return 0; // Success
55 }
56
57 // network driver implementation
58
59 #ifndef __CYGWIN__
60 #include <winsock2.h>
61 #endif
62
63 // windows.h included by bochs.h
64 #define LOG_THIS netdev->
65
66 #define BX_ETH_WIN32_LOGGING 0
67
68 #define NDIS_PACKET_TYPE_PROMISCUOUS 0x0020
69 #define Packet_ALIGNMENT sizeof(int)
70 #define Packet_WORDALIGN(x) (((x)+(Packet_ALIGNMENT-1))&~(Packet_ALIGNMENT-1))
71
72 typedef int bpf_int32;
73 typedef u_int bpf_u_int32;
74
75 /*
76 * The instruction encondings.
77 */
78
79 /* instruction classes */
80
81 #define BPF_CLASS(code) ((code) & 0x07)
82 #define BPF_LD 0x00
83 #define BPF_LDX 0x01
84 #define BPF_ST 0x02
85 #define BPF_STX 0x03
86 #define BPF_ALU 0x04
87 #define BPF_JMP 0x05
88 #define BPF_RET 0x06
89 #define BPF_MISC 0x07
90
91 /* ld/ldx fields */
92 #define BPF_SIZE(code) ((code) & 0x18)
93 #define BPF_W 0x00
94 #define BPF_H 0x08
95 #define BPF_B 0x10
96 #define BPF_MODE(code) ((code) & 0xe0)
97 #define BPF_IMM 0x00
98 #define BPF_ABS 0x20
99 #define BPF_IND 0x40
100 #define BPF_MEM 0x60
101 #define BPF_LEN 0x80
102 #define BPF_MSH 0xa0
103
104 /* alu/jmp fields */
105 #define BPF_OP(code) ((code) & 0xf0)
106 #define BPF_ADD 0x00
107 #define BPF_SUB 0x10
108 #define BPF_MUL 0x20
109 #define BPF_DIV 0x30
110 #define BPF_OR 0x40
111 #define BPF_AND 0x50
112 #define BPF_LSH 0x60
113 #define BPF_RSH 0x70
114 #define BPF_NEG 0x80
115 #define BPF_JA 0x00
116 #define BPF_JEQ 0x10
117 #define BPF_JGT 0x20
118 #define BPF_JGE 0x30
119 #define BPF_JSET 0x40
120 #define BPF_SRC(code) ((code) & 0x08)
121 #define BPF_K 0x00
122 #define BPF_X 0x08
123
124 /* ret - BPF_K and BPF_X also apply */
125 #define BPF_RVAL(code) ((code) & 0x18)
126 #define BPF_A 0x10
127
128 /* misc */
129 #define BPF_MISCOP(code) ((code) & 0xf8)
130 #define BPF_TAX 0x00
131 #define BPF_TXA 0x80
132
133 #define BPF_STMT(code, k) { (u_short)(code), 0, 0, k }
134 #define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k }
135
136 /*
137 * The instruction data structure.
138 */
139 struct bpf_insn {
140 u_short code;
141 u_char jt;
142 u_char jf;
143 bpf_u_int32 k;
144 };
145
146 struct bpf_program {
147 u_int bf_len;
148 struct bpf_insn *bf_insns;
149 };
150
151 struct bpf_hdr {
152 struct timeval bh_tstamp; /* time stamp */
153 UINT bh_caplen; /* length of captured portion */
154 UINT bh_datalen; /* original length of packet */
155 USHORT bh_hdrlen; /* length of bpf header (this struct
156 plus alignment padding) */
157 };
158
159 #define MAX_LINK_NAME_LENGTH 64
160
161 // Why don't these definitions come from including winpcap.h or something?
162 // -Bryce
163 typedef struct _ADAPTER {
164 HANDLE hFile;
165 TCHAR SymbolicLink[MAX_LINK_NAME_LENGTH];
166 int NumWrites;
167 HANDLE ReadEvent;
168 UINT ReadTimeOut; // WARNING: maybe invalid before winpcap 2.2
169 } ADAPTER, *LPADAPTER;
170
171 typedef struct _PACKET {
172 HANDLE hEvent;
173 OVERLAPPED OverLapped;
174 PVOID Buffer;
175 UINT Length;
176 UINT ulBytesReceived;
177 BOOLEAN bIoComplete;
178 } PACKET, *LPPACKET;
179
180 HINSTANCE hPacket;
181 LPADAPTER lpAdapter = 0;
182 LPPACKET pkSend;
183 LPPACKET pkRecv;
184 char buffer[256000];
185 char AdapterList[10][1024];
186 char cMacAddr[6];
187 char NetDev[512];
188 BOOL IsNT = TRUE;
189
190 typedef LPADAPTER (CDECL *POpenAdapter) (LPTSTR);
191 typedef VOID (CDECL *PCloseAdapter) (LPADAPTER);
192 typedef BOOLEAN (CDECL *PSetHwFilter) (LPADAPTER, ULONG);
193 typedef BOOLEAN (CDECL *PSetBpf) (LPADAPTER, struct bpf_program *);
194 typedef BOOLEAN (CDECL *PGetAdapterNames) (PTSTR, PULONG);
195 typedef BOOLEAN (CDECL *PSendPacket) (LPADAPTER, LPPACKET, BOOLEAN);
196 typedef BOOLEAN (CDECL *PReceivePacket) (LPADAPTER, LPPACKET, BOOLEAN);
197 typedef BOOLEAN (CDECL *PSetBuff) (LPADAPTER, int);
198 typedef BOOLEAN (CDECL *PSetReadTimeout) (LPADAPTER, int);
199 typedef LPPACKET (CDECL *PAllocatePacket) (void);
200 typedef VOID (CDECL *PInitPacket) (LPPACKET, PVOID, UINT);
201 typedef VOID (CDECL *PFreePacket) (LPPACKET);
202
203 POpenAdapter PacketOpenAdapter;
204 PCloseAdapter PacketCloseAdapter;
205 PSetHwFilter PacketSetHwFilter;
206 PSetBpf PacketSetBpf;
207 PGetAdapterNames PacketGetAdapterNames;
208 PSendPacket PacketSendPacket;
209 PReceivePacket PacketReceivePacket;
210 PSetBuff PacketSetBuff;
211 PSetReadTimeout PacketSetReadTimeout;
212 PAllocatePacket PacketAllocatePacket;
213 PInitPacket PacketInitPacket;
214 PFreePacket PacketFreePacket;
215
216 // template filter for a unicast mac address and all
217 // multicast/broadcast frames
218 static const struct bpf_insn macfilter[] = {
219 BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 2),
220 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0xaaaaaaaa, 0, 2),
221 BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 0),
222 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0x0000aaaa, 2, 0),
223 BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 0),
224 BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x01, 0, 1),
225 BPF_STMT(BPF_RET, 1514),
226 BPF_STMT(BPF_RET, 0),
227 };
228
229 //
230 // Define the class. This is private to this module
231 //
232 class bx_win32_pktmover_c : public eth_pktmover_c {
233 public:
234 bx_win32_pktmover_c(const char *netif, const char *macaddr,
235 eth_rx_handler_t rxh, eth_rx_status_t rxstat,
236 logfunctions *netdev,
237 const char *script);
238 virtual ~bx_win32_pktmover_c();
239 void sendpkt(void *buf, unsigned io_len);
240 private:
241 struct bpf_insn filter[8];
242 int rx_timer_index;
243 static void rx_timer_handler(void *);
244 void rx_timer(void);
245 #if BX_ETH_WIN32_LOGGING
246 FILE *pktlog_txt;
247 #endif
248 };
249
250 //
251 // Define the static class that registers the derived pktmover class,
252 // and allocates one on request.
253 //
254 class bx_win32_locator_c : public eth_locator_c {
255 public:
bx_win32_locator_c(void)256 bx_win32_locator_c(void) : eth_locator_c("win32") {}
257 protected:
allocate(const char * netif,const char * macaddr,eth_rx_handler_t rxh,eth_rx_status_t rxstat,logfunctions * netdev,const char * script)258 eth_pktmover_c *allocate(const char *netif, const char *macaddr,
259 eth_rx_handler_t rxh, eth_rx_status_t rxstat,
260 logfunctions *netdev, const char *script) {
261 return (new bx_win32_pktmover_c(netif, macaddr, rxh, rxstat, netdev, script));
262 }
263 } bx_win32_match;
264
265 //
266 // Define the methods for the bx_win32_pktmover derived class
267 //
268
269 // the constructor
bx_win32_pktmover_c(const char * netif,const char * macaddr,eth_rx_handler_t rxh,eth_rx_status_t rxstat,logfunctions * netdev,const char * script)270 bx_win32_pktmover_c::bx_win32_pktmover_c(
271 const char *netif, const char *macaddr,
272 eth_rx_handler_t rxh, eth_rx_status_t rxstat,
273 logfunctions *netdev, const char *script)
274 {
275 this->netdev = netdev;
276 BX_INFO(("win32 network driver"));
277 // Open Packet Driver Here.
278
279 this->rxh = rxh;
280 this->rxstat = rxstat;
281
282 hPacket = LoadLibrary("PACKET.DLL");
283 memcpy(cMacAddr, macaddr, 6);
284 if (hPacket) {
285 PacketOpenAdapter = (POpenAdapter) GetProcAddress(hPacket, "PacketOpenAdapter");
286 PacketCloseAdapter = (PCloseAdapter) GetProcAddress(hPacket, "PacketCloseAdapter");
287 PacketSetHwFilter = (PSetHwFilter) GetProcAddress(hPacket, "PacketSetHwFilter");
288 PacketSetBpf = (PSetBpf) GetProcAddress(hPacket, "PacketSetBpf");
289 PacketGetAdapterNames = (PGetAdapterNames) GetProcAddress(hPacket, "PacketGetAdapterNames");
290 PacketSendPacket = (PSendPacket) GetProcAddress(hPacket, "PacketSendPacket");
291 PacketReceivePacket = (PReceivePacket) GetProcAddress(hPacket, "PacketReceivePacket");
292 PacketSetBuff = (PSetBuff) GetProcAddress(hPacket, "PacketSetBuff");
293 PacketSetReadTimeout = (PSetReadTimeout) GetProcAddress(hPacket, "PacketSetReadTimeout");
294 PacketAllocatePacket = (PAllocatePacket) GetProcAddress(hPacket, "PacketAllocatePacket");
295 PacketInitPacket = (PInitPacket) GetProcAddress(hPacket, "PacketInitPacket");
296 PacketFreePacket = (PFreePacket) GetProcAddress(hPacket, "PacketFreePacket");
297 } else {
298 BX_PANIC(("Could not load WPCap Drivers for ethernet support!"));
299 }
300
301 memset(&NetDev, 0, sizeof(NetDev));
302 // Expecting ANSI format for WinPCap 3.1 or newer
303 strcpy(NetDev, netif);
304
305 lpAdapter = PacketOpenAdapter(NetDev);
306 if (!lpAdapter || (lpAdapter->hFile == INVALID_HANDLE_VALUE)) {
307 BX_PANIC(("Could not open adapter for ethernet reception"));
308 return;
309 }
310 PacketSetHwFilter(lpAdapter, NDIS_PACKET_TYPE_PROMISCUOUS);
311
312 /* The code below sets a BPF mac address filter
313 that seems to really kill performance, for now
314 im just using code to filter, and it works
315 better
316 */
317
318 // memcpy(&this->filter, macfilter, sizeof(macfilter));
319 // this->filter[1].k = (macaddr[2] & 0xff) << 24 | (macaddr[3] & 0xff) << 16 | (macaddr[4] & 0xff) << 8 | (macaddr[5] & 0xff);
320 // this->filter[3].k = (macaddr[0] & 0xff) << 8 | (macaddr[1] & 0xff);
321 // bp.bf_len = 8;
322 // bp.bf_insns = &this->filter[0];
323 // if (!PacketSetBpf(lpAdapter, &bp)) {
324 // BX_PANIC(("Could not set mac address BPF filter"));
325 // }
326
327 PacketSetBuff(lpAdapter, 512000);
328 PacketSetReadTimeout(lpAdapter, -1);
329
330 if ((pkSend = PacketAllocatePacket()) == NULL) {
331 BX_PANIC(("Could not allocate a send packet"));
332 }
333
334 if ((pkRecv = PacketAllocatePacket()) == NULL) {
335 BX_PANIC(("Could not allocate a recv packet"));
336 }
337 rx_timer_index =
338 DEV_register_timer(this, this->rx_timer_handler, 10000, 1, 1, "eth_win32");
339
340 #if BX_ETH_WIN32_LOGGING
341 pktlog_txt = fopen("eth_win32-pktlog.txt", "wb");
342 if (!pktlog_txt) BX_PANIC(("eth_win32-pktlog.txt failed"));
343 fprintf(pktlog_txt, "win32 packetmover readable log file\n");
344 fprintf(pktlog_txt, "host adapter = %s\n", netif);
345 fprintf(pktlog_txt, "guest MAC address = ");
346 int i;
347 for (i=0; i<6; i++)
348 fprintf(pktlog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : "\n");
349 fprintf(pktlog_txt, "--\n");
350 fflush(pktlog_txt);
351 #endif
352 }
353
~bx_win32_pktmover_c()354 bx_win32_pktmover_c::~bx_win32_pktmover_c()
355 {
356 #if BX_ETH_WIN32_LOGGING
357 fclose(pktlog_txt);
358 #endif
359 }
360
sendpkt(void * buf,unsigned io_len)361 void bx_win32_pktmover_c::sendpkt(void *buf, unsigned io_len)
362 {
363 #if BX_ETH_WIN32_LOGGING
364 write_pktlog_txt(pktlog_txt, (const Bit8u *)buf, io_len, 0);
365 #endif
366
367 // SendPacket Here.
368 PacketInitPacket(pkSend, (char *)buf, io_len);
369
370 if (!PacketSendPacket(lpAdapter, pkSend, TRUE)) {
371 BX_ERROR(("Error sending packet: %lu\n", GetLastError()));
372 }
373 }
374
rx_timer_handler(void * this_ptr)375 void bx_win32_pktmover_c::rx_timer_handler (void *this_ptr)
376 {
377 bx_win32_pktmover_c *class_ptr = (bx_win32_pktmover_c *) this_ptr;
378
379 class_ptr->rx_timer();
380 }
381
rx_timer(void)382 void bx_win32_pktmover_c::rx_timer(void)
383 {
384 // Recieve Packet ????
385 char *pBuf;
386 unsigned char *pPacket;
387 unsigned int iOffset = 0;
388 struct bpf_hdr *hdr;
389 int pktlen;
390
391 PacketInitPacket(pkRecv, (char *)buffer, 256000);
392 if (WaitForSingleObject(lpAdapter->ReadEvent,0) == WAIT_OBJECT_0 || IsNT) {
393 PacketReceivePacket(lpAdapter, pkRecv, TRUE);
394 pBuf = (char *)pkRecv->Buffer;
395 iOffset = 0;
396 while(iOffset < pkRecv->ulBytesReceived)
397 {
398 hdr = (struct bpf_hdr *)(pBuf + iOffset);
399 pPacket = (unsigned char *)(pBuf + iOffset + hdr->bh_hdrlen);
400 if (memcmp(pPacket + 6, cMacAddr, 6) != 0) // src field != ours
401 {
402 if(memcmp(pPacket, cMacAddr, 6) == 0 || memcmp(pPacket, broadcast_macaddr, 6) == 0)
403 {
404 pktlen = hdr->bh_caplen;
405 if (pktlen < MIN_RX_PACKET_LEN) pktlen = MIN_RX_PACKET_LEN;
406 #if BX_ETH_WIN32_LOGGING
407 write_pktlog_txt(pktlog_txt, pPacket, pktlen, 1);
408 #endif
409 if (this->rxstat(this->netdev) & BX_NETDEV_RXREADY) {
410 this->rxh(this->netdev, pPacket, pktlen);
411 } else {
412 BX_ERROR(("device not ready to receive data"));
413 }
414 }
415 }
416 iOffset = Packet_WORDALIGN(iOffset + (hdr->bh_hdrlen + hdr->bh_caplen));
417 }
418 }
419 }
420 #endif /* if BX_NETWORKING && BX_NETMOD_WIN32 */
421