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