ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/ether_unix.cpp
(Generate patch)

Comparing BasiliskII/src/Unix/ether_unix.cpp (file contents):
Revision 1.5 by cebix, 2001-09-02T13:50:05Z vs.
Revision 1.22 by gbeauche, 2005-06-12T22:48:48Z

# Line 1 | Line 1
1   /*
2   *  ether_unix.cpp - Ethernet device driver, Unix specific stuff (Linux and FreeBSD)
3   *
4 < *  Basilisk II (C) 1997-2001 Christian Bauer
4 > *  Basilisk II (C) 1997-2005 Christian Bauer
5   *
6   *  This program is free software; you can redistribute it and/or modify
7   *  it under the terms of the GNU General Public License as published by
# Line 20 | Line 20
20  
21   #include "sysdeps.h"
22  
23 < #include <sys/ioctl.h>
23 > #ifdef HAVE_SYS_POLL_H
24   #include <sys/poll.h>
25 + #endif
26 + #include <sys/ioctl.h>
27   #include <sys/socket.h>
28 + #include <sys/wait.h>
29   #include <netinet/in.h>
30   #include <pthread.h>
31   #include <semaphore.h>
# Line 30 | Line 33
33   #include <stdio.h>
34   #include <map>
35  
36 < #if defined(__FreeBSD__) || defined(sgi)
36 > #if defined(__FreeBSD__) || defined(sgi) || (defined(__APPLE__) && defined(__MACH__))
37 > #include <net/if.h>
38 > #endif
39 >
40 > #if defined(HAVE_LINUX_IF_H) && defined(HAVE_LINUX_IF_TUN_H)
41 > #include <linux/if.h>
42 > #include <linux/if_tun.h>
43 > #endif
44 >
45 > #if defined(HAVE_NET_IF_H) && defined(HAVE_NET_IF_TUN_H)
46   #include <net/if.h>
47 + #include <net/if_tun.h>
48 + #endif
49 +
50 + #ifdef HAVE_SLIRP
51 + #include "libslirp.h"
52   #endif
53  
54   #include "cpu_emulation.h"
# Line 52 | Line 69 | using std::map;
69   #define MONITOR 0
70  
71  
72 + // Ethernet device types
73 + enum {
74 +        NET_IF_SHEEPNET,
75 +        NET_IF_ETHERTAP,
76 +        NET_IF_TUNTAP,
77 +        NET_IF_SLIRP
78 + };
79 +
80 + // Constants
81 + static const char ETHERCONFIG_FILE_NAME[] = DATADIR "/tunconfig";
82 +
83   // 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
61 static bool is_ethertap;                                        // Flag: Ethernet device is ethertap
89   static bool udp_tunnel;                                         // Flag: UDP tunnelling active, fd is the socket descriptor
90 + static int net_if_type = -1;                            // Ethernet device type
91 + static char *net_if_name = NULL;                        // TUN/TAP device name
92 + static const char *net_if_script = NULL;        // Network config script
93 + 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 + static int slirp_input_fds[2] = { -1, -1 };     // fds of slirp input pipe
97  
98   // Attached network protocols, maps protocol type to MacOS handler address
99   static map<uint16, uint32> net_protocols;
100  
101   // Prototypes
102   static void *receive_func(void *arg);
103 + static void *slirp_receive_func(void *arg);
104 + static int poll_fd(int fd);
105  
106  
107   /*
# Line 79 | Line 115 | static bool start_thread(void)
115                  return false;
116          }
117  
118 <        pthread_attr_init(&ether_thread_attr);
83 < #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
84 <        if (geteuid() == 0) {
85 <                pthread_attr_setinheritsched(&ether_thread_attr, PTHREAD_EXPLICIT_SCHED);
86 <                pthread_attr_setschedpolicy(&ether_thread_attr, SCHED_FIFO);
87 <                struct sched_param fifo_param;
88 <                fifo_param.sched_priority = (sched_get_priority_min(SCHED_FIFO) + sched_get_priority_max(SCHED_FIFO)) / 2 + 1;
89 <                pthread_attr_setschedparam(&ether_thread_attr, &fifo_param);
90 <        }
91 < #endif
92 <
118 >        Set_pthread_attr(&ether_thread_attr, 1);
119          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 + #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          return true;
136   }
137  
# Line 106 | Line 142 | static bool start_thread(void)
142  
143   static void stop_thread(void)
144   {
145 + #ifdef HAVE_SLIRP
146 +        if (slirp_thread_active) {
147 + #ifdef HAVE_PTHREAD_CANCEL
148 +                pthread_cancel(slirp_thread);
149 + #endif
150 +                pthread_join(slirp_thread, NULL);
151 +                slirp_thread_active = false;
152 +        }
153 + #endif
154 +
155          if (thread_active) {
156 + #ifdef HAVE_PTHREAD_CANCEL
157                  pthread_cancel(ether_thread);
158 + #endif
159                  pthread_join(ether_thread, NULL);
160                  sem_destroy(&int_ack);
161                  thread_active = false;
# Line 116 | Line 164 | static void stop_thread(void)
164  
165  
166   /*
167 + *  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 +                        args[1] = net_if_name;
181 +                        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   *  Initialization
197   */
198  
# Line 129 | Line 206 | bool ether_init(void)
206          if (name == NULL)
207                  return false;
208  
209 <        // Is it Ethertap?
210 <        is_ethertap = (strncmp(name, "tap", 3) == 0);
209 >        // 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 > #ifdef HAVE_SLIRP
218 >        else if (strcmp(name, "slirp") == 0)
219 >                net_if_type = NET_IF_SLIRP;
220 > #endif
221 >        else
222 >                net_if_type = NET_IF_SHEEPNET;
223 >
224 > #ifdef HAVE_SLIRP
225 >        // Initialize slirp library
226 >        if (net_if_type == NET_IF_SLIRP) {
227 >                if (slirp_init() < 0) {
228 >                        sprintf(str, GetString(STR_SLIRP_NO_DNS_FOUND_WARN));
229 >                        WarningAlert(str);
230 >                        return false;
231 >                }
232 >
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 >
240 >                // Open slirp input pipe
241 >                if (pipe(slirp_input_fds) < 0)
242 >                        return false;
243 >        }
244 > #endif
245  
246 <        // Open sheep_net or ethertap device
246 >        // Open sheep_net or ethertap or TUN/TAP device
247          char dev_name[16];
248 <        if (is_ethertap)
248 >        switch (net_if_type) {
249 >        case NET_IF_ETHERTAP:
250                  sprintf(dev_name, "/dev/%s", name);
251 <        else
251 >                break;
252 >        case NET_IF_TUNTAP:
253 >                strcpy(dev_name, "/dev/net/tun");
254 >                break;
255 >        case NET_IF_SHEEPNET:
256                  strcpy(dev_name, "/dev/sheep_net");
257 <        fd = open(dev_name, O_RDWR);
258 <        if (fd < 0) {
259 <                sprintf(str, GetString(STR_NO_SHEEP_NET_DRIVER_WARN), dev_name, strerror(errno));
260 <                WarningAlert(str);
261 <                goto open_error;
257 >                break;
258 >        }
259 >        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 >        }
267 >
268 > #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 >                net_if_name = strdup(ifr.ifr_name);
293 >                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   #if defined(__linux__)
303          // Attach sheep_net to selected Ethernet card
304 <        if (!is_ethertap && ioctl(fd, SIOCSIFLINK, name) < 0) {
304 >        if (net_if_type == NET_IF_SHEEPNET && ioctl(fd, SIOCSIFLINK, name) < 0) {
305                  sprintf(str, GetString(STR_SHEEP_NET_ATTACH_WARN), strerror(errno));
306                  WarningAlert(str);
307                  goto open_error;
# Line 158 | Line 312 | bool ether_init(void)
312          ioctl(fd, FIONBIO, &nonblock);
313  
314          // Get Ethernet address
315 <        if (is_ethertap) {
315 >        if (net_if_type == NET_IF_ETHERTAP) {
316                  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;
# Line 166 | Line 320 | bool ether_init(void)
320                  ether_addr[3] = p >> 16;
321                  ether_addr[4] = p >> 8;
322                  ether_addr[5] = p;
323 + #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          } 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]));
# Line 184 | Line 347 | open_error:
347                  close(fd);
348                  fd = -1;
349          }
350 +        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 +        if (slirp_output_fd >= 0) {
359 +                close(slirp_output_fd);
360 +                slirp_output_fd = -1;
361 +        }
362          return false;
363   }
364  
# Line 194 | Line 369 | open_error:
369  
370   void ether_exit(void)
371   {
372 <        // Stop reception thread
373 <        if (thread_active) {
374 <                pthread_cancel(ether_thread);
375 <                pthread_join(ether_thread, NULL);
376 <                sem_destroy(&int_ack);
377 <                thread_active = false;
378 <        }
372 >        // Stop reception threads
373 >        stop_thread();
374 >
375 >        // 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          // Close sheep_net device
384          if (fd > 0)
385                  close(fd);
386 +
387 +        // 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 +        // Close slirp output buffer
394 +        if (slirp_output_fd > 0)
395 +                close(slirp_output_fd);
396   }
397  
398  
# Line 224 | Line 412 | void ether_reset(void)
412  
413   int16 ether_add_multicast(uint32 pb)
414   {
415 <        if (ioctl(fd, SIOCADDMULTI, Mac2HostAddr(pb + eMultiAddr)) < 0) {
416 <                D(bug("WARNING: Couldn't enable multicast address\n"));
417 <                if (is_ethertap)
418 <                        return noErr;
419 <                else
420 <                        return eMultiErr;
421 <        } else
415 >        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                  return noErr;
427 +        }
428   }
429  
430  
# Line 241 | Line 434 | int16 ether_add_multicast(uint32 pb)
434  
435   int16 ether_del_multicast(uint32 pb)
436   {
437 <        if (ioctl(fd, SIOCDELMULTI, Mac2HostAddr(pb + eMultiAddr)) < 0) {
438 <                D(bug("WARNING: Couldn't disable multicast address\n"));
439 <                return eMultiErr;
440 <        } else
437 >        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                  return noErr;
446 +        }
447   }
448  
449  
# Line 284 | Line 482 | int16 ether_write(uint32 wds)
482          uint8 packet[1516], *p = packet;
483          int len = 0;
484   #if defined(__linux__)
485 <        if (is_ethertap) {
485 >        if (net_if_type == NET_IF_ETHERTAP) {
486                  *p++ = 0;       // Linux ethertap discards the first 2 bytes
487                  *p++ = 0;
488                  len += 2;
# Line 301 | Line 499 | int16 ether_write(uint32 wds)
499   #endif
500  
501          // Transmit packet
502 + #ifdef HAVE_SLIRP
503 +        if (net_if_type == NET_IF_SLIRP) {
504 +                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 +                return noErr;
508 +        } else
509 + #endif
510          if (write(fd, packet, len) < 0) {
511                  D(bug("WARNING: Couldn't transmit packet\n"));
512                  return excessCollsns;
# Line 333 | Line 539 | void ether_stop_udp_thread(void)
539  
540  
541   /*
542 + *  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 +        const int slirp_input_fd = slirp_input_fds[0];
559 +
560 +        for (;;) {
561 +                // Wait for packets to arrive
562 +                fd_set rfds, wfds, xfds;
563 +                int nfds;
564 +                struct timeval tv;
565 +
566 +                // ... 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 +                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 +                tv.tv_usec = 10000;
588 +                if (select(nfds + 1, &rfds, &wfds, &xfds, &tv) >= 0)
589 +                        slirp_select_poll(&rfds, &wfds, &xfds);
590 +
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 +        }
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   *  Packet reception thread
613   */
614  
# Line 341 | Line 617 | static void *receive_func(void *arg)
617          for (;;) {
618  
619                  // Wait for packets to arrive
620 + #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                  if (res <= 0)
638                          break;
639  
# Line 367 | Line 658 | void EtherInterrupt(void)
658          D(bug("EtherIRQ\n"));
659  
660          // Call protocol handler for received packets
661 <        uint8 packet[1516];
661 >        EthernetPacket ether_packet;
662 >        uint32 packet = ether_packet.addr();
663          ssize_t length;
664          for (;;) {
665  
# Line 376 | Line 668 | void EtherInterrupt(void)
668                          // Read packet from socket
669                          struct sockaddr_in from;
670                          socklen_t from_len = sizeof(from);
671 <                        length = recvfrom(fd, packet, 1514, 0, (struct sockaddr *)&from, &from_len);
671 >                        length = recvfrom(fd, Mac2HostAddr(packet), 1514, 0, (struct sockaddr *)&from, &from_len);
672                          if (length < 14)
673                                  break;
674                          ether_udp_read(packet, length, &from);
# Line 385 | Line 677 | void EtherInterrupt(void)
677  
678                          // Read packet from sheep_net device
679   #if defined(__linux__)
680 <                        length = read(fd, packet, is_ethertap ? 1516 : 1514);
680 >                        length = read(fd, Mac2HostAddr(packet), net_if_type == NET_IF_ETHERTAP ? 1516 : 1514);
681   #else
682 <                        length = read(fd, packet, 1514);
682 >                        length = read(fd, Mac2HostAddr(packet), 1514);
683   #endif
684                          if (length < 14)
685                                  break;
# Line 395 | Line 687 | void EtherInterrupt(void)
687   #if MONITOR
688                          bug("Receiving Ethernet packet:\n");
689                          for (int i=0; i<length; i++) {
690 <                                bug("%02x ", packet[i]);
690 >                                bug("%02x ", ReadMacInt8(packet + i));
691                          }
692                          bug("\n");
693   #endif
694  
695                          // Pointer to packet data (Ethernet header)
696 <                        uint8 *p = packet;
696 >                        uint32 p = packet;
697   #if defined(__linux__)
698 <                        if (is_ethertap) {
698 >                        if (net_if_type == NET_IF_ETHERTAP) {
699                                  p += 2;                 // Linux ethertap has two random bytes before the packet
700                                  length -= 2;
701                          }
702   #endif
703  
704                          // Get packet type
705 <                        uint16 type = (p[12] << 8) | p[13];
705 >                        uint16 type = ReadMacInt16(p + 12);
706  
707                          // Look for protocol
708                          uint16 search_type = (type <= 1500 ? 0 : type);
# Line 423 | Line 715 | void EtherInterrupt(void)
715                                  continue;
716  
717                          // Copy header to RHA
718 <                        Host2Mac_memcpy(ether_data + ed_RHA, p, 14);
718 >                        Mac2Mac_memcpy(ether_data + ed_RHA, p, 14);
719                          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 <                        r.a[0] = (uint32)p + 14;                                                // Pointer to packet (host address, for ReadPacket)
725 >                        r.a[0] = p + 14;                                                                // Pointer to packet (Mac address, for ReadPacket)
726                          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                          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]));

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines