fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

mac: Switch to vmnet networking on macOS, rename scsi_tap to scsi_net

This uses the native vmnet framework instead of requiring a 3rd
party tap/tun kernel driver. Unfortunately there is no way to
configure this without root permissions, like we can by setting
permissions on a tap device.

Also fix the SCSI mode selection in mac_scsi_cmd_set_interface_mode
and mac_scsi_cmd_set_mcast_addr. These get data sent by the driver
so we need to be in the data out phase. This fixes the error in Mac
OS when switching the AppleTalk connection to EtherTalk, so now
EtherTalk works properly and we can do AppleShare over emulated
ethernet.

+402 -17
+4
Makefile.dep
··· 3223 3223 src/config.h \ 3224 3224 src/lib/tun.h 3225 3225 3226 + src/lib/vmnet.o: src/lib/vmnet.m \ 3227 + src/config.h \ 3228 + src/lib/vmnet.h 3229 + 3226 3230 src/libini/expr.o: src/libini/expr.c \ 3227 3231 src/config.h \ 3228 3232 src/libini/libini.h \
+1
Makefile.inc.in
··· 94 94 PCE_READLINE_LIBS := @PCE_READLINE_LIBS@ 95 95 96 96 PCE_ENABLE_TUN := @PCE_ENABLE_TUN@ 97 + PCE_ENABLE_VMNET := @PCE_ENABLE_VMNET@ 97 98 98 99 PCE_ENABLE_CHAR_POSIX := @PCE_ENABLE_CHAR_POSIX@ 99 100 PCE_ENABLE_CHAR_PPP := @PCE_ENABLE_CHAR_PPP@
+53
configure
··· 660 660 PCE_ENABLE_CHAR_PTY 661 661 PCE_ENABLE_CHAR_PPP 662 662 PCE_ENABLE_CHAR_POSIX 663 + PCE_ENABLE_VMNET 663 664 PCE_ENABLE_TUN 664 665 PCE_BUILD_SPECTRUM 665 666 PCE_BUILD_VIC20 ··· 782 783 enable_vic20 783 784 enable_spectrum 784 785 enable_tun 786 + enable_vmnet 785 787 enable_char_posix 786 788 enable_char_ppp 787 789 enable_char_pty ··· 1440 1442 --enable-vic20 Enable the VIC20 emulator [yes] 1441 1443 --enable-spectrum Enable the ZX Spectrum emulator [yes] 1442 1444 --enable-tun Enable tun networking [guessed] 1445 + --enable-vmnet Enable vmnet networking [guessed] 1443 1446 --enable-char-posix Enable the posix file character driver [guessed] 1444 1447 --enable-char-ppp Enable the PPP character driver [guessed] 1445 1448 --enable-char-pty Enable the pty character driver [guessed] ··· 4309 4312 printf "%s\n" "#define HAVE_UNISTD_H 1" >>confdefs.h 4310 4313 4311 4314 fi 4315 + ac_fn_c_check_header_compile "$LINENO" "vmnet/vmnet.h" "ac_cv_header_vmnet_vmnet_h" "$ac_includes_default" 4316 + if test "x$ac_cv_header_vmnet_vmnet_h" = xyes 4317 + then : 4318 + printf "%s\n" "#define HAVE_VMNET_VMNET_H 1" >>confdefs.h 4319 + 4320 + fi 4312 4321 4313 4322 4314 4323 ac_fn_c_check_header_compile "$LINENO" "stdint.h" "ac_cv_header_stdint_h" "$ac_includes_default" ··· 5625 5634 fi 5626 5635 5627 5636 5637 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable vmnet" >&5 5638 + printf %s "checking whether to enable vmnet... " >&6; } 5639 + # Check whether --enable-vmnet was given. 5640 + if test ${enable_vmnet+y} 5641 + then : 5642 + enableval=$enable_vmnet; 5643 + if test "x$enableval" = "xyes" ; then 5644 + PCE_ENABLE_VMNET=1 5645 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 5646 + printf "%s\n" "yes" >&6; } 5647 + else 5648 + PCE_ENABLE_VMNET=0 5649 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 5650 + printf "%s\n" "no" >&6; } 5651 + fi 5652 + 5653 + else $as_nop 5654 + 5655 + PCE_ENABLE_VMNET=1 5656 + test "x$ac_cv_header_vmnet_vmnet_h" = "xyes" || PCE_ENABLE_VMNET=0 5657 + if test "x$PCE_ENABLE_VMNET" = "x1" ; then 5658 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes (guess)" >&5 5659 + printf "%s\n" "yes (guess)" >&6; } 5660 + else 5661 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no (guess)" >&5 5662 + printf "%s\n" "no (guess)" >&6; } 5663 + fi 5664 + 5665 + 5666 + fi 5667 + 5668 + 5669 + if test "x$PCE_ENABLE_VMNET" = "x1" ; then 5670 + printf "%s\n" "#define PCE_ENABLE_VMNET 1" >>confdefs.h 5671 + 5672 + fi 5673 + 5674 + 5628 5675 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable the posix file character driver" >&5 5629 5676 printf %s "checking whether to enable the posix file character driver... " >&6; } 5630 5677 # Check whether --enable-char-posix was given. ··· 6318 6365 option1="$option1 tun" 6319 6366 else 6320 6367 option2="$option2 tun" 6368 + fi 6369 + 6370 + if test "x$PCE_ENABLE_VMNET" = "x1" ; then 6371 + option1="$option1 vmnet" 6372 + else 6373 + option2="$option2 vmnet" 6321 6374 fi 6322 6375 6323 6376
+35 -1
configure.ac
··· 202 202 sys/time.h \ 203 203 sys/types.h \ 204 204 termios.h \ 205 - unistd.h 205 + unistd.h \ 206 + vmnet/vmnet.h 206 207 ) 207 208 208 209 AC_CHECK_HEADER(stdint.h, ··· 667 668 fi 668 669 669 670 671 + AC_MSG_CHECKING([whether to enable vmnet]) 672 + AC_ARG_ENABLE(vmnet, 673 + [AS_HELP_STRING([--enable-vmnet], [Enable vmnet networking [guessed]])], 674 + [ 675 + if test "x$enableval" = "xyes" ; then 676 + PCE_ENABLE_VMNET=1 677 + AC_MSG_RESULT([yes]) 678 + else 679 + PCE_ENABLE_VMNET=0 680 + AC_MSG_RESULT([no]) 681 + fi 682 + ],[ 683 + PCE_ENABLE_VMNET=1 684 + test "x$ac_cv_header_vmnet_vmnet_h" = "xyes" || PCE_ENABLE_VMNET=0 685 + if test "x$PCE_ENABLE_VMNET" = "x1" ; then 686 + AC_MSG_RESULT([yes (guess)]) 687 + else 688 + AC_MSG_RESULT([no (guess)]) 689 + fi 690 + ] 691 + ) 692 + AC_SUBST(PCE_ENABLE_VMNET) 693 + if test "x$PCE_ENABLE_VMNET" = "x1" ; then 694 + AC_DEFINE(PCE_ENABLE_VMNET) 695 + fi 696 + 697 + 670 698 AC_MSG_CHECKING([whether to enable the posix file character driver]) 671 699 AC_ARG_ENABLE(char-posix, 672 700 [AS_HELP_STRING([--enable-char-posix], [Enable the posix file character driver [guessed]])], ··· 1136 1164 option1="$option1 tun" 1137 1165 else 1138 1166 option2="$option2 tun" 1167 + fi 1168 + 1169 + if test "x$PCE_ENABLE_VMNET" = "x1" ; then 1170 + option1="$option1 vmnet" 1171 + else 1172 + option2="$option2 vmnet" 1139 1173 fi 1140 1174 1141 1175
+7 -2
src/arch/macplus/Makefile.inc
··· 51 51 msg \ 52 52 rtc \ 53 53 scsi \ 54 - scsi_tap \ 54 + scsi_net \ 55 55 serial \ 56 56 sony \ 57 57 sound \ ··· 101 101 PCE_MACPLUS_OBJ_EXT += src/lib/tun.o 102 102 endif 103 103 104 + ifeq "$(PCE_ENABLE_VMNET)" "1" 105 + PCE_MACPLUS_OBJ_EXT += src/lib/vmnet.o 106 + PCE_MACPLUS_LIBS += -lobjc -framework vmnet 107 + endif 108 + 104 109 ifeq "$(PCE_BUILD_MACPLUS)" "1" 105 110 BIN += $(PCE_MACPLUS_BIN) 106 111 ETC += $(PCE_MACPLUS_ETC) ··· 126 131 $(rel)/msg.o: $(rel)/msg.c 127 132 $(rel)/rtc.o: $(rel)/rtc.c 128 133 $(rel)/scsi.o: $(rel)/scsi.c 129 - $(rel)/scsi_tap.o: $(rel)/scsi_tap.c 134 + $(rel)/scsi_net.o: $(rel)/scsi_net.c 130 135 $(rel)/serial.o: $(rel)/serial.c 131 136 $(rel)/sony.o: $(rel)/sony.c 132 137 $(rel)/sound.o: $(rel)/sound.c
+9 -3
src/arch/macplus/macplus.c
··· 1087 1087 mem_blk_t *blk; 1088 1088 unsigned long addr, size; 1089 1089 unsigned id, drive, ethernet; 1090 - const char *vendor, *product, *mac_addr, *tap_dev, *tap_cmd; 1090 + const char *vendor, *product, *mac_addr, *tap_dev, *tap_cmd, *bridge_if; 1091 1091 1092 1092 sct = ini_next_sct (ini, NULL, "scsi"); 1093 1093 ··· 1144 1144 ini_get_string (sctdev, "tap", &tap_dev, "/dev/tap0"); 1145 1145 ini_get_string (sctdev, "tap_cmd", &tap_cmd, ""); 1146 1146 ini_get_string (sctdev, "mac_addr", &mac_addr, "00:80:19:c0:ff:ee"); 1147 + ini_get_string (sctdev, "bridge_if", &bridge_if, ""); 1147 1148 1148 1149 pce_log_tag (MSG_INF, 1149 1150 "SCSI:", 1151 + #if PCE_ENABLE_VMNET 1152 + "id=%u ethernet=%u bridge=%s mac_addr=%s\n", 1153 + id, ethernet, bridge_if, mac_addr 1154 + #else 1150 1155 "id=%u ethernet=%u tap=%s cmd=%s mac_addr=%s\n", 1151 1156 id, ethernet, tap_dev, tap_cmd, mac_addr 1157 + #endif 1152 1158 ); 1153 1159 1154 - mac_scsi_set_ethernet (&sim->scsi, id, tap_dev, tap_cmd, mac_addr); 1160 + mac_scsi_set_ethernet (&sim->scsi, id, tap_dev, tap_cmd, mac_addr, bridge_if); 1155 1161 } 1156 1162 1157 1163 sctdev = ini_next_sct (sct, sctdev, "device"); ··· 1309 1315 if (sim->trm != NULL) { 1310 1316 mac_video_set_terminal (sim->video, sim->trm); 1311 1317 1312 - trm_open (sim->trm, 512, 342); 1318 + trm_open (sim->trm, w, h); 1313 1319 } 1314 1320 1315 1321 mac_video_set_color (sim->video, col0, col1);
+19 -7
src/arch/macplus/scsi.c
··· 191 191 } 192 192 } 193 193 194 - void mac_scsi_set_ethernet (mac_scsi_t *scsi, unsigned id, const char *tap_dev, const char *tap_cmd, const char *mac_addr) 194 + void mac_scsi_set_ethernet (mac_scsi_t *scsi, unsigned id, const char *tap_dev, const char *tap_cmd, const char *mac_addr, const char *bridge_if) 195 195 { 196 196 int mac_addr_ints[6]; 197 197 int ret; ··· 207 207 208 208 strlcpy (scsi->dev[id].tap_dev, tap_dev, sizeof(scsi->dev[id].tap_dev)); 209 209 strlcpy (scsi->dev[id].tap_cmd, tap_cmd, sizeof(scsi->dev[id].tap_cmd)); 210 + strlcpy (scsi->dev[id].bridge_if, bridge_if, sizeof(scsi->dev[id].bridge_if)); 210 211 211 212 ret = sscanf(mac_addr, "%x:%x:%x:%x:%x:%x", 212 213 &mac_addr_ints[0], &mac_addr_ints[1], ··· 219 220 pce_log (MSG_ERR, "*** invalid MAC address (%s)\n", mac_addr); 220 221 } 221 222 222 - if (mac_scsi_ethernet_tap_open (scsi, &scsi->dev[id]) == 0) { 223 + if (mac_scsi_ethernet_open (scsi, &scsi->dev[id]) == 0) { 223 224 scsi->dev[id].valid = 1; 224 225 } 225 226 } ··· 1063 1064 1064 1065 switch (cmd) { 1065 1066 case 0x40: 1066 - /* set MAC */ 1067 + /* set MAC (noop) */ 1068 + scsi->buf_i = 0; 1069 + scsi->buf_n = 6; 1070 + 1071 + scsi->cmd_finish = mac_scsi_cmd_write6_finish; 1072 + 1073 + mac_scsi_set_phase_data_out (scsi); 1067 1074 break; 1068 1075 1069 1076 case 0x80: 1070 - /* set mode */ 1077 + /* set mode (noop) */ 1078 + mac_scsi_set_phase_status (scsi, 0x02); 1071 1079 break; 1072 1080 1073 1081 default: 1074 1082 mac_log_deb ("scsi: unknown interface mode command (%02X)\n", cmd); 1083 + mac_scsi_set_phase_status (scsi, 0x02); 1075 1084 } 1076 - 1077 - mac_scsi_set_phase_status (scsi, 0x02); 1078 1085 } 1079 1086 1080 1087 static ··· 1089 1096 return; 1090 1097 } 1091 1098 1092 - mac_scsi_set_phase_status (scsi, 0x02); 1099 + scsi->buf_i = 0; 1100 + scsi->buf_n = scsi->cmd[4]; 1101 + 1102 + scsi->cmd_finish = mac_scsi_cmd_write6_finish; 1103 + 1104 + mac_scsi_set_phase_data_out (scsi); 1093 1105 } 1094 1106 1095 1107 static
+10 -2
src/arch/macplus/scsi.h
··· 28 28 29 29 #include <drivers/block/block.h> 30 30 31 + #if PCE_ENABLE_VMNET 32 + #include <lib/vmnet.h> 33 + #endif 34 + 31 35 enum { 32 36 MAC_SCSI_DEV_UNKNOWN, 33 37 MAC_SCSI_DEV_DISK, ··· 51 55 char tap_dev[PATH_MAX]; 52 56 char tap_cmd[PATH_MAX]; 53 57 int tap_fd; 58 + #if PCE_ENABLE_VMNET 59 + char bridge_if[20]; 60 + struct pce_vmnet_interface *vmnet; 61 + #endif 54 62 } mac_scsi_dev_t; 55 63 56 64 ··· 105 113 void mac_scsi_set_drive (mac_scsi_t *scsi, unsigned id, unsigned drive); 106 114 void mac_scsi_set_drive_vendor (mac_scsi_t *scsi, unsigned id, const char *vendor); 107 115 void mac_scsi_set_drive_product (mac_scsi_t *scsi, unsigned id, const char *product); 108 - void mac_scsi_set_ethernet (mac_scsi_t *scsi, unsigned id, const char *tap_dev, const char *tap_cmd, const char *mac_addr); 116 + void mac_scsi_set_ethernet (mac_scsi_t *scsi, unsigned id, const char *tap_dev, const char *tap_cmd, const char *mac_addr, const char *bridge_if); 109 117 110 118 unsigned char mac_scsi_get_uint8 (void *ext, unsigned long addr); 111 119 unsigned short mac_scsi_get_uint16 (void *ext, unsigned long addr); ··· 115 123 116 124 void mac_scsi_reset (mac_scsi_t *scsi); 117 125 118 - int mac_scsi_ethernet_tap_open (mac_scsi_t *scsi, mac_scsi_dev_t *dev); 126 + int mac_scsi_ethernet_open (mac_scsi_t *scsi, mac_scsi_dev_t *dev); 119 127 int mac_scsi_ethernet_data_avail (mac_scsi_dev_t *dev); 120 128 size_t mac_scsi_ethernet_read (mac_scsi_dev_t *dev, unsigned char *buf); 121 129 size_t mac_scsi_ethernet_write (mac_scsi_dev_t *dev, unsigned char *buf, size_t len);
+38 -2
src/arch/macplus/scsi_tap.c src/arch/macplus/scsi_net.c
··· 3 3 *****************************************************************************/ 4 4 5 5 /***************************************************************************** 6 - * File name: src/arch/macplus/scsi_tap.c * 6 + * File name: src/arch/macplus/scsi_net.c * 7 7 * Created: 2022-05-01 by joshua stein <jcs@jcs.org> * 8 8 * Copyright: (C) 2022 joshua stein <jcs@jcs.org> * 9 9 *****************************************************************************/ ··· 31 31 #include <poll.h> 32 32 #include <sys/fcntl.h> 33 33 #include <sys/types.h> 34 - int mac_scsi_ethernet_tap_open (mac_scsi_t *scsi, mac_scsi_dev_t *dev) 34 + 35 + int mac_scsi_ethernet_open (mac_scsi_t *scsi, mac_scsi_dev_t *dev) 35 36 { 37 + #if PCE_ENABLE_VMNET 38 + dev->vmnet = pce_vmnet_start (dev->bridge_if); 39 + if (dev->vmnet == NULL) { 40 + pce_log (MSG_ERR, "*** failed creating vmnet interface\n"); 41 + return - 1; 42 + } 43 + #else 36 44 char tap_cmd_sh[1024]; 37 45 38 46 dev->tap_fd = -1; ··· 58 66 pce_log (MSG_ERR, "*** tap command failed (%s)\n", strerror(errno)); 59 67 } 60 68 } 69 + #endif 61 70 62 71 return 0; 63 72 } ··· 66 75 { 67 76 struct pollfd fds; 68 77 78 + #if PCE_ENABLE_VMNET 79 + if (dev->vmnet == NULL) 80 + return 0; 81 + return (dev->vmnet->packets_available > 0 ? 1 : 0); 82 + #else 69 83 fds.fd = dev->tap_fd; 70 84 fds.events = POLLIN | POLLERR; 71 85 if (poll (&fds, 1, 0) < 1) { ··· 76 90 } 77 91 78 92 return 0; 93 + #endif 79 94 } 80 95 81 96 size_t mac_scsi_ethernet_read (mac_scsi_dev_t *dev, unsigned char *buf) 82 97 { 98 + #if PCE_ENABLE_VMNET 99 + size_t ret; 100 + 101 + if (dev->vmnet == NULL) 102 + return 0; 103 + 104 + ret = pce_vmnet_read(dev->vmnet, buf, 1514); 105 + if (ret == 0) 106 + dev->vmnet->packets_available = 0; 107 + return ret; 108 + #else 83 109 if (dev->tap_fd < 0) { 84 110 return 0; 85 111 } ··· 89 115 } 90 116 91 117 return read (dev->tap_fd, buf, 1514); 118 + #endif 92 119 } 93 120 94 121 size_t mac_scsi_ethernet_write (mac_scsi_dev_t *dev, unsigned char *buf, size_t len) 95 122 { 123 + #if PCE_ENABLE_VMNET 124 + size_t ret; 125 + 126 + if (dev->vmnet == NULL) 127 + return 0; 128 + 129 + return (pce_vmnet_write(dev->vmnet, buf, len) == 0 ? len : 0); 130 + #else 96 131 if (dev->tap_fd < 0) { 97 132 return 0; 98 133 } 99 134 100 135 return write (dev->tap_fd, buf, len); 136 + #endif 101 137 }
+2
src/config.h.in
··· 95 95 96 96 #undef PCE_ENABLE_TUN 97 97 98 + #undef PCE_ENABLE_VMNET 99 + 98 100 #undef PCE_ENABLE_CHAR_POSIX 99 101 #undef PCE_ENABLE_CHAR_PPP 100 102 #undef PCE_ENABLE_CHAR_PTY
+6
src/lib/Makefile.inc
··· 37 37 DIST += $(rel)/tun.c $(rel)/tun.h 38 38 endif 39 39 40 + ifeq "$(PCE_ENABLE_VMNET)" "1" 41 + LIBPCE_BAS += vmnet 42 + else 43 + DIST += $(rel)/vmnet.m $(rel)/vmnet.h 44 + endif 45 + 40 46 LIBPCE_SRC := $(foreach f,$(LIBPCE_BAS),$(rel)/$(f).c) 41 47 LIBPCE_OBJ := $(foreach f,$(LIBPCE_BAS),$(rel)/$(f).o) 42 48 LIBPCE_HDR := $(foreach f,$(LIBPCE_BAS),$(rel)/$(f).h)
+39
src/lib/vmnet.h
··· 1 + /***************************************************************************** 2 + * pce * 3 + *****************************************************************************/ 4 + 5 + /***************************************************************************** 6 + * File name: src/lib/vmnet.h * 7 + * Created: 2022-09-18 by joshua stein <jcs@jcs.org> * 8 + * Copyright: (C) 2022 joshua stein <jcs@jcs.org> * 9 + *****************************************************************************/ 10 + 11 + /***************************************************************************** 12 + * This program is free software. You can redistribute it and / or modify it * 13 + * under the terms of the GNU General Public License version 2 as published * 14 + * by the Free Software Foundation. * 15 + * * 16 + * This program is distributed in the hope that it will be useful, but * 17 + * WITHOUT ANY WARRANTY, without even the implied warranty of * 18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * 19 + * Public License for more details. * 20 + *****************************************************************************/ 21 + 22 + #ifndef PCE_LIB_VMNET_H 23 + #define PCE_LIB_VMNET_H 1 24 + 25 + #include <sys/uio.h> 26 + #include <vmnet/vmnet.h> 27 + 28 + struct pce_vmnet_interface { 29 + interface_ref interface; 30 + dispatch_queue_t if_queue; 31 + unsigned int packets_available; 32 + }; 33 + 34 + struct pce_vmnet_interface * pce_vmnet_start (char *bridge_if); 35 + void pce_vmnet_stop (struct pce_vmnet_interface *vi); 36 + int pce_vmnet_write (struct pce_vmnet_interface *vi, void *buf, size_t size); 37 + size_t pce_vmnet_read (struct pce_vmnet_interface *vi, void *buf, size_t size); 38 + 39 + #endif
+179
src/lib/vmnet.m
··· 1 + /***************************************************************************** 2 + * pce * 3 + *****************************************************************************/ 4 + 5 + /***************************************************************************** 6 + * File name: src/lib/vmnet.m * 7 + * Created: 2022-09-18 by joshua stein <jcs@jcs.org> * 8 + * Copyright: (C) 2022 joshua stein <jcs@jcs.org> * 9 + *****************************************************************************/ 10 + 11 + /***************************************************************************** 12 + * This program is free software. You can redistribute it and / or modify it * 13 + * under the terms of the GNU General Public License version 2 as published * 14 + * by the Free Software Foundation. * 15 + * * 16 + * This program is distributed in the hope that it will be useful, but * 17 + * WITHOUT ANY WARRANTY, without even the implied warranty of * 18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * 19 + * Public License for more details. * 20 + *****************************************************************************/ 21 + 22 + #include "log.h" 23 + 24 + #import "vmnet.h" 25 + 26 + struct pce_vmnet_interface * pce_vmnet_start (char *bridge_if) 27 + { 28 + __block struct pce_vmnet_interface *ret; 29 + __block vmnet_return_t if_status; 30 + 31 + ret = malloc (sizeof(struct pce_vmnet_interface)); 32 + if (ret == NULL) { 33 + return NULL; 34 + } 35 + 36 + memset (ret, 0, sizeof(struct pce_vmnet_interface)); 37 + 38 + ret->if_queue = dispatch_queue_create ("ch.hampa.pce.vmnet", DISPATCH_QUEUE_SERIAL); 39 + dispatch_semaphore_t if_start_sem = dispatch_semaphore_create (0); 40 + 41 + xpc_object_t if_desc = xpc_dictionary_create (NULL, NULL, 0); 42 + 43 + if (bridge_if == NULL || bridge_if[0] == '\0') { 44 + xpc_dictionary_set_uint64 (if_desc, vmnet_operation_mode_key, VMNET_SHARED_MODE); 45 + xpc_dictionary_set_string (if_desc, vmnet_start_address_key, "10.10.10.1"); 46 + xpc_dictionary_set_string (if_desc, vmnet_end_address_key, "10.10.10.5"); 47 + xpc_dictionary_set_string (if_desc, vmnet_subnet_mask_key, "255.255.255.0"); 48 + pce_log_tag (MSG_INF, 49 + "SCSI:", 50 + "shared net ip=%s netmask=%s\n", 51 + "10.10.10.1", "255.255.255.0" 52 + ); 53 + } else { 54 + xpc_dictionary_set_uint64 (if_desc, vmnet_operation_mode_key, VMNET_BRIDGED_MODE); 55 + xpc_dictionary_set_string (if_desc, vmnet_shared_interface_name_key, bridge_if); 56 + pce_log_tag (MSG_INF, 57 + "SCSI:", 58 + "bridged net if=%s\n", 59 + bridge_if 60 + ); 61 + } 62 + 63 + ret->interface = vmnet_start_interface (if_desc, ret->if_queue, 64 + ^(vmnet_return_t status, xpc_object_t if_param) { 65 + if_status = status; 66 + 67 + if (status != VMNET_SUCCESS) { 68 + dispatch_semaphore_signal (if_start_sem); 69 + if (status == VMNET_FAILURE) { 70 + pce_log (MSG_ERR, "*** vmnet_start_interface failed, " 71 + "try with root privileges?\n"); 72 + } 73 + return; 74 + } 75 + 76 + dispatch_semaphore_signal (if_start_sem); 77 + }); 78 + 79 + dispatch_semaphore_wait (if_start_sem, DISPATCH_TIME_FOREVER); 80 + dispatch_release (if_start_sem); 81 + xpc_release (if_desc); 82 + 83 + if (if_status != VMNET_SUCCESS) { 84 + dispatch_release (ret->if_queue); 85 + free (ret); 86 + return NULL; 87 + } 88 + 89 + vmnet_interface_set_event_callback (ret->interface, 90 + VMNET_INTERFACE_PACKETS_AVAILABLE, ret->if_queue, 91 + ^(interface_event_t event_id, xpc_object_t event) { 92 + unsigned int navail = xpc_dictionary_get_uint64 (event, 93 + vmnet_estimated_packets_available_key); 94 + ret->packets_available = navail; 95 + }); 96 + 97 + return ret; 98 + } 99 + 100 + void pce_vmnet_stop (struct pce_vmnet_interface *vi) 101 + { 102 + if (vi == NULL || vi->interface == NULL) { 103 + return; 104 + } 105 + 106 + dispatch_semaphore_t if_stop_sem = dispatch_semaphore_create (0); 107 + 108 + vmnet_interface_set_event_callback(vi->interface, 109 + VMNET_INTERFACE_PACKETS_AVAILABLE, NULL, NULL); 110 + 111 + vmnet_stop_interface (vi->interface, vi->if_queue, 112 + ^(vmnet_return_t status) { 113 + dispatch_semaphore_signal (if_stop_sem); 114 + }); 115 + 116 + dispatch_semaphore_wait (if_stop_sem, DISPATCH_TIME_FOREVER); 117 + dispatch_release (vi->if_queue); 118 + 119 + free (vi); 120 + } 121 + 122 + int pce_vmnet_write (struct pce_vmnet_interface *vi, void *buf, size_t size) 123 + { 124 + struct iovec packets_iovec = { 125 + .iov_base = buf, 126 + .iov_len = size, 127 + }; 128 + 129 + struct vmpktdesc packets = { 130 + .vm_pkt_size = size, 131 + .vm_pkt_iov = &packets_iovec, 132 + .vm_pkt_iovcnt = 1, 133 + .vm_flags = 0, 134 + }; 135 + 136 + int count = packets.vm_pkt_iovcnt; 137 + 138 + if (vi == NULL || vi->interface == NULL) { 139 + return -1; 140 + } 141 + 142 + if (vmnet_write (vi->interface, &packets, &count) != VMNET_SUCCESS) { 143 + return -1; 144 + } 145 + 146 + return 0; 147 + } 148 + 149 + size_t pce_vmnet_read (struct pce_vmnet_interface *vi, void *buf, size_t size) 150 + { 151 + struct iovec packets_iovec = { 152 + .iov_base = buf, 153 + .iov_len = size, 154 + }; 155 + 156 + struct vmpktdesc packets = { 157 + .vm_pkt_size = size, 158 + .vm_pkt_iov = &packets_iovec, 159 + .vm_pkt_iovcnt = 1, 160 + .vm_flags = 0, 161 + }; 162 + 163 + int count = 1; 164 + 165 + vmnet_return_t status = vmnet_read (vi->interface, &packets, &count); 166 + 167 + if (status != VMNET_SUCCESS) { 168 + return 0; 169 + } 170 + 171 + if (count == 0) { 172 + return 0; 173 + } 174 + 175 + if (vi->packets_available > 0) 176 + vi->packets_available--; 177 + 178 + return packets.vm_pkt_size; 179 + }