--- BasiliskII/src/ether.cpp 2001/02/02 20:52:57 1.4 +++ BasiliskII/src/ether.cpp 2001/07/12 19:48:25 1.5 @@ -32,18 +32,153 @@ #include "main.h" #include "macos_util.h" #include "emul_op.h" +#include "prefs.h" #include "ether.h" #include "ether_defs.h" +#if SUPPORTS_UDP_TUNNEL +#include +#include +#include +#include +#include +#endif + +#include + +#ifndef NO_STD_NAMESPACE +using std::map; +#endif + #define DEBUG 0 #include "debug.h" +#define MONITOR 0 + // Global variables -uint8 ether_addr[6]; // Ethernet address (set by EtherInit()) -bool net_open = false; // Flag: initialization succeeded, network device open (set by EtherInit()) +uint8 ether_addr[6]; // Ethernet address (set by ether_init()) +static bool net_open = false; // Flag: initialization succeeded, network device open (set by EtherInit()) + +static bool udp_tunnel = false; // Flag: tunnelling AppleTalk over UDP using BSD socket API +static uint16 udp_port; +static int udp_socket = -1; + +// Mac address of driver data in MacOS RAM +uint32 ether_data = 0; -uint32 ether_data = 0; // Mac address of driver data in MacOS RAM +// Attached network protocols for UDP tunneling, maps protocol type to MacOS handler address +static map udp_protocols; + + +/* + * Initialization + */ + +void EtherInit(void) +{ + net_open = false; + udp_tunnel = false; + +#if SUPPORTS_UDP_TUNNEL + // UDP tunnelling requested? + if (PrefsFindBool("udptunnel")) { + udp_tunnel = true; + udp_port = PrefsFindInt32("udpport"); + + // Open UDP socket + udp_socket = socket(PF_INET, SOCK_DGRAM, 0); + if (udp_socket < 0) { + perror("socket"); + return; + } + + // Bind to specified address and port + struct sockaddr_in sa; + memset(&sa, 0, sizeof(sa)); + sa.sin_family = AF_INET; + sa.sin_addr.s_addr = INADDR_ANY; + sa.sin_port = htons(udp_port); + if (bind(udp_socket, (struct sockaddr *)&sa, sizeof(sa)) < 0) { + perror("bind"); + close(udp_socket); + udp_socket = -1; + return; + } + + // Retrieve local IP address (or at least one of them) + socklen_t sa_len = sizeof(sa); + getsockname(udp_socket, (struct sockaddr *)&sa, &sa_len); + uint32 udp_ip = sa.sin_addr.s_addr; + if (udp_ip == INADDR_ANY || udp_ip == INADDR_LOOPBACK) { + char name[256]; + gethostname(name, sizeof(name)); + struct hostent *local = gethostbyname(name); + if (local) + udp_ip = *(uint32 *)local->h_addr_list[0]; + } + udp_ip = ntohl(udp_ip); + + // Construct dummy Ethernet address from local IP address + ether_addr[0] = 'B'; + ether_addr[1] = '2'; + ether_addr[2] = udp_ip >> 24; + ether_addr[3] = udp_ip >> 16; + ether_addr[4] = udp_ip >> 8; + ether_addr[5] = udp_ip; + 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])); + + // Set socket options + int on = 1; + setsockopt(udp_socket, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)); + ioctl(udp_socket, FIONBIO, &on); + + // Start thread for packet reception + if (!ether_start_udp_thread(udp_socket)) { + close(udp_socket); + udp_socket = -1; + return; + } + + net_open = true; + } else +#endif + if (ether_init()) + net_open = true; +} + + +/* + * Deinitialization + */ + +void EtherExit(void) +{ + if (net_open) { +#if SUPPORTS_UDP_TUNNEL + if (udp_tunnel) { + if (udp_socket >= 0) { + ether_stop_udp_thread(); + close(udp_socket); + udp_socket = -1; + } + } else +#endif + ether_exit(); + net_open = false; + } +} + + +/* + * Check whether Ethernet address is AppleTalk broadcast address + */ + +static inline bool is_apple_talk_broadcast(uint8 *p) +{ + return p[0] == 0x09 && p[1] == 0x00 && p[2] == 0x07 + && p[3] == 0xff && p[4] == 0xff && p[5] == 0xff; +} /* @@ -61,7 +196,7 @@ int16 EtherOpen(uint32 pb, uint32 dce) if (r.a[0] == 0) return openErr; ether_data = r.a[0]; - D(bug(" data %08lx\n", ether_data)); + D(bug(" data %08x\n", ether_data)); WriteMacInt16(ether_data + ed_DeferredTask + qType, dtQType); WriteMacInt32(ether_data + ed_DeferredTask + dtAddr, ether_data + ed_Code); @@ -99,48 +234,98 @@ int16 EtherControl(uint32 pb, uint32 dce uint16 code = ReadMacInt16(pb + csCode); D(bug("EtherControl %d\n", code)); switch (code) { - case 1: // KillIO + case 1: // KillIO return -1; case kENetAddMulti: // Add multicast address - D(bug("AddMulti %08lx%04x\n", ReadMacInt32(pb + eMultiAddr), ReadMacInt16(pb + eMultiAddr + 4))); - if (net_open) + D(bug(" AddMulti %08x%04x\n", ReadMacInt32(pb + eMultiAddr), ReadMacInt16(pb + eMultiAddr + 4))); + if (net_open && !udp_tunnel) return ether_add_multicast(pb); - else - return noErr; + return noErr; case kENetDelMulti: // Delete multicast address - D(bug("DelMulti %08lx%04x\n", ReadMacInt32(pb + eMultiAddr), ReadMacInt16(pb + eMultiAddr + 4))); - if (net_open) + D(bug(" DelMulti %08x%04x\n", ReadMacInt32(pb + eMultiAddr), ReadMacInt16(pb + eMultiAddr + 4))); + if (net_open && !udp_tunnel) return ether_del_multicast(pb); - else - return noErr; + return noErr; + + case kENetAttachPH: { // Attach protocol handler + uint16 type = ReadMacInt16(pb + eProtType); + uint32 handler = ReadMacInt32(pb + ePointer); + D(bug(" AttachPH prot %04x, handler %08x\n", type, handler)); + if (net_open) { + if (udp_tunnel) { + if (udp_protocols.find(type) != udp_protocols.end()) + return lapProtErr; + udp_protocols[type] = handler; + } else + return ether_attach_ph(type, handler); + } + return noErr; + } + + case kENetDetachPH: { // Detach protocol handler + uint16 type = ReadMacInt16(pb + eProtType); + D(bug(" DetachPH prot %04x\n", type)); + if (net_open) { + if (udp_tunnel) { + if (udp_protocols.erase(type) == 0) + return lapProtErr; + } else + return ether_detach_ph(type); + } + return noErr; + } - case kENetAttachPH: // Attach protocol handler - D(bug("AttachPH prot %04x, handler %08lx\n", ReadMacInt16(pb + eProtType), ReadMacInt32(pb + ePointer))); - if (net_open) - return ether_attach_ph(ReadMacInt16(pb + eProtType), ReadMacInt32(pb + ePointer)); - else - return noErr; - - case kENetDetachPH: // Detach protocol handler - D(bug("DetachPH prot %04x\n", ReadMacInt16(pb + eProtType))); - if (net_open) - return ether_detach_ph(ReadMacInt16(pb + eProtType)); - else - return noErr; - - case kENetWrite: // Transmit raw Ethernet packet - D(bug("EtherWrite\n")); - if (ReadMacInt16(ReadMacInt32(pb + ePointer)) < 14) + case kENetWrite: { // Transmit raw Ethernet packet + uint32 wds = ReadMacInt32(pb + ePointer); + D(bug(" EtherWrite\n")); + if (ReadMacInt16(wds) < 14) return eLenErr; // Header incomplete - if (net_open) - return ether_write(ReadMacInt32(pb + ePointer)); - else - return noErr; + if (net_open) { +#if SUPPORTS_UDP_TUNNEL + if (udp_tunnel) { + + // Copy packet to buffer + uint8 packet[1514]; + int len = ether_wds_to_buffer(wds, packet); + + // Set source address and extract destination address + memcpy(packet + 6, ether_addr, 6); + uint32 dest_ip; + if (packet[0] == 'B' && packet[1] == '2') + dest_ip = (packet[2] << 24) | (packet[3] << 16) | (packet[4] << 8) | packet[5]; + else if (is_apple_talk_broadcast(packet)) + dest_ip = INADDR_BROADCAST; + else + return eMultiErr; + +#if MONITOR + bug("Sending Ethernet packet:\n"); + for (int i=0; i remaining ? remaining : len; Host2Mac_memcpy(dest, *src, todo); *src += todo; @@ -181,3 +366,50 @@ void EtherReadPacket(uint8 **src, uint32 len -= todo; remaining -= todo; } + + +#if SUPPORTS_UDP_TUNNEL +/* + * Read packet from UDP socket + */ + +void ether_udp_read(uint8 *packet, int length, struct sockaddr_in *from) +{ + // Drop packets sent by us + if (memcmp(packet + 6, ether_addr, 6) == 0) + return; + +#if MONITOR + bug("Receiving Ethernet packet:\n"); + for (int i=0; i