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.16 by gbeauche, 2005-05-13T14:02:36Z

# 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 23 | Line 23
23   #include <sys/ioctl.h>
24   #include <sys/poll.h>
25   #include <sys/socket.h>
26 + #include <sys/wait.h>
27   #include <netinet/in.h>
28   #include <pthread.h>
29   #include <semaphore.h>
# Line 34 | Line 35
35   #include <net/if.h>
36   #endif
37  
38 + #if defined(HAVE_LINUX_IF_H) && defined(HAVE_LINUX_IF_TUN_H)
39 + #include <linux/if.h>
40 + #include <linux/if_tun.h>
41 + #endif
42 +
43 + #if defined(HAVE_NET_IF_H) && defined(HAVE_NET_IF_TUN_H)
44 + #include <net/if.h>
45 + #include <net/if_tun.h>
46 + #endif
47 +
48 + // XXX: slirp works on 64-bit platforms, sometimes
49 + #define HAVE_SLIRP 1
50 + #include "libslirp.h"
51 +
52   #include "cpu_emulation.h"
53   #include "main.h"
54   #include "macos_util.h"
# Line 52 | Line 67 | using std::map;
67   #define MONITOR 0
68  
69  
70 + // Ethernet device types
71 + enum {
72 +        NET_IF_SHEEPNET,
73 +        NET_IF_ETHERTAP,
74 +        NET_IF_TUNTAP,
75 +        NET_IF_SLIRP
76 + };
77 +
78 + // Constants
79 + static const char ETHERCONFIG_FILE_NAME[] = DATADIR "/tunconfig";
80 +
81   // Global variables
82   static int fd = -1;                                                     // fd of sheep_net device
83   static pthread_t ether_thread;                          // Packet reception thread
84   static pthread_attr_t ether_thread_attr;        // Packet reception thread attributes
85   static bool thread_active = false;                      // Flag: Packet reception thread installed
86   static sem_t int_ack;                                           // Interrupt acknowledge semaphore
61 static bool is_ethertap;                                        // Flag: Ethernet device is ethertap
87   static bool udp_tunnel;                                         // Flag: UDP tunnelling active, fd is the socket descriptor
88 + static int net_if_type = -1;                            // Ethernet device type
89 + static char *net_if_name = NULL;                        // TUN/TAP device name
90 + static const char *net_if_script = NULL;        // Network config script
91 + static pthread_t slirp_thread;                          // Slirp reception thread
92 + static bool slirp_thread_active = false;        // Flag: Slirp reception threadinstalled
93 + static int slirp_output_fd = -1;                        // fd of slirp output pipe
94  
95   // Attached network protocols, maps protocol type to MacOS handler address
96   static map<uint16, uint32> net_protocols;
97  
98   // Prototypes
99   static void *receive_func(void *arg);
100 + static void *slirp_receive_func(void *arg);
101  
102  
103   /*
# Line 79 | Line 111 | static bool start_thread(void)
111                  return false;
112          }
113  
114 <        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 <
114 >        Set_pthread_attr(&ether_thread_attr, 1);
115          thread_active = (pthread_create(&ether_thread, &ether_thread_attr, receive_func, NULL) == 0);
116          if (!thread_active) {
117                  printf("WARNING: Cannot start Ethernet thread");
118                  return false;
119          }
120  
121 + #ifdef HAVE_SLIRP
122 +        if (net_if_type == NET_IF_SLIRP) {
123 +                slirp_thread_active = (pthread_create(&slirp_thread, NULL, slirp_receive_func, NULL) == 0);
124 +                if (!slirp_thread_active) {
125 +                        printf("WARNING: Cannot start slirp reception thread\n");
126 +                        return false;
127 +                }
128 +        }
129 + #endif
130 +
131          return true;
132   }
133  
# Line 106 | Line 138 | static bool start_thread(void)
138  
139   static void stop_thread(void)
140   {
141 + #ifdef HAVE_SLIRP
142 +        if (slirp_thread_active) {
143 +                pthread_cancel(slirp_thread);
144 +                pthread_join(slirp_thread, NULL);
145 +                slirp_thread_active = false;
146 +        }
147 + #endif
148 +
149          if (thread_active) {
150                  pthread_cancel(ether_thread);
151                  pthread_join(ether_thread, NULL);
# Line 116 | Line 156 | static void stop_thread(void)
156  
157  
158   /*
159 + *  Execute network script up|down
160 + */
161 +
162 + static bool execute_network_script(const char *action)
163 + {
164 +        if (net_if_script == NULL || net_if_name == NULL)
165 +                return false;
166 +
167 +        int pid = fork();
168 +        if (pid >= 0) {
169 +                if (pid == 0) {
170 +                        char *args[4];
171 +                        args[0] = (char *)net_if_script;
172 +                        args[1] = net_if_name;
173 +                        args[2] = (char *)action;
174 +                        args[3] = NULL;
175 +                        execv(net_if_script, args);
176 +                        exit(1);
177 +                }
178 +                int status;
179 +                while (waitpid(pid, &status, 0) != pid);
180 +                return WIFEXITED(status) && WEXITSTATUS(status) == 0;
181 +        }
182 +
183 +        return false;
184 + }
185 +
186 +
187 + /*
188   *  Initialization
189   */
190  
# Line 129 | Line 198 | bool ether_init(void)
198          if (name == NULL)
199                  return false;
200  
201 <        // Is it Ethertap?
202 <        is_ethertap = (strncmp(name, "tap", 3) == 0);
201 >        // Determine Ethernet device type
202 >        net_if_type = -1;
203 >        if (strncmp(name, "tap", 3) == 0)
204 >                net_if_type = NET_IF_ETHERTAP;
205 > #if ENABLE_TUNTAP
206 >        else if (strcmp(name, "tun") == 0)
207 >                net_if_type = NET_IF_TUNTAP;
208 > #endif
209 > #ifdef HAVE_SLIRP
210 >        else if (strcmp(name, "slirp") == 0)
211 >                net_if_type = NET_IF_SLIRP;
212 > #endif
213 >        else
214 >                net_if_type = NET_IF_SHEEPNET;
215 >
216 > #ifdef HAVE_SLIRP
217 >        // Initialize slirp library
218 >        if (net_if_type == NET_IF_SLIRP) {
219 >                slirp_init();
220 >
221 >                // Open slirp output pipe
222 >                int fds[2];
223 >                if (pipe(fds) < 0)
224 >                        return false;
225 >                fd = fds[0];
226 >                slirp_output_fd = fds[1];
227 >        }
228 > #endif
229  
230 <        // Open sheep_net or ethertap device
230 >        // Open sheep_net or ethertap or TUN/TAP device
231          char dev_name[16];
232 <        if (is_ethertap)
232 >        switch (net_if_type) {
233 >        case NET_IF_ETHERTAP:
234                  sprintf(dev_name, "/dev/%s", name);
235 <        else
235 >                break;
236 >        case NET_IF_TUNTAP:
237 >                strcpy(dev_name, "/dev/net/tun");
238 >                break;
239 >        case NET_IF_SHEEPNET:
240                  strcpy(dev_name, "/dev/sheep_net");
241 <        fd = open(dev_name, O_RDWR);
242 <        if (fd < 0) {
243 <                sprintf(str, GetString(STR_NO_SHEEP_NET_DRIVER_WARN), dev_name, strerror(errno));
244 <                WarningAlert(str);
245 <                goto open_error;
241 >                break;
242 >        }
243 >        if (net_if_type != NET_IF_SLIRP) {
244 >                fd = open(dev_name, O_RDWR);
245 >                if (fd < 0) {
246 >                        sprintf(str, GetString(STR_NO_SHEEP_NET_DRIVER_WARN), dev_name, strerror(errno));
247 >                        WarningAlert(str);
248 >                        goto open_error;
249 >                }
250 >        }
251 >
252 > #if ENABLE_TUNTAP
253 >        // Open TUN/TAP interface
254 >        if (net_if_type == NET_IF_TUNTAP) {
255 >                struct ifreq ifr;
256 >                memset(&ifr, 0, sizeof(ifr));
257 >                ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
258 >                strcpy(ifr.ifr_name, "tun%d");
259 >                if (ioctl(fd, TUNSETIFF, (void *) &ifr) != 0) {
260 >                        sprintf(str, GetString(STR_SHEEP_NET_ATTACH_WARN), strerror(errno));
261 >                        WarningAlert(str);
262 >                        goto open_error;
263 >                }
264 >
265 >                // Get network config script file path
266 >                net_if_script = PrefsFindString("etherconfig");
267 >                if (net_if_script == NULL)
268 >                        net_if_script = ETHERCONFIG_FILE_NAME;
269 >
270 >                // Start network script up
271 >                if (net_if_script == NULL) {
272 >                        sprintf(str, GetString(STR_TUN_TAP_CONFIG_WARN), "script not found");
273 >                        WarningAlert(str);
274 >                        goto open_error;
275 >                }
276 >                net_if_name = strdup(ifr.ifr_name);
277 >                if (!execute_network_script("up")) {
278 >                        sprintf(str, GetString(STR_TUN_TAP_CONFIG_WARN), "script execute error");
279 >                        WarningAlert(str);
280 >                        goto open_error;
281 >                }
282 >                D(bug("Connected to host network interface: %s\n", net_if_name));
283          }
284 + #endif
285  
286   #if defined(__linux__)
287          // Attach sheep_net to selected Ethernet card
288 <        if (!is_ethertap && ioctl(fd, SIOCSIFLINK, name) < 0) {
288 >        if (net_if_type == NET_IF_SHEEPNET && ioctl(fd, SIOCSIFLINK, name) < 0) {
289                  sprintf(str, GetString(STR_SHEEP_NET_ATTACH_WARN), strerror(errno));
290                  WarningAlert(str);
291                  goto open_error;
# Line 158 | Line 296 | bool ether_init(void)
296          ioctl(fd, FIONBIO, &nonblock);
297  
298          // Get Ethernet address
299 <        if (is_ethertap) {
299 >        if (net_if_type == NET_IF_ETHERTAP) {
300                  pid_t p = getpid();     // If configured for multicast, ethertap requires that the lower 32 bit of the Ethernet address are our PID
301                  ether_addr[0] = 0xfe;
302                  ether_addr[1] = 0xfd;
# Line 166 | Line 304 | bool ether_init(void)
304                  ether_addr[3] = p >> 16;
305                  ether_addr[4] = p >> 8;
306                  ether_addr[5] = p;
307 + #ifdef HAVE_SLIRP
308 +        } else if (net_if_type == NET_IF_SLIRP) {
309 +                ether_addr[0] = 0x52;
310 +                ether_addr[1] = 0x54;
311 +                ether_addr[2] = 0x00;
312 +                ether_addr[3] = 0x12;
313 +                ether_addr[4] = 0x34;
314 +                ether_addr[5] = 0x56;
315 + #endif
316          } else
317                  ioctl(fd, SIOCGIFADDR, ether_addr);
318          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 331 | open_error:
331                  close(fd);
332                  fd = -1;
333          }
334 +        if (slirp_output_fd >= 0) {
335 +                close(slirp_output_fd);
336 +                slirp_output_fd = -1;
337 +        }
338          return false;
339   }
340  
# Line 202 | Line 353 | void ether_exit(void)
353                  thread_active = false;
354          }
355  
356 +        // Shut down TUN/TAP interface
357 +        if (net_if_type == NET_IF_TUNTAP)
358 +                execute_network_script("down");
359 +
360 +        // Free TUN/TAP device name
361 +        if (net_if_name)
362 +                free(net_if_name);
363 +
364          // Close sheep_net device
365          if (fd > 0)
366                  close(fd);
367 +
368 +        // Close slirp output buffer
369 +        if (slirp_output_fd > 0)
370 +                close(slirp_output_fd);
371   }
372  
373  
# Line 224 | Line 387 | void ether_reset(void)
387  
388   int16 ether_add_multicast(uint32 pb)
389   {
390 <        if (ioctl(fd, SIOCADDMULTI, Mac2HostAddr(pb + eMultiAddr)) < 0) {
391 <                D(bug("WARNING: Couldn't enable multicast address\n"));
392 <                if (is_ethertap)
393 <                        return noErr;
394 <                else
395 <                        return eMultiErr;
396 <        } else
390 >        switch (net_if_type) {
391 >        case NET_IF_ETHERTAP:
392 >        case NET_IF_SHEEPNET:
393 >                if (ioctl(fd, SIOCADDMULTI, Mac2HostAddr(pb + eMultiAddr)) < 0) {
394 >                        D(bug("WARNING: Couldn't enable multicast address\n"));
395 >                        if (net_if_type == NET_IF_ETHERTAP)
396 >                                return noErr;
397 >                        else
398 >                                return eMultiErr;
399 >                }
400 >        default:
401                  return noErr;
402 +        }
403   }
404  
405  
# Line 241 | Line 409 | int16 ether_add_multicast(uint32 pb)
409  
410   int16 ether_del_multicast(uint32 pb)
411   {
412 <        if (ioctl(fd, SIOCDELMULTI, Mac2HostAddr(pb + eMultiAddr)) < 0) {
413 <                D(bug("WARNING: Couldn't disable multicast address\n"));
414 <                return eMultiErr;
415 <        } else
412 >        switch (net_if_type) {
413 >        case NET_IF_ETHERTAP:
414 >        case NET_IF_SHEEPNET:
415 >                if (ioctl(fd, SIOCDELMULTI, Mac2HostAddr(pb + eMultiAddr)) < 0) {
416 >                        D(bug("WARNING: Couldn't disable multicast address\n"));
417 >                        return eMultiErr;
418 >                }
419 >        default:
420                  return noErr;
421 +        }
422   }
423  
424  
# Line 284 | Line 457 | int16 ether_write(uint32 wds)
457          uint8 packet[1516], *p = packet;
458          int len = 0;
459   #if defined(__linux__)
460 <        if (is_ethertap) {
460 >        if (net_if_type == NET_IF_ETHERTAP) {
461                  *p++ = 0;       // Linux ethertap discards the first 2 bytes
462                  *p++ = 0;
463                  len += 2;
# Line 301 | Line 474 | int16 ether_write(uint32 wds)
474   #endif
475  
476          // Transmit packet
477 + #ifdef HAVE_SLIRP
478 +        if (net_if_type == NET_IF_SLIRP) {
479 +                slirp_input(packet, len);
480 +                return noErr;
481 +        } else
482 + #endif
483          if (write(fd, packet, len) < 0) {
484                  D(bug("WARNING: Couldn't transmit packet\n"));
485                  return excessCollsns;
# Line 333 | Line 512 | void ether_stop_udp_thread(void)
512  
513  
514   /*
515 + *  SLIRP output buffer glue
516 + */
517 +
518 + #ifdef HAVE_SLIRP
519 + int slirp_can_output(void)
520 + {
521 +        return 1;
522 + }
523 +
524 + void slirp_output(const uint8 *packet, int len)
525 + {
526 +        write(slirp_output_fd, packet, len);
527 + }
528 +
529 + void *slirp_receive_func(void *arg)
530 + {
531 +        for (;;) {
532 +                // Wait for packets to arrive
533 +                fd_set rfds, wfds, xfds;
534 +                int nfds;
535 +                struct timeval tv;
536 +
537 +                nfds = -1;
538 +                FD_ZERO(&rfds);
539 +                FD_ZERO(&wfds);
540 +                FD_ZERO(&xfds);
541 +                slirp_select_fill(&nfds, &rfds, &wfds, &xfds);
542 +                tv.tv_sec = 0;
543 +                tv.tv_usec = 16667;
544 +                if (select(nfds + 1, &rfds, &wfds, &xfds, &tv) >= 0)
545 +                        slirp_select_poll(&rfds, &wfds, &xfds);
546 +        }
547 +        return NULL;
548 + }
549 + #else
550 + int slirp_can_output(void)
551 + {
552 +        return 0;
553 + }
554 +
555 + void slirp_output(const uint8 *packet, int len)
556 + {
557 + }
558 + #endif
559 +
560 +
561 + /*
562   *  Packet reception thread
563   */
564  
# Line 367 | Line 593 | void EtherInterrupt(void)
593          D(bug("EtherIRQ\n"));
594  
595          // Call protocol handler for received packets
596 <        uint8 packet[1516];
596 >        EthernetPacket ether_packet;
597 >        uint32 packet = ether_packet.addr();
598          ssize_t length;
599          for (;;) {
600  
# Line 376 | Line 603 | void EtherInterrupt(void)
603                          // Read packet from socket
604                          struct sockaddr_in from;
605                          socklen_t from_len = sizeof(from);
606 <                        length = recvfrom(fd, packet, 1514, 0, (struct sockaddr *)&from, &from_len);
606 >                        length = recvfrom(fd, Mac2HostAddr(packet), 1514, 0, (struct sockaddr *)&from, &from_len);
607                          if (length < 14)
608                                  break;
609                          ether_udp_read(packet, length, &from);
# Line 385 | Line 612 | void EtherInterrupt(void)
612  
613                          // Read packet from sheep_net device
614   #if defined(__linux__)
615 <                        length = read(fd, packet, is_ethertap ? 1516 : 1514);
615 >                        length = read(fd, Mac2HostAddr(packet), net_if_type == NET_IF_ETHERTAP ? 1516 : 1514);
616   #else
617 <                        length = read(fd, packet, 1514);
617 >                        length = read(fd, Mac2HostAddr(packet), 1514);
618   #endif
619                          if (length < 14)
620                                  break;
# Line 395 | Line 622 | void EtherInterrupt(void)
622   #if MONITOR
623                          bug("Receiving Ethernet packet:\n");
624                          for (int i=0; i<length; i++) {
625 <                                bug("%02x ", packet[i]);
625 >                                bug("%02x ", ReadMacInt8(packet + i));
626                          }
627                          bug("\n");
628   #endif
629  
630                          // Pointer to packet data (Ethernet header)
631 <                        uint8 *p = packet;
631 >                        uint32 p = packet;
632   #if defined(__linux__)
633 <                        if (is_ethertap) {
633 >                        if (net_if_type == NET_IF_ETHERTAP) {
634                                  p += 2;                 // Linux ethertap has two random bytes before the packet
635                                  length -= 2;
636                          }
637   #endif
638  
639                          // Get packet type
640 <                        uint16 type = (p[12] << 8) | p[13];
640 >                        uint16 type = ReadMacInt16(p + 12);
641  
642                          // Look for protocol
643                          uint16 search_type = (type <= 1500 ? 0 : type);
# Line 423 | Line 650 | void EtherInterrupt(void)
650                                  continue;
651  
652                          // Copy header to RHA
653 <                        Host2Mac_memcpy(ether_data + ed_RHA, p, 14);
653 >                        Mac2Mac_memcpy(ether_data + ed_RHA, p, 14);
654                          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)));
655  
656                          // Call protocol handler
657                          M68kRegisters r;
658                          r.d[0] = type;                                                                  // Packet type
659                          r.d[1] = length - 14;                                                   // Remaining packet length (without header, for ReadPacket)
660 <                        r.a[0] = (uint32)p + 14;                                                // Pointer to packet (host address, for ReadPacket)
660 >                        r.a[0] = p + 14;                                                                // Pointer to packet (Mac address, for ReadPacket)
661                          r.a[3] = ether_data + ed_RHA + 14;                              // Pointer behind header in RHA
662                          r.a[4] = ether_data + ed_ReadPacket;                    // Pointer to ReadPacket/ReadRest routines
663                          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