ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/ether_unix.cpp
Revision: 1.22
Committed: 2005-06-12T22:48:48Z (19 years, 3 months ago) by gbeauche
Branch: MAIN
Changes since 1.21: +5 -1 lines
Log Message:
Enable Basilisk II to work even if slirp_init() failed. Disable ethernet
emulation in that case, don't exit(1).

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 gbeauche 1.21 static int slirp_input_fds[2] = { -1, -1 }; // fds of slirp input pipe
97 cebix 1.1
98 cebix 1.3 // Attached network protocols, maps protocol type to MacOS handler address
99     static map<uint16, uint32> net_protocols;
100    
101 cebix 1.1 // Prototypes
102     static void *receive_func(void *arg);
103 gbeauche 1.15 static void *slirp_receive_func(void *arg);
104 gbeauche 1.17 static int poll_fd(int fd);
105 cebix 1.1
106    
107     /*
108 cebix 1.2 * Start packet reception thread
109     */
110    
111     static bool start_thread(void)
112     {
113     if (sem_init(&int_ack, 0, 0) < 0) {
114     printf("WARNING: Cannot init semaphore");
115     return false;
116     }
117    
118 cebix 1.7 Set_pthread_attr(&ether_thread_attr, 1);
119 cebix 1.2 thread_active = (pthread_create(&ether_thread, &ether_thread_attr, receive_func, NULL) == 0);
120     if (!thread_active) {
121     printf("WARNING: Cannot start Ethernet thread");
122     return false;
123     }
124    
125 gbeauche 1.15 #ifdef HAVE_SLIRP
126     if (net_if_type == NET_IF_SLIRP) {
127     slirp_thread_active = (pthread_create(&slirp_thread, NULL, slirp_receive_func, NULL) == 0);
128     if (!slirp_thread_active) {
129     printf("WARNING: Cannot start slirp reception thread\n");
130     return false;
131     }
132     }
133     #endif
134    
135 cebix 1.2 return true;
136     }
137    
138    
139     /*
140     * Stop packet reception thread
141     */
142    
143     static void stop_thread(void)
144     {
145 gbeauche 1.15 #ifdef HAVE_SLIRP
146     if (slirp_thread_active) {
147 gbeauche 1.20 #ifdef HAVE_PTHREAD_CANCEL
148 gbeauche 1.15 pthread_cancel(slirp_thread);
149 gbeauche 1.20 #endif
150 gbeauche 1.15 pthread_join(slirp_thread, NULL);
151     slirp_thread_active = false;
152     }
153     #endif
154    
155 cebix 1.2 if (thread_active) {
156 gbeauche 1.20 #ifdef HAVE_PTHREAD_CANCEL
157 cebix 1.2 pthread_cancel(ether_thread);
158 gbeauche 1.20 #endif
159 cebix 1.2 pthread_join(ether_thread, NULL);
160     sem_destroy(&int_ack);
161     thread_active = false;
162     }
163     }
164    
165    
166     /*
167 gbeauche 1.9 * Execute network script up|down
168     */
169    
170     static bool execute_network_script(const char *action)
171     {
172     if (net_if_script == NULL || net_if_name == NULL)
173     return false;
174    
175     int pid = fork();
176     if (pid >= 0) {
177     if (pid == 0) {
178     char *args[4];
179     args[0] = (char *)net_if_script;
180 gbeauche 1.10 args[1] = net_if_name;
181 gbeauche 1.9 args[2] = (char *)action;
182     args[3] = NULL;
183     execv(net_if_script, args);
184     exit(1);
185     }
186     int status;
187     while (waitpid(pid, &status, 0) != pid);
188     return WIFEXITED(status) && WEXITSTATUS(status) == 0;
189     }
190    
191     return false;
192     }
193    
194    
195     /*
196 cebix 1.1 * Initialization
197     */
198    
199 cebix 1.2 bool ether_init(void)
200 cebix 1.1 {
201     int nonblock = 1;
202     char str[256];
203    
204     // Do nothing if no Ethernet device specified
205     const char *name = PrefsFindString("ether");
206     if (name == NULL)
207 cebix 1.2 return false;
208 cebix 1.1
209 gbeauche 1.9 // Determine Ethernet device type
210     net_if_type = -1;
211     if (strncmp(name, "tap", 3) == 0)
212     net_if_type = NET_IF_ETHERTAP;
213     #if ENABLE_TUNTAP
214     else if (strcmp(name, "tun") == 0)
215     net_if_type = NET_IF_TUNTAP;
216     #endif
217 gbeauche 1.15 #ifdef HAVE_SLIRP
218     else if (strcmp(name, "slirp") == 0)
219     net_if_type = NET_IF_SLIRP;
220     #endif
221 gbeauche 1.9 else
222     net_if_type = NET_IF_SHEEPNET;
223 cebix 1.1
224 gbeauche 1.15 #ifdef HAVE_SLIRP
225     // Initialize slirp library
226     if (net_if_type == NET_IF_SLIRP) {
227 gbeauche 1.22 if (slirp_init() < 0) {
228     sprintf(str, GetString(STR_SLIRP_NO_DNS_FOUND_WARN));
229     WarningAlert(str);
230     return false;
231     }
232 gbeauche 1.15
233     // Open slirp output pipe
234     int fds[2];
235     if (pipe(fds) < 0)
236     return false;
237     fd = fds[0];
238     slirp_output_fd = fds[1];
239 gbeauche 1.21
240     // Open slirp input pipe
241     if (pipe(slirp_input_fds) < 0)
242     return false;
243 gbeauche 1.15 }
244     #endif
245    
246 gbeauche 1.11 // Open sheep_net or ethertap or TUN/TAP device
247 cebix 1.1 char dev_name[16];
248 gbeauche 1.9 switch (net_if_type) {
249     case NET_IF_ETHERTAP:
250 cebix 1.1 sprintf(dev_name, "/dev/%s", name);
251 gbeauche 1.9 break;
252     case NET_IF_TUNTAP:
253 gbeauche 1.11 strcpy(dev_name, "/dev/net/tun");
254 gbeauche 1.9 break;
255     case NET_IF_SHEEPNET:
256 cebix 1.1 strcpy(dev_name, "/dev/sheep_net");
257 gbeauche 1.9 break;
258     }
259 gbeauche 1.15 if (net_if_type != NET_IF_SLIRP) {
260     fd = open(dev_name, O_RDWR);
261     if (fd < 0) {
262     sprintf(str, GetString(STR_NO_SHEEP_NET_DRIVER_WARN), dev_name, strerror(errno));
263     WarningAlert(str);
264     goto open_error;
265     }
266 cebix 1.1 }
267    
268 gbeauche 1.9 #if ENABLE_TUNTAP
269     // Open TUN/TAP interface
270     if (net_if_type == NET_IF_TUNTAP) {
271     struct ifreq ifr;
272     memset(&ifr, 0, sizeof(ifr));
273     ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
274     strcpy(ifr.ifr_name, "tun%d");
275     if (ioctl(fd, TUNSETIFF, (void *) &ifr) != 0) {
276     sprintf(str, GetString(STR_SHEEP_NET_ATTACH_WARN), strerror(errno));
277     WarningAlert(str);
278     goto open_error;
279     }
280    
281     // Get network config script file path
282     net_if_script = PrefsFindString("etherconfig");
283     if (net_if_script == NULL)
284     net_if_script = ETHERCONFIG_FILE_NAME;
285    
286     // Start network script up
287     if (net_if_script == NULL) {
288     sprintf(str, GetString(STR_TUN_TAP_CONFIG_WARN), "script not found");
289     WarningAlert(str);
290     goto open_error;
291     }
292 gbeauche 1.10 net_if_name = strdup(ifr.ifr_name);
293 gbeauche 1.9 if (!execute_network_script("up")) {
294     sprintf(str, GetString(STR_TUN_TAP_CONFIG_WARN), "script execute error");
295     WarningAlert(str);
296     goto open_error;
297     }
298     D(bug("Connected to host network interface: %s\n", net_if_name));
299     }
300     #endif
301    
302 cebix 1.1 #if defined(__linux__)
303     // Attach sheep_net to selected Ethernet card
304 gbeauche 1.9 if (net_if_type == NET_IF_SHEEPNET && ioctl(fd, SIOCSIFLINK, name) < 0) {
305 cebix 1.1 sprintf(str, GetString(STR_SHEEP_NET_ATTACH_WARN), strerror(errno));
306     WarningAlert(str);
307     goto open_error;
308     }
309     #endif
310    
311     // Set nonblocking I/O
312     ioctl(fd, FIONBIO, &nonblock);
313    
314     // Get Ethernet address
315 gbeauche 1.9 if (net_if_type == NET_IF_ETHERTAP) {
316 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
317     ether_addr[0] = 0xfe;
318     ether_addr[1] = 0xfd;
319     ether_addr[2] = p >> 24;
320     ether_addr[3] = p >> 16;
321     ether_addr[4] = p >> 8;
322     ether_addr[5] = p;
323 gbeauche 1.15 #ifdef HAVE_SLIRP
324     } else if (net_if_type == NET_IF_SLIRP) {
325     ether_addr[0] = 0x52;
326     ether_addr[1] = 0x54;
327     ether_addr[2] = 0x00;
328     ether_addr[3] = 0x12;
329     ether_addr[4] = 0x34;
330     ether_addr[5] = 0x56;
331     #endif
332 cebix 1.1 } else
333     ioctl(fd, SIOCGIFADDR, ether_addr);
334     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]));
335    
336     // Start packet reception thread
337 cebix 1.2 if (!start_thread())
338 cebix 1.1 goto open_error;
339    
340     // Everything OK
341 cebix 1.2 return true;
342 cebix 1.1
343     open_error:
344 cebix 1.2 stop_thread();
345    
346 cebix 1.1 if (fd > 0) {
347     close(fd);
348     fd = -1;
349     }
350 gbeauche 1.21 if (slirp_input_fds[0] >= 0) {
351     close(slirp_input_fds[0]);
352     slirp_input_fds[0] = -1;
353     }
354     if (slirp_input_fds[1] >= 0) {
355     close(slirp_input_fds[1]);
356     slirp_input_fds[1] = -1;
357     }
358 gbeauche 1.15 if (slirp_output_fd >= 0) {
359     close(slirp_output_fd);
360     slirp_output_fd = -1;
361     }
362 cebix 1.2 return false;
363 cebix 1.1 }
364    
365    
366     /*
367     * Deinitialization
368     */
369    
370 cebix 1.2 void ether_exit(void)
371 cebix 1.1 {
372 gbeauche 1.20 // Stop reception threads
373     stop_thread();
374 cebix 1.1
375 gbeauche 1.10 // Shut down TUN/TAP interface
376     if (net_if_type == NET_IF_TUNTAP)
377     execute_network_script("down");
378    
379     // Free TUN/TAP device name
380     if (net_if_name)
381     free(net_if_name);
382    
383 cebix 1.1 // Close sheep_net device
384     if (fd > 0)
385     close(fd);
386 gbeauche 1.15
387 gbeauche 1.21 // Close slirp input buffer
388     if (slirp_input_fds[0] >= 0)
389     close(slirp_input_fds[0]);
390     if (slirp_input_fds[1] >= 0)
391     close(slirp_input_fds[1]);
392    
393 gbeauche 1.15 // Close slirp output buffer
394     if (slirp_output_fd > 0)
395     close(slirp_output_fd);
396 cebix 1.1 }
397    
398    
399     /*
400     * Reset
401     */
402    
403 cebix 1.3 void ether_reset(void)
404 cebix 1.1 {
405 cebix 1.3 net_protocols.clear();
406 cebix 1.1 }
407    
408    
409     /*
410     * Add multicast address
411     */
412    
413     int16 ether_add_multicast(uint32 pb)
414     {
415 gbeauche 1.15 switch (net_if_type) {
416     case NET_IF_ETHERTAP:
417     case NET_IF_SHEEPNET:
418     if (ioctl(fd, SIOCADDMULTI, Mac2HostAddr(pb + eMultiAddr)) < 0) {
419     D(bug("WARNING: Couldn't enable multicast address\n"));
420     if (net_if_type == NET_IF_ETHERTAP)
421     return noErr;
422     else
423     return eMultiErr;
424     }
425     default:
426 cebix 1.1 return noErr;
427 gbeauche 1.15 }
428 cebix 1.1 }
429    
430    
431     /*
432     * Delete multicast address
433     */
434    
435     int16 ether_del_multicast(uint32 pb)
436     {
437 gbeauche 1.15 switch (net_if_type) {
438     case NET_IF_ETHERTAP:
439     case NET_IF_SHEEPNET:
440     if (ioctl(fd, SIOCDELMULTI, Mac2HostAddr(pb + eMultiAddr)) < 0) {
441     D(bug("WARNING: Couldn't disable multicast address\n"));
442     return eMultiErr;
443     }
444     default:
445 cebix 1.1 return noErr;
446 gbeauche 1.15 }
447 cebix 1.1 }
448    
449    
450     /*
451     * Attach protocol handler
452     */
453    
454     int16 ether_attach_ph(uint16 type, uint32 handler)
455     {
456 cebix 1.3 if (net_protocols.find(type) != net_protocols.end())
457 cebix 1.1 return lapProtErr;
458 cebix 1.3 net_protocols[type] = handler;
459     return noErr;
460 cebix 1.1 }
461    
462    
463     /*
464     * Detach protocol handler
465     */
466    
467     int16 ether_detach_ph(uint16 type)
468     {
469 cebix 1.3 if (net_protocols.erase(type) == 0)
470 cebix 1.1 return lapProtErr;
471 cebix 1.3 return noErr;
472 cebix 1.1 }
473    
474    
475     /*
476     * Transmit raw ethernet packet
477     */
478    
479     int16 ether_write(uint32 wds)
480     {
481     // Copy packet to buffer
482     uint8 packet[1516], *p = packet;
483     int len = 0;
484     #if defined(__linux__)
485 gbeauche 1.9 if (net_if_type == NET_IF_ETHERTAP) {
486 cebix 1.1 *p++ = 0; // Linux ethertap discards the first 2 bytes
487     *p++ = 0;
488     len += 2;
489     }
490     #endif
491 cebix 1.2 len += ether_wds_to_buffer(wds, p);
492 cebix 1.1
493     #if MONITOR
494     bug("Sending Ethernet packet:\n");
495     for (int i=0; i<len; i++) {
496     bug("%02x ", packet[i]);
497     }
498     bug("\n");
499     #endif
500    
501     // Transmit packet
502 gbeauche 1.15 #ifdef HAVE_SLIRP
503     if (net_if_type == NET_IF_SLIRP) {
504 gbeauche 1.21 const int slirp_input_fd = slirp_input_fds[1];
505     write(slirp_input_fd, &len, sizeof(len));
506     write(slirp_input_fd, packet, len);
507 gbeauche 1.15 return noErr;
508     } else
509     #endif
510 cebix 1.1 if (write(fd, packet, len) < 0) {
511     D(bug("WARNING: Couldn't transmit packet\n"));
512     return excessCollsns;
513     } else
514     return noErr;
515     }
516    
517    
518     /*
519 cebix 1.2 * Start UDP packet reception thread
520     */
521    
522     bool ether_start_udp_thread(int socket_fd)
523     {
524     fd = socket_fd;
525     udp_tunnel = true;
526     return start_thread();
527     }
528    
529    
530     /*
531     * Stop UDP packet reception thread
532     */
533    
534     void ether_stop_udp_thread(void)
535     {
536     stop_thread();
537     fd = -1;
538     }
539    
540    
541     /*
542 gbeauche 1.15 * SLIRP output buffer glue
543     */
544    
545     #ifdef HAVE_SLIRP
546     int slirp_can_output(void)
547     {
548     return 1;
549     }
550    
551     void slirp_output(const uint8 *packet, int len)
552     {
553     write(slirp_output_fd, packet, len);
554     }
555    
556     void *slirp_receive_func(void *arg)
557     {
558 gbeauche 1.21 const int slirp_input_fd = slirp_input_fds[0];
559    
560 gbeauche 1.15 for (;;) {
561     // Wait for packets to arrive
562     fd_set rfds, wfds, xfds;
563     int nfds;
564     struct timeval tv;
565    
566 gbeauche 1.21 // ... in the input queue
567     FD_ZERO(&rfds);
568     FD_SET(slirp_input_fd, &rfds);
569     tv.tv_sec = 0;
570     tv.tv_usec = 0;
571     if (select(slirp_input_fd + 1, &rfds, NULL, NULL, &tv) > 0) {
572     int len;
573     read(slirp_input_fd, &len, sizeof(len));
574     uint8 packet[1516];
575     assert(len <= sizeof(packet));
576     read(slirp_input_fd, packet, len);
577     slirp_input(packet, len);
578     }
579    
580     // ... in the output queue
581 gbeauche 1.15 nfds = -1;
582     FD_ZERO(&rfds);
583     FD_ZERO(&wfds);
584     FD_ZERO(&xfds);
585     slirp_select_fill(&nfds, &rfds, &wfds, &xfds);
586     tv.tv_sec = 0;
587 gbeauche 1.21 tv.tv_usec = 10000;
588 gbeauche 1.15 if (select(nfds + 1, &rfds, &wfds, &xfds, &tv) >= 0)
589     slirp_select_poll(&rfds, &wfds, &xfds);
590 gbeauche 1.20
591     #ifdef HAVE_PTHREAD_TESTCANCEL
592     // Explicit cancellation point if select() was not covered
593     // This seems to be the case on MacOS X 10.2
594     pthread_testcancel();
595     #endif
596 gbeauche 1.15 }
597     return NULL;
598     }
599     #else
600     int slirp_can_output(void)
601     {
602     return 0;
603     }
604    
605     void slirp_output(const uint8 *packet, int len)
606     {
607     }
608     #endif
609    
610    
611     /*
612 cebix 1.1 * Packet reception thread
613     */
614    
615     static void *receive_func(void *arg)
616     {
617     for (;;) {
618    
619     // Wait for packets to arrive
620 gbeauche 1.20 #if HAVE_POLL
621     struct pollfd pf = {fd, POLLIN, 0};
622     int res = poll(&pf, 1, -1);
623     #else
624     fd_set rfds;
625     FD_ZERO(&rfds);
626     FD_SET(fd, &rfds);
627     // A NULL timeout could cause select() to block indefinitely,
628     // even if it is supposed to be a cancellation point [MacOS X]
629     struct timeval tv = { 0, 20000 };
630     int res = select(fd + 1, &rfds, NULL, NULL, &tv);
631     #ifdef HAVE_PTHREAD_TESTCANCEL
632     pthread_testcancel();
633     #endif
634     if (res == 0 || (res == -1 && errno == EINTR))
635     continue;
636     #endif
637 cebix 1.1 if (res <= 0)
638     break;
639    
640     // Trigger Ethernet interrupt
641     D(bug(" packet received, triggering Ethernet interrupt\n"));
642     SetInterruptFlag(INTFLAG_ETHER);
643     TriggerInterrupt();
644    
645     // Wait for interrupt acknowledge by EtherInterrupt()
646     sem_wait(&int_ack);
647     }
648     return NULL;
649     }
650    
651    
652     /*
653     * Ethernet interrupt - activate deferred tasks to call IODone or protocol handlers
654     */
655    
656     void EtherInterrupt(void)
657     {
658     D(bug("EtherIRQ\n"));
659    
660     // Call protocol handler for received packets
661 gbeauche 1.14 EthernetPacket ether_packet;
662     uint32 packet = ether_packet.addr();
663 cebix 1.2 ssize_t length;
664 cebix 1.1 for (;;) {
665    
666 cebix 1.2 if (udp_tunnel) {
667    
668     // Read packet from socket
669     struct sockaddr_in from;
670     socklen_t from_len = sizeof(from);
671 gbeauche 1.14 length = recvfrom(fd, Mac2HostAddr(packet), 1514, 0, (struct sockaddr *)&from, &from_len);
672 cebix 1.2 if (length < 14)
673     break;
674     ether_udp_read(packet, length, &from);
675    
676     } else {
677    
678     // Read packet from sheep_net device
679 cebix 1.1 #if defined(__linux__)
680 gbeauche 1.14 length = read(fd, Mac2HostAddr(packet), net_if_type == NET_IF_ETHERTAP ? 1516 : 1514);
681 cebix 1.1 #else
682 gbeauche 1.14 length = read(fd, Mac2HostAddr(packet), 1514);
683 cebix 1.1 #endif
684 cebix 1.2 if (length < 14)
685     break;
686 cebix 1.1
687     #if MONITOR
688 cebix 1.2 bug("Receiving Ethernet packet:\n");
689     for (int i=0; i<length; i++) {
690 gbeauche 1.14 bug("%02x ", ReadMacInt8(packet + i));
691 cebix 1.2 }
692     bug("\n");
693 cebix 1.1 #endif
694    
695 cebix 1.2 // Pointer to packet data (Ethernet header)
696 gbeauche 1.14 uint32 p = packet;
697 cebix 1.1 #if defined(__linux__)
698 gbeauche 1.9 if (net_if_type == NET_IF_ETHERTAP) {
699 cebix 1.2 p += 2; // Linux ethertap has two random bytes before the packet
700     length -= 2;
701     }
702 cebix 1.1 #endif
703    
704 cebix 1.2 // Get packet type
705 gbeauche 1.14 uint16 type = ReadMacInt16(p + 12);
706 cebix 1.1
707 cebix 1.2 // Look for protocol
708 cebix 1.3 uint16 search_type = (type <= 1500 ? 0 : type);
709     if (net_protocols.find(search_type) == net_protocols.end())
710 cebix 1.2 continue;
711 cebix 1.3 uint32 handler = net_protocols[search_type];
712 cebix 1.2
713     // No default handler
714 cebix 1.3 if (handler == 0)
715 cebix 1.2 continue;
716    
717     // Copy header to RHA
718 gbeauche 1.14 Mac2Mac_memcpy(ether_data + ed_RHA, p, 14);
719 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)));
720    
721     // Call protocol handler
722     M68kRegisters r;
723     r.d[0] = type; // Packet type
724     r.d[1] = length - 14; // Remaining packet length (without header, for ReadPacket)
725 gbeauche 1.14 r.a[0] = p + 14; // Pointer to packet (Mac address, for ReadPacket)
726 cebix 1.2 r.a[3] = ether_data + ed_RHA + 14; // Pointer behind header in RHA
727     r.a[4] = ether_data + ed_ReadPacket; // Pointer to ReadPacket/ReadRest routines
728 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]));
729     Execute68k(handler, &r);
730 cebix 1.2 }
731 cebix 1.1 }
732    
733     // Acknowledge interrupt to reception thread
734     D(bug(" EtherIRQ done\n"));
735     sem_post(&int_ack);
736     }