ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/ether_unix.cpp
(Generate patch)

Comparing BasiliskII/src/Unix/ether_unix.cpp (file contents):
Revision 1.7 by cebix, 2002-02-07T16:10:55Z vs.
Revision 1.23 by gbeauche, 2005-07-03T08:21:32Z

# Line 1 | Line 1
1   /*
2   *  ether_unix.cpp - Ethernet device driver, Unix specific stuff (Linux and FreeBSD)
3   *
4 < *  Basilisk II (C) 1997-2002 Christian Bauer
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
# Line 20 | Line 20
20  
21   #include "sysdeps.h"
22  
23 < #include <sys/ioctl.h>
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>
# Line 30 | Line 33
33   #include <stdio.h>
34   #include <map>
35  
36 < #if defined(__FreeBSD__) || defined(sgi)
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"
# Line 49 | Line 66 | using std::map;
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
61 static bool is_ethertap;                                        // Flag: Ethernet device is ethertap
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   /*
# Line 86 | Line 133 | static bool start_thread(void)
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  
# Line 96 | Line 153 | static bool start_thread(void)
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                  pthread_join(ether_thread, NULL);
171                  sem_destroy(&int_ack);
172                  thread_active = false;
# Line 106 | Line 175 | static void stop_thread(void)
175  
176  
177   /*
178 + *  Execute network script up|down
179 + */
180 +
181 + static bool execute_network_script(const char *action)
182 + {
183 +        if (net_if_script == NULL || net_if_name == NULL)
184 +                return false;
185 +
186 +        int pid = fork();
187 +        if (pid >= 0) {
188 +                if (pid == 0) {
189 +                        char *args[4];
190 +                        args[0] = (char *)net_if_script;
191 +                        args[1] = net_if_name;
192 +                        args[2] = (char *)action;
193 +                        args[3] = NULL;
194 +                        execv(net_if_script, args);
195 +                        exit(1);
196 +                }
197 +                int status;
198 +                while (waitpid(pid, &status, 0) != pid);
199 +                return WIFEXITED(status) && WEXITSTATUS(status) == 0;
200 +        }
201 +
202 +        return false;
203 + }
204 +
205 +
206 + /*
207   *  Initialization
208   */
209  
# Line 119 | Line 217 | bool ether_init(void)
217          if (name == NULL)
218                  return false;
219  
220 <        // Is it Ethertap?
221 <        is_ethertap = (strncmp(name, "tap", 3) == 0);
220 >        // Determine Ethernet device type
221 >        net_if_type = -1;
222 >        if (strncmp(name, "tap", 3) == 0)
223 >                net_if_type = NET_IF_ETHERTAP;
224 > #if ENABLE_TUNTAP
225 >        else if (strcmp(name, "tun") == 0)
226 >                net_if_type = NET_IF_TUNTAP;
227 > #endif
228 > #ifdef HAVE_SLIRP
229 >        else if (strcmp(name, "slirp") == 0)
230 >                net_if_type = NET_IF_SLIRP;
231 > #endif
232 >        else
233 >                net_if_type = NET_IF_SHEEPNET;
234 >
235 > #ifdef HAVE_SLIRP
236 >        // Initialize slirp library
237 >        if (net_if_type == NET_IF_SLIRP) {
238 >                if (slirp_init() < 0) {
239 >                        sprintf(str, GetString(STR_SLIRP_NO_DNS_FOUND_WARN));
240 >                        WarningAlert(str);
241 >                        return false;
242 >                }
243 >
244 >                // Open slirp output pipe
245 >                int fds[2];
246 >                if (pipe(fds) < 0)
247 >                        return false;
248 >                fd = fds[0];
249 >                slirp_output_fd = fds[1];
250 >
251 >                // Open slirp input pipe
252 >                if (pipe(slirp_input_fds) < 0)
253 >                        return false;
254 >        }
255 > #endif
256  
257 <        // Open sheep_net or ethertap device
257 >        // Open sheep_net or ethertap or TUN/TAP device
258          char dev_name[16];
259 <        if (is_ethertap)
259 >        switch (net_if_type) {
260 >        case NET_IF_ETHERTAP:
261                  sprintf(dev_name, "/dev/%s", name);
262 <        else
262 >                break;
263 >        case NET_IF_TUNTAP:
264 >                strcpy(dev_name, "/dev/net/tun");
265 >                break;
266 >        case NET_IF_SHEEPNET:
267                  strcpy(dev_name, "/dev/sheep_net");
268 <        fd = open(dev_name, O_RDWR);
269 <        if (fd < 0) {
270 <                sprintf(str, GetString(STR_NO_SHEEP_NET_DRIVER_WARN), dev_name, strerror(errno));
271 <                WarningAlert(str);
272 <                goto open_error;
268 >                break;
269 >        }
270 >        if (net_if_type != NET_IF_SLIRP) {
271 >                fd = open(dev_name, O_RDWR);
272 >                if (fd < 0) {
273 >                        sprintf(str, GetString(STR_NO_SHEEP_NET_DRIVER_WARN), dev_name, strerror(errno));
274 >                        WarningAlert(str);
275 >                        goto open_error;
276 >                }
277          }
278  
279 + #if ENABLE_TUNTAP
280 +        // Open TUN/TAP interface
281 +        if (net_if_type == NET_IF_TUNTAP) {
282 +                struct ifreq ifr;
283 +                memset(&ifr, 0, sizeof(ifr));
284 +                ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
285 +                strcpy(ifr.ifr_name, "tun%d");
286 +                if (ioctl(fd, TUNSETIFF, (void *) &ifr) != 0) {
287 +                        sprintf(str, GetString(STR_SHEEP_NET_ATTACH_WARN), strerror(errno));
288 +                        WarningAlert(str);
289 +                        goto open_error;
290 +                }
291 +
292 +                // Get network config script file path
293 +                net_if_script = PrefsFindString("etherconfig");
294 +                if (net_if_script == NULL)
295 +                        net_if_script = ETHERCONFIG_FILE_NAME;
296 +
297 +                // Start network script up
298 +                if (net_if_script == NULL) {
299 +                        sprintf(str, GetString(STR_TUN_TAP_CONFIG_WARN), "script not found");
300 +                        WarningAlert(str);
301 +                        goto open_error;
302 +                }
303 +                net_if_name = strdup(ifr.ifr_name);
304 +                if (!execute_network_script("up")) {
305 +                        sprintf(str, GetString(STR_TUN_TAP_CONFIG_WARN), "script execute error");
306 +                        WarningAlert(str);
307 +                        goto open_error;
308 +                }
309 +                D(bug("Connected to host network interface: %s\n", net_if_name));
310 +        }
311 + #endif
312 +
313   #if defined(__linux__)
314          // Attach sheep_net to selected Ethernet card
315 <        if (!is_ethertap && ioctl(fd, SIOCSIFLINK, name) < 0) {
315 >        if (net_if_type == NET_IF_SHEEPNET && ioctl(fd, SIOCSIFLINK, name) < 0) {
316                  sprintf(str, GetString(STR_SHEEP_NET_ATTACH_WARN), strerror(errno));
317                  WarningAlert(str);
318                  goto open_error;
# Line 148 | Line 323 | bool ether_init(void)
323          ioctl(fd, FIONBIO, &nonblock);
324  
325          // Get Ethernet address
326 <        if (is_ethertap) {
326 >        if (net_if_type == NET_IF_ETHERTAP) {
327                  pid_t p = getpid();     // If configured for multicast, ethertap requires that the lower 32 bit of the Ethernet address are our PID
328                  ether_addr[0] = 0xfe;
329                  ether_addr[1] = 0xfd;
# Line 156 | Line 331 | bool ether_init(void)
331                  ether_addr[3] = p >> 16;
332                  ether_addr[4] = p >> 8;
333                  ether_addr[5] = p;
334 + #ifdef HAVE_SLIRP
335 +        } else if (net_if_type == NET_IF_SLIRP) {
336 +                ether_addr[0] = 0x52;
337 +                ether_addr[1] = 0x54;
338 +                ether_addr[2] = 0x00;
339 +                ether_addr[3] = 0x12;
340 +                ether_addr[4] = 0x34;
341 +                ether_addr[5] = 0x56;
342 + #endif
343          } else
344                  ioctl(fd, SIOCGIFADDR, ether_addr);
345          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]));
# Line 174 | Line 358 | open_error:
358                  close(fd);
359                  fd = -1;
360          }
361 +        if (slirp_input_fds[0] >= 0) {
362 +                close(slirp_input_fds[0]);
363 +                slirp_input_fds[0] = -1;
364 +        }
365 +        if (slirp_input_fds[1] >= 0) {
366 +                close(slirp_input_fds[1]);
367 +                slirp_input_fds[1] = -1;
368 +        }
369 +        if (slirp_output_fd >= 0) {
370 +                close(slirp_output_fd);
371 +                slirp_output_fd = -1;
372 +        }
373          return false;
374   }
375  
# Line 184 | Line 380 | open_error:
380  
381   void ether_exit(void)
382   {
383 <        // Stop reception thread
384 <        if (thread_active) {
385 <                pthread_cancel(ether_thread);
386 <                pthread_join(ether_thread, NULL);
387 <                sem_destroy(&int_ack);
388 <                thread_active = false;
389 <        }
383 >        // Stop reception threads
384 >        stop_thread();
385 >
386 >        // Shut down TUN/TAP interface
387 >        if (net_if_type == NET_IF_TUNTAP)
388 >                execute_network_script("down");
389 >
390 >        // Free TUN/TAP device name
391 >        if (net_if_name)
392 >                free(net_if_name);
393  
394          // Close sheep_net device
395          if (fd > 0)
396                  close(fd);
397 +
398 +        // Close slirp input buffer
399 +        if (slirp_input_fds[0] >= 0)
400 +                close(slirp_input_fds[0]);
401 +        if (slirp_input_fds[1] >= 0)
402 +                close(slirp_input_fds[1]);
403 +
404 +        // Close slirp output buffer
405 +        if (slirp_output_fd > 0)
406 +                close(slirp_output_fd);
407 +
408 + #if STATISTICS
409 +        // Show statistics
410 +        printf("%ld messages put on write queue\n", num_wput);
411 +        printf("%ld error acks\n", num_error_acks);
412 +        printf("%ld packets transmitted (%ld raw, %ld normal)\n", num_tx_packets, num_tx_raw_packets, num_tx_normal_packets);
413 +        printf("%ld tx packets dropped because buffer full\n", num_tx_buffer_full);
414 +        printf("%ld packets received\n", num_rx_packets);
415 +        printf("%ld packets passed upstream (%ld Fast Path, %ld normal)\n", num_rx_fastpath + num_unitdata_ind, num_rx_fastpath, num_unitdata_ind);
416 +        printf("EtherIRQ called %ld times\n", num_ether_irq);
417 +        printf("%ld rx packets dropped due to low memory\n", num_rx_no_mem);
418 +        printf("%ld rx packets dropped because no stream found\n", num_rx_dropped);
419 +        printf("%ld rx packets dropped because stream not ready\n", num_rx_stream_not_ready);
420 +        printf("%ld rx packets dropped because no memory for unitdata_ind\n", num_rx_no_unitdata_mem);
421 + #endif
422   }
423  
424  
425   /*
426 + *  Glue around low-level implementation
427 + */
428 +
429 + #ifdef SHEEPSHAVER
430 + // Error codes
431 + enum {
432 +        eMultiErr               = -91,
433 +        eLenErr                 = -92,
434 +        lapProtErr              = -94,
435 +        excessCollsns   = -95
436 + };
437 +
438 + // Initialize ethernet
439 + void EtherInit(void)
440 + {
441 +        net_open = false;
442 +
443 +        // Do nothing if the user disabled the network
444 +        if (PrefsFindBool("nonet"))
445 +                return;
446 +
447 +        net_open = ether_init();
448 + }
449 +
450 + // Exit ethernet
451 + void EtherExit(void)
452 + {
453 +        ether_exit();
454 +        net_open = false;
455 + }
456 +
457 + // Get ethernet hardware address
458 + void AO_get_ethernet_address(uint32 arg)
459 + {
460 +        uint8 *addr = Mac2HostAddr(arg);
461 +        if (net_open)
462 +                OTCopy48BitAddress(ether_addr, addr);
463 +        else {
464 +                addr[0] = 0x12;
465 +                addr[1] = 0x34;
466 +                addr[2] = 0x56;
467 +                addr[3] = 0x78;
468 +                addr[4] = 0x9a;
469 +                addr[5] = 0xbc;
470 +        }
471 +        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]));
472 + }
473 +
474 + // Add multicast address
475 + void AO_enable_multicast(uint32 addr)
476 + {
477 +        if (net_open)
478 +                ether_do_add_multicast(Mac2HostAddr(addr));
479 + }
480 +
481 + // Disable multicast address
482 + void AO_disable_multicast(uint32 addr)
483 + {
484 +        if (net_open)
485 +                ether_do_del_multicast(Mac2HostAddr(addr));
486 + }
487 +
488 + // Transmit one packet
489 + void AO_transmit_packet(uint32 mp)
490 + {
491 +        if (net_open) {
492 +                switch (ether_do_write(mp)) {
493 +                case noErr:
494 +                        num_tx_packets++;
495 +                        break;
496 +                case excessCollsns:
497 +                        num_tx_buffer_full++;
498 +                        break;
499 +                }
500 +        }
501 + }
502 +
503 + // Copy packet data from message block to linear buffer
504 + static inline int ether_arg_to_buffer(uint32 mp, uint8 *p)
505 + {
506 +        return ether_msgb_to_buffer(mp, p);
507 + }
508 +
509 + // Ethernet interrupt
510 + void EtherIRQ(void)
511 + {
512 +        D(bug("EtherIRQ\n"));
513 +        num_ether_irq++;
514 +
515 +        OTEnterInterrupt();
516 +        ether_do_interrupt();
517 +        OTLeaveInterrupt();
518 +
519 +        // Acknowledge interrupt to reception thread
520 +        D(bug(" EtherIRQ done\n"));
521 +        sem_post(&int_ack);
522 + }
523 + #else
524 + // Add multicast address
525 + int16 ether_add_multicast(uint32 pb)
526 + {
527 +        return ether_do_add_multicast(Mac2HostAddr(pb + eMultiAddr));
528 + }
529 +
530 + // Disable multicast address
531 + int16 ether_del_multicast(uint32 pb)
532 + {
533 +        return ether_do_del_multicast(Mac2HostAddr(pb + eMultiAddr));
534 + }
535 +
536 + // Transmit one packet
537 + int16 ether_write(uint32 wds)
538 + {
539 +        return ether_do_write(wds);
540 + }
541 +
542 + // Copy packet data from WDS to linear buffer
543 + static inline int ether_arg_to_buffer(uint32 wds, uint8 *p)
544 + {
545 +        return ether_wds_to_buffer(wds, p);
546 + }
547 +
548 + // Dispatch packet to protocol handler
549 + static void ether_dispatch_packet(uint32 p, uint32 length)
550 + {
551 +        // Get packet type
552 +        uint16 type = ReadMacInt16(p + 12);
553 +
554 +        // Look for protocol
555 +        uint16 search_type = (type <= 1500 ? 0 : type);
556 +        if (net_protocols.find(search_type) == net_protocols.end())
557 +                return;
558 +        uint32 handler = net_protocols[search_type];
559 +
560 +        // No default handler
561 +        if (handler == 0)
562 +                return;
563 +
564 +        // Copy header to RHA
565 +        Mac2Mac_memcpy(ether_data + ed_RHA, p, 14);
566 +        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)));
567 +
568 +        // Call protocol handler
569 +        M68kRegisters r;
570 +        r.d[0] = type;                                                                  // Packet type
571 +        r.d[1] = length - 14;                                                   // Remaining packet length (without header, for ReadPacket)
572 +        r.a[0] = p + 14;                                                                // Pointer to packet (Mac address, for ReadPacket)
573 +        r.a[3] = ether_data + ed_RHA + 14;                              // Pointer behind header in RHA
574 +        r.a[4] = ether_data + ed_ReadPacket;                    // Pointer to ReadPacket/ReadRest routines
575 +        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]));
576 +        Execute68k(handler, &r);
577 + }
578 +
579 + // Ethernet interrupt
580 + void EtherInterrupt(void)
581 + {
582 +        D(bug("EtherIRQ\n"));
583 +        ether_do_interrupt();
584 +
585 +        // Acknowledge interrupt to reception thread
586 +        D(bug(" EtherIRQ done\n"));
587 +        sem_post(&int_ack);
588 + }
589 + #endif
590 +
591 +
592 + /*
593   *  Reset
594   */
595  
# Line 212 | Line 603 | void ether_reset(void)
603   *  Add multicast address
604   */
605  
606 < int16 ether_add_multicast(uint32 pb)
606 > static int16 ether_do_add_multicast(uint8 *addr)
607   {
608 <        if (ioctl(fd, SIOCADDMULTI, Mac2HostAddr(pb + eMultiAddr)) < 0) {
609 <                D(bug("WARNING: Couldn't enable multicast address\n"));
610 <                if (is_ethertap)
611 <                        return noErr;
612 <                else
613 <                        return eMultiErr;
614 <        } else
608 >        switch (net_if_type) {
609 >        case NET_IF_ETHERTAP:
610 >        case NET_IF_SHEEPNET:
611 >                if (ioctl(fd, SIOCADDMULTI, addr) < 0) {
612 >                        D(bug("WARNING: Couldn't enable multicast address\n"));
613 >                        if (net_if_type == NET_IF_ETHERTAP)
614 >                                return noErr;
615 >                        else
616 >                                return eMultiErr;
617 >                }
618 >        default:
619                  return noErr;
620 +        }
621   }
622  
623  
# Line 229 | Line 625 | int16 ether_add_multicast(uint32 pb)
625   *  Delete multicast address
626   */
627  
628 < int16 ether_del_multicast(uint32 pb)
628 > static int16 ether_do_del_multicast(uint8 *addr)
629   {
630 <        if (ioctl(fd, SIOCDELMULTI, Mac2HostAddr(pb + eMultiAddr)) < 0) {
631 <                D(bug("WARNING: Couldn't disable multicast address\n"));
632 <                return eMultiErr;
633 <        } else
630 >        switch (net_if_type) {
631 >        case NET_IF_ETHERTAP:
632 >        case NET_IF_SHEEPNET:
633 >                if (ioctl(fd, SIOCDELMULTI, addr) < 0) {
634 >                        D(bug("WARNING: Couldn't disable multicast address\n"));
635 >                        return eMultiErr;
636 >                }
637 >        default:
638                  return noErr;
639 +        }
640   }
641  
642  
# Line 268 | Line 669 | int16 ether_detach_ph(uint16 type)
669   *  Transmit raw ethernet packet
670   */
671  
672 < int16 ether_write(uint32 wds)
672 > static int16 ether_do_write(uint32 arg)
673   {
674          // Copy packet to buffer
675          uint8 packet[1516], *p = packet;
676          int len = 0;
677   #if defined(__linux__)
678 <        if (is_ethertap) {
678 >        if (net_if_type == NET_IF_ETHERTAP) {
679                  *p++ = 0;       // Linux ethertap discards the first 2 bytes
680                  *p++ = 0;
681                  len += 2;
682          }
683   #endif
684 <        len += ether_wds_to_buffer(wds, p);
684 >        len += ether_arg_to_buffer(arg, p);
685  
686   #if MONITOR
687          bug("Sending Ethernet packet:\n");
# Line 291 | Line 692 | int16 ether_write(uint32 wds)
692   #endif
693  
694          // Transmit packet
695 + #ifdef HAVE_SLIRP
696 +        if (net_if_type == NET_IF_SLIRP) {
697 +                const int slirp_input_fd = slirp_input_fds[1];
698 +                write(slirp_input_fd, &len, sizeof(len));
699 +                write(slirp_input_fd, packet, len);
700 +                return noErr;
701 +        } else
702 + #endif
703          if (write(fd, packet, len) < 0) {
704                  D(bug("WARNING: Couldn't transmit packet\n"));
705                  return excessCollsns;
# Line 323 | Line 732 | void ether_stop_udp_thread(void)
732  
733  
734   /*
735 + *  SLIRP output buffer glue
736 + */
737 +
738 + #ifdef HAVE_SLIRP
739 + int slirp_can_output(void)
740 + {
741 +        return 1;
742 + }
743 +
744 + void slirp_output(const uint8 *packet, int len)
745 + {
746 +        write(slirp_output_fd, packet, len);
747 + }
748 +
749 + void *slirp_receive_func(void *arg)
750 + {
751 +        const int slirp_input_fd = slirp_input_fds[0];
752 +
753 +        for (;;) {
754 +                // Wait for packets to arrive
755 +                fd_set rfds, wfds, xfds;
756 +                int nfds;
757 +                struct timeval tv;
758 +
759 +                // ... in the input queue
760 +                FD_ZERO(&rfds);
761 +                FD_SET(slirp_input_fd, &rfds);
762 +                tv.tv_sec = 0;
763 +                tv.tv_usec = 0;
764 +                if (select(slirp_input_fd + 1, &rfds, NULL, NULL, &tv) > 0) {
765 +                        int len;
766 +                        read(slirp_input_fd, &len, sizeof(len));
767 +                        uint8 packet[1516];
768 +                        assert(len <= sizeof(packet));
769 +                        read(slirp_input_fd, packet, len);
770 +                        slirp_input(packet, len);
771 +                }
772 +
773 +                // ... in the output queue
774 +                nfds = -1;
775 +                FD_ZERO(&rfds);
776 +                FD_ZERO(&wfds);
777 +                FD_ZERO(&xfds);
778 +                slirp_select_fill(&nfds, &rfds, &wfds, &xfds);
779 +                tv.tv_sec = 0;
780 +                tv.tv_usec = 10000;
781 +                if (select(nfds + 1, &rfds, &wfds, &xfds, &tv) >= 0)
782 +                        slirp_select_poll(&rfds, &wfds, &xfds);
783 +
784 + #ifdef HAVE_PTHREAD_TESTCANCEL
785 +                // Explicit cancellation point if select() was not covered
786 +                // This seems to be the case on MacOS X 10.2
787 +                pthread_testcancel();
788 + #endif
789 +        }
790 +        return NULL;
791 + }
792 + #else
793 + int slirp_can_output(void)
794 + {
795 +        return 0;
796 + }
797 +
798 + void slirp_output(const uint8 *packet, int len)
799 + {
800 + }
801 + #endif
802 +
803 +
804 + /*
805   *  Packet reception thread
806   */
807  
# Line 331 | Line 810 | static void *receive_func(void *arg)
810          for (;;) {
811  
812                  // Wait for packets to arrive
813 + #if HAVE_POLL
814                  struct pollfd pf = {fd, POLLIN, 0};
815                  int res = poll(&pf, 1, -1);
816 + #else
817 +                fd_set rfds;
818 +                FD_ZERO(&rfds);
819 +                FD_SET(fd, &rfds);
820 +                // A NULL timeout could cause select() to block indefinitely,
821 +                // even if it is supposed to be a cancellation point [MacOS X]
822 +                struct timeval tv = { 0, 20000 };
823 +                int res = select(fd + 1, &rfds, NULL, NULL, &tv);
824 + #ifdef HAVE_PTHREAD_TESTCANCEL
825 +                pthread_testcancel();
826 + #endif
827 +                if (res == 0 || (res == -1 && errno == EINTR))
828 +                        continue;
829 + #endif
830                  if (res <= 0)
831                          break;
832  
833 <                // Trigger Ethernet interrupt
834 <                D(bug(" packet received, triggering Ethernet interrupt\n"));
835 <                SetInterruptFlag(INTFLAG_ETHER);
836 <                TriggerInterrupt();
837 <
838 <                // Wait for interrupt acknowledge by EtherInterrupt()
839 <                sem_wait(&int_ack);
833 >                if (ether_driver_opened) {
834 >                        // Trigger Ethernet interrupt
835 >                        D(bug(" packet received, triggering Ethernet interrupt\n"));
836 >                        SetInterruptFlag(INTFLAG_ETHER);
837 >                        TriggerInterrupt();
838 >
839 >                        // Wait for interrupt acknowledge by EtherInterrupt()
840 >                        sem_wait(&int_ack);
841 >                } else
842 >                        usleep(20000);
843          }
844          return NULL;
845   }
# Line 352 | Line 849 | static void *receive_func(void *arg)
849   *  Ethernet interrupt - activate deferred tasks to call IODone or protocol handlers
850   */
851  
852 < void EtherInterrupt(void)
852 > void ether_do_interrupt(void)
853   {
357        D(bug("EtherIRQ\n"));
358
854          // Call protocol handler for received packets
855 <        uint8 packet[1516];
855 >        EthernetPacket ether_packet;
856 >        uint32 packet = ether_packet.addr();
857          ssize_t length;
858          for (;;) {
859  
860 + #ifndef SHEEPSHAVER
861                  if (udp_tunnel) {
862  
863                          // Read packet from socket
864                          struct sockaddr_in from;
865                          socklen_t from_len = sizeof(from);
866 <                        length = recvfrom(fd, packet, 1514, 0, (struct sockaddr *)&from, &from_len);
866 >                        length = recvfrom(fd, Mac2HostAddr(packet), 1514, 0, (struct sockaddr *)&from, &from_len);
867                          if (length < 14)
868                                  break;
869                          ether_udp_read(packet, length, &from);
870  
871 <                } else {
871 >                } else
872 > #endif
873 >                {
874  
875                          // Read packet from sheep_net device
876   #if defined(__linux__)
877 <                        length = read(fd, packet, is_ethertap ? 1516 : 1514);
877 >                        length = read(fd, Mac2HostAddr(packet), net_if_type == NET_IF_ETHERTAP ? 1516 : 1514);
878   #else
879 <                        length = read(fd, packet, 1514);
879 >                        length = read(fd, Mac2HostAddr(packet), 1514);
880   #endif
881                          if (length < 14)
882                                  break;
# Line 385 | Line 884 | void EtherInterrupt(void)
884   #if MONITOR
885                          bug("Receiving Ethernet packet:\n");
886                          for (int i=0; i<length; i++) {
887 <                                bug("%02x ", packet[i]);
887 >                                bug("%02x ", ReadMacInt8(packet + i));
888                          }
889                          bug("\n");
890   #endif
891  
892                          // Pointer to packet data (Ethernet header)
893 <                        uint8 *p = packet;
893 >                        uint32 p = packet;
894   #if defined(__linux__)
895 <                        if (is_ethertap) {
895 >                        if (net_if_type == NET_IF_ETHERTAP) {
896                                  p += 2;                 // Linux ethertap has two random bytes before the packet
897                                  length -= 2;
898                          }
899   #endif
900  
901 <                        // Get packet type
902 <                        uint16 type = (p[12] << 8) | p[13];
404 <
405 <                        // Look for protocol
406 <                        uint16 search_type = (type <= 1500 ? 0 : type);
407 <                        if (net_protocols.find(search_type) == net_protocols.end())
408 <                                continue;
409 <                        uint32 handler = net_protocols[search_type];
410 <
411 <                        // No default handler
412 <                        if (handler == 0)
413 <                                continue;
414 <
415 <                        // Copy header to RHA
416 <                        Host2Mac_memcpy(ether_data + ed_RHA, p, 14);
417 <                        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)));
418 <
419 <                        // Call protocol handler
420 <                        M68kRegisters r;
421 <                        r.d[0] = type;                                                                  // Packet type
422 <                        r.d[1] = length - 14;                                                   // Remaining packet length (without header, for ReadPacket)
423 <                        r.a[0] = (uint32)p + 14;                                                // Pointer to packet (host address, for ReadPacket)
424 <                        r.a[3] = ether_data + ed_RHA + 14;                              // Pointer behind header in RHA
425 <                        r.a[4] = ether_data + ed_ReadPacket;                    // Pointer to ReadPacket/ReadRest routines
426 <                        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]));
427 <                        Execute68k(handler, &r);
901 >                        // Dispatch packet
902 >                        ether_dispatch_packet(p, length);
903                  }
904          }
430
431        // Acknowledge interrupt to reception thread
432        D(bug(" EtherIRQ done\n"));
433        sem_post(&int_ack);
905   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines