ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/ether_unix.cpp
Revision: 1.20
Committed: 2005-05-15T17:22:12Z (19 years, 6 months ago) by gbeauche
Branch: MAIN
Changes since 1.19: +29 -26 lines
Log Message:
Fix and factor out ether_exit(). Pitifully, MacOS X 10.2 does not make select()
a cancellation point when it is passed a NULL timeout. Workarounded in
receive_func() with a full inline of poll_fd() + pthread_testcancel().

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * ether_unix.cpp - Ethernet device driver, Unix specific stuff (Linux and FreeBSD)
3     *
4 gbeauche 1.13 * Basilisk II (C) 1997-2005 Christian Bauer
5 cebix 1.1 *
6     * This program is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19     */
20    
21     #include "sysdeps.h"
22    
23 gbeauche 1.17 #ifdef HAVE_SYS_POLL_H
24     #include <sys/poll.h>
25     #endif
26 cebix 1.1 #include <sys/ioctl.h>
27 cebix 1.3 #include <sys/socket.h>
28 gbeauche 1.9 #include <sys/wait.h>
29 cebix 1.3 #include <netinet/in.h>
30 cebix 1.1 #include <pthread.h>
31     #include <semaphore.h>
32     #include <errno.h>
33     #include <stdio.h>
34 cebix 1.3 #include <map>
35 cebix 1.2
36 gbeauche 1.17 #if defined(__FreeBSD__) || defined(sgi) || (defined(__APPLE__) && defined(__MACH__))
37 cebix 1.1 #include <net/if.h>
38     #endif
39    
40 gbeauche 1.9 #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 gbeauche 1.18 #ifdef HAVE_SLIRP
51 gbeauche 1.16 #include "libslirp.h"
52 gbeauche 1.18 #endif
53 gbeauche 1.15
54 cebix 1.1 #include "cpu_emulation.h"
55     #include "main.h"
56     #include "macos_util.h"
57     #include "prefs.h"
58     #include "user_strings.h"
59     #include "ether.h"
60     #include "ether_defs.h"
61    
62 cebix 1.3 #ifndef NO_STD_NAMESPACE
63     using std::map;
64     #endif
65    
66 cebix 1.1 #define DEBUG 0
67     #include "debug.h"
68    
69     #define MONITOR 0
70    
71    
72 gbeauche 1.9 // Ethernet device types
73     enum {
74     NET_IF_SHEEPNET,
75     NET_IF_ETHERTAP,
76     NET_IF_TUNTAP,
77 gbeauche 1.15 NET_IF_SLIRP
78 gbeauche 1.9 };
79    
80     // Constants
81     static const char ETHERCONFIG_FILE_NAME[] = DATADIR "/tunconfig";
82    
83 cebix 1.1 // Global variables
84     static int fd = -1; // fd of sheep_net device
85     static pthread_t ether_thread; // Packet reception thread
86     static pthread_attr_t ether_thread_attr; // Packet reception thread attributes
87     static bool thread_active = false; // Flag: Packet reception thread installed
88     static sem_t int_ack; // Interrupt acknowledge semaphore
89 cebix 1.2 static bool udp_tunnel; // Flag: UDP tunnelling active, fd is the socket descriptor
90 gbeauche 1.9 static int net_if_type = -1; // Ethernet device type
91 gbeauche 1.10 static char *net_if_name = NULL; // TUN/TAP device name
92 gbeauche 1.9 static const char *net_if_script = NULL; // Network config script
93 gbeauche 1.15 static pthread_t slirp_thread; // Slirp reception thread
94     static bool slirp_thread_active = false; // Flag: Slirp reception threadinstalled
95     static int slirp_output_fd = -1; // fd of slirp output pipe
96 cebix 1.1
97 cebix 1.3 // Attached network protocols, maps protocol type to MacOS handler address
98     static map<uint16, uint32> net_protocols;
99    
100 cebix 1.1 // Prototypes
101     static void *receive_func(void *arg);
102 gbeauche 1.15 static void *slirp_receive_func(void *arg);
103 gbeauche 1.17 static int poll_fd(int fd);
104 cebix 1.1
105    
106     /*
107 cebix 1.2 * Start packet reception thread
108     */
109    
110     static bool start_thread(void)
111     {
112     if (sem_init(&int_ack, 0, 0) < 0) {
113     printf("WARNING: Cannot init semaphore");
114     return false;
115     }
116    
117 cebix 1.7 Set_pthread_attr(&ether_thread_attr, 1);
118 cebix 1.2 thread_active = (pthread_create(&ether_thread, &ether_thread_attr, receive_func, NULL) == 0);
119     if (!thread_active) {
120     printf("WARNING: Cannot start Ethernet thread");
121     return false;
122     }
123    
124 gbeauche 1.15 #ifdef HAVE_SLIRP
125     if (net_if_type == NET_IF_SLIRP) {
126     slirp_thread_active = (pthread_create(&slirp_thread, NULL, slirp_receive_func, NULL) == 0);
127     if (!slirp_thread_active) {
128     printf("WARNING: Cannot start slirp reception thread\n");
129     return false;
130     }
131     }
132     #endif
133    
134 cebix 1.2 return true;
135     }
136    
137    
138     /*
139     * Stop packet reception thread
140     */
141    
142     static void stop_thread(void)
143     {
144 gbeauche 1.15 #ifdef HAVE_SLIRP
145     if (slirp_thread_active) {
146 gbeauche 1.20 #ifdef HAVE_PTHREAD_CANCEL
147 gbeauche 1.15 pthread_cancel(slirp_thread);
148 gbeauche 1.20 #endif
149 gbeauche 1.15 pthread_join(slirp_thread, NULL);
150     slirp_thread_active = false;
151     }
152     #endif
153    
154 cebix 1.2 if (thread_active) {
155 gbeauche 1.20 #ifdef HAVE_PTHREAD_CANCEL
156 cebix 1.2 pthread_cancel(ether_thread);
157 gbeauche 1.20 #endif
158 cebix 1.2 pthread_join(ether_thread, NULL);
159     sem_destroy(&int_ack);
160     thread_active = false;
161     }
162     }
163    
164    
165     /*
166 gbeauche 1.9 * Execute network script up|down
167     */
168    
169     static bool execute_network_script(const char *action)
170     {
171     if (net_if_script == NULL || net_if_name == NULL)
172     return false;
173    
174     int pid = fork();
175     if (pid >= 0) {
176     if (pid == 0) {
177     char *args[4];
178     args[0] = (char *)net_if_script;
179 gbeauche 1.10 args[1] = net_if_name;
180 gbeauche 1.9 args[2] = (char *)action;
181     args[3] = NULL;
182     execv(net_if_script, args);
183     exit(1);
184     }
185     int status;
186     while (waitpid(pid, &status, 0) != pid);
187     return WIFEXITED(status) && WEXITSTATUS(status) == 0;
188     }
189    
190     return false;
191     }
192    
193    
194     /*
195 cebix 1.1 * Initialization
196     */
197    
198 cebix 1.2 bool ether_init(void)
199 cebix 1.1 {
200     int nonblock = 1;
201     char str[256];
202    
203     // Do nothing if no Ethernet device specified
204     const char *name = PrefsFindString("ether");
205     if (name == NULL)
206 cebix 1.2 return false;
207 cebix 1.1
208 gbeauche 1.9 // Determine Ethernet device type
209     net_if_type = -1;
210     if (strncmp(name, "tap", 3) == 0)
211     net_if_type = NET_IF_ETHERTAP;
212     #if ENABLE_TUNTAP
213     else if (strcmp(name, "tun") == 0)
214     net_if_type = NET_IF_TUNTAP;
215     #endif
216 gbeauche 1.15 #ifdef HAVE_SLIRP
217     else if (strcmp(name, "slirp") == 0)
218     net_if_type = NET_IF_SLIRP;
219     #endif
220 gbeauche 1.9 else
221     net_if_type = NET_IF_SHEEPNET;
222 cebix 1.1
223 gbeauche 1.15 #ifdef HAVE_SLIRP
224     // Initialize slirp library
225     if (net_if_type == NET_IF_SLIRP) {
226     slirp_init();
227    
228     // Open slirp output pipe
229     int fds[2];
230     if (pipe(fds) < 0)
231     return false;
232     fd = fds[0];
233     slirp_output_fd = fds[1];
234     }
235     #endif
236    
237 gbeauche 1.11 // Open sheep_net or ethertap or TUN/TAP device
238 cebix 1.1 char dev_name[16];
239 gbeauche 1.9 switch (net_if_type) {
240     case NET_IF_ETHERTAP:
241 cebix 1.1 sprintf(dev_name, "/dev/%s", name);
242 gbeauche 1.9 break;
243     case NET_IF_TUNTAP:
244 gbeauche 1.11 strcpy(dev_name, "/dev/net/tun");
245 gbeauche 1.9 break;
246     case NET_IF_SHEEPNET:
247 cebix 1.1 strcpy(dev_name, "/dev/sheep_net");
248 gbeauche 1.9 break;
249     }
250 gbeauche 1.15 if (net_if_type != NET_IF_SLIRP) {
251     fd = open(dev_name, O_RDWR);
252     if (fd < 0) {
253     sprintf(str, GetString(STR_NO_SHEEP_NET_DRIVER_WARN), dev_name, strerror(errno));
254     WarningAlert(str);
255     goto open_error;
256     }
257 cebix 1.1 }
258    
259 gbeauche 1.9 #if ENABLE_TUNTAP
260     // Open TUN/TAP interface
261     if (net_if_type == NET_IF_TUNTAP) {
262     struct ifreq ifr;
263     memset(&ifr, 0, sizeof(ifr));
264     ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
265     strcpy(ifr.ifr_name, "tun%d");
266     if (ioctl(fd, TUNSETIFF, (void *) &ifr) != 0) {
267     sprintf(str, GetString(STR_SHEEP_NET_ATTACH_WARN), strerror(errno));
268     WarningAlert(str);
269     goto open_error;
270     }
271    
272     // Get network config script file path
273     net_if_script = PrefsFindString("etherconfig");
274     if (net_if_script == NULL)
275     net_if_script = ETHERCONFIG_FILE_NAME;
276    
277     // Start network script up
278     if (net_if_script == NULL) {
279     sprintf(str, GetString(STR_TUN_TAP_CONFIG_WARN), "script not found");
280     WarningAlert(str);
281     goto open_error;
282     }
283 gbeauche 1.10 net_if_name = strdup(ifr.ifr_name);
284 gbeauche 1.9 if (!execute_network_script("up")) {
285     sprintf(str, GetString(STR_TUN_TAP_CONFIG_WARN), "script execute error");
286     WarningAlert(str);
287     goto open_error;
288     }
289     D(bug("Connected to host network interface: %s\n", net_if_name));
290     }
291     #endif
292    
293 cebix 1.1 #if defined(__linux__)
294     // Attach sheep_net to selected Ethernet card
295 gbeauche 1.9 if (net_if_type == NET_IF_SHEEPNET && ioctl(fd, SIOCSIFLINK, name) < 0) {
296 cebix 1.1 sprintf(str, GetString(STR_SHEEP_NET_ATTACH_WARN), strerror(errno));
297     WarningAlert(str);
298     goto open_error;
299     }
300     #endif
301    
302     // Set nonblocking I/O
303     ioctl(fd, FIONBIO, &nonblock);
304    
305     // Get Ethernet address
306 gbeauche 1.9 if (net_if_type == NET_IF_ETHERTAP) {
307 cebix 1.1 pid_t p = getpid(); // If configured for multicast, ethertap requires that the lower 32 bit of the Ethernet address are our PID
308     ether_addr[0] = 0xfe;
309     ether_addr[1] = 0xfd;
310     ether_addr[2] = p >> 24;
311     ether_addr[3] = p >> 16;
312     ether_addr[4] = p >> 8;
313     ether_addr[5] = p;
314 gbeauche 1.15 #ifdef HAVE_SLIRP
315     } else if (net_if_type == NET_IF_SLIRP) {
316     ether_addr[0] = 0x52;
317     ether_addr[1] = 0x54;
318     ether_addr[2] = 0x00;
319     ether_addr[3] = 0x12;
320     ether_addr[4] = 0x34;
321     ether_addr[5] = 0x56;
322     #endif
323 cebix 1.1 } else
324     ioctl(fd, SIOCGIFADDR, ether_addr);
325     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]));
326    
327     // Start packet reception thread
328 cebix 1.2 if (!start_thread())
329 cebix 1.1 goto open_error;
330    
331     // Everything OK
332 cebix 1.2 return true;
333 cebix 1.1
334     open_error:
335 cebix 1.2 stop_thread();
336    
337 cebix 1.1 if (fd > 0) {
338     close(fd);
339     fd = -1;
340     }
341 gbeauche 1.15 if (slirp_output_fd >= 0) {
342     close(slirp_output_fd);
343     slirp_output_fd = -1;
344     }
345 cebix 1.2 return false;
346 cebix 1.1 }
347    
348    
349     /*
350     * Deinitialization
351     */
352    
353 cebix 1.2 void ether_exit(void)
354 cebix 1.1 {
355 gbeauche 1.20 // Stop reception threads
356     stop_thread();
357 cebix 1.1
358 gbeauche 1.10 // Shut down TUN/TAP interface
359     if (net_if_type == NET_IF_TUNTAP)
360     execute_network_script("down");
361    
362     // Free TUN/TAP device name
363     if (net_if_name)
364     free(net_if_name);
365    
366 cebix 1.1 // Close sheep_net device
367     if (fd > 0)
368     close(fd);
369 gbeauche 1.15
370     // Close slirp output buffer
371     if (slirp_output_fd > 0)
372     close(slirp_output_fd);
373 cebix 1.1 }
374    
375    
376     /*
377     * Reset
378     */
379    
380 cebix 1.3 void ether_reset(void)
381 cebix 1.1 {
382 cebix 1.3 net_protocols.clear();
383 cebix 1.1 }
384    
385    
386     /*
387     * Add multicast address
388     */
389    
390     int16 ether_add_multicast(uint32 pb)
391     {
392 gbeauche 1.15 switch (net_if_type) {
393     case NET_IF_ETHERTAP:
394     case NET_IF_SHEEPNET:
395     if (ioctl(fd, SIOCADDMULTI, Mac2HostAddr(pb + eMultiAddr)) < 0) {
396     D(bug("WARNING: Couldn't enable multicast address\n"));
397     if (net_if_type == NET_IF_ETHERTAP)
398     return noErr;
399     else
400     return eMultiErr;
401     }
402     default:
403 cebix 1.1 return noErr;
404 gbeauche 1.15 }
405 cebix 1.1 }
406    
407    
408     /*
409     * Delete multicast address
410     */
411    
412     int16 ether_del_multicast(uint32 pb)
413     {
414 gbeauche 1.15 switch (net_if_type) {
415     case NET_IF_ETHERTAP:
416     case NET_IF_SHEEPNET:
417     if (ioctl(fd, SIOCDELMULTI, Mac2HostAddr(pb + eMultiAddr)) < 0) {
418     D(bug("WARNING: Couldn't disable multicast address\n"));
419     return eMultiErr;
420     }
421     default:
422 cebix 1.1 return noErr;
423 gbeauche 1.15 }
424 cebix 1.1 }
425    
426    
427     /*
428     * Attach protocol handler
429     */
430    
431     int16 ether_attach_ph(uint16 type, uint32 handler)
432     {
433 cebix 1.3 if (net_protocols.find(type) != net_protocols.end())
434 cebix 1.1 return lapProtErr;
435 cebix 1.3 net_protocols[type] = handler;
436     return noErr;
437 cebix 1.1 }
438    
439    
440     /*
441     * Detach protocol handler
442     */
443    
444     int16 ether_detach_ph(uint16 type)
445     {
446 cebix 1.3 if (net_protocols.erase(type) == 0)
447 cebix 1.1 return lapProtErr;
448 cebix 1.3 return noErr;
449 cebix 1.1 }
450    
451    
452     /*
453     * Transmit raw ethernet packet
454     */
455    
456     int16 ether_write(uint32 wds)
457     {
458     // Copy packet to buffer
459     uint8 packet[1516], *p = packet;
460     int len = 0;
461     #if defined(__linux__)
462 gbeauche 1.9 if (net_if_type == NET_IF_ETHERTAP) {
463 cebix 1.1 *p++ = 0; // Linux ethertap discards the first 2 bytes
464     *p++ = 0;
465     len += 2;
466     }
467     #endif
468 cebix 1.2 len += ether_wds_to_buffer(wds, p);
469 cebix 1.1
470     #if MONITOR
471     bug("Sending Ethernet packet:\n");
472     for (int i=0; i<len; i++) {
473     bug("%02x ", packet[i]);
474     }
475     bug("\n");
476     #endif
477    
478     // Transmit packet
479 gbeauche 1.15 #ifdef HAVE_SLIRP
480     if (net_if_type == NET_IF_SLIRP) {
481     slirp_input(packet, len);
482     return noErr;
483     } else
484     #endif
485 cebix 1.1 if (write(fd, packet, len) < 0) {
486     D(bug("WARNING: Couldn't transmit packet\n"));
487     return excessCollsns;
488     } else
489     return noErr;
490     }
491    
492    
493     /*
494 cebix 1.2 * Start UDP packet reception thread
495     */
496    
497     bool ether_start_udp_thread(int socket_fd)
498     {
499     fd = socket_fd;
500     udp_tunnel = true;
501     return start_thread();
502     }
503    
504    
505     /*
506     * Stop UDP packet reception thread
507     */
508    
509     void ether_stop_udp_thread(void)
510     {
511     stop_thread();
512     fd = -1;
513     }
514    
515    
516     /*
517 gbeauche 1.15 * SLIRP output buffer glue
518     */
519    
520     #ifdef HAVE_SLIRP
521     int slirp_can_output(void)
522     {
523     return 1;
524     }
525    
526     void slirp_output(const uint8 *packet, int len)
527     {
528     write(slirp_output_fd, packet, len);
529     }
530    
531     void *slirp_receive_func(void *arg)
532     {
533     for (;;) {
534     // Wait for packets to arrive
535     fd_set rfds, wfds, xfds;
536     int nfds;
537     struct timeval tv;
538    
539     nfds = -1;
540     FD_ZERO(&rfds);
541     FD_ZERO(&wfds);
542     FD_ZERO(&xfds);
543     slirp_select_fill(&nfds, &rfds, &wfds, &xfds);
544     tv.tv_sec = 0;
545     tv.tv_usec = 16667;
546     if (select(nfds + 1, &rfds, &wfds, &xfds, &tv) >= 0)
547     slirp_select_poll(&rfds, &wfds, &xfds);
548 gbeauche 1.20
549     #ifdef HAVE_PTHREAD_TESTCANCEL
550     // Explicit cancellation point if select() was not covered
551     // This seems to be the case on MacOS X 10.2
552     pthread_testcancel();
553     #endif
554 gbeauche 1.15 }
555     return NULL;
556     }
557     #else
558     int slirp_can_output(void)
559     {
560     return 0;
561     }
562    
563     void slirp_output(const uint8 *packet, int len)
564     {
565     }
566     #endif
567    
568    
569     /*
570 cebix 1.1 * Packet reception thread
571     */
572    
573     static void *receive_func(void *arg)
574     {
575     for (;;) {
576    
577     // Wait for packets to arrive
578 gbeauche 1.20 #if HAVE_POLL
579     struct pollfd pf = {fd, POLLIN, 0};
580     int res = poll(&pf, 1, -1);
581     #else
582     fd_set rfds;
583     FD_ZERO(&rfds);
584     FD_SET(fd, &rfds);
585     // A NULL timeout could cause select() to block indefinitely,
586     // even if it is supposed to be a cancellation point [MacOS X]
587     struct timeval tv = { 0, 20000 };
588     int res = select(fd + 1, &rfds, NULL, NULL, &tv);
589     #ifdef HAVE_PTHREAD_TESTCANCEL
590     pthread_testcancel();
591     #endif
592     if (res == 0 || (res == -1 && errno == EINTR))
593     continue;
594     #endif
595 cebix 1.1 if (res <= 0)
596     break;
597    
598     // Trigger Ethernet interrupt
599     D(bug(" packet received, triggering Ethernet interrupt\n"));
600     SetInterruptFlag(INTFLAG_ETHER);
601     TriggerInterrupt();
602    
603     // Wait for interrupt acknowledge by EtherInterrupt()
604     sem_wait(&int_ack);
605     }
606     return NULL;
607     }
608    
609    
610     /*
611     * Ethernet interrupt - activate deferred tasks to call IODone or protocol handlers
612     */
613    
614     void EtherInterrupt(void)
615     {
616     D(bug("EtherIRQ\n"));
617    
618     // Call protocol handler for received packets
619 gbeauche 1.14 EthernetPacket ether_packet;
620     uint32 packet = ether_packet.addr();
621 cebix 1.2 ssize_t length;
622 cebix 1.1 for (;;) {
623    
624 cebix 1.2 if (udp_tunnel) {
625    
626     // Read packet from socket
627     struct sockaddr_in from;
628     socklen_t from_len = sizeof(from);
629 gbeauche 1.14 length = recvfrom(fd, Mac2HostAddr(packet), 1514, 0, (struct sockaddr *)&from, &from_len);
630 cebix 1.2 if (length < 14)
631     break;
632     ether_udp_read(packet, length, &from);
633    
634     } else {
635    
636     // Read packet from sheep_net device
637 cebix 1.1 #if defined(__linux__)
638 gbeauche 1.14 length = read(fd, Mac2HostAddr(packet), net_if_type == NET_IF_ETHERTAP ? 1516 : 1514);
639 cebix 1.1 #else
640 gbeauche 1.14 length = read(fd, Mac2HostAddr(packet), 1514);
641 cebix 1.1 #endif
642 cebix 1.2 if (length < 14)
643     break;
644 cebix 1.1
645     #if MONITOR
646 cebix 1.2 bug("Receiving Ethernet packet:\n");
647     for (int i=0; i<length; i++) {
648 gbeauche 1.14 bug("%02x ", ReadMacInt8(packet + i));
649 cebix 1.2 }
650     bug("\n");
651 cebix 1.1 #endif
652    
653 cebix 1.2 // Pointer to packet data (Ethernet header)
654 gbeauche 1.14 uint32 p = packet;
655 cebix 1.1 #if defined(__linux__)
656 gbeauche 1.9 if (net_if_type == NET_IF_ETHERTAP) {
657 cebix 1.2 p += 2; // Linux ethertap has two random bytes before the packet
658     length -= 2;
659     }
660 cebix 1.1 #endif
661    
662 cebix 1.2 // Get packet type
663 gbeauche 1.14 uint16 type = ReadMacInt16(p + 12);
664 cebix 1.1
665 cebix 1.2 // Look for protocol
666 cebix 1.3 uint16 search_type = (type <= 1500 ? 0 : type);
667     if (net_protocols.find(search_type) == net_protocols.end())
668 cebix 1.2 continue;
669 cebix 1.3 uint32 handler = net_protocols[search_type];
670 cebix 1.2
671     // No default handler
672 cebix 1.3 if (handler == 0)
673 cebix 1.2 continue;
674    
675     // Copy header to RHA
676 gbeauche 1.14 Mac2Mac_memcpy(ether_data + ed_RHA, p, 14);
677 cebix 1.2 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)));
678    
679     // Call protocol handler
680     M68kRegisters r;
681     r.d[0] = type; // Packet type
682     r.d[1] = length - 14; // Remaining packet length (without header, for ReadPacket)
683 gbeauche 1.14 r.a[0] = p + 14; // Pointer to packet (Mac address, for ReadPacket)
684 cebix 1.2 r.a[3] = ether_data + ed_RHA + 14; // Pointer behind header in RHA
685     r.a[4] = ether_data + ed_ReadPacket; // Pointer to ReadPacket/ReadRest routines
686 cebix 1.3 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]));
687     Execute68k(handler, &r);
688 cebix 1.2 }
689 cebix 1.1 }
690    
691     // Acknowledge interrupt to reception thread
692     D(bug(" EtherIRQ done\n"));
693     sem_post(&int_ack);
694     }