ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/AmigaOS/ether_amiga.cpp
Revision: 1.7
Committed: 2001-07-12T19:48:26Z (23 years, 4 months ago) by cebix
Branch: MAIN
Changes since 1.6: +6 -6 lines
Log Message:
- Implemented AppleTalk-over-UDP tunnelling, activated by setting "udptunnel"
  to "true". This uses the BSD socket API, so it's fairly portable (currently
  only imeplemented under Unix, though). This works by sending raw Ethernet
  packets as UDP packets to a fixed port number ("udpport", default is 6066),
  using IP broadcasts to simulate Ethernet broad- and multicasts. Currently
  only tested with AppleTalk.

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * ether_amiga.cpp - Ethernet device driver, AmigaOS specific stuff
3     *
4 cebix 1.6 * Basilisk II (C) 1997-2001 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 <exec/types.h>
22     #include <exec/memory.h>
23     #include <exec/errors.h>
24     #include <dos/dos.h>
25     #include <dos/dosextens.h>
26     #include <dos/dostags.h>
27     #include <devices/sana2.h>
28     #include <proto/exec.h>
29     #include <proto/dos.h>
30    
31     #include "sysdeps.h"
32     #include "cpu_emulation.h"
33     #include "main.h"
34     #include "prefs.h"
35     #include "user_strings.h"
36     #include "macos_util.h"
37     #include "ether.h"
38     #include "ether_defs.h"
39    
40     #define DEBUG 0
41     #include "debug.h"
42    
43     #define MONITOR 0
44    
45    
46     // These messages are sent to the network process
47     const uint32 MSG_CLEANUP = 'clea'; // Remove all protocols
48     const uint32 MSG_ADD_MULTI = 'addm'; // Add multicast address
49     const uint32 MSG_DEL_MULTI = 'delm'; // Add multicast address
50     const uint32 MSG_ATTACH_PH = 'atph'; // Attach protocol handler
51     const uint32 MSG_DETACH_PH = 'deph'; // Attach protocol handler
52     const uint32 MSG_WRITE = 'writ'; // Write packet
53    
54     struct NetMessage : public Message {
55     NetMessage(uint32 what_, const struct MsgPort *reply_port)
56     {
57     what = what_;
58     mn_ReplyPort = (struct MsgPort *)reply_port;
59     mn_Length = sizeof(*this);
60     }
61     uint32 what;
62     uint32 pointer;
63     uint16 type;
64     int16 result;
65     };
66    
67    
68     // List of attached protocols
69     static const int NUM_READ_REQUESTS = 32; // Number of read requests that are sent to device in advance
70    
71     struct NetProtocol : public Node {
72     struct IOSana2Req read_io[NUM_READ_REQUESTS];
73     uint8 read_buf[NUM_READ_REQUESTS][1518]; // 14 bytes header, 1500 bytes data, 4 bytes CRC
74     uint16 type;
75     uint32 handler;
76     };
77    
78     static struct List prot_list;
79    
80    
81     // Global variables
82     static struct Process *net_proc = NULL; // Network device handler process
83     static bool proc_error; // Flag: process didn't initialize
84     static struct MsgPort *proc_port = NULL; // Message port of process, for communication with main task
85     static struct MsgPort *reply_port = NULL; // Reply port for communication with process
86     static struct MsgPort *read_port = NULL; // Reply port for read IORequests (set up and owned by network process)
87    
88     static bool write_done = false; // Flag: write request done
89    
90     extern struct Task *MainTask; // Pointer to main task (from main_amiga.cpp)
91    
92    
93     // Prototypes
94     static void net_func(void);
95    
96    
97     /*
98     * Send message to network process
99     */
100    
101     static int16 send_to_proc(uint32 what, uint32 pointer = 0, uint16 type = 0)
102     {
103     D(bug("sending %08lx to net_proc\n", what));
104     NetMessage msg(what, reply_port);
105     msg.pointer = pointer;
106     msg.type = type;
107     PutMsg(proc_port, &msg);
108     WaitPort(reply_port);
109     GetMsg(reply_port);
110     D(bug(" sent\n"));
111     return msg.result;
112     }
113    
114    
115     /*
116     * Initialization
117     */
118    
119 cebix 1.7 bool ether_init(void)
120 cebix 1.1 {
121     // Do nothing if no Ethernet device specified
122     if (PrefsFindString("ether") == NULL)
123 cebix 1.7 return false;
124 cebix 1.1
125     // Initialize protocol list
126     NewList(&prot_list);
127    
128     // Create message port
129     reply_port = CreateMsgPort();
130     if (reply_port == NULL)
131     goto open_error;
132     D(bug("signal mask %08lx\n", 1 << reply_port->mp_SigBit));
133    
134     // Start process
135     proc_error = false;
136     SetSignal(0, SIGF_SINGLE);
137     net_proc = CreateNewProcTags(
138 cebix 1.2 NP_Entry, (ULONG)net_func,
139     NP_Name, (ULONG)"Basilisk II Ethernet Task",
140 cebix 1.1 NP_Priority, 1,
141     TAG_END
142     );
143     if (net_proc == NULL)
144     goto open_error;
145    
146     // Wait for signal from process
147     Wait(SIGF_SINGLE);
148    
149     // Initialization error? Then bail out
150     if (proc_error)
151     goto open_error;
152    
153     // Everything OK
154 cebix 1.7 return true;
155 cebix 1.1
156     open_error:
157     net_proc = NULL;
158     if (reply_port) {
159     DeleteMsgPort(reply_port);
160     reply_port = NULL;
161     }
162 cebix 1.7 return false;
163 cebix 1.1 }
164    
165    
166     /*
167     * Deinitialization
168     */
169    
170 cebix 1.7 void ether_exit(void)
171 cebix 1.1 {
172     // Stop process
173     if (net_proc) {
174     SetSignal(0, SIGF_SINGLE);
175     Signal(&net_proc->pr_Task, SIGBREAKF_CTRL_C);
176     Wait(SIGF_SINGLE);
177     }
178    
179     // Delete reply port
180     if (reply_port) {
181     DeleteMsgPort(reply_port);
182     reply_port = NULL;
183     }
184     }
185    
186    
187     /*
188     * Reset
189     */
190    
191     void EtherReset(void)
192     {
193     // Remove all protocols
194 cebix 1.7 if (net_proc)
195 cebix 1.1 send_to_proc(MSG_CLEANUP);
196     }
197    
198    
199     /*
200     * Add multicast address
201     */
202    
203     int16 ether_add_multicast(uint32 pb)
204     {
205     return send_to_proc(MSG_ADD_MULTI, pb);
206     }
207    
208    
209     /*
210     * Delete multicast address
211     */
212    
213     int16 ether_del_multicast(uint32 pb)
214     {
215     return send_to_proc(MSG_DEL_MULTI, pb);
216     }
217    
218    
219     /*
220     * Attach protocol handler
221     */
222    
223     int16 ether_attach_ph(uint16 type, uint32 handler)
224     {
225     return send_to_proc(MSG_ATTACH_PH, handler, type);
226     }
227    
228    
229     /*
230     * Detach protocol handler
231     */
232    
233     int16 ether_detach_ph(uint16 type)
234     {
235     return send_to_proc(MSG_DETACH_PH, type);
236     }
237    
238    
239     /*
240     * Transmit raw ethernet packet
241     */
242    
243     int16 ether_write(uint32 wds)
244     {
245     send_to_proc(MSG_WRITE, wds);
246     return 1; // Command in progress
247     }
248    
249    
250     /*
251     * Remove protocol from protocol list
252     */
253    
254     static void remove_protocol(NetProtocol *p)
255     {
256     // Remove from list
257     Forbid();
258     Remove(p);
259     Permit();
260    
261     // Cancel read requests
262     for (int i=0; i<NUM_READ_REQUESTS; i++) {
263     AbortIO((struct IORequest *)(p->read_io + i));
264     WaitIO((struct IORequest *)(p->read_io + i));
265     }
266    
267     // Free protocol struct
268     FreeMem(p, sizeof(NetProtocol));
269     }
270    
271    
272     /*
273     * Remove all protocols
274     */
275    
276     static void remove_all_protocols(void)
277     {
278     NetProtocol *n = (NetProtocol *)prot_list.lh_Head, *next;
279     while ((next = (NetProtocol *)n->ln_Succ) != NULL) {
280     remove_protocol(n);
281     n = next;
282     }
283     }
284    
285    
286     /*
287     * Copy received network packet to Mac side
288     */
289    
290 cebix 1.2 static __saveds __regargs LONG copy_to_buff(uint8 *to /*a0*/, uint8 *from /*a1*/, uint32 packet_len /*d0*/)
291 cebix 1.1 {
292     D(bug("CopyToBuff to %08lx, from %08lx, size %08lx\n", to, from, packet_len));
293    
294     // It would be more efficient (and take up less memory) if we
295     // could invoke the packet handler from here. But we don't know
296     // in what context we run, so calling Execute68k() would not be
297     // a good idea, and even worse, we might run inside a hardware
298     // interrupt, so we can't even trigger a Basilisk interrupt from
299     // here and wait for its completion.
300     CopyMem(from, to, packet_len);
301     #if MONITOR
302     bug("Receiving Ethernet packet:\n");
303     for (int i=0; i<packet_len; i++) {
304     bug("%02lx ", from[i]);
305     }
306     bug("\n");
307     #endif
308     return 1;
309     }
310    
311    
312     /*
313     * Copy data from Mac WDS to outgoing network packet
314     */
315    
316 cebix 1.2 static __saveds __regargs LONG copy_from_buff(uint8 *to /*a0*/, char *wds /*a1*/, uint32 packet_len /*d0*/)
317 cebix 1.1 {
318     D(bug("CopyFromBuff to %08lx, wds %08lx, size %08lx\n", to, wds, packet_len));
319     #if MONITOR
320     bug("Sending Ethernet packet:\n");
321     #endif
322     for (;;) {
323 cebix 1.2 int len = ReadMacInt16((uint32)wds);
324 cebix 1.1 if (len == 0)
325     break;
326     #if MONITOR
327 cebix 1.2 uint8 *adr = Mac2HostAddr(ReadMacInt32((uint32)wds + 2));
328 cebix 1.1 for (int i=0; i<len; i++) {
329     bug("%02lx ", adr[i]);
330     }
331     #endif
332 cebix 1.2 CopyMem(Mac2HostAddr(ReadMacInt32((uint32)wds + 2)), to, len);
333 cebix 1.1 to += len;
334     wds += 6;
335     }
336     #if MONITOR
337     bug("\n");
338     #endif
339     return 1;
340     }
341    
342    
343     /*
344     * Process for communication with the Ethernet device
345     */
346    
347     static __saveds void net_func(void)
348     {
349 jlachmann 1.5 const char *str;
350     BYTE od_error;
351 cebix 1.1 struct MsgPort *write_port = NULL, *control_port = NULL;
352     struct IOSana2Req *write_io = NULL, *control_io = NULL;
353     bool opened = false;
354     ULONG read_mask = 0, write_mask = 0, proc_port_mask = 0;
355     struct Sana2DeviceQuery query_data = {sizeof(Sana2DeviceQuery)};
356     ULONG buffer_tags[] = {
357     S2_CopyToBuff, (uint32)copy_to_buff,
358     S2_CopyFromBuff, (uint32)copy_from_buff,
359     TAG_END
360     };
361    
362     // Default: error occured
363     proc_error = true;
364    
365     // Create message port for communication with main task
366     proc_port = CreateMsgPort();
367     if (proc_port == NULL)
368     goto quit;
369     proc_port_mask = 1 << proc_port->mp_SigBit;
370    
371     // Create message ports for device I/O
372     read_port = CreateMsgPort();
373     if (read_port == NULL)
374     goto quit;
375     read_mask = 1 << read_port->mp_SigBit;
376     write_port = CreateMsgPort();
377     if (write_port == NULL)
378     goto quit;
379     write_mask = 1 << write_port->mp_SigBit;
380     control_port = CreateMsgPort();
381     if (control_port == NULL)
382     goto quit;
383    
384     // Create control IORequest
385     control_io = (struct IOSana2Req *)CreateIORequest(control_port, sizeof(struct IOSana2Req));
386     if (control_io == NULL)
387     goto quit;
388     control_io->ios2_Req.io_Message.mn_Node.ln_Type = 0; // Avoid CheckIO() bug
389    
390     // Parse device name
391     char dev_name[256];
392     ULONG dev_unit;
393 jlachmann 1.5
394     str = PrefsFindString("ether");
395     if (str)
396     {
397     const char *FirstSlash = strchr(str, '/');
398     const char *LastSlash = strrchr(str, '/');
399    
400     if (FirstSlash && FirstSlash && FirstSlash != LastSlash)
401     {
402     // Device name contains path, i.e. "Networks/xyzzy.device"
403     const char *lp = str;
404     char *dp = dev_name;
405    
406     while (lp != LastSlash)
407     *dp++ = *lp++;
408     *dp = '\0';
409    
410     if (strlen(dev_name) < 1)
411     goto quit;
412    
413     if (1 != sscanf(LastSlash, "/%ld", &dev_unit))
414     goto quit;
415    
416     // printf("dev=<%s> unit=%d\n", dev_name, dev_unit);
417     }
418     else
419     {
420     if (2 != sscanf(str, "%[^/]/%ld", dev_name, &dev_unit))
421     goto quit;
422     }
423     }
424     else
425 cebix 1.1 goto quit;
426    
427     // Open device
428     control_io->ios2_BufferManagement = buffer_tags;
429 jlachmann 1.5 od_error = OpenDevice((UBYTE *)dev_name, dev_unit, (struct IORequest *)control_io, 0);
430     if (0 != od_error || control_io->ios2_Req.io_Device == 0)
431     {
432     printf("WARNING: OpenDevice(<%s>, unit=%d) returned error %d)\n", (UBYTE *)dev_name, dev_unit, od_error);
433 cebix 1.1 goto quit;
434 jlachmann 1.5 }
435 cebix 1.1 opened = true;
436    
437     // Is it Ethernet?
438     control_io->ios2_Req.io_Command = S2_DEVICEQUERY;
439     control_io->ios2_StatData = (void *)&query_data;
440     DoIO((struct IORequest *)control_io);
441     if (control_io->ios2_Req.io_Error)
442     goto quit;
443     if (query_data.HardwareType != S2WireType_Ethernet) {
444     WarningAlert(GetString(STR_NOT_ETHERNET_WARN));
445     goto quit;
446     }
447    
448     // Yes, create IORequest for writing
449     write_io = (struct IOSana2Req *)CreateIORequest(write_port, sizeof(struct IOSana2Req));
450     if (write_io == NULL)
451     goto quit;
452     memcpy(write_io, control_io, sizeof(struct IOSana2Req));
453     write_io->ios2_Req.io_Message.mn_Node.ln_Type = 0; // Avoid CheckIO() bug
454     write_io->ios2_Req.io_Message.mn_ReplyPort = write_port;
455    
456     // Configure Ethernet
457     control_io->ios2_Req.io_Command = S2_GETSTATIONADDRESS;
458     DoIO((struct IORequest *)control_io);
459     memcpy(ether_addr, control_io->ios2_DstAddr, 6);
460     memcpy(control_io->ios2_SrcAddr, control_io->ios2_DstAddr, 6);
461     control_io->ios2_Req.io_Command = S2_CONFIGINTERFACE;
462     DoIO((struct IORequest *)control_io);
463     D(bug("Ethernet address %08lx %08lx\n", *(uint32 *)ether_addr, *(uint16 *)(ether_addr + 4)));
464    
465     // Initialization went well, inform main task
466     proc_error = false;
467     Signal(MainTask, SIGF_SINGLE);
468    
469     // Main loop
470     for (;;) {
471    
472     // Wait for I/O and messages (CTRL_C is used for quitting the task)
473     ULONG sig = Wait(proc_port_mask | read_mask | write_mask | SIGBREAKF_CTRL_C);
474    
475     // Main task wants to quit us
476     if (sig & SIGBREAKF_CTRL_C)
477     break;
478    
479     // Main task sent a command to us
480     if (sig & proc_port_mask) {
481     struct NetMessage *msg;
482     while (msg = (NetMessage *)GetMsg(proc_port)) {
483     D(bug("net_proc received %08lx\n", msg->what));
484     switch (msg->what) {
485     case MSG_CLEANUP:
486     remove_all_protocols();
487     break;
488    
489     case MSG_ADD_MULTI:
490     control_io->ios2_Req.io_Command = S2_ADDMULTICASTADDRESS;
491 cebix 1.3 Mac2Host_memcpy(control_io->ios2_SrcAddr, msg->pointer + eMultiAddr, 6);
492 cebix 1.1 DoIO((struct IORequest *)control_io);
493     if (control_io->ios2_Req.io_Error == S2ERR_NOT_SUPPORTED) {
494     WarningAlert(GetString(STR_NO_MULTICAST_WARN));
495     msg->result = noErr;
496     } else if (control_io->ios2_Req.io_Error)
497     msg->result = eMultiErr;
498     else
499     msg->result = noErr;
500     break;
501    
502     case MSG_DEL_MULTI:
503     control_io->ios2_Req.io_Command = S2_DELMULTICASTADDRESS;
504 cebix 1.3 Mac2Host_memcpy(control_io->ios2_SrcAddr, msg->pointer + eMultiAddr, 6);
505 cebix 1.1 DoIO((struct IORequest *)control_io);
506     if (control_io->ios2_Req.io_Error)
507     msg->result = eMultiErr;
508     else
509     msg->result = noErr;
510     break;
511    
512     case MSG_ATTACH_PH: {
513     uint16 type = msg->type;
514     uint32 handler = msg->pointer;
515    
516     // Protocol of that type already installed?
517     NetProtocol *p = (NetProtocol *)prot_list.lh_Head, *next;
518     while ((next = (NetProtocol *)p->ln_Succ) != NULL) {
519     if (p->type == type) {
520     msg->result = lapProtErr;
521     goto reply;
522     }
523     p = next;
524     }
525    
526     // Allocate NetProtocol, set type and handler
527     p = (NetProtocol *)AllocMem(sizeof(NetProtocol), MEMF_PUBLIC);
528     if (p == NULL) {
529     msg->result = lapProtErr;
530     goto reply;
531     }
532     p->type = type;
533     p->handler = handler;
534    
535     // Set up and submit read requests
536     for (int i=0; i<NUM_READ_REQUESTS; i++) {
537     memcpy(p->read_io + i, control_io, sizeof(struct IOSana2Req));
538     p->read_io[i].ios2_Req.io_Message.mn_Node.ln_Name = (char *)p; // Hide pointer to NetProtocol in node name
539     p->read_io[i].ios2_Req.io_Message.mn_Node.ln_Type = 0; // Avoid CheckIO() bug
540     p->read_io[i].ios2_Req.io_Message.mn_ReplyPort = read_port;
541     p->read_io[i].ios2_Req.io_Command = CMD_READ;
542     p->read_io[i].ios2_PacketType = type;
543     p->read_io[i].ios2_Data = p->read_buf[i];
544     p->read_io[i].ios2_Req.io_Flags = SANA2IOF_RAW;
545     BeginIO((struct IORequest *)(p->read_io + i));
546     }
547    
548     // Add protocol to list
549     AddTail(&prot_list, p);
550    
551     // Everything OK
552     msg->result = noErr;
553     break;
554     }
555    
556     case MSG_DETACH_PH: {
557     uint16 type = msg->type;
558     msg->result = lapProtErr;
559     NetProtocol *p = (NetProtocol *)prot_list.lh_Head, *next;
560     while ((next = (NetProtocol *)p->ln_Succ) != NULL) {
561     if (p->type == type) {
562     remove_protocol(p);
563     msg->result = noErr;
564     break;
565     }
566     p = next;
567     }
568     break;
569     }
570    
571     case MSG_WRITE: {
572     // Get pointer to Write Data Structure
573     uint32 wds = msg->pointer;
574     write_io->ios2_Data = (void *)wds;
575    
576     // Calculate total packet length
577     long len = 0;
578     uint32 tmp = wds;
579     for (;;) {
580     int16 w = ReadMacInt16(tmp);
581     if (w == 0)
582     break;
583     len += w;
584     tmp += 6;
585     }
586     write_io->ios2_DataLength = len;
587    
588     // Get destination address, set source address
589     uint32 hdr = ReadMacInt32(wds + 2);
590 cebix 1.3 Mac2Host_memcpy(write_io->ios2_DstAddr, hdr, 6);
591     Host2Mac_memcpy(hdr + 6, ether_addr, 6);
592 cebix 1.1
593     // Get packet type
594     uint32 type = ReadMacInt16(hdr + 12);
595     if (type <= 1500)
596     type = 0; // 802.3 packet
597     write_io->ios2_PacketType = type;
598    
599     // Multicast/broadcard packet?
600     if (write_io->ios2_DstAddr[0] & 1) {
601     if (*(uint32 *)(write_io->ios2_DstAddr) == 0xffffffff && *(uint16 *)(write_io->ios2_DstAddr + 4) == 0xffff)
602     write_io->ios2_Req.io_Command = S2_BROADCAST;
603     else
604     write_io->ios2_Req.io_Command = S2_MULTICAST;
605     } else
606     write_io->ios2_Req.io_Command = CMD_WRITE;
607    
608     // Send packet
609     write_done = false;
610     write_io->ios2_Req.io_Flags = SANA2IOF_RAW;
611     BeginIO((IORequest *)write_io);
612     break;
613     }
614     }
615     reply: D(bug(" net_proc replying\n"));
616     ReplyMsg(msg);
617     }
618     }
619    
620     // Packet received
621     if (sig & read_mask) {
622     D(bug(" packet received, triggering Ethernet interrupt\n"));
623     SetInterruptFlag(INTFLAG_ETHER);
624     TriggerInterrupt();
625     }
626    
627     // Packet write completed
628     if (sig & write_mask) {
629     GetMsg(write_port);
630     WriteMacInt32(ether_data + ed_Result, write_io->ios2_Req.io_Error ? excessCollsns : 0);
631     write_done = true;
632     D(bug(" packet write done, triggering Ethernet interrupt\n"));
633     SetInterruptFlag(INTFLAG_ETHER);
634     TriggerInterrupt();
635     }
636     }
637     quit:
638    
639     // Close everything
640     remove_all_protocols();
641     if (opened) {
642     if (CheckIO((struct IORequest *)write_io) == 0) {
643     AbortIO((struct IORequest *)write_io);
644     WaitIO((struct IORequest *)write_io);
645     }
646     CloseDevice((struct IORequest *)control_io);
647     }
648     if (write_io)
649     DeleteIORequest(write_io);
650     if (control_io)
651     DeleteIORequest(control_io);
652     if (control_port)
653     DeleteMsgPort(control_port);
654     if (write_port)
655     DeleteMsgPort(write_port);
656     if (read_port)
657     DeleteMsgPort(read_port);
658    
659     // Send signal to main task to confirm termination
660     Forbid();
661     Signal(MainTask, SIGF_SINGLE);
662     }
663    
664    
665     /*
666     * Ethernet interrupt - activate deferred tasks to call IODone or protocol handlers
667     */
668    
669     void EtherInterrupt(void)
670     {
671     D(bug("EtherIRQ\n"));
672    
673     // Packet write done, enqueue DT to call IODone
674     if (write_done) {
675 cebix 1.2 EnqueueMac(ether_data + ed_DeferredTask, 0xd92);
676 cebix 1.1 write_done = false;
677     }
678    
679     // Call protocol handler for received packets
680     IOSana2Req *io;
681     while (io = (struct IOSana2Req *)GetMsg(read_port)) {
682    
683     // Get pointer to NetProtocol (hidden in node name)
684     NetProtocol *p = (NetProtocol *)io->ios2_Req.io_Message.mn_Node.ln_Name;
685    
686     // No default handler
687     if (p->handler == 0)
688     continue;
689    
690     // Copy header to RHA
691 cebix 1.3 Host2Mac_memcpy(ether_data + ed_RHA, io->ios2_Data, 14);
692 cebix 1.1 D(bug(" header %08lx%04lx %08lx%04lx %04lx\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)));
693    
694     // Call protocol handler
695     M68kRegisters r;
696     r.d[0] = *(uint16 *)((uint32)io->ios2_Data + 12); // Packet type
697     r.d[1] = io->ios2_DataLength - 18; // Remaining packet length (without header, for ReadPacket) (-18 because the CRC is also included)
698     r.a[0] = (uint32)io->ios2_Data + 14; // Pointer to packet (host address, for ReadPacket)
699     r.a[3] = ether_data + ed_RHA + 14; // Pointer behind header in RHA
700     r.a[4] = ether_data + ed_ReadPacket; // Pointer to ReadPacket/ReadRest routines
701     D(bug(" calling protocol handler %08lx, type %08lx, length %08lx, data %08lx, rha %08lx, read_packet %08lx\n", p->handler, r.d[0], r.d[1], r.a[0], r.a[3], r.a[4]));
702     Execute68k(p->handler, &r);
703    
704     // Resend IORequest
705     io->ios2_Req.io_Flags = SANA2IOF_RAW;
706     BeginIO((struct IORequest *)io);
707     }
708     D(bug(" EtherIRQ done\n"));
709     }