@@ -224,48 +224,100 @@ static void on_vmnet_packets_available(interface_ref iface, int64_t estim_count,
224224
225225static interface_ref start (struct state * state , struct cli_options * cliopt ) {
226226 INFOF ("Initializing vmnet.framework (mode %d)" , cliopt -> vmnet_mode );
227- xpc_object_t dict = xpc_dictionary_create (NULL , NULL , 0 );
228- xpc_dictionary_set_uint64 (dict , vmnet_operation_mode_key , cliopt -> vmnet_mode );
229- if (cliopt -> vmnet_interface != NULL ) {
230- INFOF ("Using network interface \"%s\"" , cliopt -> vmnet_interface );
231- xpc_dictionary_set_string (dict , vmnet_shared_interface_name_key , cliopt -> vmnet_interface );
232- }
233-
234- if (!uuid_is_null (cliopt -> vmnet_network_identifier )) {
235- xpc_dictionary_set_uuid (dict , vmnet_network_identifier_key , cliopt -> vmnet_network_identifier );
236- }
237-
238- if (cliopt -> vmnet_gateway != NULL ) {
239- xpc_dictionary_set_string (dict , vmnet_start_address_key , cliopt -> vmnet_gateway );
240- xpc_dictionary_set_string (dict , vmnet_end_address_key , cliopt -> vmnet_dhcp_end );
241- xpc_dictionary_set_string (dict , vmnet_subnet_mask_key , cliopt -> vmnet_mask );
242- }
243-
244- xpc_dictionary_set_uuid (dict , vmnet_interface_id_key , cliopt -> vmnet_interface_id );
245-
246- if (cliopt -> vmnet_nat66_prefix != NULL ) {
247- xpc_dictionary_set_string (dict , vmnet_nat66_prefix_key , cliopt -> vmnet_nat66_prefix );
248- }
249227
250228 dispatch_semaphore_t sem = dispatch_semaphore_create (0 );
251-
252- __block interface_ref iface ;
253- __block vmnet_return_t status ;
254-
229+ __block interface_ref iface = NULL ;
230+ __block vmnet_return_t status = VMNET_FAILURE ;
255231 __block uint64_t max_bytes = 0 ;
256- iface = vmnet_start_interface (
257- dict , state -> host_queue , ^(vmnet_return_t x_status , xpc_object_t x_param ) {
232+ vmnet_start_interface_completion_handler_t on_started =
233+ ^(vmnet_return_t x_status , xpc_object_t x_param ) {
258234 status = x_status ;
259235 if (x_status == VMNET_SUCCESS ) {
260236 print_vmnet_start_param (x_param );
261237 max_bytes = xpc_dictionary_get_uint64 (x_param , vmnet_max_packet_size_key );
262238 }
263239 dispatch_semaphore_signal (sem );
264- });
265- dispatch_semaphore_wait (sem , DISPATCH_TIME_FOREVER );
266- xpc_release (dict );
240+ };
241+
242+ if (cliopt -> vmnet_disable_dhcp ) {
243+ // The DHCP server can only be disabled via the vmnet_network_configuration
244+ // API, which is macOS 26+. Guard at both compile time (SDK has the symbols)
245+ // and runtime (the host actually provides them).
246+ #if defined(__MAC_OS_X_VERSION_MAX_ALLOWED ) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 260000
247+ if (__builtin_available (macOS 26.0 , * )) {
248+ vmnet_return_t st = VMNET_FAILURE ;
249+ vmnet_network_configuration_ref cfg =
250+ vmnet_network_configuration_create (cliopt -> vmnet_mode , & st );
251+ if (cfg == NULL ) {
252+ ERRORF ("vmnet_network_configuration_create: [%d] %s" , st , vmnet_strerror (st ));
253+ return NULL ;
254+ }
255+ if (cliopt -> vmnet_interface != NULL ) {
256+ INFOF ("Using network interface \"%s\"" , cliopt -> vmnet_interface );
257+ st = vmnet_network_configuration_set_external_interface (cfg , cliopt -> vmnet_interface );
258+ if (st != VMNET_SUCCESS ) {
259+ ERRORF ("vmnet_network_configuration_set_external_interface: [%d] %s" , st ,
260+ vmnet_strerror (st ));
261+ return NULL ;
262+ }
263+ }
264+ if (cliopt -> vmnet_gateway != NULL ) {
265+ struct in_addr subnet , mask ;
266+ if (!inet_aton (cliopt -> vmnet_gateway , & subnet ) || !inet_aton (cliopt -> vmnet_mask , & mask )) {
267+ ERRORN ("inet_aton" );
268+ return NULL ;
269+ }
270+ vmnet_network_configuration_set_ipv4_subnet (cfg , & subnet , & mask );
271+ }
272+ vmnet_network_configuration_disable_dhcp (cfg );
273+ vmnet_network_ref net = vmnet_network_create (cfg , & st );
274+ if (net == NULL ) {
275+ ERRORF ("vmnet_network_create: [%d] %s" , st , vmnet_strerror (st ));
276+ return NULL ;
277+ }
278+ xpc_object_t desc = xpc_dictionary_create (NULL , NULL , 0 );
279+ iface = vmnet_interface_start_with_network (net , desc , state -> host_queue , on_started );
280+ dispatch_semaphore_wait (sem , DISPATCH_TIME_FOREVER );
281+ xpc_release (desc );
282+ } else {
283+ ERROR ("--vmnet-disable-dhcp requires macOS 26.0 or later" );
284+ return NULL ;
285+ }
286+ #else
287+ ERROR ("--vmnet-disable-dhcp requires building against the macOS 26 SDK or later" );
288+ return NULL ;
289+ #endif
290+ } else {
291+ xpc_object_t dict = xpc_dictionary_create (NULL , NULL , 0 );
292+ xpc_dictionary_set_uint64 (dict , vmnet_operation_mode_key , cliopt -> vmnet_mode );
293+ if (cliopt -> vmnet_interface != NULL ) {
294+ INFOF ("Using network interface \"%s\"" , cliopt -> vmnet_interface );
295+ xpc_dictionary_set_string (dict , vmnet_shared_interface_name_key , cliopt -> vmnet_interface );
296+ }
297+
298+ if (!uuid_is_null (cliopt -> vmnet_network_identifier )) {
299+ xpc_dictionary_set_uuid (dict , vmnet_network_identifier_key , cliopt -> vmnet_network_identifier );
300+ }
301+
302+ if (cliopt -> vmnet_gateway != NULL ) {
303+ xpc_dictionary_set_string (dict , vmnet_start_address_key , cliopt -> vmnet_gateway );
304+ xpc_dictionary_set_string (dict , vmnet_end_address_key , cliopt -> vmnet_dhcp_end );
305+ xpc_dictionary_set_string (dict , vmnet_subnet_mask_key , cliopt -> vmnet_mask );
306+ }
307+
308+ xpc_dictionary_set_uuid (dict , vmnet_interface_id_key , cliopt -> vmnet_interface_id );
309+
310+ if (cliopt -> vmnet_nat66_prefix != NULL ) {
311+ xpc_dictionary_set_string (dict , vmnet_nat66_prefix_key , cliopt -> vmnet_nat66_prefix );
312+ }
313+
314+ iface = vmnet_start_interface (dict , state -> host_queue , on_started );
315+ dispatch_semaphore_wait (sem , DISPATCH_TIME_FOREVER );
316+ xpc_release (dict );
317+ }
318+
267319 if (status != VMNET_SUCCESS ) {
268- ERRORF ("vmnet_start_interface : [%d] %s" , status , vmnet_strerror (status ));
320+ ERRORF ("vmnet start interface : [%d] %s" , status , vmnet_strerror (status ));
269321 return NULL ;
270322 }
271323
0 commit comments