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.4 by cebix, 2001-02-02T20:52:57Z vs.
Revision 1.10 by cebix, 2002-01-17T20:31:01Z

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines