diff --git a/BasiliskII/src/MacOSX/etherslavetool.c b/BasiliskII/src/MacOSX/etherslavetool.c new file mode 100644 index 00000000..08a18d97 --- /dev/null +++ b/BasiliskII/src/MacOSX/etherslavetool.c @@ -0,0 +1,277 @@ +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include + +#include + +static int openBpf(char *ifname); +static int retreiveAuthInfo(void); +static int mainLoop(int sd); + +int main(int argc, char **argv) { + char *ifName; + int ret; + int sd; + + if(argc != 2) { + return 255; + } + + ifName = argv[1]; + + ret = retreiveAuthInfo(); + if(ret != 0) { + return 254; + } + + fflush(stdout); + + sd = openBpf(ifName); + if(sd < 0) { + return 253; + } + + fflush(stdout); + + ret = mainLoop(sd); + + close(sd); + + if(ret < 0) { + return 252; + } + + return 0; +} + +static int mainLoop(int sd) { + fd_set readSet; + char *outgoing, *incoming; + unsigned short *outLen; + unsigned short *inLen; + int inIndex, outIndex; + u_int blen = 0; + int ret; + int fret = 0; + struct bpf_hdr *hdr; + int pktLen; + int frameLen; + int pad; + + if(ioctl(sd, BIOCGBLEN, &blen) < 0) { + return -1; + } + + incoming = malloc(blen); + if(incoming == NULL) { + return -2; + } + + outgoing = malloc(blen); + if(outgoing == NULL) { + free(outgoing); + return -3; + } + + inIndex = 0; + outIndex = 0; + + outLen = (unsigned short *)outgoing; + + while(1) { + int i; + FD_ZERO(&readSet); + FD_SET(0, &readSet); + FD_SET(sd, &readSet); + + ret = select(sd + 1, &readSet, NULL, NULL, NULL); + if(ret < 0) { + fret = -4; + break; + } + + if(FD_ISSET(0, &readSet)) { + if(outIndex < 2) { + ret = read(0, outgoing + outIndex, 2-outIndex); + } else { + ret = read(0, outgoing + outIndex, *outLen - outIndex + 2); + } + + if(ret < 1) { + fret = -5; + break; + } + + outIndex += ret; + if(outIndex > 1) { + fflush(stdout); + + if((*outLen + 2) > blen) { + fret = -6; + break; + } + + if(outIndex == (*outLen + 2)) { + ret = write(sd, outLen + 1, *outLen); + if(ret != *outLen) { + fret = -7; + break; + } + outIndex = 0; + } + } + + } + + if(FD_ISSET(sd, &readSet)) { + int i; + + ret = read(sd, incoming, blen); + if(ret < 1) { + fret = -8; + break; + } + + hdr = (struct bpf_hdr *)incoming; + inLen = (unsigned short *)(incoming + 16); + + do { + pktLen = hdr->bh_caplen; + frameLen = pktLen + 18; + + if((pktLen < 0) || (frameLen > ret) || (frameLen < 0)) { + fret = -9; + break; + } + *inLen = pktLen; + + write(0, inLen, pktLen + 2); + if((frameLen & 0x03) == 0) { + pad = 0; + } else { + pad = 4 - (frameLen & 0x03); + } + + ret -= (frameLen + pad); + hdr = (struct bpf_hdr *)((unsigned char *)hdr + frameLen + pad); + inLen = (unsigned short *)((unsigned char *)hdr + 16); + } while (ret > 0); + + if(fret != 0) { + break; + } + } + } + + free(incoming); + free(outgoing); + + return fret; +} + +static int retreiveAuthInfo(void) { + AuthorizationRef aRef; + OSStatus status; + AuthorizationRights myRights; + AuthorizationRights *newRights; + AuthorizationItem *myItem; + AuthorizationItem myItems[1]; + AuthorizationItemSet *mySet; + int i; + + status = AuthorizationCopyPrivilegedReference(&aRef, kAuthorizationFlagDefaults); + if(status != errAuthorizationSuccess) { + return -1; + } + + status = AuthorizationCopyInfo(aRef, NULL, &mySet); + if(status != errAuthorizationSuccess) { + AuthorizationFree(aRef, kAuthorizationFlagDestroyRights); + return -1; + } + + myItems[0].name = "system.privilege.admin"; + myItems[0].valueLength = 0; + myItems[0].value = NULL; + myItems[0].flags = 0; + + myRights.count = sizeof (myItems) / sizeof (myItems[0]); + myRights.items = myItems; + + status = AuthorizationCopyRights(aRef, &myRights, NULL, + kAuthorizationFlagExtendRights, + &newRights); + if(status != errAuthorizationSuccess) { + AuthorizationFreeItemSet(mySet); + AuthorizationFree(aRef, kAuthorizationFlagDestroyRights); + return -2; + } + + AuthorizationFreeItemSet(newRights); + AuthorizationFreeItemSet(mySet); + AuthorizationFree(aRef, kAuthorizationFlagDestroyRights); + + return 0; +} + +static int openBpf(char *ifname) { + u_int blen = 0; + struct ifreq ifreq; + u_int arg; + + int sd = open("/dev/bpf2", O_RDWR); + + if(sd < 0) { + return -1; + } + + if(ioctl(sd, BIOCGBLEN, &blen) < 0) { + close(sd); + return -2; + } + + bzero(&ifreq, sizeof(ifreq)); + strncpy(ifreq.ifr_name, ifname, IFNAMSIZ); + + arg = 0; + if(ioctl(sd, BIOCSETIF, &ifreq) < 0) { + close(sd); + return -3; + } + + arg = 0; + if(ioctl(sd, BIOCSSEESENT, &arg) < 0) { + close(sd); + return -4; + } + + arg = 1; + if(ioctl(sd, BIOCPROMISC, &arg) < 0) { + close(sd); + return -5; + } + + arg = 1; + if(ioctl(sd, BIOCIMMEDIATE, &arg) < 0) { + close(sd); + return -6; + } + + return sd; +} diff --git a/BasiliskII/src/MacOSX/runtool.m b/BasiliskII/src/MacOSX/runtool.m new file mode 100644 index 00000000..64f39f9d --- /dev/null +++ b/BasiliskII/src/MacOSX/runtool.m @@ -0,0 +1,79 @@ +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include + +#include + +FILE * runTool(const char *ifName); + +FILE * runTool(const char *ifName) { + OSStatus authStatus; + FILE *fp; + char *args[] = {"ethsheeptool", NULL, NULL}; + int ret; + const char *path; + + path = [[[NSBundle mainBundle] + pathForResource:@"etherslavetool" ofType: nil] UTF8String]; + + if(path == NULL) { + return NULL; + } + + AuthorizationFlags authFlags; + AuthorizationRef authRef; + AuthorizationItem authItems[1]; + AuthorizationRights authRights; + + args[1] = (char *)ifName; + + authFlags = kAuthorizationFlagExtendRights | + kAuthorizationFlagInteractionAllowed | + kAuthorizationFlagPreAuthorize; + + authItems[0].name = "system.privilege.admin"; + authItems[0].valueLength = 0; + authItems[0].value = NULL; + authItems[0].flags = 0; + + authRights.count = sizeof (authItems) / sizeof (authItems[0]); + authRights.items = authItems; + + authStatus = AuthorizationCreate(&authRights, + kAuthorizationEmptyEnvironment, + authFlags, + &authRef); + + if(authStatus != errAuthorizationSuccess) { + fprintf(stderr, "%s: AuthorizationCreate() failed.\n", __func__); + return NULL; + } + + authStatus = AuthorizationExecuteWithPrivileges(authRef, + path, + kAuthorizationFlagDefaults, + args + 1, + &fp); + + if(authStatus != errAuthorizationSuccess) { + fprintf(stderr, "%s: AuthorizationExecWithPrivileges() failed.\n", __func__); + return NULL; + } + + return fp; +} diff --git a/BasiliskII/src/Unix/.gitignore b/BasiliskII/src/Unix/.gitignore index cc9e93f6..6d074222 100644 --- a/BasiliskII/src/Unix/.gitignore +++ b/BasiliskII/src/Unix/.gitignore @@ -1,6 +1,7 @@ # Object files obj/* BasiliskII +etherslavetool # Autotools generated files Makefile diff --git a/BasiliskII/src/Unix/Makefile.in b/BasiliskII/src/Unix/Makefile.in index e50326a8..57a1c9d9 100644 --- a/BasiliskII/src/Unix/Makefile.in +++ b/BasiliskII/src/Unix/Makefile.in @@ -74,6 +74,10 @@ CXXFLAGS += $(GUI_CFLAGS) LIBS += $(GUI_LIBS) endif +ifeq (@MACOSX_ETHERSLAVE@,yes) +PROGS += etherslavetool +endif + ## Rules .PHONY: modules install installdirs uninstall mostlyclean clean distclean depend dep .SUFFIXES: @@ -138,6 +142,9 @@ $(GUI_APP)_app: $(GUI_APP) ../MacOSX/Info.plist ../MacOSX/$(APP).icns mkdir -p $(GUI_APP_APP)/Contents/Resources ./cpr.sh ../MacOSX/$(APP).icns $(GUI_APP_APP)/Contents/Resources/$(GUI_APP).icns +etherslavetool: ../MacOSX/etherslavetool.c + $(CC) $(CPPFLAGS) $(DEFS) $(CFLAGS) $(LIBS) $< -o $@ + modules: cd Linux/NetDriver; make diff --git a/BasiliskII/src/Unix/configure.ac b/BasiliskII/src/Unix/configure.ac index 62d45f57..93ff7aac 100644 --- a/BasiliskII/src/Unix/configure.ac +++ b/BasiliskII/src/Unix/configure.ac @@ -21,6 +21,9 @@ AC_ARG_ENABLE(standalone-gui,[ --enable-standalone-gui enable a standalone GUI dnl Mac OS X GUI. AC_ARG_ENABLE(macosx-gui, [ --enable-macosx-gui enable Mac OS X GUI [default=no]], [WANT_MACOSX_GUI=$enableval], [WANT_MACOSX_GUI=no]) +dnl Mac OS X etherslave support +AC_ARG_ENABLE(macosx-etherslave, [ --enable-macosx-etherslave enable Mac OS X Sound [default=no]], [WANT_MACOSX_ETHERSLAVE=$enableval], [WANT_MACOSX_ETHERSLAVE=no]) + dnl Video options. AC_ARG_ENABLE(xf86-dga, [ --enable-xf86-dga use the XFree86 DGA extension [default=yes]], [WANT_XF86_DGA=$enableval], [WANT_XF86_DGA=yes]) AC_ARG_ENABLE(xf86-vidmode, [ --enable-xf86-vidmode use the XFree86 VidMode extension [default=yes]], [WANT_XF86_VIDMODE=$enableval], [WANT_XF86_VIDMODE=yes]) @@ -724,6 +727,14 @@ else EXTRASYSSRCS="$EXTRASYSSRCS main_unix.cpp prefs_unix.cpp" fi +if [[ "x$WANT_MACOSX_ETHERSLAVE" = "xyes" ]]; then + EXTRASYSSRCS="$EXTRASYSSRCS ../MacOSX/runtool.m" + LIBS="$LIBS -framework Security" + AC_DEFINE(ENABLE_MACOSX_ETHERSLAVE, 1, [Define if supporting "etherslave" network device.]) +fi + +AC_SUBST(MACOSX_ETHERSLAVE, $WANT_MACOSX_ETHERSLAVE) + dnl SDL overrides if [[ "x$WANT_SDL" = "xyes" ]]; then AC_DEFINE(USE_SDL, 1, [Define to enble SDL support]) diff --git a/BasiliskII/src/Unix/ether_unix.cpp b/BasiliskII/src/Unix/ether_unix.cpp index 526ee29c..a2c07d2a 100644 --- a/BasiliskII/src/Unix/ether_unix.cpp +++ b/BasiliskII/src/Unix/ether_unix.cpp @@ -41,6 +41,12 @@ #endif #include #include + +#ifdef ENABLE_MACOSX_ETHERSLAVE +#include +#include +#endif + #include #include #include @@ -93,9 +99,17 @@ enum { NET_IF_SHEEPNET, NET_IF_ETHERTAP, NET_IF_TUNTAP, - NET_IF_SLIRP + NET_IF_SLIRP, + NET_IF_ETHERSLAVE }; + +#ifdef ENABLE_MACOSX_ETHERSLAVE +extern "C" { + extern FILE * runTool(const char *ifName); +} +#endif + // Constants #if ENABLE_TUNTAP static const char ETHERCONFIG_FILE_NAME[] = DATADIR "/tunconfig"; @@ -122,6 +136,11 @@ static uint8 ether_addr[6]; // Our Ethernet address const bool ether_driver_opened = true; // Flag: is the MacOS driver opened? #endif + +#ifdef ENABLE_MACOSX_ETHERSLAVE +static uint8 packet_buffer[2048]; +#endif + // Attached network protocols, maps protocol type to MacOS handler address static map net_protocols; @@ -135,6 +154,11 @@ static void ether_do_interrupt(void); static void slirp_add_redirs(); static int slirp_add_redir(const char *redir_str); +#ifdef ENABLE_MACOSX_ETHERSLAVE +static int getmacaddress(const char* dev, unsigned char *addr); +static bool openEtherSlave(const char *ifName); +static int readpacket(void); +#endif /* * Start packet reception thread @@ -235,6 +259,9 @@ bool ether_init(void) // Do nothing if no Ethernet device specified const char *name = PrefsFindString("ether"); +#ifdef ENABLE_MACOSX_ETHERSLAVE + const char *slaveDev = PrefsFindString("etherslavedev"); +#endif if (name == NULL) return false; @@ -249,6 +276,10 @@ bool ether_init(void) #ifdef HAVE_SLIRP else if (strcmp(name, "slirp") == 0) net_if_type = NET_IF_SLIRP; +#endif +#ifdef ENABLE_MACOSX_ETHERSLAVE + else if (strcmp(name, "etherslave") == 0) + net_if_type = NET_IF_ETHERSLAVE; #endif else net_if_type = NET_IF_SHEEPNET; @@ -300,6 +331,14 @@ bool ether_init(void) case NET_IF_SHEEPNET: strcpy(dev_name, "/dev/sheep_net"); break; +#ifdef ENABLE_MACOSX_ETHERSLAVE + case NET_IF_ETHERSLAVE: + if(slaveDev == NULL) { + WarningAlert("etherslavedev not defined in preferences."); + return false; + } + return openEtherSlave(slaveDev); +#endif } if (net_if_type != NET_IF_SLIRP) { fd = open(dev_name, O_RDWR); @@ -750,6 +789,21 @@ static int16 ether_do_write(uint32 arg) write(slirp_input_fd, packet, len); return noErr; } else +#endif +#ifdef ENABLE_MACOSX_ETHERSLAVE + if (net_if_type == NET_IF_ETHERSLAVE) { + unsigned short pktlen; + + pktlen = len; + if(write(fd, &pktlen, 2) < 2) { + return excessCollsns; + } + + if(write(fd, packet, len) < len) { + return excessCollsns; + } + return noErr; + } else #endif if (write(fd, packet, len) < 0) { D(bug("WARNING: Couldn't transmit packet\n")); @@ -884,6 +938,13 @@ static void *receive_func(void *arg) if (res <= 0) break; +#ifdef ENABLE_MACOSX_ETHERSLAVE + if (net_if_type == NET_IF_ETHERSLAVE) { + if(readpacket() < 1) { + break; + } + } +#endif if (ether_driver_opened) { // Trigger Ethernet interrupt D(bug(" packet received, triggering Ethernet interrupt\n")); @@ -923,6 +984,18 @@ void ether_do_interrupt(void) ether_udp_read(packet, length, &from); } else +#endif +#ifdef ENABLE_MACOSX_ETHERSLAVE + if (net_if_type == NET_IF_ETHERSLAVE) { + unsigned short *pktlen; + uint32 p = packet; + + pktlen = (unsigned short *)packet_buffer; + length = *pktlen; + memcpy(Mac2HostAddr(packet), pktlen + 1, length); + ether_dispatch_packet(p, length); + break; + } else #endif { @@ -1049,3 +1122,110 @@ static int slirp_add_redir(const char *redir_str) WarningAlert(str); return -1; } + +#ifdef ENABLE_MACOSX_ETHERSLAVE +static int getmacaddress(const char* dev, unsigned char *addr) +{ + struct ifaddrs *ifaddrs, *next; + int ret = -1; + struct sockaddr_dl *sa; + + if(getifaddrs(&ifaddrs) != 0) { + perror("getifaddrs"); + return -1; + } + + next = ifaddrs; + while(next != NULL) { + switch(next->ifa_addr->sa_family) { + case AF_LINK: + if(!strcmp(dev, next->ifa_name)) { + sa = (struct sockaddr_dl *)next->ifa_addr; + memcpy(addr, LLADDR(sa), 6); + ret = 0; + } + break; + default: + break; + } + next = next->ifa_next; + } + + freeifaddrs(ifaddrs); + + return ret; +} + +static bool openEtherSlave(const char *ifName) +{ + FILE *fp; + char str[64]; + + str[sizeof(str)-1] = '\0'; + + if(getmacaddress(ifName, ether_addr) != 0) { + snprintf(str, sizeof(str)-1, "Unable to find interface %s.", + ifName); + WarningAlert(str); + return false; + } + + fp = runTool(ifName); + if(fp == NULL) { + snprintf(str, sizeof(str)-1, "Unable to run ether slave helper tool."); + WarningAlert(str); + return false; + } + + fd = dup(fileno(fp)); + fclose(fp); + + if(start_thread() == false) { + close(fd); + fd = -1; + return false; + } + + return true; +} + +static int readpacket() +{ + int index; + unsigned short *pktLen; + int ret = -1; + + pktLen = (unsigned short *)packet_buffer; + + index = 0; + while(1) { + if(index < 2) { + ret = read(fd, packet_buffer + index, 2 - index); + } else { + ret = read(fd, packet_buffer + index, *pktLen - index + 2); + } + + if(ret < 1) { + fprintf(stderr, "%s: read() returned %d.\n", __func__, ret); + break; + } + + index += ret; + + if(index > 1) { + if(*pktLen > (sizeof(packet_buffer) + 2)) { + fprintf(stderr, "%s: pktLen (%d) too large.\n", __func__, *pktLen); + break; + } + + if(index == (*pktLen + 2)) { + ret = *pktLen; + break; + } + } + } + + return ret; +} + +#endif diff --git a/BasiliskII/src/Unix/prefs_unix.cpp b/BasiliskII/src/Unix/prefs_unix.cpp index a92cd640..43f70fb6 100644 --- a/BasiliskII/src/Unix/prefs_unix.cpp +++ b/BasiliskII/src/Unix/prefs_unix.cpp @@ -40,6 +40,9 @@ prefs_desc platform_prefs_items[] = { {"mixer", TYPE_STRING, false, "audio mixer device name"}, #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION {"ignoresegv", TYPE_BOOLEAN, false, "ignore illegal memory accesses"}, +#endif +#ifdef ENABLE_MACOSX_ETHERSLAVE + {"etherslavedev", TYPE_STRING, false, "ethernet device for etherslave ethernet"}, #endif {"idlewait", TYPE_BOOLEAN, false, "sleep when idle"}, {NULL, TYPE_END, false, NULL} // End of list