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.5 by cebix, 2001-09-02T13:50:05Z vs.
Revision 1.24 by nigel, 2005-12-29T13:40:25Z

# Line 1 | Line 1
1   /*
2   *  ether_unix.cpp - Ethernet device driver, Unix specific stuff (Linux and FreeBSD)
3   *
4 < *  Basilisk II (C) 1997-2001 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 79 | Line 126 | static bool start_thread(void)
126                  return false;
127          }
128  
129 <        pthread_attr_init(&ether_thread_attr);
83 < #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
84 <        if (geteuid() == 0) {
85 <                pthread_attr_setinheritsched(&ether_thread_attr, PTHREAD_EXPLICIT_SCHED);
86 <                pthread_attr_setschedpolicy(&ether_thread_attr, SCHED_FIFO);
87 <                struct sched_param fifo_param;
88 <                fifo_param.sched_priority = (sched_get_priority_min(SCHED_FIFO) + sched_get_priority_max(SCHED_FIFO)) / 2 + 1;
89 <                pthread_attr_setschedparam(&ether_thread_attr, &fifo_param);
90 <        }
91 < #endif
92 <
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  
# Line 106 | 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 + #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          }
# Line 116 | Line 180 | static void stop_thread(void)
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  
# Line 129 | Line 222 | bool ether_init(void)
222          if (name == NULL)
223                  return false;
224  
225 <        // Is it Ethertap?
226 <        is_ethertap = (strncmp(name, "tap", 3) == 0);
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 device
262 >        // Open sheep_net or ethertap or TUN/TAP device
263          char dev_name[16];
264 <        if (is_ethertap)
264 >        switch (net_if_type) {
265 >        case NET_IF_ETHERTAP:
266                  sprintf(dev_name, "/dev/%s", name);
267 <        else
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 <        fd = open(dev_name, O_RDWR);
274 <        if (fd < 0) {
275 <                sprintf(str, GetString(STR_NO_SHEEP_NET_DRIVER_WARN), dev_name, strerror(errno));
276 <                WarningAlert(str);
277 <                goto open_error;
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 (!is_ethertap && ioctl(fd, SIOCSIFLINK, name) < 0) {
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;
# Line 158 | Line 328 | bool ether_init(void)
328          ioctl(fd, FIONBIO, &nonblock);
329  
330          // Get Ethernet address
331 <        if (is_ethertap) {
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;
# Line 166 | Line 336 | bool ether_init(void)
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]));
# Line 184 | Line 363 | open_error:
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  
# Line 194 | Line 385 | open_error:
385  
386   void ether_exit(void)
387   {
388 <        // Stop reception thread
389 <        if (thread_active) {
390 <                pthread_cancel(ether_thread);
391 <                pthread_join(ether_thread, NULL);
392 <                sem_destroy(&int_ack);
393 <                thread_active = false;
394 <        }
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
# Line 222 | Line 608 | void ether_reset(void)
608   *  Add multicast address
609   */
610  
611 < int16 ether_add_multicast(uint32 pb)
611 > static int16 ether_do_add_multicast(uint8 *addr)
612   {
613 <        if (ioctl(fd, SIOCADDMULTI, Mac2HostAddr(pb + eMultiAddr)) < 0) {
614 <                D(bug("WARNING: Couldn't enable multicast address\n"));
615 <                if (is_ethertap)
616 <                        return noErr;
617 <                else
618 <                        return eMultiErr;
619 <        } else
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  
# Line 239 | Line 630 | int16 ether_add_multicast(uint32 pb)
630   *  Delete multicast address
631   */
632  
633 < int16 ether_del_multicast(uint32 pb)
633 > static int16 ether_do_del_multicast(uint8 *addr)
634   {
635 <        if (ioctl(fd, SIOCDELMULTI, Mac2HostAddr(pb + eMultiAddr)) < 0) {
636 <                D(bug("WARNING: Couldn't disable multicast address\n"));
637 <                return eMultiErr;
638 <        } else
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  
# Line 278 | Line 674 | int16 ether_detach_ph(uint16 type)
674   *  Transmit raw ethernet packet
675   */
676  
677 < int16 ether_write(uint32 wds)
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 (is_ethertap) {
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_wds_to_buffer(wds, p);
689 >        len += ether_arg_to_buffer(arg, p);
690  
691   #if MONITOR
692          bug("Sending Ethernet packet:\n");
# Line 301 | Line 697 | int16 ether_write(uint32 wds)
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;
# Line 333 | Line 737 | void ether_stop_udp_thread(void)
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  
# Line 341 | Line 815 | static void *receive_func(void *arg)
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 <                // Trigger Ethernet interrupt
839 <                D(bug(" packet received, triggering Ethernet interrupt\n"));
840 <                SetInterruptFlag(INTFLAG_ETHER);
841 <                TriggerInterrupt();
842 <
843 <                // Wait for interrupt acknowledge by EtherInterrupt()
844 <                sem_wait(&int_ack);
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   }
# Line 362 | Line 854 | static void *receive_func(void *arg)
854   *  Ethernet interrupt - activate deferred tasks to call IODone or protocol handlers
855   */
856  
857 < void EtherInterrupt(void)
857 > void ether_do_interrupt(void)
858   {
367        D(bug("EtherIRQ\n"));
368
859          // Call protocol handler for received packets
860 <        uint8 packet[1516];
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, packet, 1514, 0, (struct sockaddr *)&from, &from_len);
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 {
876 >                } else
877 > #endif
878 >                {
879  
880                          // Read packet from sheep_net device
881   #if defined(__linux__)
882 <                        length = read(fd, packet, is_ethertap ? 1516 : 1514);
882 >                        length = read(fd, Mac2HostAddr(packet), net_if_type == NET_IF_ETHERTAP ? 1516 : 1514);
883   #else
884 <                        length = read(fd, packet, 1514);
884 >                        length = read(fd, Mac2HostAddr(packet), 1514);
885   #endif
886                          if (length < 14)
887                                  break;
# Line 395 | Line 889 | void EtherInterrupt(void)
889   #if MONITOR
890                          bug("Receiving Ethernet packet:\n");
891                          for (int i=0; i<length; i++) {
892 <                                bug("%02x ", packet[i]);
892 >                                bug("%02x ", ReadMacInt8(packet + i));
893                          }
894                          bug("\n");
895   #endif
896  
897                          // Pointer to packet data (Ethernet header)
898 <                        uint8 *p = packet;
898 >                        uint32 p = packet;
899   #if defined(__linux__)
900 <                        if (is_ethertap) {
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 <                        // Get packet type
907 <                        uint16 type = (p[12] << 8) | p[13];
414 <
415 <                        // Look for protocol
416 <                        uint16 search_type = (type <= 1500 ? 0 : type);
417 <                        if (net_protocols.find(search_type) == net_protocols.end())
418 <                                continue;
419 <                        uint32 handler = net_protocols[search_type];
420 <
421 <                        // No default handler
422 <                        if (handler == 0)
423 <                                continue;
424 <
425 <                        // Copy header to RHA
426 <                        Host2Mac_memcpy(ether_data + ed_RHA, p, 14);
427 <                        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)));
428 <
429 <                        // Call protocol handler
430 <                        M68kRegisters r;
431 <                        r.d[0] = type;                                                                  // Packet type
432 <                        r.d[1] = length - 14;                                                   // Remaining packet length (without header, for ReadPacket)
433 <                        r.a[0] = (uint32)p + 14;                                                // Pointer to packet (host address, for ReadPacket)
434 <                        r.a[3] = ether_data + ed_RHA + 14;                              // Pointer behind header in RHA
435 <                        r.a[4] = ether_data + ed_ReadPacket;                    // Pointer to ReadPacket/ReadRest routines
436 <                        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]));
437 <                        Execute68k(handler, &r);
906 >                        // Dispatch packet
907 >                        ether_dispatch_packet(p, length);
908                  }
909          }
440
441        // Acknowledge interrupt to reception thread
442        D(bug(" EtherIRQ done\n"));
443        sem_post(&int_ack);
910   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines