1 /* sim_ether.c: OS-dependent network routines
2 ------------------------------------------------------------------------------
3 Copyright (c) 2002-2007, David T. Hittner
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:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
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.
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.
26 ------------------------------------------------------------------------------
28 This ethernet simulation is based on the PCAP and WinPcap packages.
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.
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.
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.
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)
55 ------------------------------------------------------------------------------
57 Supported/Tested Platforms:
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
68 VMS Alpha/Itanium VMS only, needs VMS libpcap
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
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
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
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.
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
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
130 - Specifies that you are using an older version of libpcap
131 which doesn't provide a pcap_sendpacket API.
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
137 ------------------------------------------------------------------------------
139 Modification history:
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
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
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
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
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
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
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
239 ------------------------------------------------------------------------------
243 #include "sim_ether.h"
244 #include "sim_sock.h"
246 extern FILE *sim_log
;
249 /*============================================================================*/
250 /* OS-independant ethernet routines */
251 /*============================================================================*/
253 t_stat
eth_mac_scan (ETH_MAC
* mac
, char* strmac
)
256 short unsigned int num
;
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};
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
;
267 /* copy string to local storage for mangling */
268 strcpy(cptr
, strmac
);
270 /* make sure byte separators are OK */
271 for (i
=2; i
<len
; i
=i
+3) {
272 if ((cptr
[i
] != '-') &&
274 (cptr
[i
] != ':')) return SCPE_ARG
;
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
;
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 */
293 /* new mac is OK, copy into passed mac */
294 memcpy (*mac
, newmac
, sizeof(ETH_MAC
));
298 void eth_mac_fmt(ETH_MAC
* mac
, char* buff
)
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]);
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
351 uint32
eth_crc32(uint32 crc
, const void* vbuf
, size_t len
)
353 const uint32 mask
= 0xFFFFFFFF;
354 const unsigned char* buf
= (const unsigned char*)vbuf
;
358 crc
= (crc
>> 8) ^ crcTable
[ (crc
^ (*buf
++)) & 0xFF ];
362 void eth_add_crc32(ETH_PACK
* packet
)
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 */
371 packet
->crc_len
= 0; /* appending crc would destroy packet */
375 void eth_setcrc(ETH_DEV
* dev
, int need_crc
)
377 dev
->need_crc
= need_crc
;
380 void eth_packet_trace_ex(ETH_DEV
* dev
, const uint8
*msg
, int len
, char* txt
, int dmp
)
382 if (dev
->dptr
->dctrl
& dev
->dbit
) {
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
);
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))) {
401 sim_debug(dev
->dbit
, dev
->dptr
, "%04X thru %04X same as above\r\n", i
-(16*same
), i
-1);
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
];
416 sim_debug(dev
->dbit
, dev
->dptr
, "%04X%-48s %s\r\n", i
, outbuf
, strbuf
);
419 sim_debug(dev
->dbit
, dev
->dptr
, "%04X thru %04X same as above\r\n", i
-(16*same
), len
-1);
424 void eth_packet_trace(ETH_DEV
* dev
, const uint8
*msg
, int len
, char* txt
)
426 eth_packet_trace_ex(dev
, msg
, len
, txt
, 1/*len > ETH_MAX_PACKET*/);
429 char* eth_getname(int number
, char* name
)
431 ETH_LIST list
[ETH_MAX_DEVICE
];
432 int count
= eth_devices(ETH_MAX_DEVICE
, list
);
434 if (count
<= number
) return 0;
435 strcpy(name
, list
[number
].name
);
439 char* eth_getname_bydesc(char* desc
, char* name
)
441 ETH_LIST list
[ETH_MAX_DEVICE
];
442 int count
= eth_devices(ETH_MAX_DEVICE
, list
);
446 for (i
=0; i
<count
; i
++) {
448 int k
= strlen(list
[i
].desc
);
450 if (j
!= k
) continue;
452 if (tolower(list
[i
].desc
[k
]) != tolower(desc
[k
]))
454 if (found
== 0) continue;
456 /* found a case-insensitive description match */
457 strcpy(name
, list
[i
].name
);
464 /* strncasecmp() is not available on all platforms */
465 int eth_strncasecmp(char* string1
, char* string2
, int len
)
468 unsigned char s1
, s2
;
470 for (i
=0; i
<len
; i
++) {
473 if (islower (s1
)) s1
= toupper (s1
);
474 if (islower (s2
)) s2
= toupper (s2
);
480 if (s1
== 0) return 0;
485 char* eth_getname_byname(char* name
, char* temp
)
487 ETH_LIST list
[ETH_MAX_DEVICE
];
488 int count
= eth_devices(ETH_MAX_DEVICE
, list
);
493 for (i
=0; i
<count
&& !found
; i
++) {
494 if (eth_strncasecmp(name
, list
[i
].name
, n
) == 0) {
496 strcpy(temp
, list
[i
].name
); /* only case might be different */
506 void eth_zero(ETH_DEV
* dev
)
508 /* set all members to NULL OR 0 */
509 memset(dev
, 0, sizeof(ETH_DEV
));
510 dev
->reflections
= -1; /* not established yet */
513 t_stat
eth_show (FILE* st
, UNIT
* uptr
, int32 val
, void* desc
)
515 ETH_LIST list
[ETH_MAX_DEVICE
];
516 int number
= eth_devices(ETH_MAX_DEVICE
, list
);
518 fprintf(st
, "ETH devices:\n");
520 fprintf(st
, " network support not available in simulator\n");
523 fprintf(st
, " no network devices are available\n");
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
);
534 t_stat
ethq_init(ETH_QUE
* que
, int max
)
536 /* create dynamic queue if it does not exist */
538 size_t size
= sizeof(struct eth_item
) * max
;
540 que
->item
= (struct eth_item
*) malloc(size
);
542 /* init dynamic memory */
543 memset(que
->item
, 0, size
);
545 /* failed to allocate memory */
546 char* msg
= "EthQ: failed to allocate dynamic queue[%d]\r\n";
548 if (sim_log
) fprintf(sim_log
, msg
, max
);
555 void ethq_clear(ETH_QUE
* que
)
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;
563 void ethq_remove(ETH_QUE
* que
)
565 struct eth_item
* item
= &que
->item
[que
->head
];
568 memset(item
, 0, sizeof(struct eth_item
));
569 if (++que
->head
== que
->max
)
575 void ethq_insert(ETH_QUE
* que
, int32 type
, ETH_PACK
* pack
, int32 status
)
577 struct eth_item
* item
;
579 /* if queue empty, set pointers to beginning */
585 /* find new tail of the circular queue */
586 if (++que
->tail
== que
->max
)
588 if (++que
->count
> que
->max
) {
589 que
->count
= que
->max
;
590 /* lose oldest packet */
591 if (++que
->head
== que
->max
)
595 if (que
->count
> que
->high
)
596 que
->high
= que
->count
;
598 /* set information in (new) tail item */
599 item
= &que
->item
[que
->tail
];
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
;
608 /*============================================================================*/
609 /* Non-implemented versions */
610 /*============================================================================*/
612 #if !defined (USE_NETWORK) && !defined(USE_SHARED)
613 t_stat
eth_open(ETH_DEV
* dev
, char* name
, DEVICE
* dptr
, uint32 dbit
)
615 t_stat
eth_close (ETH_DEV
* dev
)
617 t_stat
eth_write (ETH_DEV
* dev
, ETH_PACK
* packet
, ETH_PCALLBACK routine
)
619 t_stat
eth_read (ETH_DEV
* dev
, ETH_PACK
* packet
, ETH_PCALLBACK routine
)
621 t_stat
eth_filter (ETH_DEV
* dev
, int addr_count
, ETH_MAC
* addresses
,
622 ETH_BOOL all_multicast
, ETH_BOOL promiscuous
)
624 int eth_devices (int max
, ETH_LIST
* dev
)
626 #else /* endif unimplemented */
628 /*============================================================================*/
629 /* WIN32, Linux, and xBSD routines use WinPcap and libpcap packages */
630 /* OpenVMS Alpha uses a WinPcap port and an associated execlet */
631 /*============================================================================*/
633 #if defined (xBSD) && !defined(__APPLE__)
634 #include <sys/ioctl.h>
641 /* Allows windows to look up user-defined adapter names */
646 #if defined(_WIN32) && defined(USE_SHARED)
647 /* Dynamic DLL loading technique and modified source comes from
648 Etherial/WireShark capture_pcap.c */
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";
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);
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
);
681 /* load wpcap.dll as required */
682 int load_wpcap(void) {
684 case 0: /* not loaded */
685 /* attempt to load DLL */
686 hDll
= LoadLibrary(TEXT("wpcap.dll"));
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";
694 fprintf (sim_log
, msg
);
695 fprintf (sim_log
, msg2
);
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
);
719 if (dll_loaded
== 1) {
720 /* log successful load */
721 char* version
= p_pcap_lib_version();
722 printf("%s\n", version
);
724 fprintf(sim_log
, "%s\n", version
);
727 default: /* loaded or failed */
730 return (dll_loaded
== 1) ? 1 : 0;
733 /* define functions with dynamic revectoring */
734 void pcap_close(pcap_t
* a
) {
735 if (load_wpcap() != 0) {
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
);
748 int pcap_datalink(pcap_t
* a
) {
749 if (load_wpcap() != 0) {
750 return p_pcap_datalink(a
);
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
);
764 int pcap_findalldevs(pcap_if_t
** a
, char* b
) {
765 if (load_wpcap() != 0) {
766 return p_pcap_findalldevs(a
, b
);
774 void pcap_freealldevs(pcap_if_t
* a
) {
775 if (load_wpcap() != 0) {
776 p_pcap_freealldevs(a
);
780 void pcap_freecode(struct bpf_program
* a
) {
781 if (load_wpcap() != 0) {
786 char* pcap_geterr(pcap_t
* a
) {
787 if (load_wpcap() != 0) {
788 return p_pcap_geterr(a
);
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
);
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
);
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
);
818 int pcap_setfilter(pcap_t
* a
, struct bpf_program
* b
) {
819 if (load_wpcap() != 0) {
820 return p_pcap_setfilter(a
, b
);
827 /* Some platforms have always had pcap_sendpacket */
828 #if defined(_WIN32) || defined(VMS)
829 #define HAS_PCAP_SENDPACKET 1
831 /* The latest libpcap and WinPcap all have pcap_sendpacket */
832 #if !defined (NEED_PCAP_SENDPACKET)
833 #define HAS_PCAP_SENDPACKET 1
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
)
843 #if defined (__linux)
844 return (send(pcap_fileno(handle
), msg
, len
, 0) == len
)? 0 : -1;
846 return (write(pcap_fileno(handle
), msg
, len
) == len
)? 0 : -1;
849 #endif /* !HAS_PCAP_SENDPACKET */
851 #if defined (USE_READER_THREAD)
854 void eth_callback(u_char
* info
, const struct pcap_pkthdr
* header
, const u_char
* data
);
857 _eth_reader(void *arg
)
859 ETH_DEV
* volatile dev
= (ETH_DEV
*)arg
;
861 struct timeval timeout
;
864 timeout
.tv_usec
= 200*1000;
866 sim_debug(dev
->dbit
, dev
->dptr
, "Reader Thread Starting\n");
868 while (dev
->handle
) {
869 #if defined (MUST_DO_SELECT)
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;
878 /* dispatch read request queue available packets */
879 status
= pcap_dispatch((pcap_t
*)dev
->handle
, -1, ð_callback
, (u_char
*)dev
);
882 /* dispatch read request queue available packets */
883 status
= pcap_dispatch((pcap_t
*)dev
->handle
, 1, ð_callback
, (u_char
*)dev
);
887 sim_debug(dev
->dbit
, dev
->dptr
, "Reader Thread Exiting\n");
892 t_stat
eth_open(ETH_DEV
* dev
, char* name
, DEVICE
* dptr
, uint32 dbit
)
894 const int bufsz
= (BUFSIZ
< ETH_MAX_PACKET
) ? ETH_MAX_PACKET
: BUFSIZ
;
895 char errbuf
[PCAP_ERRBUF_SIZE
];
897 char* savname
= name
;
901 /* initialize device */
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')
911 num
= atoi(&name
[3]);
912 savname
= eth_getname(num
, temp
);
913 if (savname
== 0) /* didn't translate */
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 */
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
);
935 msg
= "Eth: opened %s\r\n";
936 printf (msg
, savname
);
937 if (sim_log
) fprintf (sim_log
, msg
, savname
);
940 /* save name of device */
941 dev
->name
= malloc(strlen(savname
)+1);
942 strcpy(dev
->name
, savname
);
944 /* save debugging information */
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. */
953 ioctl(pcap_fileno(dev
->handle
), BIOCSHDRCMPLT
, &one
);
957 #if defined (USE_READER_THREAD)
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
);
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
);
977 #endif /* !defined (USE_READER_THREAD */
981 t_stat
eth_close(ETH_DEV
* dev
)
983 char* msg
= "Eth: closed %s\r\n";
986 /* make sure device exists */
987 if (!dev
) return SCPE_UNATT
;
989 /* close the device */
990 pcap
= (pcap_t
*)dev
->handle
;
993 printf (msg
, dev
->name
);
994 if (sim_log
) fprintf (sim_log
, msg
, dev
->name
);
996 #if defined (USE_READER_THREAD)
997 pthread_join (dev
->reader_thread
, NULL
);
1000 /* clean up the mess */
1007 t_stat
eth_reflect(ETH_DEV
* dev
, ETH_MAC mac
)
1009 ETH_PACK send
, recv
;
1012 struct timeval delay
;
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 */
1023 dev
->reflections
= 0;
1024 eth_filter(dev
, 1, (ETH_MAC
*)mac
, 0, 0);
1026 /* send the packet */
1027 status
= eth_write (dev
, &send
, NULL
);
1028 if (status
!= SCPE_OK
) {
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
));
1038 /* if/when we have a sim_os_msleep() we'll use it here instead of this select() */
1040 delay
.tv_usec
= 50*1000;
1041 select(0, NULL
, NULL
, NULL
, &delay
); /* make sure things settle into the read path */
1043 /* empty the read queue and count the reflections */
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)
1049 } while (recv
.len
> 0);
1051 sim_debug(dev
->dbit
, dev
->dptr
, "Reflections = %d\n", dev
->reflections
);
1052 return dev
->reflections
;
1055 t_stat
eth_write(ETH_DEV
* dev
, ETH_PACK
* packet
, ETH_PCALLBACK routine
)
1057 int status
= 1; /* default to failure */
1059 /* make sure device exists */
1060 if (!dev
) return SCPE_UNATT
;
1062 /* make sure packet exists */
1063 if (!packet
) return SCPE_ARG
;
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");
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
);
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
;
1076 } /* if packet->len */
1078 /* call optional write callback function */
1082 return ((status
== 0) ? SCPE_OK
: SCPE_IOERR
);
1085 void eth_callback(u_char
* info
, const struct pcap_pkthdr
* header
, const u_char
* data
)
1087 ETH_DEV
* dev
= (ETH_DEV
*) info
;
1090 #else /* !USE_BPF */
1096 // eth_packet_trace (dev, data, header->len, "received");
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;
1103 /* all multicast mode? */
1104 if (dev
->all_multicast
&& (data
[0] & 0x01)) to_me
= 1;
1106 /* promiscuous mode? */
1107 if (dev
->promiscuous
) to_me
= 1;
1108 #endif /* USE_BPF */
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
--;
1125 #else /* !USE_BPF */
1126 if (to_me
&& !from_me
) {
1128 #if defined (USE_READER_THREAD)
1129 ETH_PACK tmp_packet
;
1131 /* set data in passed read packet */
1132 tmp_packet
.len
= header
->len
;
1133 memcpy(tmp_packet
.msg
, data
, header
->len
);
1135 eth_add_crc32(&tmp_packet
);
1137 eth_packet_trace (dev
, tmp_packet
.msg
, tmp_packet
.len
, "rcvqd");
1139 pthread_mutex_lock (&dev
->lock
);
1140 ethq_insert(&dev
->read_queue
, 2, &tmp_packet
, 0);
1141 pthread_mutex_unlock (&dev
->lock
);
1143 /* set data in passed read packet */
1144 dev
->read_packet
->len
= header
->len
;
1145 memcpy(dev
->read_packet
->msg
, data
, header
->len
);
1147 eth_add_crc32(dev
->read_packet
);
1149 eth_packet_trace (dev
, dev
->read_packet
->msg
, dev
->read_packet
->len
, "reading");
1151 /* call optional read callback function */
1152 if (dev
->read_callback
)
1153 (dev
->read_callback
)(0);
1158 t_stat
eth_read(ETH_DEV
* dev
, ETH_PACK
* packet
, ETH_PCALLBACK routine
)
1162 /* make sure device exists */
1164 if (!dev
) return SCPE_UNATT
;
1166 /* make sure packet exists */
1167 if (!packet
) return SCPE_ARG
;
1169 #if !defined (USE_READER_THREAD)
1170 /* set read packet */
1171 dev
->read_packet
= packet
;
1174 /* set optional callback routine */
1175 dev
->read_callback
= routine
;
1177 /* dispatch read request to either receive a filtered packet or timeout */
1179 status
= pcap_dispatch((pcap_t
*)dev
->handle
, 1, ð_callback
, (u_char
*)dev
);
1180 } while ((status
) && (0 == packet
->len
));
1182 #else /* USE_READER_THREAD */
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
);
1192 ethq_remove(&dev
->read_queue
);
1194 pthread_mutex_unlock (&dev
->lock
);
1200 t_stat
eth_filter(ETH_DEV
* dev
, int addr_count
, ETH_MAC
* addresses
,
1201 ETH_BOOL all_multicast
, ETH_BOOL promiscuous
)
1204 bpf_u_int32 bpf_subnet
, bpf_netmask
;
1205 char buf
[110+66*ETH_FILTER_MAX
];
1206 char errbuf
[PCAP_ERRBUF_SIZE
];
1211 struct bpf_program bpf
;
1215 /* make sure device exists */
1216 if (!dev
) return SCPE_UNATT
;
1218 /* filter count OK? */
1219 if ((addr_count
< 0) || (addr_count
> ETH_FILTER_MAX
))
1222 if (!addresses
) return SCPE_ARG
;
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
;
1229 /* store other flags */
1230 dev
->all_multicast
= all_multicast
;
1231 dev
->promiscuous
= promiscuous
;
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
++) {
1238 eth_mac_fmt(&dev
->filter_address
[i
], mac
);
1239 sim_debug(dev
->dbit
, dev
->dptr
, " Addr[%d]: %s\n", i
, mac
);
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");
1247 /* test reflections */
1248 if (dev
->reflections
== -1)
1249 status
= eth_reflect(dev
, dev
->filter_address
[0]);
1251 /* setup BPF filters and other fields to minimize packet delivery */
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
);
1263 if (dev
->all_multicast
)
1264 sprintf(&buf
[strlen(buf
)], "%s(ether multicast)", (*buf
) ? " or " : "");
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
);
1282 sprintf (&buf
[strlen(buf
)], ")");
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
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
);
1311 sim_debug(dev
->dbit
, dev
->dptr
, "BPF string is: |%s|\n", buf
);
1314 /* get netmask, which is required for compiling */
1315 if (pcap_lookupnet(dev
->handle
, &bpf_subnet
, &bpf_netmask
, errbuf
)<0) {
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";
1329 if (sim_log
) fprintf (sim_log
, msg
, buf
);
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
);
1338 #ifdef USE_SETNONBLOCK
1339 /* set file non-blocking */
1340 status
= pcap_setnonblock (dev
->handle
, 1, errbuf
);
1341 #endif /* USE_SETNONBLOCK */
1343 pcap_freecode(&bpf
);
1345 #endif /* USE_BPF */
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.
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.
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.
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.
1369 int eth_host_devices(int used
, int max
, ETH_LIST
* list
)
1373 char errbuf
[PCAP_ERRBUF_SIZE
];
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];
1388 /* replace device description with user-defined adapter name (if defined) */
1389 for (i
=0; i
<used
; i
++) {
1393 DWORD reglen
, regtype
;
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
, ®hnd
)) != ERROR_SUCCESS
) {
1409 reglen
= sizeof(regval
);
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
, ®type
, regval
, ®len
)) != ERROR_SUCCESS
) {
1414 RegCloseKey (reghnd
);
1417 /* make sure value is the right type, bail if not acceptable */
1418 if((regtype
!= REG_SZ
) || (reglen
> sizeof(regval
))) {
1419 RegCloseKey (reghnd
);
1422 /* registry value seems OK, finish up and replace description */
1423 RegCloseKey (reghnd
);
1424 sprintf (list
[i
].desc
, "%s", regval
);
1432 int eth_devices(int max
, ETH_LIST
* list
)
1437 char errbuf
[PCAP_ERRBUF_SIZE
];
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
);
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;
1450 sprintf(list
[i
].name
, "%s", dev
->name
);
1451 if (dev
->description
)
1452 sprintf(list
[i
].desc
, "%s", dev
->description
);
1454 sprintf(list
[i
].desc
, "%s", "No description available");
1455 if (i
++ >= max
) break;
1458 /* free device list */
1459 pcap_freealldevs(alldevs
);
1463 /* Add any host specific devices and/or validate those already found */
1464 i
= eth_host_devices(i
, max
, list
);
1466 /* return device count */
1470 #endif /* USE_NETWORK */