ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/ether.cpp
Revision: 1.5
Committed: 2001-07-12T19:48:25Z (23 years, 4 months ago) by cebix
Branch: MAIN
Changes since 1.4: +269 -37 lines
Log Message:
- Implemented AppleTalk-over-UDP tunnelling, activated by setting "udptunnel"
  to "true". This uses the BSD socket API, so it's fairly portable (currently
  only imeplemented under Unix, though). This works by sending raw Ethernet
  packets as UDP packets to a fixed port number ("udpport", default is 6066),
  using IP broadcasts to simulate Ethernet broad- and multicasts. Currently
  only tested with AppleTalk.

File Contents

# Content
1 /*
2 * ether.cpp - Ethernet device driver
3 *
4 * Basilisk II (C) 1997-2001 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
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 /*
22 * SEE ALSO
23 * Inside Macintosh: Devices, chapter 1 "Device Manager"
24 * Inside Macintosh: Networking, chapter 11 "Ethernet, Token Ring, and FDDI"
25 * Inside AppleTalk, chapter 3 "Ethernet and TokenTalk Link Access Protocols"
26 */
27
28 #include <string.h>
29
30 #include "sysdeps.h"
31 #include "cpu_emulation.h"
32 #include "main.h"
33 #include "macos_util.h"
34 #include "emul_op.h"
35 #include "prefs.h"
36 #include "ether.h"
37 #include "ether_defs.h"
38
39 #if SUPPORTS_UDP_TUNNEL
40 #include <netinet/in.h>
41 #include <sys/socket.h>
42 #include <sys/ioctl.h>
43 #include <netdb.h>
44 #include <errno.h>
45 #endif
46
47 #include <map>
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 // Global variables
60 uint8 ether_addr[6]; // Ethernet address (set by ether_init())
61 static bool net_open = false; // Flag: initialization succeeded, network device open (set by EtherInit())
62
63 static bool udp_tunnel = false; // Flag: tunnelling AppleTalk over UDP using BSD socket API
64 static uint16 udp_port;
65 static int udp_socket = -1;
66
67 // Mac address of driver data in MacOS RAM
68 uint32 ether_data = 0;
69
70 // Attached network protocols for UDP tunneling, maps protocol type to MacOS handler address
71 static map<uint16, uint32> udp_protocols;
72
73
74 /*
75 * Initialization
76 */
77
78 void EtherInit(void)
79 {
80 net_open = false;
81 udp_tunnel = false;
82
83 #if SUPPORTS_UDP_TUNNEL
84 // UDP tunnelling requested?
85 if (PrefsFindBool("udptunnel")) {
86 udp_tunnel = true;
87 udp_port = PrefsFindInt32("udpport");
88
89 // Open UDP socket
90 udp_socket = socket(PF_INET, SOCK_DGRAM, 0);
91 if (udp_socket < 0) {
92 perror("socket");
93 return;
94 }
95
96 // Bind to specified address and port
97 struct sockaddr_in sa;
98 memset(&sa, 0, sizeof(sa));
99 sa.sin_family = AF_INET;
100 sa.sin_addr.s_addr = INADDR_ANY;
101 sa.sin_port = htons(udp_port);
102 if (bind(udp_socket, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
103 perror("bind");
104 close(udp_socket);
105 udp_socket = -1;
106 return;
107 }
108
109 // Retrieve local IP address (or at least one of them)
110 socklen_t sa_len = sizeof(sa);
111 getsockname(udp_socket, (struct sockaddr *)&sa, &sa_len);
112 uint32 udp_ip = sa.sin_addr.s_addr;
113 if (udp_ip == INADDR_ANY || udp_ip == INADDR_LOOPBACK) {
114 char name[256];
115 gethostname(name, sizeof(name));
116 struct hostent *local = gethostbyname(name);
117 if (local)
118 udp_ip = *(uint32 *)local->h_addr_list[0];
119 }
120 udp_ip = ntohl(udp_ip);
121
122 // Construct dummy Ethernet address from local IP address
123 ether_addr[0] = 'B';
124 ether_addr[1] = '2';
125 ether_addr[2] = udp_ip >> 24;
126 ether_addr[3] = udp_ip >> 16;
127 ether_addr[4] = udp_ip >> 8;
128 ether_addr[5] = udp_ip;
129 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]));
130
131 // Set socket options
132 int on = 1;
133 setsockopt(udp_socket, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
134 ioctl(udp_socket, FIONBIO, &on);
135
136 // Start thread for packet reception
137 if (!ether_start_udp_thread(udp_socket)) {
138 close(udp_socket);
139 udp_socket = -1;
140 return;
141 }
142
143 net_open = true;
144 } else
145 #endif
146 if (ether_init())
147 net_open = true;
148 }
149
150
151 /*
152 * Deinitialization
153 */
154
155 void EtherExit(void)
156 {
157 if (net_open) {
158 #if SUPPORTS_UDP_TUNNEL
159 if (udp_tunnel) {
160 if (udp_socket >= 0) {
161 ether_stop_udp_thread();
162 close(udp_socket);
163 udp_socket = -1;
164 }
165 } else
166 #endif
167 ether_exit();
168 net_open = false;
169 }
170 }
171
172
173 /*
174 * Check whether Ethernet address is AppleTalk broadcast address
175 */
176
177 static inline bool is_apple_talk_broadcast(uint8 *p)
178 {
179 return p[0] == 0x09 && p[1] == 0x00 && p[2] == 0x07
180 && p[3] == 0xff && p[4] == 0xff && p[5] == 0xff;
181 }
182
183
184 /*
185 * Driver Open() routine
186 */
187
188 int16 EtherOpen(uint32 pb, uint32 dce)
189 {
190 D(bug("EtherOpen\n"));
191
192 // Allocate driver data
193 M68kRegisters r;
194 r.d[0] = SIZEOF_etherdata;
195 Execute68kTrap(0xa71e, &r); // NewPtrSysClear()
196 if (r.a[0] == 0)
197 return openErr;
198 ether_data = r.a[0];
199 D(bug(" data %08x\n", ether_data));
200
201 WriteMacInt16(ether_data + ed_DeferredTask + qType, dtQType);
202 WriteMacInt32(ether_data + ed_DeferredTask + dtAddr, ether_data + ed_Code);
203 WriteMacInt32(ether_data + ed_DeferredTask + dtParam, ether_data + ed_Result);
204 // Deferred function for signalling that packet write is complete (pointer to mydtResult in a1)
205 WriteMacInt16(ether_data + ed_Code, 0x2019); // move.l (a1)+,d0 (result)
206 WriteMacInt16(ether_data + ed_Code + 2, 0x2251); // move.l (a1),a1 (dce)
207 WriteMacInt32(ether_data + ed_Code + 4, 0x207808fc); // move.l JIODone,a0
208 WriteMacInt16(ether_data + ed_Code + 8, 0x4ed0); // jmp (a0)
209
210 WriteMacInt32(ether_data + ed_DCE, dce);
211 // ReadPacket/ReadRest routines
212 WriteMacInt16(ether_data + ed_ReadPacket, 0x6010); // bra 2
213 WriteMacInt16(ether_data + ed_ReadPacket + 2, 0x3003); // move.w d3,d0
214 WriteMacInt16(ether_data + ed_ReadPacket + 4, 0x9041); // sub.w d1,d0
215 WriteMacInt16(ether_data + ed_ReadPacket + 6, 0x4a43); // tst.w d3
216 WriteMacInt16(ether_data + ed_ReadPacket + 8, 0x6702); // beq 1
217 WriteMacInt16(ether_data + ed_ReadPacket + 10, M68K_EMUL_OP_ETHER_READ_PACKET);
218 WriteMacInt16(ether_data + ed_ReadPacket + 12, 0x3600); //1 move.w d0,d3
219 WriteMacInt16(ether_data + ed_ReadPacket + 14, 0x7000); // moveq #0,d0
220 WriteMacInt16(ether_data + ed_ReadPacket + 16, 0x4e75); // rts
221 WriteMacInt16(ether_data + ed_ReadPacket + 18, M68K_EMUL_OP_ETHER_READ_PACKET); //2
222 WriteMacInt16(ether_data + ed_ReadPacket + 20, 0x4a43); // tst.w d3
223 WriteMacInt16(ether_data + ed_ReadPacket + 22, 0x4e75); // rts
224 return 0;
225 }
226
227
228 /*
229 * Driver Control() routine
230 */
231
232 int16 EtherControl(uint32 pb, uint32 dce)
233 {
234 uint16 code = ReadMacInt16(pb + csCode);
235 D(bug("EtherControl %d\n", code));
236 switch (code) {
237 case 1: // KillIO
238 return -1;
239
240 case kENetAddMulti: // Add multicast address
241 D(bug(" AddMulti %08x%04x\n", ReadMacInt32(pb + eMultiAddr), ReadMacInt16(pb + eMultiAddr + 4)));
242 if (net_open && !udp_tunnel)
243 return ether_add_multicast(pb);
244 return noErr;
245
246 case kENetDelMulti: // Delete multicast address
247 D(bug(" DelMulti %08x%04x\n", ReadMacInt32(pb + eMultiAddr), ReadMacInt16(pb + eMultiAddr + 4)));
248 if (net_open && !udp_tunnel)
249 return ether_del_multicast(pb);
250 return noErr;
251
252 case kENetAttachPH: { // Attach protocol handler
253 uint16 type = ReadMacInt16(pb + eProtType);
254 uint32 handler = ReadMacInt32(pb + ePointer);
255 D(bug(" AttachPH prot %04x, handler %08x\n", type, handler));
256 if (net_open) {
257 if (udp_tunnel) {
258 if (udp_protocols.find(type) != udp_protocols.end())
259 return lapProtErr;
260 udp_protocols[type] = handler;
261 } else
262 return ether_attach_ph(type, handler);
263 }
264 return noErr;
265 }
266
267 case kENetDetachPH: { // Detach protocol handler
268 uint16 type = ReadMacInt16(pb + eProtType);
269 D(bug(" DetachPH prot %04x\n", type));
270 if (net_open) {
271 if (udp_tunnel) {
272 if (udp_protocols.erase(type) == 0)
273 return lapProtErr;
274 } else
275 return ether_detach_ph(type);
276 }
277 return noErr;
278 }
279
280 case kENetWrite: { // Transmit raw Ethernet packet
281 uint32 wds = ReadMacInt32(pb + ePointer);
282 D(bug(" EtherWrite\n"));
283 if (ReadMacInt16(wds) < 14)
284 return eLenErr; // Header incomplete
285 if (net_open) {
286 #if SUPPORTS_UDP_TUNNEL
287 if (udp_tunnel) {
288
289 // Copy packet to buffer
290 uint8 packet[1514];
291 int len = ether_wds_to_buffer(wds, packet);
292
293 // Set source address and extract destination address
294 memcpy(packet + 6, ether_addr, 6);
295 uint32 dest_ip;
296 if (packet[0] == 'B' && packet[1] == '2')
297 dest_ip = (packet[2] << 24) | (packet[3] << 16) | (packet[4] << 8) | packet[5];
298 else if (is_apple_talk_broadcast(packet))
299 dest_ip = INADDR_BROADCAST;
300 else
301 return eMultiErr;
302
303 #if MONITOR
304 bug("Sending Ethernet packet:\n");
305 for (int i=0; i<len; i++) {
306 bug("%02x ", packet[i]);
307 }
308 bug("\n");
309 #endif
310
311 // Send packet
312 struct sockaddr_in sa;
313 sa.sin_family = AF_INET;
314 sa.sin_addr.s_addr = htonl(dest_ip);
315 sa.sin_port = htons(udp_port);
316 if (sendto(udp_socket, packet, len, 0, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
317 D(bug("WARNING: Couldn't transmit packet\n"));
318 return excessCollsns;
319 }
320 } else
321 #endif
322 return ether_write(wds);
323 }
324 return noErr;
325 }
326
327 case kENetGetInfo: { // Get device information/statistics
328 D(bug(" GetInfo buf %08x, size %d\n", ReadMacInt32(pb + ePointer), ReadMacInt16(pb + eBuffSize)));
329
330 // Collect info (only ethernet address)
331 uint8 buf[18];
332 memset(buf, 0, 18);
333 memcpy(buf, ether_addr, 6);
334
335 // Transfer info to supplied buffer
336 int16 size = ReadMacInt16(pb + eBuffSize);
337 if (size > 18)
338 size = 18;
339 WriteMacInt16(pb + eDataSize, size); // Number of bytes actually written
340 Host2Mac_memcpy(ReadMacInt32(pb + ePointer), buf, size);
341 return noErr;
342 }
343
344 case kENetSetGeneral: // Set general mode (always in general mode)
345 D(bug(" SetGeneral\n"));
346 return noErr;
347
348 default:
349 printf("WARNING: Unknown EtherControl(%d)\n", code);
350 return controlErr;
351 }
352 }
353
354
355 /*
356 * Ethernet ReadPacket routine
357 */
358
359 void EtherReadPacket(uint8 **src, uint32 &dest, uint32 &len, uint32 &remaining)
360 {
361 D(bug("EtherReadPacket src %p, dest %08x, len %08x, remaining %08x\n", *src, dest, len, remaining));
362 uint32 todo = len > remaining ? remaining : len;
363 Host2Mac_memcpy(dest, *src, todo);
364 *src += todo;
365 dest += todo;
366 len -= todo;
367 remaining -= todo;
368 }
369
370
371 #if SUPPORTS_UDP_TUNNEL
372 /*
373 * Read packet from UDP socket
374 */
375
376 void ether_udp_read(uint8 *packet, int length, struct sockaddr_in *from)
377 {
378 // Drop packets sent by us
379 if (memcmp(packet + 6, ether_addr, 6) == 0)
380 return;
381
382 #if MONITOR
383 bug("Receiving Ethernet packet:\n");
384 for (int i=0; i<length; i++) {
385 bug("%02x ", packet[i]);
386 }
387 bug("\n");
388 #endif
389
390 // Get packet type
391 uint16 type = (packet[12] << 8) | packet[13];
392
393 // Look for protocol
394 uint16 search_type = (type <= 1500 ? 0 : type);
395 if (udp_protocols.find(search_type) == udp_protocols.end())
396 return;
397 uint32 handler = udp_protocols[search_type];
398 if (handler == 0)
399 return;
400
401 // Copy header to RHA
402 Host2Mac_memcpy(ether_data + ed_RHA, packet, 14);
403 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)));
404
405 // Call protocol handler
406 M68kRegisters r;
407 r.d[0] = type; // Packet type
408 r.d[1] = length - 14; // Remaining packet length (without header, for ReadPacket)
409 r.a[0] = (uint32)packet + 14; // Pointer to packet (host address, for ReadPacket)
410 r.a[3] = ether_data + ed_RHA + 14; // Pointer behind header in RHA
411 r.a[4] = ether_data + ed_ReadPacket; // Pointer to ReadPacket/ReadRest routines
412 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]));
413 Execute68k(handler, &r);
414 }
415 #endif