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.2 by cebix, 2001-07-12T19:48:27Z vs.
Revision 1.26 by gbeauche, 2006-01-21T20:48:17Z

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines