First Commit of my working state
[simh.git] / sim_ether.c
1 /* sim_ether.c: OS-dependent network routines
2 ------------------------------------------------------------------------------
3 Copyright (c) 2002-2007, David T. Hittner
4
5 Permission is hereby granted, free of charge, to any person obtaining a
6 copy of this software and associated documentation files (the "Software"),
7 to deal in the Software without restriction, including without limitation
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 and/or sell copies of the Software, and to permit persons to whom the
10 Software is furnished to do so, subject to the following conditions:
11
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22 Except as contained in this notice, the name of the author shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from the author.
25
26 ------------------------------------------------------------------------------
27
28 This ethernet simulation is based on the PCAP and WinPcap packages.
29
30 PCAP/WinPcap was chosen as the basis for network code since it is the most
31 "universal" of the various network packages available. Using this style has
32 allowed rapid network development for the major SIMH platforms. Developing
33 a network package specifically for SIMH was rejected due to the time required;
34 the advantage would be a more easily compiled and integrated code set.
35
36 There are various problems associated with use of ethernet networking, which
37 would be true regardless of the network package used, since there are no
38 universally accepted networking methods. The most serious of these is getting
39 the proper networking package loaded onto the system, since most environments
40 do not come with the network interface packages loaded.
41
42 The second most serious network issue relates to security. The network
43 simulation needs to simulate operating system level functionality (packet
44 driving). However, the host network programming interfaces tend to operate at
45 the user level of functionality, so getting to the full functionality of
46 the network interface usually requires that the person executing the
47 network code be a privileged user of the host system. See the PCAP/WinPcap
48 documentation for the appropriate host platform if unprivileged use of
49 networking is needed - there may be known workarounds.
50
51 Define one of the two macros below to enable networking:
52 USE_NETWORK - Create statically linked network code
53 USE_SHARED - Create dynamically linked network code (_WIN32 only)
54
55 ------------------------------------------------------------------------------
56
57 Supported/Tested Platforms:
58
59 Windows(NT,2K,XP,2K3) WinPcap V3.0+
60 Linux libpcap at least 0.9
61 OpenBSD,FreeBSD,NetBSD libpcap at least 0.9
62 MAC OS/X libpcap at least 0.9
63 Solaris Sparc libpcap at least 0.9
64 Solaris Intel libpcap at least 0.9
65 AIX ??
66 HP/UX ??
67 Compaq Tru64 Unix ??
68 VMS Alpha/Itanium VMS only, needs VMS libpcap
69
70 WinPcap is available from:
71 http://winpcap.polito.it/
72 libpcap for VMS is available from:
73 http://simh.trailing-edge.com/sources/vms-pcap.zip
74 libpcap for other Unix platforms is available at:
75 Current Version: http://www.tcpdump.org/daily/libpcap-current.tar.gz
76 Released Version: http://www.tcpdump.org/release/
77 Note: You can only use the released version if it is at least
78 version 0.9
79
80
81 We've gotten the tarball, unpacked, built and installed it with:
82 gzip -dc libpcap-current.tar.gz | tar xvf -
83 cd libpcap-directory-name
84 ./configure
85 make
86 make install
87 Note: The "make install" step generally will have to be done as root.
88 This will install libpcap in /usr/local/lib and /usr/local/include
89 It is then important to make sure that you get the just installed
90 libpcap components referenced during your build. This is generally
91 achieved by invoking gcc with:
92 -isystem /usr/local/include -L /usr/local/lib
93
94
95 Note: Building for the platforms indicated above, with the indicated libpcap,
96 should automatically leverage the appropriate mechanisms contained here.
97 Things are structured so that it is likely to work for any other as yet
98 untested platform. If it works for you, please let the author know so we
99 can update the table above. If it doesn't work, then the following #define
100 variables can influence the operation on an untested platform.
101
102 USE_BPF - Determines if this code leverages a libpcap/WinPcap
103 provided bpf packet filtering facility. All tested
104 environments have bpf facilities that work the way we
105 need them to. However a new one might not. undefine
106 this variable to let this code do its own filtering.
107 USE_SETNONBLOCK - Specifies whether the libpcap environment's non-blocking
108 semantics are to be leveraged. This helps to manage the
109 varying behaviours of the kernel packet facilities
110 leveraged by libpcap.
111 USE_READER_THREAD - Specifies that packet reading should be done in the
112 context of a separate thread. The Posix threading
113 APIs are used. This option is less efficient than the
114 default non-threaded approach, but it exists since some
115 platforms don't want to work with nonblocking libpcap
116 semantics. OpenBSD and NetBSD either don't have pthread
117 APIs available, or they are too buggy to be useful.
118 Using the threaded approach may require special compile
119 and/or link time switches (i.e. -lpthread or -pthread,
120 etc.) Consult the documentation for your platform as
121 needed.
122 MUST_DO_SELECT - Specifies that when USE_READER_THREAD is active, that
123 select() should be used to determin when available
124 packets are ready for reading. Otherwise, we depend
125 on the libpcap/kernel packet timeout specified on
126 pcap_open_live. If USE_READER_THREAD is not set, then
127 MUST_DO_SELECT is irrelevant
128
129 NEED_PCAP_SENDPACKET
130 - Specifies that you are using an older version of libpcap
131 which doesn't provide a pcap_sendpacket API.
132
133 NOTE: Changing these defines is done in either sim_ether.h OR on the global
134 compiler command line which builds all of the modules included in a
135 simulator.
136
137 ------------------------------------------------------------------------------
138
139 Modification history:
140
141 17-May-07 DTH Fixed non-ethernet device removal loop (from Naoki Hamada)
142 15-May-07 DTH Added dynamic loading of wpcap.dll;
143 Corrected exceed max index bug in ethX lookup
144 04-May-07 DTH Corrected failure to look up ethernet device names in
145 the registry on Windows XP x64
146 10-Jul-06 RMS Fixed linux conditionalization (from Chaskiel Grundman)
147 02-Jun-06 JDB Fixed compiler warning for incompatible sscanf parameter
148 15-Dec-05 DTH Patched eth_host_devices [remove non-ethernet devices]
149 (from Mark Pizzolato and Galen Tackett, 08-Jun-05)
150 Patched eth_open [tun fix](from Antal Ritter, 06-Oct-05)
151 30-Nov-05 DTH Added option to regenerate CRC on received packets; some
152 ethernet devices need to pass it on to the simulation, and by
153 the time libpcap/winpcap gets the packet, the host OS network
154 layer has already stripped CRC out of the packet
155 01-Dec-04 DTH Added Windows user-defined adapter names (from Timothe Litt)
156 25-Mar-04 MP Revised comments and minor #defines to deal with updated
157 libpcap which now provides pcap_sendpacket on all platforms.
158 04-Feb-04 MP Returned success/fail status from eth_write to support
159 determining if the current libpcap connection can successfully
160 write packets.
161 Added threaded approach to reading packets since
162 this works better on some platforms (solaris intel) than the
163 inconsistently implemented non-blocking read approach.
164 04-Feb-04 DTH Converted ETH_DEBUG to sim_debug
165 13-Jan-04 MP tested and fixed on OpenBSD, NetBS and FreeBSD.
166 09-Jan-04 MP removed the BIOCSHDRCMPLT ioctl() for OS/X
167 05-Jan-04 DTH Added eth_mac_scan
168 30-Dec-03 DTH Cleaned up queue routines, added no network support message
169 26-Dec-03 DTH Added ethernet show and queue functions from pdp11_xq
170 15-Dec-03 MP polished generic libpcap support.
171 05-Dec-03 DTH Genericized eth_devices() and #ifdefs
172 03-Dec-03 MP Added Solaris support
173 02-Dec-03 DTH Corrected decnet fix to use reflection counting
174 01-Dec-03 DTH Added BPF source filtering and reflection counting
175 28-Nov-03 DTH Rewrote eth_devices using universal pcap_findalldevs()
176 25-Nov-03 DTH Verified DECNET_FIX, reversed ifdef to mainstream code
177 19-Nov-03 MP Fixed BPF functionality on Linux/BSD.
178 17-Nov-03 DTH Added xBSD simplification
179 14-Nov-03 DTH Added #ifdef DECNET_FIX for problematic duplicate detection code
180 13-Nov-03 DTH Merged in __FreeBSD__ support
181 21-Oct-03 MP Added enriched packet dumping for debugging
182 20-Oct-03 MP Added support for multiple ethernet devices on VMS
183 20-Sep-03 Ankan Add VMS support (Alpha only)
184 29-Sep-03 MP Changed separator character in eth_fmt_mac to be ":" to
185 format ethernet addresses the way the BPF compile engine
186 wants to see them.
187 Added BPF support to filter packets
188 Added missing printf in eth_close
189 07-Jun-03 MP Added WIN32 support for DECNET duplicate address detection.
190 06-Jun-03 MP Fixed formatting of Ethernet Protocol Type in eth_packet_trace
191 30-May-03 DTH Changed WIN32 to _WIN32 for consistency
192 07-Mar-03 MP Fixed Linux implementation of PacketGetAdapterNames to also
193 work on Red Hat 6.2-sparc and Debian 3.0r1-sparc.
194 03-Mar-03 MP Changed logging to be consistent on stdout and sim_log
195 01-Feb-03 MP Changed type of local variables in eth_packet_trace to
196 conform to the interface needs of eth_mac_fmt wich produces
197 char data instead of unsigned char data. Suggested by the
198 DECC compiler.
199 15-Jan-03 DTH Corrected PacketGetAdapterNames parameter2 datatype
200 26-Dec-02 DTH Merged Mark Pizzolato's enhancements with main source
201 Added networking documentation
202 Changed _DEBUG to ETH_DEBUG
203 20-Dec-02 MP Added display of packet CRC to the eth_packet_trace.
204 This helps distinguish packets with identical lengths
205 and protocols.
206 05-Dec-02 MP With the goal of draining the input buffer more rapidly
207 changed eth_read to call pcap_dispatch repeatedly until
208 either a timeout returns nothing or a packet allowed by
209 the filter is seen. This more closely reflects how the
210 pcap layer will work when the filtering is actually done
211 by a bpf filter.
212 31-Oct-02 DTH Added USE_NETWORK conditional
213 Reworked not attached test
214 Added OpenBSD support (from Federico Schwindt)
215 Added ethX detection simplification (from Megan Gentry)
216 Removed sections of temporary code
217 Added parameter validation
218 23-Oct-02 DTH Beta 5 released
219 22-Oct-02 DTH Added all_multicast and promiscuous support
220 Fixed not attached behavior
221 21-Oct-02 DTH Added NetBSD support (from Jason Thorpe)
222 Patched buffer size to make sure entire packet is read in
223 Made 'ethX' check characters passed as well as length
224 Corrected copyright again
225 16-Oct-02 DTH Beta 4 released
226 Corrected copyright
227 09-Oct-02 DTH Beta 3 released
228 Added pdp11 write acceleration (from Patrick Caulfield)
229 08-Oct-02 DTH Beta 2 released
230 Integrated with 2.10-0p4
231 Added variable vector and copyrights
232 04-Oct-02 DTH Added linux support (from Patrick Caulfield)
233 03-Oct-02 DTH Beta version of xq/sim_ether released for SIMH 2.09-11
234 24-Sep-02 DTH Finished eth_devices, eth_getname
235 18-Sep-02 DTH Callbacks implemented
236 13-Sep-02 DTH Basic packet read/write written
237 20-Aug-02 DTH Created Sim_Ether for O/S independant ethernet implementation
238
239 ------------------------------------------------------------------------------
240 */
241
242 #include <ctype.h>
243 #include "sim_ether.h"
244 #include "sim_sock.h"
245
246 extern FILE *sim_log;
247
248
249 /*============================================================================*/
250 /* OS-independant ethernet routines */
251 /*============================================================================*/
252
253 t_stat eth_mac_scan (ETH_MAC* mac, char* strmac)
254 {
255 int i, j;
256 short unsigned int num;
257 char cptr[18];
258 int len = strlen(strmac);
259 const ETH_MAC zeros = {0,0,0,0,0,0};
260 const ETH_MAC ones = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
261 ETH_MAC newmac;
262
263 /* format of string must be 6 double-digit hex bytes with valid separators
264 ideally, this mac scanner could allow more flexible formatting later */
265 if (len != 17) return SCPE_ARG;
266
267 /* copy string to local storage for mangling */
268 strcpy(cptr, strmac);
269
270 /* make sure byte separators are OK */
271 for (i=2; i<len; i=i+3) {
272 if ((cptr[i] != '-') &&
273 (cptr[i] != '.') &&
274 (cptr[i] != ':')) return SCPE_ARG;
275 cptr[i] = '\0';
276 }
277
278 /* get and set address bytes */
279 for (i=0, j=0; i<len; i=i+3, j++) {
280 int valid = strspn(&cptr[i], "0123456789abcdefABCDEF");
281 if (valid < 2) return SCPE_ARG;
282 sscanf(&cptr[i], "%hx", &num);
283 newmac[j] = (unsigned char) num;
284 }
285
286 /* final check - mac cannot be broadcast or multicast address */
287 if (!memcmp(newmac, zeros, sizeof(ETH_MAC)) || /* broadcast */
288 !memcmp(newmac, ones, sizeof(ETH_MAC)) || /* broadcast */
289 (newmac[0] & 0x01) /* multicast */
290 )
291 return SCPE_ARG;
292
293 /* new mac is OK, copy into passed mac */
294 memcpy (*mac, newmac, sizeof(ETH_MAC));
295 return SCPE_OK;
296 }
297
298 void eth_mac_fmt(ETH_MAC* mac, char* buff)
299 {
300 uint8* m = (uint8*) mac;
301 sprintf(buff, "%02X:%02X:%02X:%02X:%02X:%02X", m[0], m[1], m[2], m[3], m[4], m[5]);
302 return;
303 }
304
305 static const uint32 crcTable[256] = {
306 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
307 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
308 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
309 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
310 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
311 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
312 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
313 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
314 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
315 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
316 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
317 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
318 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
319 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
320 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
321 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
322 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
323 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
324 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
325 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
326 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
327 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
328 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
329 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
330 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
331 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
332 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
333 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
334 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
335 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
336 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
337 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
338 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
339 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
340 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
341 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
342 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
343 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
344 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
345 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
346 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
347 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
348 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
349 };
350
351 uint32 eth_crc32(uint32 crc, const void* vbuf, size_t len)
352 {
353 const uint32 mask = 0xFFFFFFFF;
354 const unsigned char* buf = (const unsigned char*)vbuf;
355
356 crc ^= mask;
357 while (0 != len--)
358 crc = (crc >> 8) ^ crcTable[ (crc ^ (*buf++)) & 0xFF ];
359 return(crc ^ mask);
360 }
361
362 void eth_add_crc32(ETH_PACK* packet)
363 {
364 if (packet->len <= ETH_MAX_PACKET) {
365 uint32 crc = eth_crc32(0, packet->msg, packet->len); /* calculate CRC */
366 uint32 ncrc = htonl(crc); /* CRC in network order */
367 int size = sizeof(ncrc); /* size of crc field */
368 memcpy(&packet->msg[packet->len], &ncrc, size); /* append crc to packet */
369 packet->crc_len = packet->len + size; /* set packet crc length */
370 } else {
371 packet->crc_len = 0; /* appending crc would destroy packet */
372 }
373 }
374
375 void eth_setcrc(ETH_DEV* dev, int need_crc)
376 {
377 dev->need_crc = need_crc;
378 }
379
380 void eth_packet_trace_ex(ETH_DEV* dev, const uint8 *msg, int len, char* txt, int dmp)
381 {
382 if (dev->dptr->dctrl & dev->dbit) {
383 char src[20];
384 char dst[20];
385 unsigned short* proto = (unsigned short*) &msg[12];
386 uint32 crc = eth_crc32(0, msg, len);
387 eth_mac_fmt((ETH_MAC*)&msg[0], dst);
388 eth_mac_fmt((ETH_MAC*)&msg[6], src);
389 sim_debug(dev->dbit, dev->dptr, "%s dst: %s src: %s proto: 0x%04X len: %d crc: %X\n",
390 txt, dst, src, ntohs(*proto), len, crc);
391 if (dmp) {
392 int i, same, group, sidx, oidx;
393 char outbuf[80], strbuf[18];
394 static char hex[] = "0123456789ABCDEF";
395 for (i=same=0; i<len; i += 16) {
396 if ((i > 0) && (0 == memcmp(&msg[i], &msg[i-16], 16))) {
397 ++same;
398 continue;
399 }
400 if (same > 0) {
401 sim_debug(dev->dbit, dev->dptr, "%04X thru %04X same as above\r\n", i-(16*same), i-1);
402 same = 0;
403 }
404 group = (((len - i) > 16) ? 16 : (len - i));
405 for (sidx=oidx=0; sidx<group; ++sidx) {
406 outbuf[oidx++] = ' ';
407 outbuf[oidx++] = hex[(msg[i+sidx]>>4)&0xf];
408 outbuf[oidx++] = hex[msg[i+sidx]&0xf];
409 if (isprint(msg[i+sidx]))
410 strbuf[sidx] = msg[i+sidx];
411 else
412 strbuf[sidx] = '.';
413 }
414 outbuf[oidx] = '\0';
415 strbuf[sidx] = '\0';
416 sim_debug(dev->dbit, dev->dptr, "%04X%-48s %s\r\n", i, outbuf, strbuf);
417 }
418 if (same > 0)
419 sim_debug(dev->dbit, dev->dptr, "%04X thru %04X same as above\r\n", i-(16*same), len-1);
420 }
421 }
422 }
423
424 void eth_packet_trace(ETH_DEV* dev, const uint8 *msg, int len, char* txt)
425 {
426 eth_packet_trace_ex(dev, msg, len, txt, 1/*len > ETH_MAX_PACKET*/);
427 }
428
429 char* eth_getname(int number, char* name)
430 {
431 ETH_LIST list[ETH_MAX_DEVICE];
432 int count = eth_devices(ETH_MAX_DEVICE, list);
433
434 if (count <= number) return 0;
435 strcpy(name, list[number].name);
436 return name;
437 }
438
439 char* eth_getname_bydesc(char* desc, char* name)
440 {
441 ETH_LIST list[ETH_MAX_DEVICE];
442 int count = eth_devices(ETH_MAX_DEVICE, list);
443 int i;
444 int j=strlen(desc);
445
446 for (i=0; i<count; i++) {
447 int found = 1;
448 int k = strlen(list[i].desc);
449
450 if (j != k) continue;
451 for (k=0; k<j; k++)
452 if (tolower(list[i].desc[k]) != tolower(desc[k]))
453 found = 0;
454 if (found == 0) continue;
455
456 /* found a case-insensitive description match */
457 strcpy(name, list[i].name);
458 return name;
459 }
460 /* not found */
461 return 0;
462 }
463
464 /* strncasecmp() is not available on all platforms */
465 int eth_strncasecmp(char* string1, char* string2, int len)
466 {
467 int i;
468 unsigned char s1, s2;
469
470 for (i=0; i<len; i++) {
471 s1 = string1[i];
472 s2 = string2[i];
473 if (islower (s1)) s1 = toupper (s1);
474 if (islower (s2)) s2 = toupper (s2);
475
476 if (s1 < s2)
477 return -1;
478 if (s1 > s2)
479 return 1;
480 if (s1 == 0) return 0;
481 }
482 return 0;
483 }
484
485 char* eth_getname_byname(char* name, char* temp)
486 {
487 ETH_LIST list[ETH_MAX_DEVICE];
488 int count = eth_devices(ETH_MAX_DEVICE, list);
489 int i, n, found;
490
491 found = 0;
492 n = strlen(name);
493 for (i=0; i<count && !found; i++) {
494 if (eth_strncasecmp(name, list[i].name, n) == 0) {
495 found = 1;
496 strcpy(temp, list[i].name); /* only case might be different */
497 }
498 }
499 if (found) {
500 return temp;
501 } else {
502 return 0;
503 }
504 }
505
506 void eth_zero(ETH_DEV* dev)
507 {
508 /* set all members to NULL OR 0 */
509 memset(dev, 0, sizeof(ETH_DEV));
510 dev->reflections = -1; /* not established yet */
511 }
512
513 t_stat eth_show (FILE* st, UNIT* uptr, int32 val, void* desc)
514 {
515 ETH_LIST list[ETH_MAX_DEVICE];
516 int number = eth_devices(ETH_MAX_DEVICE, list);
517
518 fprintf(st, "ETH devices:\n");
519 if (number == -1)
520 fprintf(st, " network support not available in simulator\n");
521 else
522 if (number == 0)
523 fprintf(st, " no network devices are available\n");
524 else {
525 int i, min, len;
526 for (i=0, min=0; i<number; i++)
527 if ((len = strlen(list[i].name)) > min) min = len;
528 for (i=0; i<number; i++)
529 fprintf(st," %d %-*s (%s)\n", i, min, list[i].name, list[i].desc);
530 }
531 return SCPE_OK;
532 }
533
534 t_stat ethq_init(ETH_QUE* que, int max)
535 {
536 /* create dynamic queue if it does not exist */
537 if (!que->item) {
538 size_t size = sizeof(struct eth_item) * max;
539 que->max = max;
540 que->item = (struct eth_item *) malloc(size);
541 if (que->item) {
542 /* init dynamic memory */
543 memset(que->item, 0, size);
544 } else {
545 /* failed to allocate memory */
546 char* msg = "EthQ: failed to allocate dynamic queue[%d]\r\n";
547 printf(msg, max);
548 if (sim_log) fprintf(sim_log, msg, max);
549 return SCPE_MEM;
550 };
551 };
552 return SCPE_OK;
553 }
554
555 void ethq_clear(ETH_QUE* que)
556 {
557 /* clear packet array */
558 memset(que->item, 0, sizeof(struct eth_item) * que->max);
559 /* clear rest of structure */
560 que->count = que->head = que->tail = que->loss = que->high = 0;
561 }
562
563 void ethq_remove(ETH_QUE* que)
564 {
565 struct eth_item* item = &que->item[que->head];
566
567 if (que->count) {
568 memset(item, 0, sizeof(struct eth_item));
569 if (++que->head == que->max)
570 que->head = 0;
571 que->count--;
572 }
573 }
574
575 void ethq_insert(ETH_QUE* que, int32 type, ETH_PACK* pack, int32 status)
576 {
577 struct eth_item* item;
578
579 /* if queue empty, set pointers to beginning */
580 if (!que->count) {
581 que->head = 0;
582 que->tail = -1;
583 }
584
585 /* find new tail of the circular queue */
586 if (++que->tail == que->max)
587 que->tail = 0;
588 if (++que->count > que->max) {
589 que->count = que->max;
590 /* lose oldest packet */
591 if (++que->head == que->max)
592 que->head = 0;
593 que->loss++;
594 }
595 if (que->count > que->high)
596 que->high = que->count;
597
598 /* set information in (new) tail item */
599 item = &que->item[que->tail];
600 item->type = type;
601 item->packet.len = pack->len;
602 item->packet.used = 0;
603 item->packet.crc_len = pack->crc_len;
604 memcpy(item->packet.msg, pack->msg, ((pack->len > pack->crc_len) ? pack->len : pack->crc_len));
605 item->packet.status = status;
606 }
607
608 /*============================================================================*/
609 /* Non-implemented versions */
610 /*============================================================================*/
611
612 #if !defined (USE_NETWORK) && !defined(USE_SHARED)
613 t_stat eth_open(ETH_DEV* dev, char* name, DEVICE* dptr, uint32 dbit)
614 {return SCPE_NOFNC;}
615 t_stat eth_close (ETH_DEV* dev)
616 {return SCPE_NOFNC;}
617 t_stat eth_write (ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine)
618 {return SCPE_NOFNC;}
619 t_stat eth_read (ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine)
620 {return SCPE_NOFNC;}
621 t_stat eth_filter (ETH_DEV* dev, int addr_count, ETH_MAC* addresses,
622 ETH_BOOL all_multicast, ETH_BOOL promiscuous)
623 {return SCPE_NOFNC;}
624 int eth_devices (int max, ETH_LIST* dev)
625 {return -1;}
626 #else /* endif unimplemented */
627
628 /*============================================================================*/
629 /* WIN32, Linux, and xBSD routines use WinPcap and libpcap packages */
630 /* OpenVMS Alpha uses a WinPcap port and an associated execlet */
631 /*============================================================================*/
632
633 #if defined (xBSD) && !defined(__APPLE__)
634 #include <sys/ioctl.h>
635 #include <net/bpf.h>
636 #endif /* xBSD */
637
638 #include <pcap.h>
639 #include <string.h>
640
641 /* Allows windows to look up user-defined adapter names */
642 #if defined(_WIN32)
643 #include <winreg.h>
644 #endif
645
646 #if defined(_WIN32) && defined(USE_SHARED)
647 /* Dynamic DLL loading technique and modified source comes from
648 Etherial/WireShark capture_pcap.c */
649
650 /* Dynamic DLL load variables */
651 static HINSTANCE hDll = 0; /* handle to DLL */
652 static int dll_loaded = 0; /* 0=not loaded, 1=loaded, 2=DLL load failed, 3=Func load failed */
653 static char* no_wpcap = "wpcap load failure";
654
655 /* define pointers to pcap functions needed */
656 static void (*p_pcap_close) (pcap_t *);
657 static int (*p_pcap_compile) (pcap_t *, struct bpf_program *, char *, int, bpf_u_int32);
658 static int (*p_pcap_datalink) (pcap_t *);
659 static int (*p_pcap_dispatch) (pcap_t *, int, pcap_handler, u_char *);
660 static int (*p_pcap_findalldevs) (pcap_if_t **, char *);
661 static void (*p_pcap_freealldevs) (pcap_if_t *);
662 static void (*p_pcap_freecode) (struct bpf_program *);
663 static char* (*p_pcap_geterr) (pcap_t *);
664 static int (*p_pcap_lookupnet) (const char *, bpf_u_int32 *, bpf_u_int32 *, char *);
665 static pcap_t* (*p_pcap_open_live) (const char *, int, int, int, char *);
666 static int (*p_pcap_sendpacket) (pcap_t* handle, const u_char* msg, int len);
667 static int (*p_pcap_setfilter) (pcap_t *, struct bpf_program *);
668 static char* (*p_pcap_lib_version) (void);
669
670 /* load function pointer from DLL */
671 void load_function(char* function, void** func_ptr) {
672 *func_ptr = GetProcAddress(hDll, function);
673 if (*func_ptr == 0) {
674 char* msg = "Eth: Failed to find function '%s' in wpcap.dll\r\n";
675 printf (msg, function);
676 if (sim_log) fprintf (sim_log, msg, function);
677 dll_loaded = 3;
678 }
679 }
680
681 /* load wpcap.dll as required */
682 int load_wpcap(void) {
683 switch(dll_loaded) {
684 case 0: /* not loaded */
685 /* attempt to load DLL */
686 hDll = LoadLibrary(TEXT("wpcap.dll"));
687 if (hDll == 0) {
688 /* failed to load DLL */
689 char* msg = "Eth: Failed to load wpcap.dll\r\n";
690 char* msg2 = "Eth: You must install WinPcap 4.x to use networking\r\n";
691 printf (msg);
692 printf (msg2);
693 if (sim_log) {
694 fprintf (sim_log, msg);
695 fprintf (sim_log, msg2);
696 }
697 dll_loaded = 2;
698 break;
699 } else {
700 /* DLL loaded OK */
701 dll_loaded = 1;
702 }
703
704 /* load required functions; sets dll_load=3 on error */
705 load_function("pcap_close", (void**) &p_pcap_close);
706 load_function("pcap_compile", (void**) &p_pcap_compile);
707 load_function("pcap_datalink", (void**) &p_pcap_datalink);
708 load_function("pcap_dispatch", (void**) &p_pcap_dispatch);
709 load_function("pcap_findalldevs", (void**) &p_pcap_findalldevs);
710 load_function("pcap_freealldevs", (void**) &p_pcap_freealldevs);
711 load_function("pcap_freecode", (void**) &p_pcap_freecode);
712 load_function("pcap_geterr", (void**) &p_pcap_geterr);
713 load_function("pcap_lookupnet", (void**) &p_pcap_lookupnet);
714 load_function("pcap_open_live", (void**) &p_pcap_open_live);
715 load_function("pcap_sendpacket", (void**) &p_pcap_sendpacket);
716 load_function("pcap_setfilter", (void**) &p_pcap_setfilter);
717 load_function("pcap_lib_version", (void**) &p_pcap_lib_version);
718
719 if (dll_loaded == 1) {
720 /* log successful load */
721 char* version = p_pcap_lib_version();
722 printf("%s\n", version);
723 if (sim_log)
724 fprintf(sim_log, "%s\n", version);
725 }
726 break;
727 default: /* loaded or failed */
728 break;
729 }
730 return (dll_loaded == 1) ? 1 : 0;
731 }
732
733 /* define functions with dynamic revectoring */
734 void pcap_close(pcap_t* a) {
735 if (load_wpcap() != 0) {
736 p_pcap_close(a);
737 }
738 }
739
740 int pcap_compile(pcap_t* a, struct bpf_program* b, char* c, int d, bpf_u_int32 e) {
741 if (load_wpcap() != 0) {
742 return p_pcap_compile(a, b, c, d, e);
743 } else {
744 return 0;
745 }
746 }
747
748 int pcap_datalink(pcap_t* a) {
749 if (load_wpcap() != 0) {
750 return p_pcap_datalink(a);
751 } else {
752 return 0;
753 }
754 }
755
756 int pcap_dispatch(pcap_t* a, int b, pcap_handler c, u_char* d) {
757 if (load_wpcap() != 0) {
758 return p_pcap_dispatch(a, b, c, d);
759 } else {
760 return 0;
761 }
762 }
763
764 int pcap_findalldevs(pcap_if_t** a, char* b) {
765 if (load_wpcap() != 0) {
766 return p_pcap_findalldevs(a, b);
767 } else {
768 *a = 0;
769 strcpy(b, no_wpcap);
770 return -1;
771 }
772 }
773
774 void pcap_freealldevs(pcap_if_t* a) {
775 if (load_wpcap() != 0) {
776 p_pcap_freealldevs(a);
777 }
778 }
779
780 void pcap_freecode(struct bpf_program* a) {
781 if (load_wpcap() != 0) {
782 p_pcap_freecode(a);
783 }
784 }
785
786 char* pcap_geterr(pcap_t* a) {
787 if (load_wpcap() != 0) {
788 return p_pcap_geterr(a);
789 } else {
790 return (char*) 0;
791 }
792 }
793
794 int pcap_lookupnet(const char* a, bpf_u_int32* b, bpf_u_int32* c, char* d) {
795 if (load_wpcap() != 0) {
796 return p_pcap_lookupnet(a, b, c, d);
797 } else {
798 return 0;
799 }
800 }
801
802 pcap_t* pcap_open_live(const char* a, int b, int c, int d, char* e) {
803 if (load_wpcap() != 0) {
804 return p_pcap_open_live(a, b, c, d, e);
805 } else {
806 return (pcap_t*) 0;
807 }
808 }
809
810 int pcap_sendpacket(pcap_t* a, const u_char* b, int c) {
811 if (load_wpcap() != 0) {
812 return p_pcap_sendpacket(a, b, c);
813 } else {
814 return 0;
815 }
816 }
817
818 int pcap_setfilter(pcap_t* a, struct bpf_program* b) {
819 if (load_wpcap() != 0) {
820 return p_pcap_setfilter(a, b);
821 } else {
822 return 0;
823 }
824 }
825 #endif
826
827 /* Some platforms have always had pcap_sendpacket */
828 #if defined(_WIN32) || defined(VMS)
829 #define HAS_PCAP_SENDPACKET 1
830 #else
831 /* The latest libpcap and WinPcap all have pcap_sendpacket */
832 #if !defined (NEED_PCAP_SENDPACKET)
833 #define HAS_PCAP_SENDPACKET 1
834 #endif
835 #endif
836
837 #if !defined (HAS_PCAP_SENDPACKET)
838 /* libpcap has no function to write a packet, so we need to implement
839 pcap_sendpacket() for compatibility with the WinPcap base code.
840 Return value: 0=Success, -1=Failure */
841 int pcap_sendpacket(pcap_t* handle, const u_char* msg, int len)
842 {
843 #if defined (__linux)
844 return (send(pcap_fileno(handle), msg, len, 0) == len)? 0 : -1;
845 #else
846 return (write(pcap_fileno(handle), msg, len) == len)? 0 : -1;
847 #endif /* linux */
848 }
849 #endif /* !HAS_PCAP_SENDPACKET */
850
851 #if defined (USE_READER_THREAD)
852 #include <pthread.h>
853
854 void eth_callback(u_char* info, const struct pcap_pkthdr* header, const u_char* data);
855
856 static void *
857 _eth_reader(void *arg)
858 {
859 ETH_DEV* volatile dev = (ETH_DEV*)arg;
860 int status;
861 struct timeval timeout;
862
863 timeout.tv_sec = 0;
864 timeout.tv_usec = 200*1000;
865
866 sim_debug(dev->dbit, dev->dptr, "Reader Thread Starting\n");
867
868 while (dev->handle) {
869 #if defined (MUST_DO_SELECT)
870 int sel_ret;
871
872 fd_set setl;
873 FD_ZERO(&setl);
874 FD_SET(pcap_get_selectable_fd((pcap_t *)dev->handle), &setl);
875 sel_ret = select(1+pcap_get_selectable_fd((pcap_t *)dev->handle), &setl, NULL, NULL, &timeout);
876 if (sel_ret < 0 && errno != EINTR) break;
877 if (sel_ret > 0) {
878 /* dispatch read request queue available packets */
879 status = pcap_dispatch((pcap_t*)dev->handle, -1, &eth_callback, (u_char*)dev);
880 }
881 #else
882 /* dispatch read request queue available packets */
883 status = pcap_dispatch((pcap_t*)dev->handle, 1, &eth_callback, (u_char*)dev);
884 #endif
885 }
886
887 sim_debug(dev->dbit, dev->dptr, "Reader Thread Exiting\n");
888 return NULL;
889 }
890 #endif
891
892 t_stat eth_open(ETH_DEV* dev, char* name, DEVICE* dptr, uint32 dbit)
893 {
894 const int bufsz = (BUFSIZ < ETH_MAX_PACKET) ? ETH_MAX_PACKET : BUFSIZ;
895 char errbuf[PCAP_ERRBUF_SIZE];
896 char temp[1024];
897 char* savname = name;
898 int num;
899 char* msg;
900
901 /* initialize device */
902 eth_zero(dev);
903
904 /* translate name of type "ethX" to real device name */
905 if ((strlen(name) == 4)
906 && (tolower(name[0]) == 'e')
907 && (tolower(name[1]) == 't')
908 && (tolower(name[2]) == 'h')
909 && isdigit(name[3])
910 ) {
911 num = atoi(&name[3]);
912 savname = eth_getname(num, temp);
913 if (savname == 0) /* didn't translate */
914 return SCPE_OPENERR;
915 } else {
916 /* are they trying to use device description? */
917 savname = eth_getname_bydesc(name, temp);
918 if (savname == 0) { /* didn't translate */
919 /* probably is not ethX and has no description */
920 savname = eth_getname_byname(name, temp);
921 if (savname == 0) /* didn't translate */
922 return SCPE_OPENERR;
923 }
924 }
925
926 /* attempt to connect device */
927 memset(errbuf, 0, sizeof(errbuf));
928 dev->handle = (void*) pcap_open_live(savname, bufsz, ETH_PROMISC, PCAP_READ_TIMEOUT, errbuf);
929 if (!dev->handle) { /* can't open device */
930 msg = "Eth: pcap_open_live error - %s\r\n";
931 printf (msg, errbuf);
932 if (sim_log) fprintf (sim_log, msg, errbuf);
933 return SCPE_OPENERR;
934 } else {
935 msg = "Eth: opened %s\r\n";
936 printf (msg, savname);
937 if (sim_log) fprintf (sim_log, msg, savname);
938 }
939
940 /* save name of device */
941 dev->name = malloc(strlen(savname)+1);
942 strcpy(dev->name, savname);
943
944 /* save debugging information */
945 dev->dptr = dptr;
946 dev->dbit = dbit;
947
948 #if !defined(HAS_PCAP_SENDPACKET) && defined (xBSD) && !defined (__APPLE__)
949 /* Tell the kernel that the header is fully-formed when it gets it.
950 This is required in order to fake the src address. */
951 {
952 int one = 1;
953 ioctl(pcap_fileno(dev->handle), BIOCSHDRCMPLT, &one);
954 }
955 #endif /* xBSD */
956
957 #if defined (USE_READER_THREAD)
958 {
959 pthread_attr_t attr;
960
961 ethq_init (&dev->read_queue, 200); /* initialize FIFO queue */
962 pthread_mutex_init (&dev->lock, NULL);
963 pthread_attr_init(&attr);
964 pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
965 pthread_create (&dev->reader_thread, &attr, _eth_reader, (void *)dev);
966 pthread_attr_destroy(&attr);
967 }
968 #else /* !defined (USE_READER_THREAD */
969 #ifdef USE_SETNONBLOCK
970 /* set ethernet device non-blocking so pcap_dispatch() doesn't hang */
971 if (pcap_setnonblock (dev->handle, 1, errbuf) == -1) {
972 msg = "Eth: Failed to set non-blocking: %s\r\n";
973 printf (msg, errbuf);
974 if (sim_log) fprintf (sim_log, msg, errbuf);
975 }
976 #endif
977 #endif /* !defined (USE_READER_THREAD */
978 return SCPE_OK;
979 }
980
981 t_stat eth_close(ETH_DEV* dev)
982 {
983 char* msg = "Eth: closed %s\r\n";
984 pcap_t *pcap;
985
986 /* make sure device exists */
987 if (!dev) return SCPE_UNATT;
988
989 /* close the device */
990 pcap = (pcap_t *)dev->handle;
991 dev->handle = NULL;
992 pcap_close(pcap);
993 printf (msg, dev->name);
994 if (sim_log) fprintf (sim_log, msg, dev->name);
995
996 #if defined (USE_READER_THREAD)
997 pthread_join (dev->reader_thread, NULL);
998 #endif
999
1000 /* clean up the mess */
1001 free(dev->name);
1002 eth_zero(dev);
1003
1004 return SCPE_OK;
1005 }
1006
1007 t_stat eth_reflect(ETH_DEV* dev, ETH_MAC mac)
1008 {
1009 ETH_PACK send, recv;
1010 t_stat status;
1011 int i;
1012 struct timeval delay;
1013
1014 /* build a packet */
1015 memset (&send, 0, sizeof(ETH_PACK));
1016 send.len = ETH_MIN_PACKET; /* minimum packet size */
1017 memcpy(&send.msg[0], mac, sizeof(ETH_MAC)); /* target address */
1018 memcpy(&send.msg[6], mac, sizeof(ETH_MAC)); /* source address */
1019 send.msg[12] = 0x90; /* loopback packet type */
1020 for (i=14; i<send.len; i++)
1021 send.msg[i] = 32 + i; /* gibberish */
1022
1023 dev->reflections = 0;
1024 eth_filter(dev, 1, (ETH_MAC *)mac, 0, 0);
1025
1026 /* send the packet */
1027 status = eth_write (dev, &send, NULL);
1028 if (status != SCPE_OK) {
1029 char *msg;
1030 msg = "Eth: Error Transmitting packet: %s\r\n"
1031 "You may need to run as root, or install a libpcap version\r\n"
1032 "which is at least 0.9 from www.tcpdump.org\r\n";
1033 printf(msg, strerror(errno));
1034 if (sim_log) fprintf (sim_log, msg, strerror(errno));
1035 return status;
1036 }
1037
1038 /* if/when we have a sim_os_msleep() we'll use it here instead of this select() */
1039 delay.tv_sec = 0;
1040 delay.tv_usec = 50*1000;
1041 select(0, NULL, NULL, NULL, &delay); /* make sure things settle into the read path */
1042
1043 /* empty the read queue and count the reflections */
1044 do {
1045 memset (&recv, 0, sizeof(ETH_PACK));
1046 status = eth_read (dev, &recv, NULL);
1047 if (memcmp(send.msg, recv.msg, ETH_MIN_PACKET)== 0)
1048 dev->reflections++;
1049 } while (recv.len > 0);
1050
1051 sim_debug(dev->dbit, dev->dptr, "Reflections = %d\n", dev->reflections);
1052 return dev->reflections;
1053 }
1054
1055 t_stat eth_write(ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine)
1056 {
1057 int status = 1; /* default to failure */
1058
1059 /* make sure device exists */
1060 if (!dev) return SCPE_UNATT;
1061
1062 /* make sure packet exists */
1063 if (!packet) return SCPE_ARG;
1064
1065 /* make sure packet is acceptable length */
1066 if ((packet->len >= ETH_MIN_PACKET) && (packet->len <= ETH_MAX_PACKET)) {
1067 eth_packet_trace (dev, packet->msg, packet->len, "writing");
1068
1069 /* dispatch write request (synchronous; no need to save write info to dev) */
1070 status = pcap_sendpacket((pcap_t*)dev->handle, (u_char*)packet->msg, packet->len);
1071
1072 /* detect sending of decnet loopback packet */
1073 if ((status == 0) && DECNET_SELF_FRAME(dev->decnet_addr, packet->msg))
1074 dev->decnet_self_sent += dev->reflections;
1075
1076 } /* if packet->len */
1077
1078 /* call optional write callback function */
1079 if (routine)
1080 (routine)(status);
1081
1082 return ((status == 0) ? SCPE_OK : SCPE_IOERR);
1083 }
1084
1085 void eth_callback(u_char* info, const struct pcap_pkthdr* header, const u_char* data)
1086 {
1087 ETH_DEV* dev = (ETH_DEV*) info;
1088 #ifdef USE_BPF
1089 int to_me = 1;
1090 #else /* !USE_BPF */
1091 int to_me = 0;
1092 int from_me = 0;
1093 int i;
1094
1095 #ifdef ETH_DEBUG
1096 // eth_packet_trace (dev, data, header->len, "received");
1097 #endif
1098 for (i = 0; i < dev->addr_count; i++) {
1099 if (memcmp(data, dev->filter_address[i], 6) == 0) to_me = 1;
1100 if (memcmp(&data[6], dev->filter_address[i], 6) == 0) from_me = 1;
1101 }
1102
1103 /* all multicast mode? */
1104 if (dev->all_multicast && (data[0] & 0x01)) to_me = 1;
1105
1106 /* promiscuous mode? */
1107 if (dev->promiscuous) to_me = 1;
1108 #endif /* USE_BPF */
1109
1110 /* detect sending of decnet loopback packet */
1111 if (DECNET_SELF_FRAME(dev->decnet_addr, data)) {
1112 /* lower reflection count - if already zero, pass it on */
1113 if (dev->decnet_self_sent > 0) {
1114 dev->decnet_self_sent--;
1115 to_me = 0;
1116 }
1117 #ifndef USE_BPF
1118 else
1119 from_me = 0;
1120 #endif
1121 }
1122
1123 #ifdef USE_BPF
1124 if (to_me) {
1125 #else /* !USE_BPF */
1126 if (to_me && !from_me) {
1127 #endif
1128 #if defined (USE_READER_THREAD)
1129 ETH_PACK tmp_packet;
1130
1131 /* set data in passed read packet */
1132 tmp_packet.len = header->len;
1133 memcpy(tmp_packet.msg, data, header->len);
1134 if (dev->need_crc)
1135 eth_add_crc32(&tmp_packet);
1136
1137 eth_packet_trace (dev, tmp_packet.msg, tmp_packet.len, "rcvqd");
1138
1139 pthread_mutex_lock (&dev->lock);
1140 ethq_insert(&dev->read_queue, 2, &tmp_packet, 0);
1141 pthread_mutex_unlock (&dev->lock);
1142 #else
1143 /* set data in passed read packet */
1144 dev->read_packet->len = header->len;
1145 memcpy(dev->read_packet->msg, data, header->len);
1146 if (dev->need_crc)
1147 eth_add_crc32(dev->read_packet);
1148
1149 eth_packet_trace (dev, dev->read_packet->msg, dev->read_packet->len, "reading");
1150
1151 /* call optional read callback function */
1152 if (dev->read_callback)
1153 (dev->read_callback)(0);
1154 #endif
1155 }
1156 }
1157
1158 t_stat eth_read(ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine)
1159 {
1160 int status;
1161
1162 /* make sure device exists */
1163
1164 if (!dev) return SCPE_UNATT;
1165
1166 /* make sure packet exists */
1167 if (!packet) return SCPE_ARG;
1168
1169 #if !defined (USE_READER_THREAD)
1170 /* set read packet */
1171 dev->read_packet = packet;
1172 packet->len = 0;
1173
1174 /* set optional callback routine */
1175 dev->read_callback = routine;
1176
1177 /* dispatch read request to either receive a filtered packet or timeout */
1178 do {
1179 status = pcap_dispatch((pcap_t*)dev->handle, 1, &eth_callback, (u_char*)dev);
1180 } while ((status) && (0 == packet->len));
1181
1182 #else /* USE_READER_THREAD */
1183
1184 status = 0;
1185 pthread_mutex_lock (&dev->lock);
1186 if (dev->read_queue.count > 0) {
1187 ETH_ITEM* item = &dev->read_queue.item[dev->read_queue.head];
1188 packet->len = item->packet.len;
1189 memcpy(packet->msg, item->packet.msg, packet->len);
1190 if (routine)
1191 routine(status);
1192 ethq_remove(&dev->read_queue);
1193 }
1194 pthread_mutex_unlock (&dev->lock);
1195 #endif
1196
1197 return SCPE_OK;
1198 }
1199
1200 t_stat eth_filter(ETH_DEV* dev, int addr_count, ETH_MAC* addresses,
1201 ETH_BOOL all_multicast, ETH_BOOL promiscuous)
1202 {
1203 int i;
1204 bpf_u_int32 bpf_subnet, bpf_netmask;
1205 char buf[110+66*ETH_FILTER_MAX];
1206 char errbuf[PCAP_ERRBUF_SIZE];
1207 char mac[20];
1208 char* buf2;
1209 t_stat status;
1210 #ifdef USE_BPF
1211 struct bpf_program bpf;
1212 char* msg;
1213 #endif
1214
1215 /* make sure device exists */
1216 if (!dev) return SCPE_UNATT;
1217
1218 /* filter count OK? */
1219 if ((addr_count < 0) || (addr_count > ETH_FILTER_MAX))
1220 return SCPE_ARG;
1221 else
1222 if (!addresses) return SCPE_ARG;
1223
1224 /* set new filter addresses */
1225 for (i = 0; i < addr_count; i++)
1226 memcpy(dev->filter_address[i], addresses[i], sizeof(ETH_MAC));
1227 dev->addr_count = addr_count;
1228
1229 /* store other flags */
1230 dev->all_multicast = all_multicast;
1231 dev->promiscuous = promiscuous;
1232
1233 /* print out filter information if debugging */
1234 if (dev->dptr->dctrl & dev->dbit) {
1235 sim_debug(dev->dbit, dev->dptr, "Filter Set\n");
1236 for (i = 0; i < addr_count; i++) {
1237 char mac[20];
1238 eth_mac_fmt(&dev->filter_address[i], mac);
1239 sim_debug(dev->dbit, dev->dptr, " Addr[%d]: %s\n", i, mac);
1240 }
1241 if (dev->all_multicast)
1242 sim_debug(dev->dbit, dev->dptr, "All Multicast\n");
1243 if (dev->promiscuous)
1244 sim_debug(dev->dbit, dev->dptr, "Promiscuous\n");
1245 }
1246
1247 /* test reflections */
1248 if (dev->reflections == -1)
1249 status = eth_reflect(dev, dev->filter_address[0]);
1250
1251 /* setup BPF filters and other fields to minimize packet delivery */
1252 strcpy(buf, "");
1253
1254 /* construct destination filters - since the real ethernet interface was set
1255 into promiscuous mode by eth_open(), we need to filter out the packets that
1256 our simulated interface doesn't want. */
1257 if (!dev->promiscuous) {
1258 for (i = 0; i < addr_count; i++) {
1259 eth_mac_fmt(&dev->filter_address[i], mac);
1260 if (!strstr(buf, mac)) /* eliminate duplicates */
1261 sprintf(&buf[strlen(buf)], "%s(ether dst %s)", (*buf) ? " or " : "", mac);
1262 }
1263 if (dev->all_multicast)
1264 sprintf(&buf[strlen(buf)], "%s(ether multicast)", (*buf) ? " or " : "");
1265 }
1266
1267 /* construct source filters - this prevents packets from being reflected back
1268 by systems where WinPcap and libpcap cause packet reflections. Note that
1269 some systems do not reflect packets at all. This *assumes* that the
1270 simulated NIC will not send out packets with multicast source fields. */
1271 if ((addr_count > 0) && (dev->reflections > 0)) {
1272 if (strlen(buf) > 0)
1273 sprintf(&buf[strlen(buf)], " and ");
1274 sprintf (&buf[strlen(buf)], "not (");
1275 buf2 = &buf[strlen(buf)];
1276 for (i = 0; i < addr_count; i++) {
1277 if (dev->filter_address[i][0] & 0x01) continue; /* skip multicast addresses */
1278 eth_mac_fmt(&dev->filter_address[i], mac);
1279 if (!strstr(buf2, mac)) /* eliminate duplicates */
1280 sprintf(&buf2[strlen(buf2)], "%s(ether src %s)", (*buf2) ? " or " : "", mac);
1281 }
1282 sprintf (&buf[strlen(buf)], ")");
1283 }
1284 /* When starting, DECnet sends out a packet with the source and destination
1285 addresses set to the same value as the DECnet MAC address. This packet is
1286 designed to find and help diagnose DECnet address conflicts. Normally, this
1287 packet would not be seen by the sender, only by the other machine that has
1288 the same DECnet address. If the ethernet subsystem is reflecting packets,
1289 DECnet will fail to start if it sees the reflected packet, since it thinks
1290 another system is using this DECnet address. We have to let these packets
1291 through, so that if another machine has the same DECnet address that we
1292 can detect it. Both eth_write() and eth_callback() help by checking the
1293 reflection count - eth_write() adds the reflection count to
1294 dev->decnet_self_sent, and eth_callback() check the value - if the
1295 dev->decnet_self_sent count is zero, then the packet has come from another
1296 machine with the same address, and needs to be passed on to the simulated
1297 machine. */
1298 memset(dev->decnet_addr, 0, sizeof(ETH_MAC));
1299 /* check for decnet address in filters */
1300 if ((addr_count) && (dev->reflections > 0)) {
1301 for (i = 0; i < addr_count; i++) {
1302 eth_mac_fmt(&dev->filter_address[i], mac);
1303 if (memcmp(mac, "AA:00:04", 8) == 0) {
1304 memcpy(dev->decnet_addr, &dev->filter_address[i], sizeof(ETH_MAC));
1305 /* let packets through where dst and src are the same as our decnet address */
1306 sprintf (&buf[strlen(buf)], " or ((ether dst %s) and (ether src %s))", mac, mac);
1307 break;
1308 }
1309 }
1310 }
1311 sim_debug(dev->dbit, dev->dptr, "BPF string is: |%s|\n", buf);
1312
1313
1314 /* get netmask, which is required for compiling */
1315 if (pcap_lookupnet(dev->handle, &bpf_subnet, &bpf_netmask, errbuf)<0) {
1316 bpf_netmask = 0;
1317 }
1318
1319 #ifdef USE_BPF
1320 /* compile filter string */
1321 if ((status = pcap_compile(dev->handle, &bpf, buf, 1, bpf_netmask)) < 0) {
1322 sprintf(errbuf, "%s", pcap_geterr(dev->handle));
1323 msg = "Eth: pcap_compile error: %s\r\n";
1324 printf(msg, errbuf);
1325 if (sim_log) fprintf (sim_log, msg, errbuf);
1326 /* show erroneous BPF string */
1327 msg = "Eth: BPF string is: |%s|\r\n";
1328 printf (msg, buf);
1329 if (sim_log) fprintf (sim_log, msg, buf);
1330 } else {
1331 /* apply compiled filter string */
1332 if ((status = pcap_setfilter(dev->handle, &bpf)) < 0) {
1333 sprintf(errbuf, "%s", pcap_geterr(dev->handle));
1334 msg = "Eth: pcap_setfilter error: %s\r\n";
1335 printf(msg, errbuf);
1336 if (sim_log) fprintf (sim_log, msg, errbuf);
1337 } else {
1338 #ifdef USE_SETNONBLOCK
1339 /* set file non-blocking */
1340 status = pcap_setnonblock (dev->handle, 1, errbuf);
1341 #endif /* USE_SETNONBLOCK */
1342 }
1343 pcap_freecode(&bpf);
1344 }
1345 #endif /* USE_BPF */
1346
1347 return SCPE_OK;
1348 }
1349
1350 /*
1351 The libpcap provided API pcap_findalldevs() on most platforms, will
1352 leverage the getifaddrs() API if it is available in preference to
1353 alternate platform specific methods of determining the interface list.
1354
1355 A limitation of getifaddrs() is that it returns only interfaces which
1356 have associated addresses. This may not include all of the interesting
1357 interfaces that we are interested in since a host may have dedicated
1358 interfaces for a simulator, which is otherwise unused by the host.
1359
1360 One could hand craft the the build of libpcap to specifically use
1361 alternate methods to implement pcap_findalldevs(). However, this can
1362 get tricky, and would then result in a sort of deviant libpcap.
1363
1364 This routine exists to allow platform specific code to validate and/or
1365 extend the set of available interfaces to include any that are not
1366 returned by pcap_findalldevs.
1367
1368 */
1369 int eth_host_devices(int used, int max, ETH_LIST* list)
1370 {
1371 pcap_t* conn;
1372 int i, j, datalink;
1373 char errbuf[PCAP_ERRBUF_SIZE];
1374
1375 for (i=0; i<used; ++i) {
1376 /* Cull any non-ethernet interface types */
1377 conn = pcap_open_live(list[i].name, ETH_MAX_PACKET, ETH_PROMISC, PCAP_READ_TIMEOUT, errbuf);
1378 if (NULL != conn) datalink = pcap_datalink(conn), pcap_close(conn);
1379 if ((NULL == conn) || (datalink != DLT_EN10MB)) {
1380 for (j=i; j<used-1; ++j)
1381 list[j] = list[j+1];
1382 --used;
1383 --i;
1384 }
1385 } /* for */
1386
1387 #if defined(_WIN32)
1388 /* replace device description with user-defined adapter name (if defined) */
1389 for (i=0; i<used; i++) {
1390 char regkey[2048];
1391 char regval[2048];
1392 LONG status;
1393 DWORD reglen, regtype;
1394 HKEY reghnd;
1395
1396 /* These registry keys don't seem to exist for all devices, so we simply ignore errors. */
1397 /* Windows XP x64 registry uses wide characters by default,
1398 so we force use of narrow characters by using the 'A'(ANSI) version of RegOpenKeyEx.
1399 This could cause some problems later, if this code is internationalized. Ideally,
1400 the pcap lookup will return wide characters, and we should use them to build a wide
1401 registry key, rather than hardcoding the string as we do here. */
1402 if(list[i].name[strlen( "\\Device\\NPF_" )] == '{') {
1403 sprintf( regkey, "SYSTEM\\CurrentControlSet\\Control\\Network\\"
1404 "{4D36E972-E325-11CE-BFC1-08002BE10318}\\%hs\\Connection", list[i].name+
1405 strlen( "\\Device\\NPF_" ) );
1406 if((status = RegOpenKeyExA (HKEY_LOCAL_MACHINE, regkey, 0, KEY_QUERY_VALUE, &reghnd)) != ERROR_SUCCESS) {
1407 continue;
1408 }
1409 reglen = sizeof(regval);
1410
1411 /* look for user-defined adapter name, bail if not found */
1412 /* same comment about Windows XP x64 (above) using RegQueryValueEx */
1413 if((status = RegQueryValueExA (reghnd, "Name", NULL, &regtype, regval, &reglen)) != ERROR_SUCCESS) {
1414 RegCloseKey (reghnd);
1415 continue;
1416 }
1417 /* make sure value is the right type, bail if not acceptable */
1418 if((regtype != REG_SZ) || (reglen > sizeof(regval))) {
1419 RegCloseKey (reghnd);
1420 continue;
1421 }
1422 /* registry value seems OK, finish up and replace description */
1423 RegCloseKey (reghnd );
1424 sprintf (list[i].desc, "%s", regval);
1425 }
1426 } /* for */
1427 #endif
1428
1429 return used;
1430 }
1431
1432 int eth_devices(int max, ETH_LIST* list)
1433 {
1434 pcap_if_t* alldevs;
1435 pcap_if_t* dev;
1436 int i = 0;
1437 char errbuf[PCAP_ERRBUF_SIZE];
1438
1439 #ifndef DONT_USE_PCAP_FINDALLDEVS
1440 /* retrieve the device list */
1441 if (pcap_findalldevs(&alldevs, errbuf) == -1) {
1442 char* msg = "Eth: error in pcap_findalldevs: %s\r\n";
1443 printf (msg, errbuf);
1444 if (sim_log) fprintf (sim_log, msg, errbuf);
1445 } else {
1446 /* copy device list into the passed structure */
1447 for (i=0, dev=alldevs; dev; dev=dev->next) {
1448 if ((dev->flags & PCAP_IF_LOOPBACK) || (!strcmp("any", dev->name))) continue;
1449 list[i].num = i;
1450 sprintf(list[i].name, "%s", dev->name);
1451 if (dev->description)
1452 sprintf(list[i].desc, "%s", dev->description);
1453 else
1454 sprintf(list[i].desc, "%s", "No description available");
1455 if (i++ >= max) break;
1456 }
1457
1458 /* free device list */
1459 pcap_freealldevs(alldevs);
1460 }
1461 #endif
1462
1463 /* Add any host specific devices and/or validate those already found */
1464 i = eth_host_devices(i, max, list);
1465
1466 /* return device count */
1467 return i;
1468 }
1469
1470 #endif /* USE_NETWORK */