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.2 by cebix, 2001-07-12T19:48:27Z vs.
Revision 1.11 by gbeauche, 2004-05-12T11:46:34Z

# 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-2004 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 22 | Line 22
22  
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>
30   #include <errno.h>
31   #include <stdio.h>
32 + #include <map>
33  
34 < #include <netinet/in.h>
35 < #include <sys/socket.h>
34 > #if defined(__FreeBSD__) || defined(sgi)
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(__FreeBSD__)
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   #include "cpu_emulation.h"
# Line 42 | Line 53
53   #include "ether.h"
54   #include "ether_defs.h"
55  
56 + #ifndef NO_STD_NAMESPACE
57 + using std::map;
58 + #endif
59 +
60   #define DEBUG 0
61   #include "debug.h"
62  
63   #define MONITOR 0
64  
65  
66 < // List of attached protocols
67 < struct NetProtocol {
68 <        NetProtocol *next;
69 <        uint16 type;
70 <        uint32 handler;
66 > // Ethernet device types
67 > enum {
68 >        NET_IF_SHEEPNET,
69 >        NET_IF_ETHERTAP,
70 >        NET_IF_TUNTAP,
71   };
72  
73 < static NetProtocol *prot_list = NULL;
74 <
73 > // Constants
74 > static const char ETHERCONFIG_FILE_NAME[] = DATADIR "/tunconfig";
75  
76   // Global variables
77   static int fd = -1;                                                     // fd of sheep_net device
# Line 64 | Line 79 | static pthread_t ether_thread;                         // Pac
79   static pthread_attr_t ether_thread_attr;        // Packet reception thread attributes
80   static bool thread_active = false;                      // Flag: Packet reception thread installed
81   static sem_t int_ack;                                           // Interrupt acknowledge semaphore
67 static bool is_ethertap;                                        // Flag: Ethernet device is ethertap
82   static bool udp_tunnel;                                         // Flag: UDP tunnelling active, fd is the socket descriptor
83 + static int net_if_type = -1;                            // Ethernet device type
84 + static char *net_if_name = NULL;                        // TUN/TAP device name
85 + static const char *net_if_script = NULL;        // Network config script
86 +
87 + // Attached network protocols, maps protocol type to MacOS handler address
88 + static map<uint16, uint32> net_protocols;
89  
90   // Prototypes
91   static void *receive_func(void *arg);
92  
93  
94   /*
75 *  Find protocol in list
76 */
77
78 static NetProtocol *find_protocol(uint16 type)
79 {
80        // All 802.2 types are the same
81        if (type <= 1500)
82                type = 0;
83
84        // Search list (we could use hashing here but there are usually only three
85        // handlers installed: 0x0000 for AppleTalk and 0x0800/0x0806 for TCP/IP)
86        NetProtocol *p = prot_list;
87        while (p) {
88                if (p->type == type)
89                        return p;
90                p = p->next;
91        }
92        return NULL;
93 }
94
95
96 /*
97 *  Remove all protocols
98 */
99
100 static void remove_all_protocols(void)
101 {
102        NetProtocol *p = prot_list;
103        while (p) {
104                NetProtocol *next = p->next;
105                delete p;
106                p = next;
107        }
108        prot_list = NULL;
109 }
110
111
112 /*
95   *  Start packet reception thread
96   */
97  
# Line 120 | Line 102 | static bool start_thread(void)
102                  return false;
103          }
104  
105 <        pthread_attr_init(&ether_thread_attr);
124 < #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
125 <        if (geteuid() == 0) {
126 <                pthread_attr_setinheritsched(&ether_thread_attr, PTHREAD_EXPLICIT_SCHED);
127 <                pthread_attr_setschedpolicy(&ether_thread_attr, SCHED_FIFO);
128 <                struct sched_param fifo_param;
129 <                fifo_param.sched_priority = (sched_get_priority_min(SCHED_FIFO) + sched_get_priority_max(SCHED_FIFO)) / 2 + 1;
130 <                pthread_attr_setschedparam(&ether_thread_attr, &fifo_param);
131 <        }
132 < #endif
133 <
105 >        Set_pthread_attr(&ether_thread_attr, 1);
106          thread_active = (pthread_create(&ether_thread, &ether_thread_attr, receive_func, NULL) == 0);
107          if (!thread_active) {
108                  printf("WARNING: Cannot start Ethernet thread");
# Line 157 | Line 129 | static void stop_thread(void)
129  
130  
131   /*
132 + *  Execute network script up|down
133 + */
134 +
135 + static bool execute_network_script(const char *action)
136 + {
137 +        if (net_if_script == NULL || net_if_name == NULL)
138 +                return false;
139 +
140 +        int pid = fork();
141 +        if (pid >= 0) {
142 +                if (pid == 0) {
143 +                        char *args[4];
144 +                        args[0] = (char *)net_if_script;
145 +                        args[1] = net_if_name;
146 +                        args[2] = (char *)action;
147 +                        args[3] = NULL;
148 +                        execv(net_if_script, args);
149 +                        exit(1);
150 +                }
151 +                int status;
152 +                while (waitpid(pid, &status, 0) != pid);
153 +                return WIFEXITED(status) && WEXITSTATUS(status) == 0;
154 +        }
155 +
156 +        return false;
157 + }
158 +
159 +
160 + /*
161   *  Initialization
162   */
163  
# Line 170 | Line 171 | bool ether_init(void)
171          if (name == NULL)
172                  return false;
173  
174 <        // Is it Ethertap?
175 <        is_ethertap = (strncmp(name, "tap", 3) == 0);
174 >        // Determine Ethernet device type
175 >        net_if_type = -1;
176 >        if (strncmp(name, "tap", 3) == 0)
177 >                net_if_type = NET_IF_ETHERTAP;
178 > #if ENABLE_TUNTAP
179 >        else if (strcmp(name, "tun") == 0)
180 >                net_if_type = NET_IF_TUNTAP;
181 > #endif
182 >        else
183 >                net_if_type = NET_IF_SHEEPNET;
184  
185 <        // Open sheep_net or ethertap device
185 >        // Open sheep_net or ethertap or TUN/TAP device
186          char dev_name[16];
187 <        if (is_ethertap)
187 >        switch (net_if_type) {
188 >        case NET_IF_ETHERTAP:
189                  sprintf(dev_name, "/dev/%s", name);
190 <        else
190 >                break;
191 >        case NET_IF_TUNTAP:
192 >                strcpy(dev_name, "/dev/net/tun");
193 >                break;
194 >        case NET_IF_SHEEPNET:
195                  strcpy(dev_name, "/dev/sheep_net");
196 +                break;
197 +        }
198          fd = open(dev_name, O_RDWR);
199          if (fd < 0) {
200                  sprintf(str, GetString(STR_NO_SHEEP_NET_DRIVER_WARN), dev_name, strerror(errno));
# Line 186 | Line 202 | bool ether_init(void)
202                  goto open_error;
203          }
204  
205 + #if ENABLE_TUNTAP
206 +        // Open TUN/TAP interface
207 +        if (net_if_type == NET_IF_TUNTAP) {
208 +                struct ifreq ifr;
209 +                memset(&ifr, 0, sizeof(ifr));
210 +                ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
211 +                strcpy(ifr.ifr_name, "tun%d");
212 +                if (ioctl(fd, TUNSETIFF, (void *) &ifr) != 0) {
213 +                        sprintf(str, GetString(STR_SHEEP_NET_ATTACH_WARN), strerror(errno));
214 +                        WarningAlert(str);
215 +                        goto open_error;
216 +                }
217 +
218 +                // Get network config script file path
219 +                net_if_script = PrefsFindString("etherconfig");
220 +                if (net_if_script == NULL)
221 +                        net_if_script = ETHERCONFIG_FILE_NAME;
222 +
223 +                // Start network script up
224 +                if (net_if_script == NULL) {
225 +                        sprintf(str, GetString(STR_TUN_TAP_CONFIG_WARN), "script not found");
226 +                        WarningAlert(str);
227 +                        goto open_error;
228 +                }
229 +                net_if_name = strdup(ifr.ifr_name);
230 +                if (!execute_network_script("up")) {
231 +                        sprintf(str, GetString(STR_TUN_TAP_CONFIG_WARN), "script execute error");
232 +                        WarningAlert(str);
233 +                        goto open_error;
234 +                }
235 +                D(bug("Connected to host network interface: %s\n", net_if_name));
236 +        }
237 + #endif
238 +
239   #if defined(__linux__)
240          // Attach sheep_net to selected Ethernet card
241 <        if (!is_ethertap && ioctl(fd, SIOCSIFLINK, name) < 0) {
241 >        if (net_if_type == NET_IF_SHEEPNET && ioctl(fd, SIOCSIFLINK, name) < 0) {
242                  sprintf(str, GetString(STR_SHEEP_NET_ATTACH_WARN), strerror(errno));
243                  WarningAlert(str);
244                  goto open_error;
# Line 199 | Line 249 | bool ether_init(void)
249          ioctl(fd, FIONBIO, &nonblock);
250  
251          // Get Ethernet address
252 <        if (is_ethertap) {
252 >        if (net_if_type == NET_IF_ETHERTAP) {
253                  pid_t p = getpid();     // If configured for multicast, ethertap requires that the lower 32 bit of the Ethernet address are our PID
254                  ether_addr[0] = 0xfe;
255                  ether_addr[1] = 0xfd;
# Line 243 | Line 293 | void ether_exit(void)
293                  thread_active = false;
294          }
295  
296 +        // Shut down TUN/TAP interface
297 +        if (net_if_type == NET_IF_TUNTAP)
298 +                execute_network_script("down");
299 +
300 +        // Free TUN/TAP device name
301 +        if (net_if_name)
302 +                free(net_if_name);
303 +
304          // Close sheep_net device
305          if (fd > 0)
306                  close(fd);
249
250        // Remove all protocols
251        remove_all_protocols();
307   }
308  
309  
# Line 256 | Line 311 | void ether_exit(void)
311   *  Reset
312   */
313  
314 < void EtherReset(void)
314 > void ether_reset(void)
315   {
316 <        remove_all_protocols();
316 >        net_protocols.clear();
317   }
318  
319  
# Line 268 | Line 323 | void EtherReset(void)
323  
324   int16 ether_add_multicast(uint32 pb)
325   {
326 <        if (ioctl(fd, SIOCADDMULTI, Mac2HostAddr(pb + eMultiAddr)) < 0) {
326 >        if (net_if_type != NET_IF_TUNTAP && ioctl(fd, SIOCADDMULTI, Mac2HostAddr(pb + eMultiAddr)) < 0) {
327                  D(bug("WARNING: Couldn't enable multicast address\n"));
328 <                if (is_ethertap)
328 >                if (net_if_type == NET_IF_ETHERTAP)
329                          return noErr;
330                  else
331                          return eMultiErr;
# Line 285 | Line 340 | int16 ether_add_multicast(uint32 pb)
340  
341   int16 ether_del_multicast(uint32 pb)
342   {
343 <        if (ioctl(fd, SIOCDELMULTI, Mac2HostAddr(pb + eMultiAddr)) < 0) {
343 >        if (net_if_type != NET_IF_TUNTAP && ioctl(fd, SIOCDELMULTI, Mac2HostAddr(pb + eMultiAddr)) < 0) {
344                  D(bug("WARNING: Couldn't disable multicast address\n"));
345                  return eMultiErr;
346          } else
# Line 299 | Line 354 | int16 ether_del_multicast(uint32 pb)
354  
355   int16 ether_attach_ph(uint16 type, uint32 handler)
356   {
357 <        // Already attached?
303 <        NetProtocol *p = find_protocol(type);
304 <        if (p != NULL)
357 >        if (net_protocols.find(type) != net_protocols.end())
358                  return lapProtErr;
359 <        else {
360 <                // No, create and attach
308 <                p = new NetProtocol;
309 <                p->next = prot_list;
310 <                p->type = type;
311 <                p->handler = handler;
312 <                prot_list = p;
313 <                return noErr;
314 <        }
359 >        net_protocols[type] = handler;
360 >        return noErr;
361   }
362  
363  
# Line 321 | Line 367 | int16 ether_attach_ph(uint16 type, uint3
367  
368   int16 ether_detach_ph(uint16 type)
369   {
370 <        NetProtocol *p = find_protocol(type);
325 <        if (p != NULL) {
326 <                NetProtocol *q = prot_list;
327 <                if (p == q) {
328 <                        prot_list = p->next;
329 <                        delete p;
330 <                        return noErr;
331 <                }
332 <                while (q) {
333 <                        if (q->next == p) {
334 <                                q->next = p->next;
335 <                                delete p;
336 <                                return noErr;
337 <                        }
338 <                        q = q->next;
339 <                }
340 <                return lapProtErr;
341 <        } else
370 >        if (net_protocols.erase(type) == 0)
371                  return lapProtErr;
372 +        return noErr;
373   }
374  
375  
# Line 349 | Line 379 | int16 ether_detach_ph(uint16 type)
379  
380   int16 ether_write(uint32 wds)
381   {
352        // Set source address
353        uint32 hdr = ReadMacInt32(wds + 2);
354        Host2Mac_memcpy(hdr + 6, ether_addr, 6);
355
382          // Copy packet to buffer
383          uint8 packet[1516], *p = packet;
384          int len = 0;
385   #if defined(__linux__)
386 <        if (is_ethertap) {
386 >        if (net_if_type == NET_IF_ETHERTAP) {
387                  *p++ = 0;       // Linux ethertap discards the first 2 bytes
388                  *p++ = 0;
389                  len += 2;
# Line 458 | Line 484 | void EtherInterrupt(void)
484  
485                          // Read packet from sheep_net device
486   #if defined(__linux__)
487 <                        length = read(fd, packet, is_ethertap ? 1516 : 1514);
487 >                        length = read(fd, packet, net_if_type == NET_IF_ETHERTAP ? 1516 : 1514);
488   #else
489                          length = read(fd, packet, 1514);
490   #endif
# Line 476 | Line 502 | void EtherInterrupt(void)
502                          // Pointer to packet data (Ethernet header)
503                          uint8 *p = packet;
504   #if defined(__linux__)
505 <                        if (is_ethertap) {
505 >                        if (net_if_type == NET_IF_ETHERTAP) {
506                                  p += 2;                 // Linux ethertap has two random bytes before the packet
507                                  length -= 2;
508                          }
# Line 486 | Line 512 | void EtherInterrupt(void)
512                          uint16 type = (p[12] << 8) | p[13];
513  
514                          // Look for protocol
515 <                        NetProtocol *prot = find_protocol(type);
516 <                        if (prot == NULL)
515 >                        uint16 search_type = (type <= 1500 ? 0 : type);
516 >                        if (net_protocols.find(search_type) == net_protocols.end())
517                                  continue;
518 +                        uint32 handler = net_protocols[search_type];
519  
520                          // No default handler
521 <                        if (prot->handler == 0)
521 >                        if (handler == 0)
522                                  continue;
523  
524                          // Copy header to RHA
# Line 505 | Line 532 | void EtherInterrupt(void)
532                          r.a[0] = (uint32)p + 14;                                                // Pointer to packet (host address, for ReadPacket)
533                          r.a[3] = ether_data + ed_RHA + 14;                              // Pointer behind header in RHA
534                          r.a[4] = ether_data + ed_ReadPacket;                    // Pointer to ReadPacket/ReadRest routines
535 <                        D(bug(" calling protocol handler %08x, type %08x, length %08x, data %08x, rha %08x, read_packet %08x\n", prot->handler, r.d[0], r.d[1], r.a[0], r.a[3], r.a[4]));
536 <                        Execute68k(prot->handler, &r);
535 >                        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]));
536 >                        Execute68k(handler, &r);
537                  }
538          }
539  

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines