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

Comparing BasiliskII/src/ether.cpp (file contents):
Revision 1.1.1.1 by cebix, 1999-10-03T14:16:25Z vs.
Revision 1.16 by gbeauche, 2008-01-01T09:40:31Z

# Line 1 | Line 1
1   /*
2   *  ether.cpp - Ethernet device driver
3   *
4 < *  Basilisk II (C) 1997-1999 Christian Bauer
4 > *  Basilisk II (C) 1997-2008 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 25 | Line 25
25   *    Inside AppleTalk, chapter 3 "Ethernet and TokenTalk Link Access Protocols"
26   */
27  
28 + #include "sysdeps.h"
29 +
30   #include <string.h>
31 + #include <map>
32 +
33 + #if SUPPORTS_UDP_TUNNEL
34 + #include <netinet/in.h>
35 + #include <sys/socket.h>
36 + #include <sys/ioctl.h>
37 + #include <netdb.h>
38 + #include <unistd.h>
39 + #include <errno.h>
40 + #endif
41  
30 #include "sysdeps.h"
42   #include "cpu_emulation.h"
43   #include "main.h"
44   #include "macos_util.h"
45   #include "emul_op.h"
46 + #include "prefs.h"
47   #include "ether.h"
48   #include "ether_defs.h"
49  
50 + #ifndef NO_STD_NAMESPACE
51 + using std::map;
52 + #endif
53 +
54   #define DEBUG 0
55   #include "debug.h"
56  
57 + #define MONITOR 0
58 +
59 +
60 + #ifdef __BEOS__
61 + #define CLOSESOCKET closesocket
62 + #else
63 + #define CLOSESOCKET close
64 + #endif
65 +
66  
67   // Global variables
68 < uint8 ether_addr[6];    // Ethernet address (set by EtherInit())
69 < bool net_open = false;  // Flag: initialization succeeded, network device open (set by EtherInit())
68 > uint8 ether_addr[6];                    // Ethernet address (set by ether_init())
69 > static bool net_open = false;   // Flag: initialization succeeded, network device open (set by EtherInit())
70 >
71 > static bool udp_tunnel = false; // Flag: tunnelling AppleTalk over UDP using BSD socket API
72 > static uint16 udp_port;
73 > static int udp_socket = -1;
74 >
75 > // Mac address of driver data in MacOS RAM
76 > uint32 ether_data = 0;
77 >
78 > // Attached network protocols for UDP tunneling, maps protocol type to MacOS handler address
79 > static map<uint16, uint32> udp_protocols;
80 >
81 >
82 > /*
83 > *  Initialization
84 > */
85 >
86 > void EtherInit(void)
87 > {
88 >        net_open = false;
89 >        udp_tunnel = false;
90 >
91 > #if SUPPORTS_UDP_TUNNEL
92 >        // UDP tunnelling requested?
93 >        if (PrefsFindBool("udptunnel")) {
94 >                udp_tunnel = true;
95 >                udp_port = PrefsFindInt32("udpport");
96 >
97 >                // Open UDP socket
98 >                udp_socket = socket(PF_INET, SOCK_DGRAM, 0);
99 >                if (udp_socket < 0) {
100 >                        perror("socket");
101 >                        return;
102 >                }
103 >
104 >                // Bind to specified address and port
105 >                struct sockaddr_in sa;
106 >                memset(&sa, 0, sizeof(sa));
107 >                sa.sin_family = AF_INET;
108 >                sa.sin_addr.s_addr = INADDR_ANY;
109 >                sa.sin_port = htons(udp_port);
110 >                if (bind(udp_socket, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
111 >                        perror("bind");
112 >                        CLOSESOCKET(udp_socket);
113 >                        udp_socket = -1;
114 >                        return;
115 >                }
116 >
117 >                // Retrieve local IP address (or at least one of them)
118 >                socklen_t sa_length = sizeof(sa);
119 >                getsockname(udp_socket, (struct sockaddr *)&sa, &sa_length);
120 >                uint32 udp_ip = sa.sin_addr.s_addr;
121 >                if (udp_ip == INADDR_ANY || udp_ip == INADDR_LOOPBACK) {
122 >                        char name[256];
123 >                        gethostname(name, sizeof(name));
124 >                        struct hostent *local = gethostbyname(name);
125 >                        if (local)
126 >                                udp_ip = *(uint32 *)local->h_addr_list[0];
127 >                }
128 >                udp_ip = ntohl(udp_ip);
129 >
130 >                // Construct dummy Ethernet address from local IP address
131 >                ether_addr[0] = 'B';
132 >                ether_addr[1] = '2';
133 >                ether_addr[2] = udp_ip >> 24;
134 >                ether_addr[3] = udp_ip >> 16;
135 >                ether_addr[4] = udp_ip >> 8;
136 >                ether_addr[5] = udp_ip;
137 >                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]));
138 >
139 >                // Set socket options
140 >                int on = 1;
141 > #ifdef __BEOS__
142 >                setsockopt(udp_socket, SOL_SOCKET, SO_NONBLOCK, &on, sizeof(on));
143 > #else
144 >                setsockopt(udp_socket, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
145 >                ioctl(udp_socket, FIONBIO, &on);
146 > #endif
147 >
148 >                // Start thread for packet reception
149 >                if (!ether_start_udp_thread(udp_socket)) {
150 >                        CLOSESOCKET(udp_socket);
151 >                        udp_socket = -1;
152 >                        return;
153 >                }
154 >
155 >                net_open = true;
156 >        } else
157 > #endif
158 >                if (ether_init())
159 >                        net_open = true;
160 > }
161 >
162 >
163 > /*
164 > *  Deinitialization
165 > */
166 >
167 > void EtherExit(void)
168 > {
169 >        if (net_open) {
170 > #if SUPPORTS_UDP_TUNNEL
171 >                if (udp_tunnel) {
172 >                        if (udp_socket >= 0) {
173 >                                ether_stop_udp_thread();
174 >                                CLOSESOCKET(udp_socket);
175 >                                udp_socket = -1;
176 >                        }
177 >                } else
178 > #endif
179 >                        ether_exit();
180 >                net_open = false;
181 >        }
182 > }
183 >
184 >
185 > /*
186 > *  Reset
187 > */
188 >
189 > void EtherReset(void)
190 > {
191 >        udp_protocols.clear();
192 >        ether_reset();
193 > }
194 >
195 >
196 > /*
197 > *  Check whether Ethernet address is AppleTalk or Ethernet broadcast address
198 > */
199  
200 < uint32 ether_data = 0;  // Mac address of driver data in MacOS RAM
200 > static inline bool is_apple_talk_broadcast(uint8 *p)
201 > {
202 >        return p[0] == 0x09 && p[1] == 0x00 && p[2] == 0x07
203 >            && p[3] == 0xff && p[4] == 0xff && p[5] == 0xff;
204 > }
205 >
206 > static inline bool is_ethernet_broadcast(uint8 *p)
207 > {
208 >        return p[0] == 0xff && p[1] == 0xff && p[2] == 0xff
209 >            && p[3] == 0xff && p[4] == 0xff && p[5] == 0xff;
210 > }
211  
212  
213   /*
# Line 61 | Line 225 | int16 EtherOpen(uint32 pb, uint32 dce)
225          if (r.a[0] == 0)
226                  return openErr;
227          ether_data = r.a[0];
228 <        D(bug(" data %08lx\n", ether_data));
228 >        D(bug(" data %08x\n", ether_data));
229  
230          WriteMacInt16(ether_data + ed_DeferredTask + qType, dtQType);
231          WriteMacInt32(ether_data + ed_DeferredTask + dtAddr, ether_data + ed_Code);
# Line 99 | Line 263 | int16 EtherControl(uint32 pb, uint32 dce
263          uint16 code = ReadMacInt16(pb + csCode);
264          D(bug("EtherControl %d\n", code));
265          switch (code) {
266 <                case 1:         // KillIO
266 >                case 1:                                 // KillIO
267                          return -1;
268  
269                  case kENetAddMulti:             // Add multicast address
270 <                        D(bug("AddMulti %08lx%04x\n", ReadMacInt32(pb + eMultiAddr), ReadMacInt16(pb + eMultiAddr + 4)));
271 <                        if (net_open)
270 >                        D(bug(" AddMulti %08x%04x\n", ReadMacInt32(pb + eMultiAddr), ReadMacInt16(pb + eMultiAddr + 4)));
271 >                        if (net_open && !udp_tunnel)
272                                  return ether_add_multicast(pb);
273 <                        else
110 <                                return noErr;
273 >                        return noErr;
274  
275                  case kENetDelMulti:             // Delete multicast address
276 <                        D(bug("DelMulti %08lx%04x\n", ReadMacInt32(pb + eMultiAddr), ReadMacInt16(pb + eMultiAddr + 4)));
277 <                        if (net_open)
276 >                        D(bug(" DelMulti %08x%04x\n", ReadMacInt32(pb + eMultiAddr), ReadMacInt16(pb + eMultiAddr + 4)));
277 >                        if (net_open && !udp_tunnel)
278                                  return ether_del_multicast(pb);
279 <                        else
280 <                                return noErr;
279 >                        return noErr;
280 >
281 >                case kENetAttachPH: {   // Attach protocol handler
282 >                        uint16 type = ReadMacInt16(pb + eProtType);
283 >                        uint32 handler = ReadMacInt32(pb + ePointer);
284 >                        D(bug(" AttachPH prot %04x, handler %08x\n", type, handler));
285 >                        if (net_open) {
286 >                                if (udp_tunnel) {
287 >                                        if (udp_protocols.find(type) != udp_protocols.end())
288 >                                                return lapProtErr;
289 >                                        udp_protocols[type] = handler;
290 >                                } else
291 >                                        return ether_attach_ph(type, handler);
292 >                        }
293 >                        return noErr;
294 >                }
295 >
296 >                case kENetDetachPH: {   // Detach protocol handler
297 >                        uint16 type = ReadMacInt16(pb + eProtType);
298 >                        D(bug(" DetachPH prot %04x\n", type));
299 >                        if (net_open) {
300 >                                if (udp_tunnel) {
301 >                                        if (udp_protocols.erase(type) == 0)
302 >                                                return lapProtErr;
303 >                                } else
304 >                                        return ether_detach_ph(type);
305 >                        }
306 >                        return noErr;
307 >                }
308  
309 <                case kENetAttachPH:             // Attach protocol handler
310 <                        D(bug("AttachPH prot %04x, handler %08lx\n", ReadMacInt16(pb + eProtType), ReadMacInt32(pb + ePointer)));
311 <                        if (net_open)
312 <                                return ether_attach_ph(ReadMacInt16(pb + eProtType), ReadMacInt32(pb + ePointer));
123 <                        else
124 <                                return noErr;
125 <
126 <                case kENetDetachPH:             // Detach protocol handler
127 <                        D(bug("DetachPH prot %04x\n", ReadMacInt16(pb + eProtType)));
128 <                        if (net_open)
129 <                                return ether_detach_ph(ReadMacInt16(pb + eProtType));
130 <                        else
131 <                                return noErr;
132 <
133 <                case kENetWrite:                // Transmit raw Ethernet packet
134 <                        D(bug("EtherWrite\n"));
135 <                        if (ReadMacInt16(ReadMacInt32(pb + ePointer)) < 14)
309 >                case kENetWrite: {              // Transmit raw Ethernet packet
310 >                        uint32 wds = ReadMacInt32(pb + ePointer);
311 >                        D(bug(" EtherWrite "));
312 >                        if (ReadMacInt16(wds) < 14)
313                                  return eLenErr; // Header incomplete
314 <                        if (net_open)
315 <                                return ether_write(ReadMacInt32(pb + ePointer));
316 <                        else
317 <                                return noErr;
314 >
315 >                        // Set source address
316 >                        uint32 hdr = ReadMacInt32(wds + 2);
317 >                        Host2Mac_memcpy(hdr + 6, ether_addr, 6);
318 >                        D(bug("to %08x%04x, type %04x\n", ReadMacInt32(hdr), ReadMacInt16(hdr + 4), ReadMacInt16(hdr + 12)));
319 >
320 >                        if (net_open) {
321 > #if SUPPORTS_UDP_TUNNEL
322 >                                if (udp_tunnel) {
323 >
324 >                                        // Copy packet to buffer
325 >                                        uint8 packet[1514];
326 >                                        int len = ether_wds_to_buffer(wds, packet);
327 >
328 >                                        // Extract destination address
329 >                                        uint32 dest_ip;
330 >                                        if (packet[0] == 'B' && packet[1] == '2')
331 >                                                dest_ip = (packet[2] << 24) | (packet[3] << 16) | (packet[4] << 8) | packet[5];
332 >                                        else if (is_apple_talk_broadcast(packet) || is_ethernet_broadcast(packet))
333 >                                                dest_ip = INADDR_BROADCAST;
334 >                                        else
335 >                                                return eMultiErr;
336 >
337 > #if MONITOR
338 >                                        bug("Sending Ethernet packet:\n");
339 >                                        for (int i=0; i<len; i++) {
340 >                                                bug("%02x ", packet[i]);
341 >                                        }
342 >                                        bug("\n");
343 > #endif
344 >
345 >                                        // Send packet
346 >                                        struct sockaddr_in sa;
347 >                                        sa.sin_family = AF_INET;
348 >                                        sa.sin_addr.s_addr = htonl(dest_ip);
349 >                                        sa.sin_port = htons(udp_port);
350 >                                        if (sendto(udp_socket, packet, len, 0, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
351 >                                                D(bug("WARNING: Couldn't transmit packet\n"));
352 >                                                return excessCollsns;
353 >                                        }
354 >                                } else
355 > #endif
356 >                                        return ether_write(wds);
357 >                        }
358 >                        return noErr;
359 >                }
360  
361                  case kENetGetInfo: {    // Get device information/statistics
362 <                        D(bug("GetInfo buf %08lx, size %d\n", ReadMacInt32(pb + ePointer), ReadMacInt16(pb + eBuffSize)));
362 >                        D(bug(" GetInfo buf %08x, size %d\n", ReadMacInt32(pb + ePointer), ReadMacInt16(pb + eBuffSize)));
363  
364                          // Collect info (only ethernet address)
365                          uint8 buf[18];
# Line 152 | Line 371 | int16 EtherControl(uint32 pb, uint32 dce
371                          if (size > 18)
372                                  size = 18;
373                          WriteMacInt16(pb + eDataSize, size);    // Number of bytes actually written
374 <                        memcpy(Mac2HostAddr(ReadMacInt32(pb + ePointer)), buf, size);
374 >                        Host2Mac_memcpy(ReadMacInt32(pb + ePointer), buf, size);
375                          return noErr;
376                  }
377  
378                  case kENetSetGeneral:   // Set general mode (always in general mode)
379 <                        D(bug("SetGeneral\n"));
379 >                        D(bug(" SetGeneral\n"));
380                          return noErr;
381  
382                  default:
# Line 171 | Line 390 | int16 EtherControl(uint32 pb, uint32 dce
390   *  Ethernet ReadPacket routine
391   */
392  
393 < void EtherReadPacket(uint8 **src, uint32 &dest, uint32 &len, uint32 &remaining)
393 > void EtherReadPacket(uint32 &src, uint32 &dest, uint32 &len, uint32 &remaining)
394   {
395 <        D(bug("EtherReadPacket src %08lx, dest %08lx, len %08lx, remaining %08lx\n", *src, dest, len, remaining));
395 >        D(bug("EtherReadPacket src %08x, dest %08x, len %08x, remaining %08x\n", src, dest, len, remaining));
396          uint32 todo = len > remaining ? remaining : len;
397 <        memcpy(Mac2HostAddr(dest), *src, todo);
398 <        *src += todo;
397 >        Mac2Mac_memcpy(dest, src, todo);
398 >        src += todo;
399          dest += todo;
400          len -= todo;
401          remaining -= todo;
402   }
403 +
404 +
405 + #if SUPPORTS_UDP_TUNNEL
406 + /*
407 + *  Read packet from UDP socket
408 + */
409 +
410 + void ether_udp_read(uint32 packet, int length, struct sockaddr_in *from)
411 + {
412 +        // Drop packets sent by us
413 +        if (memcmp(Mac2HostAddr(packet) + 6, ether_addr, 6) == 0)
414 +                return;
415 +
416 + #if MONITOR
417 +        bug("Receiving Ethernet packet:\n");
418 +        for (int i=0; i<length; i++) {
419 +                bug("%02x ", ReadMacInt8(packet + i));
420 +        }
421 +        bug("\n");
422 + #endif
423 +
424 +        // Get packet type
425 +        uint16 type = ReadMacInt16(packet + 12);
426 +
427 +        // Look for protocol
428 +        uint16 search_type = (type <= 1500 ? 0 : type);
429 +        if (udp_protocols.find(search_type) == udp_protocols.end())
430 +                return;
431 +        uint32 handler = udp_protocols[search_type];
432 +        if (handler == 0)
433 +                return;
434 +
435 +        // Copy header to RHA
436 +        Mac2Mac_memcpy(ether_data + ed_RHA, packet, 14);
437 +        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)));
438 +
439 +        // Call protocol handler
440 +        M68kRegisters r;
441 +        r.d[0] = type;                                                                  // Packet type
442 +        r.d[1] = length - 14;                                                   // Remaining packet length (without header, for ReadPacket)
443 +        r.a[0] = packet + 14;                                                   // Pointer to packet (Mac address, for ReadPacket)
444 +        r.a[3] = ether_data + ed_RHA + 14;                              // Pointer behind header in RHA
445 +        r.a[4] = ether_data + ed_ReadPacket;                    // Pointer to ReadPacket/ReadRest routines
446 +        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]));
447 +        Execute68k(handler, &r);
448 + }
449 + #endif
450 +
451 +
452 + /*
453 + *  Ethernet packet allocator
454 + */
455 +
456 + #if SIZEOF_VOID_P != 4 || REAL_ADDRESSING == 0
457 + static uint32 ether_packet = 0;                 // Ethernet packet (cached allocation)
458 + static uint32 n_ether_packets = 0;              // Number of ethernet packets allocated so far (should be at most 1)
459 +
460 + EthernetPacket::EthernetPacket()
461 + {
462 +        ++n_ether_packets;
463 +        if (ether_packet && n_ether_packets == 1)
464 +                packet = ether_packet;
465 +        else {
466 +        M68kRegisters r;
467 +        r.d[0] = 1516;
468 +        Execute68kTrap(0xa71e, &r);             // NewPtrSysClear()
469 +                assert(r.a[0] != 0);
470 +                packet = r.a[0];
471 +                if (ether_packet == 0)
472 +                        ether_packet = packet;
473 +        }
474 + }
475 +
476 + EthernetPacket::~EthernetPacket()
477 + {
478 +        --n_ether_packets;
479 +        if (packet != ether_packet) {
480 +                M68kRegisters r;
481 +                r.a[0] = packet;
482 +                Execute68kTrap(0xa01f, &r);             // DisposePtr
483 +        }
484 +        if (n_ether_packets > 0) {
485 +                bug("WARNING: Nested allocation of ethernet packets!\n");
486 +        }
487 + }
488 + #endif

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines