ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/ether_unix.cpp
Revision: 1.24
Committed: 2005-12-29T13:40:25Z (18 years, 11 months ago) by nigel
Branch: MAIN
CVS Tags: nigel-build-17
Changes since 1.23: +5 -0 lines
Log Message:
Small hack for clean exits on Nigel's OS X port

File Contents

# Content
1 /*
2 * ether_unix.cpp - Ethernet device driver, Unix specific stuff (Linux and FreeBSD)
3 *
4 * Basilisk II (C) 1997-2005 Christian Bauer
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include "sysdeps.h"
22
23 #ifdef HAVE_SYS_POLL_H
24 #include <sys/poll.h>
25 #endif
26 #include <sys/ioctl.h>
27 #include <sys/socket.h>
28 #include <sys/wait.h>
29 #include <netinet/in.h>
30 #include <pthread.h>
31 #include <semaphore.h>
32 #include <errno.h>
33 #include <stdio.h>
34 #include <map>
35
36 #if defined(__FreeBSD__) || defined(sgi) || (defined(__APPLE__) && defined(__MACH__))
37 #include <net/if.h>
38 #endif
39
40 #if defined(HAVE_LINUX_IF_H) && defined(HAVE_LINUX_IF_TUN_H)
41 #include <linux/if.h>
42 #include <linux/if_tun.h>
43 #endif
44
45 #if defined(HAVE_NET_IF_H) && defined(HAVE_NET_IF_TUN_H)
46 #include <net/if.h>
47 #include <net/if_tun.h>
48 #endif
49
50 #ifdef HAVE_SLIRP
51 #include "libslirp.h"
52 #endif
53
54 #include "cpu_emulation.h"
55 #include "main.h"
56 #include "macos_util.h"
57 #include "prefs.h"
58 #include "user_strings.h"
59 #include "ether.h"
60 #include "ether_defs.h"
61
62 #ifndef NO_STD_NAMESPACE
63 using std::map;
64 #endif
65
66 #define DEBUG 0
67 #include "debug.h"
68
69 #define STATISTICS 0
70 #define MONITOR 0
71
72
73 // Ethernet device types
74 enum {
75 NET_IF_SHEEPNET,
76 NET_IF_ETHERTAP,
77 NET_IF_TUNTAP,
78 NET_IF_SLIRP
79 };
80
81 // Constants
82 static const char ETHERCONFIG_FILE_NAME[] = DATADIR "/tunconfig";
83
84 // Global variables
85 static int fd = -1; // fd of sheep_net device
86 static pthread_t ether_thread; // Packet reception thread
87 static pthread_attr_t ether_thread_attr; // Packet reception thread attributes
88 static bool thread_active = false; // Flag: Packet reception thread installed
89 static sem_t int_ack; // Interrupt acknowledge semaphore
90 static bool udp_tunnel; // Flag: UDP tunnelling active, fd is the socket descriptor
91 static int net_if_type = -1; // Ethernet device type
92 static char *net_if_name = NULL; // TUN/TAP device name
93 static const char *net_if_script = NULL; // Network config script
94 static pthread_t slirp_thread; // Slirp reception thread
95 static bool slirp_thread_active = false; // Flag: Slirp reception threadinstalled
96 static int slirp_output_fd = -1; // fd of slirp output pipe
97 static int slirp_input_fds[2] = { -1, -1 }; // fds of slirp input pipe
98 #ifdef SHEEPSHAVER
99 static bool net_open = false; // Flag: initialization succeeded, network device open
100 static uint8 ether_addr[6]; // Our Ethernet address
101 #else
102 const bool ether_driver_opened = true; // Flag: is the MacOS driver opened?
103 #endif
104
105 // Attached network protocols, maps protocol type to MacOS handler address
106 static map<uint16, uint32> net_protocols;
107
108 // Prototypes
109 static void *receive_func(void *arg);
110 static void *slirp_receive_func(void *arg);
111 static int poll_fd(int fd);
112 static int16 ether_do_add_multicast(uint8 *addr);
113 static int16 ether_do_del_multicast(uint8 *addr);
114 static int16 ether_do_write(uint32 arg);
115 static void ether_do_interrupt(void);
116
117
118 /*
119 * Start packet reception thread
120 */
121
122 static bool start_thread(void)
123 {
124 if (sem_init(&int_ack, 0, 0) < 0) {
125 printf("WARNING: Cannot init semaphore");
126 return false;
127 }
128
129 Set_pthread_attr(&ether_thread_attr, 1);
130 thread_active = (pthread_create(&ether_thread, &ether_thread_attr, receive_func, NULL) == 0);
131 if (!thread_active) {
132 printf("WARNING: Cannot start Ethernet thread");
133 return false;
134 }
135
136 #ifdef HAVE_SLIRP
137 if (net_if_type == NET_IF_SLIRP) {
138 slirp_thread_active = (pthread_create(&slirp_thread, NULL, slirp_receive_func, NULL) == 0);
139 if (!slirp_thread_active) {
140 printf("WARNING: Cannot start slirp reception thread\n");
141 return false;
142 }
143 }
144 #endif
145
146 return true;
147 }
148
149
150 /*
151 * Stop packet reception thread
152 */
153
154 static void stop_thread(void)
155 {
156 #ifdef HAVE_SLIRP
157 if (slirp_thread_active) {
158 #ifdef HAVE_PTHREAD_CANCEL
159 pthread_cancel(slirp_thread);
160 #endif
161 pthread_join(slirp_thread, NULL);
162 slirp_thread_active = false;
163 }
164 #endif
165
166 if (thread_active) {
167 #ifdef HAVE_PTHREAD_CANCEL
168 pthread_cancel(ether_thread);
169 #endif
170 #ifdef AQUA
171 // This call, which waits for ether_thread to terminate,
172 // never returns when used in Nigel's OS X port.
173 #else
174 pthread_join(ether_thread, NULL);
175 #endif
176 sem_destroy(&int_ack);
177 thread_active = false;
178 }
179 }
180
181
182 /*
183 * Execute network script up|down
184 */
185
186 static bool execute_network_script(const char *action)
187 {
188 if (net_if_script == NULL || net_if_name == NULL)
189 return false;
190
191 int pid = fork();
192 if (pid >= 0) {
193 if (pid == 0) {
194 char *args[4];
195 args[0] = (char *)net_if_script;
196 args[1] = net_if_name;
197 args[2] = (char *)action;
198 args[3] = NULL;
199 execv(net_if_script, args);
200 exit(1);
201 }
202 int status;
203 while (waitpid(pid, &status, 0) != pid);
204 return WIFEXITED(status) && WEXITSTATUS(status) == 0;
205 }
206
207 return false;
208 }
209
210
211 /*
212 * Initialization
213 */
214
215 bool ether_init(void)
216 {
217 int nonblock = 1;
218 char str[256];
219
220 // Do nothing if no Ethernet device specified
221 const char *name = PrefsFindString("ether");
222 if (name == NULL)
223 return false;
224
225 // Determine Ethernet device type
226 net_if_type = -1;
227 if (strncmp(name, "tap", 3) == 0)
228 net_if_type = NET_IF_ETHERTAP;
229 #if ENABLE_TUNTAP
230 else if (strcmp(name, "tun") == 0)
231 net_if_type = NET_IF_TUNTAP;
232 #endif
233 #ifdef HAVE_SLIRP
234 else if (strcmp(name, "slirp") == 0)
235 net_if_type = NET_IF_SLIRP;
236 #endif
237 else
238 net_if_type = NET_IF_SHEEPNET;
239
240 #ifdef HAVE_SLIRP
241 // Initialize slirp library
242 if (net_if_type == NET_IF_SLIRP) {
243 if (slirp_init() < 0) {
244 sprintf(str, GetString(STR_SLIRP_NO_DNS_FOUND_WARN));
245 WarningAlert(str);
246 return false;
247 }
248
249 // Open slirp output pipe
250 int fds[2];
251 if (pipe(fds) < 0)
252 return false;
253 fd = fds[0];
254 slirp_output_fd = fds[1];
255
256 // Open slirp input pipe
257 if (pipe(slirp_input_fds) < 0)
258 return false;
259 }
260 #endif
261
262 // Open sheep_net or ethertap or TUN/TAP device
263 char dev_name[16];
264 switch (net_if_type) {
265 case NET_IF_ETHERTAP:
266 sprintf(dev_name, "/dev/%s", name);
267 break;
268 case NET_IF_TUNTAP:
269 strcpy(dev_name, "/dev/net/tun");
270 break;
271 case NET_IF_SHEEPNET:
272 strcpy(dev_name, "/dev/sheep_net");
273 break;
274 }
275 if (net_if_type != NET_IF_SLIRP) {
276 fd = open(dev_name, O_RDWR);
277 if (fd < 0) {
278 sprintf(str, GetString(STR_NO_SHEEP_NET_DRIVER_WARN), dev_name, strerror(errno));
279 WarningAlert(str);
280 goto open_error;
281 }
282 }
283
284 #if ENABLE_TUNTAP
285 // Open TUN/TAP interface
286 if (net_if_type == NET_IF_TUNTAP) {
287 struct ifreq ifr;
288 memset(&ifr, 0, sizeof(ifr));
289 ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
290 strcpy(ifr.ifr_name, "tun%d");
291 if (ioctl(fd, TUNSETIFF, (void *) &ifr) != 0) {
292 sprintf(str, GetString(STR_SHEEP_NET_ATTACH_WARN), strerror(errno));
293 WarningAlert(str);
294 goto open_error;
295 }
296
297 // Get network config script file path
298 net_if_script = PrefsFindString("etherconfig");
299 if (net_if_script == NULL)
300 net_if_script = ETHERCONFIG_FILE_NAME;
301
302 // Start network script up
303 if (net_if_script == NULL) {
304 sprintf(str, GetString(STR_TUN_TAP_CONFIG_WARN), "script not found");
305 WarningAlert(str);
306 goto open_error;
307 }
308 net_if_name = strdup(ifr.ifr_name);
309 if (!execute_network_script("up")) {
310 sprintf(str, GetString(STR_TUN_TAP_CONFIG_WARN), "script execute error");
311 WarningAlert(str);
312 goto open_error;
313 }
314 D(bug("Connected to host network interface: %s\n", net_if_name));
315 }
316 #endif
317
318 #if defined(__linux__)
319 // Attach sheep_net to selected Ethernet card
320 if (net_if_type == NET_IF_SHEEPNET && ioctl(fd, SIOCSIFLINK, name) < 0) {
321 sprintf(str, GetString(STR_SHEEP_NET_ATTACH_WARN), strerror(errno));
322 WarningAlert(str);
323 goto open_error;
324 }
325 #endif
326
327 // Set nonblocking I/O
328 ioctl(fd, FIONBIO, &nonblock);
329
330 // Get Ethernet address
331 if (net_if_type == NET_IF_ETHERTAP) {
332 pid_t p = getpid(); // If configured for multicast, ethertap requires that the lower 32 bit of the Ethernet address are our PID
333 ether_addr[0] = 0xfe;
334 ether_addr[1] = 0xfd;
335 ether_addr[2] = p >> 24;
336 ether_addr[3] = p >> 16;
337 ether_addr[4] = p >> 8;
338 ether_addr[5] = p;
339 #ifdef HAVE_SLIRP
340 } else if (net_if_type == NET_IF_SLIRP) {
341 ether_addr[0] = 0x52;
342 ether_addr[1] = 0x54;
343 ether_addr[2] = 0x00;
344 ether_addr[3] = 0x12;
345 ether_addr[4] = 0x34;
346 ether_addr[5] = 0x56;
347 #endif
348 } else
349 ioctl(fd, SIOCGIFADDR, ether_addr);
350 D(bug("Ethernet address %02x %02x %02x %02x %02x %02x\n", ether_addr[0], ether_addr[1], ether_addr[2], ether_addr[3], ether_addr[4], ether_addr[5]));
351
352 // Start packet reception thread
353 if (!start_thread())
354 goto open_error;
355
356 // Everything OK
357 return true;
358
359 open_error:
360 stop_thread();
361
362 if (fd > 0) {
363 close(fd);
364 fd = -1;
365 }
366 if (slirp_input_fds[0] >= 0) {
367 close(slirp_input_fds[0]);
368 slirp_input_fds[0] = -1;
369 }
370 if (slirp_input_fds[1] >= 0) {
371 close(slirp_input_fds[1]);
372 slirp_input_fds[1] = -1;
373 }
374 if (slirp_output_fd >= 0) {
375 close(slirp_output_fd);
376 slirp_output_fd = -1;
377 }
378 return false;
379 }
380
381
382 /*
383 * Deinitialization
384 */
385
386 void ether_exit(void)
387 {
388 // Stop reception threads
389 stop_thread();
390
391 // Shut down TUN/TAP interface
392 if (net_if_type == NET_IF_TUNTAP)
393 execute_network_script("down");
394
395 // Free TUN/TAP device name
396 if (net_if_name)
397 free(net_if_name);
398
399 // Close sheep_net device
400 if (fd > 0)
401 close(fd);
402
403 // Close slirp input buffer
404 if (slirp_input_fds[0] >= 0)
405 close(slirp_input_fds[0]);
406 if (slirp_input_fds[1] >= 0)
407 close(slirp_input_fds[1]);
408
409 // Close slirp output buffer
410 if (slirp_output_fd > 0)
411 close(slirp_output_fd);
412
413 #if STATISTICS
414 // Show statistics
415 printf("%ld messages put on write queue\n", num_wput);
416 printf("%ld error acks\n", num_error_acks);
417 printf("%ld packets transmitted (%ld raw, %ld normal)\n", num_tx_packets, num_tx_raw_packets, num_tx_normal_packets);
418 printf("%ld tx packets dropped because buffer full\n", num_tx_buffer_full);
419 printf("%ld packets received\n", num_rx_packets);
420 printf("%ld packets passed upstream (%ld Fast Path, %ld normal)\n", num_rx_fastpath + num_unitdata_ind, num_rx_fastpath, num_unitdata_ind);
421 printf("EtherIRQ called %ld times\n", num_ether_irq);
422 printf("%ld rx packets dropped due to low memory\n", num_rx_no_mem);
423 printf("%ld rx packets dropped because no stream found\n", num_rx_dropped);
424 printf("%ld rx packets dropped because stream not ready\n", num_rx_stream_not_ready);
425 printf("%ld rx packets dropped because no memory for unitdata_ind\n", num_rx_no_unitdata_mem);
426 #endif
427 }
428
429
430 /*
431 * Glue around low-level implementation
432 */
433
434 #ifdef SHEEPSHAVER
435 // Error codes
436 enum {
437 eMultiErr = -91,
438 eLenErr = -92,
439 lapProtErr = -94,
440 excessCollsns = -95
441 };
442
443 // Initialize ethernet
444 void EtherInit(void)
445 {
446 net_open = false;
447
448 // Do nothing if the user disabled the network
449 if (PrefsFindBool("nonet"))
450 return;
451
452 net_open = ether_init();
453 }
454
455 // Exit ethernet
456 void EtherExit(void)
457 {
458 ether_exit();
459 net_open = false;
460 }
461
462 // Get ethernet hardware address
463 void AO_get_ethernet_address(uint32 arg)
464 {
465 uint8 *addr = Mac2HostAddr(arg);
466 if (net_open)
467 OTCopy48BitAddress(ether_addr, addr);
468 else {
469 addr[0] = 0x12;
470 addr[1] = 0x34;
471 addr[2] = 0x56;
472 addr[3] = 0x78;
473 addr[4] = 0x9a;
474 addr[5] = 0xbc;
475 }
476 D(bug("AO_get_ethernet_address: got address %02x%02x%02x%02x%02x%02x\n", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]));
477 }
478
479 // Add multicast address
480 void AO_enable_multicast(uint32 addr)
481 {
482 if (net_open)
483 ether_do_add_multicast(Mac2HostAddr(addr));
484 }
485
486 // Disable multicast address
487 void AO_disable_multicast(uint32 addr)
488 {
489 if (net_open)
490 ether_do_del_multicast(Mac2HostAddr(addr));
491 }
492
493 // Transmit one packet
494 void AO_transmit_packet(uint32 mp)
495 {
496 if (net_open) {
497 switch (ether_do_write(mp)) {
498 case noErr:
499 num_tx_packets++;
500 break;
501 case excessCollsns:
502 num_tx_buffer_full++;
503 break;
504 }
505 }
506 }
507
508 // Copy packet data from message block to linear buffer
509 static inline int ether_arg_to_buffer(uint32 mp, uint8 *p)
510 {
511 return ether_msgb_to_buffer(mp, p);
512 }
513
514 // Ethernet interrupt
515 void EtherIRQ(void)
516 {
517 D(bug("EtherIRQ\n"));
518 num_ether_irq++;
519
520 OTEnterInterrupt();
521 ether_do_interrupt();
522 OTLeaveInterrupt();
523
524 // Acknowledge interrupt to reception thread
525 D(bug(" EtherIRQ done\n"));
526 sem_post(&int_ack);
527 }
528 #else
529 // Add multicast address
530 int16 ether_add_multicast(uint32 pb)
531 {
532 return ether_do_add_multicast(Mac2HostAddr(pb + eMultiAddr));
533 }
534
535 // Disable multicast address
536 int16 ether_del_multicast(uint32 pb)
537 {
538 return ether_do_del_multicast(Mac2HostAddr(pb + eMultiAddr));
539 }
540
541 // Transmit one packet
542 int16 ether_write(uint32 wds)
543 {
544 return ether_do_write(wds);
545 }
546
547 // Copy packet data from WDS to linear buffer
548 static inline int ether_arg_to_buffer(uint32 wds, uint8 *p)
549 {
550 return ether_wds_to_buffer(wds, p);
551 }
552
553 // Dispatch packet to protocol handler
554 static void ether_dispatch_packet(uint32 p, uint32 length)
555 {
556 // Get packet type
557 uint16 type = ReadMacInt16(p + 12);
558
559 // Look for protocol
560 uint16 search_type = (type <= 1500 ? 0 : type);
561 if (net_protocols.find(search_type) == net_protocols.end())
562 return;
563 uint32 handler = net_protocols[search_type];
564
565 // No default handler
566 if (handler == 0)
567 return;
568
569 // Copy header to RHA
570 Mac2Mac_memcpy(ether_data + ed_RHA, p, 14);
571 D(bug(" header %08x%04x %08x%04x %04x\n", ReadMacInt32(ether_data + ed_RHA), ReadMacInt16(ether_data + ed_RHA + 4), ReadMacInt32(ether_data + ed_RHA + 6), ReadMacInt16(ether_data + ed_RHA + 10), ReadMacInt16(ether_data + ed_RHA + 12)));
572
573 // Call protocol handler
574 M68kRegisters r;
575 r.d[0] = type; // Packet type
576 r.d[1] = length - 14; // Remaining packet length (without header, for ReadPacket)
577 r.a[0] = p + 14; // Pointer to packet (Mac address, for ReadPacket)
578 r.a[3] = ether_data + ed_RHA + 14; // Pointer behind header in RHA
579 r.a[4] = ether_data + ed_ReadPacket; // Pointer to ReadPacket/ReadRest routines
580 D(bug(" calling protocol handler %08x, type %08x, length %08x, data %08x, rha %08x, read_packet %08x\n", handler, r.d[0], r.d[1], r.a[0], r.a[3], r.a[4]));
581 Execute68k(handler, &r);
582 }
583
584 // Ethernet interrupt
585 void EtherInterrupt(void)
586 {
587 D(bug("EtherIRQ\n"));
588 ether_do_interrupt();
589
590 // Acknowledge interrupt to reception thread
591 D(bug(" EtherIRQ done\n"));
592 sem_post(&int_ack);
593 }
594 #endif
595
596
597 /*
598 * Reset
599 */
600
601 void ether_reset(void)
602 {
603 net_protocols.clear();
604 }
605
606
607 /*
608 * Add multicast address
609 */
610
611 static int16 ether_do_add_multicast(uint8 *addr)
612 {
613 switch (net_if_type) {
614 case NET_IF_ETHERTAP:
615 case NET_IF_SHEEPNET:
616 if (ioctl(fd, SIOCADDMULTI, addr) < 0) {
617 D(bug("WARNING: Couldn't enable multicast address\n"));
618 if (net_if_type == NET_IF_ETHERTAP)
619 return noErr;
620 else
621 return eMultiErr;
622 }
623 default:
624 return noErr;
625 }
626 }
627
628
629 /*
630 * Delete multicast address
631 */
632
633 static int16 ether_do_del_multicast(uint8 *addr)
634 {
635 switch (net_if_type) {
636 case NET_IF_ETHERTAP:
637 case NET_IF_SHEEPNET:
638 if (ioctl(fd, SIOCDELMULTI, addr) < 0) {
639 D(bug("WARNING: Couldn't disable multicast address\n"));
640 return eMultiErr;
641 }
642 default:
643 return noErr;
644 }
645 }
646
647
648 /*
649 * Attach protocol handler
650 */
651
652 int16 ether_attach_ph(uint16 type, uint32 handler)
653 {
654 if (net_protocols.find(type) != net_protocols.end())
655 return lapProtErr;
656 net_protocols[type] = handler;
657 return noErr;
658 }
659
660
661 /*
662 * Detach protocol handler
663 */
664
665 int16 ether_detach_ph(uint16 type)
666 {
667 if (net_protocols.erase(type) == 0)
668 return lapProtErr;
669 return noErr;
670 }
671
672
673 /*
674 * Transmit raw ethernet packet
675 */
676
677 static int16 ether_do_write(uint32 arg)
678 {
679 // Copy packet to buffer
680 uint8 packet[1516], *p = packet;
681 int len = 0;
682 #if defined(__linux__)
683 if (net_if_type == NET_IF_ETHERTAP) {
684 *p++ = 0; // Linux ethertap discards the first 2 bytes
685 *p++ = 0;
686 len += 2;
687 }
688 #endif
689 len += ether_arg_to_buffer(arg, p);
690
691 #if MONITOR
692 bug("Sending Ethernet packet:\n");
693 for (int i=0; i<len; i++) {
694 bug("%02x ", packet[i]);
695 }
696 bug("\n");
697 #endif
698
699 // Transmit packet
700 #ifdef HAVE_SLIRP
701 if (net_if_type == NET_IF_SLIRP) {
702 const int slirp_input_fd = slirp_input_fds[1];
703 write(slirp_input_fd, &len, sizeof(len));
704 write(slirp_input_fd, packet, len);
705 return noErr;
706 } else
707 #endif
708 if (write(fd, packet, len) < 0) {
709 D(bug("WARNING: Couldn't transmit packet\n"));
710 return excessCollsns;
711 } else
712 return noErr;
713 }
714
715
716 /*
717 * Start UDP packet reception thread
718 */
719
720 bool ether_start_udp_thread(int socket_fd)
721 {
722 fd = socket_fd;
723 udp_tunnel = true;
724 return start_thread();
725 }
726
727
728 /*
729 * Stop UDP packet reception thread
730 */
731
732 void ether_stop_udp_thread(void)
733 {
734 stop_thread();
735 fd = -1;
736 }
737
738
739 /*
740 * SLIRP output buffer glue
741 */
742
743 #ifdef HAVE_SLIRP
744 int slirp_can_output(void)
745 {
746 return 1;
747 }
748
749 void slirp_output(const uint8 *packet, int len)
750 {
751 write(slirp_output_fd, packet, len);
752 }
753
754 void *slirp_receive_func(void *arg)
755 {
756 const int slirp_input_fd = slirp_input_fds[0];
757
758 for (;;) {
759 // Wait for packets to arrive
760 fd_set rfds, wfds, xfds;
761 int nfds;
762 struct timeval tv;
763
764 // ... in the input queue
765 FD_ZERO(&rfds);
766 FD_SET(slirp_input_fd, &rfds);
767 tv.tv_sec = 0;
768 tv.tv_usec = 0;
769 if (select(slirp_input_fd + 1, &rfds, NULL, NULL, &tv) > 0) {
770 int len;
771 read(slirp_input_fd, &len, sizeof(len));
772 uint8 packet[1516];
773 assert(len <= sizeof(packet));
774 read(slirp_input_fd, packet, len);
775 slirp_input(packet, len);
776 }
777
778 // ... in the output queue
779 nfds = -1;
780 FD_ZERO(&rfds);
781 FD_ZERO(&wfds);
782 FD_ZERO(&xfds);
783 slirp_select_fill(&nfds, &rfds, &wfds, &xfds);
784 tv.tv_sec = 0;
785 tv.tv_usec = 10000;
786 if (select(nfds + 1, &rfds, &wfds, &xfds, &tv) >= 0)
787 slirp_select_poll(&rfds, &wfds, &xfds);
788
789 #ifdef HAVE_PTHREAD_TESTCANCEL
790 // Explicit cancellation point if select() was not covered
791 // This seems to be the case on MacOS X 10.2
792 pthread_testcancel();
793 #endif
794 }
795 return NULL;
796 }
797 #else
798 int slirp_can_output(void)
799 {
800 return 0;
801 }
802
803 void slirp_output(const uint8 *packet, int len)
804 {
805 }
806 #endif
807
808
809 /*
810 * Packet reception thread
811 */
812
813 static void *receive_func(void *arg)
814 {
815 for (;;) {
816
817 // Wait for packets to arrive
818 #if HAVE_POLL
819 struct pollfd pf = {fd, POLLIN, 0};
820 int res = poll(&pf, 1, -1);
821 #else
822 fd_set rfds;
823 FD_ZERO(&rfds);
824 FD_SET(fd, &rfds);
825 // A NULL timeout could cause select() to block indefinitely,
826 // even if it is supposed to be a cancellation point [MacOS X]
827 struct timeval tv = { 0, 20000 };
828 int res = select(fd + 1, &rfds, NULL, NULL, &tv);
829 #ifdef HAVE_PTHREAD_TESTCANCEL
830 pthread_testcancel();
831 #endif
832 if (res == 0 || (res == -1 && errno == EINTR))
833 continue;
834 #endif
835 if (res <= 0)
836 break;
837
838 if (ether_driver_opened) {
839 // Trigger Ethernet interrupt
840 D(bug(" packet received, triggering Ethernet interrupt\n"));
841 SetInterruptFlag(INTFLAG_ETHER);
842 TriggerInterrupt();
843
844 // Wait for interrupt acknowledge by EtherInterrupt()
845 sem_wait(&int_ack);
846 } else
847 usleep(20000);
848 }
849 return NULL;
850 }
851
852
853 /*
854 * Ethernet interrupt - activate deferred tasks to call IODone or protocol handlers
855 */
856
857 void ether_do_interrupt(void)
858 {
859 // Call protocol handler for received packets
860 EthernetPacket ether_packet;
861 uint32 packet = ether_packet.addr();
862 ssize_t length;
863 for (;;) {
864
865 #ifndef SHEEPSHAVER
866 if (udp_tunnel) {
867
868 // Read packet from socket
869 struct sockaddr_in from;
870 socklen_t from_len = sizeof(from);
871 length = recvfrom(fd, Mac2HostAddr(packet), 1514, 0, (struct sockaddr *)&from, &from_len);
872 if (length < 14)
873 break;
874 ether_udp_read(packet, length, &from);
875
876 } else
877 #endif
878 {
879
880 // Read packet from sheep_net device
881 #if defined(__linux__)
882 length = read(fd, Mac2HostAddr(packet), net_if_type == NET_IF_ETHERTAP ? 1516 : 1514);
883 #else
884 length = read(fd, Mac2HostAddr(packet), 1514);
885 #endif
886 if (length < 14)
887 break;
888
889 #if MONITOR
890 bug("Receiving Ethernet packet:\n");
891 for (int i=0; i<length; i++) {
892 bug("%02x ", ReadMacInt8(packet + i));
893 }
894 bug("\n");
895 #endif
896
897 // Pointer to packet data (Ethernet header)
898 uint32 p = packet;
899 #if defined(__linux__)
900 if (net_if_type == NET_IF_ETHERTAP) {
901 p += 2; // Linux ethertap has two random bytes before the packet
902 length -= 2;
903 }
904 #endif
905
906 // Dispatch packet
907 ether_dispatch_packet(p, length);
908 }
909 }
910 }