[PATCH 2/4] mountmgr.sys: Add support for querying DHCP parameters on Linux.

Hans Leidekker hans at codeweavers.com
Tue Nov 19 07:44:58 CST 2019


Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
 dlls/mountmgr.sys/Makefile.in |   2 +-
 dlls/mountmgr.sys/dbus.c      | 271 ++++++++++++++++++++++++++++++++++
 dlls/mountmgr.sys/mountmgr.c  |  40 +++++
 dlls/mountmgr.sys/mountmgr.h  |   3 +
 include/ddk/mountmgr.h        |  21 +++
 5 files changed, 336 insertions(+), 1 deletion(-)

diff --git a/dlls/mountmgr.sys/Makefile.in b/dlls/mountmgr.sys/Makefile.in
index 511484b10b..738f071390 100644
--- a/dlls/mountmgr.sys/Makefile.in
+++ b/dlls/mountmgr.sys/Makefile.in
@@ -1,6 +1,6 @@
 MODULE    = mountmgr.sys
 IMPORTS   = uuid advapi32 ntoskrnl
-DELAYIMPORTS = user32
+DELAYIMPORTS = user32 iphlpapi
 EXTRADLLFLAGS = -Wl,--subsystem,native
 EXTRAINCL = $(DBUS_CFLAGS) $(HAL_CFLAGS)
 EXTRALIBS = $(DISKARBITRATION_LIBS)
diff --git a/dlls/mountmgr.sys/dbus.c b/dlls/mountmgr.sys/dbus.c
index 7e373e6f91..b96cb0df4c 100644
--- a/dlls/mountmgr.sys/dbus.c
+++ b/dlls/mountmgr.sys/dbus.c
@@ -36,6 +36,13 @@
 #include "mountmgr.h"
 #include "winnls.h"
 #include "excpt.h"
+#include "winsock2.h"
+#include "ws2ipdef.h"
+#include "nldef.h"
+#include "netioapi.h"
+#include "inaddr.h"
+#include "ip2string.h"
+#include "dhcpcsdk.h"
 
 #include "wine/library.h"
 #include "wine/exception.h"
@@ -48,6 +55,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(mountmgr);
 #define DBUS_FUNCS \
     DO_FUNC(dbus_bus_add_match); \
     DO_FUNC(dbus_bus_get); \
+    DO_FUNC(dbus_bus_get_private); \
     DO_FUNC(dbus_bus_remove_match); \
     DO_FUNC(dbus_connection_add_filter); \
     DO_FUNC(dbus_connection_read_write_dispatch); \
@@ -762,6 +770,269 @@ void initialize_dbus(void)
     CloseHandle( handle );
 }
 
+/* The udisks dispatch loop will block all threads using the same connection, so we'll
+   use a private connection. Multiple threads can make methods calls at the same time
+   on the same connection, according to the documentation.
+ */
+static DBusConnection *dhcp_connection;
+static DBusConnection *get_dhcp_connection(void)
+{
+    if (!dhcp_connection)
+    {
+        DBusError error;
+        p_dbus_error_init( &error );
+        if (!(dhcp_connection = p_dbus_bus_get_private( DBUS_BUS_SYSTEM, &error )))
+        {
+            WARN( "failed to get system dbus connection: %s\n", error.message );
+            p_dbus_error_free( &error );
+        }
+    }
+    return dhcp_connection;
+}
+
+static DBusMessage *device_by_iface_request( const char *iface )
+{
+    DBusMessage *request, *reply;
+    DBusMessageIter iter;
+    DBusError error;
+
+    request = p_dbus_message_new_method_call( "org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager",
+                                              "org.freedesktop.NetworkManager", "GetDeviceByIpIface" );
+    if (!request) return NULL;
+
+    p_dbus_message_iter_init_append( request, &iter );
+    p_dbus_message_iter_append_basic( &iter, DBUS_TYPE_STRING, &iface );
+
+    p_dbus_error_init( &error );
+    reply = p_dbus_connection_send_with_reply_and_block( get_dhcp_connection(), request, -1, &error );
+    p_dbus_message_unref( request );
+    if (!reply)
+    {
+        WARN( "failed: %s\n", error.message );
+        p_dbus_error_free( &error );
+        return NULL;
+    }
+
+    p_dbus_error_free( &error );
+    return reply;
+}
+
+#define IF_NAMESIZE 16
+static BOOL map_adapter_name( const WCHAR *name, char *unix_name, DWORD len )
+{
+    WCHAR unix_nameW[IF_NAMESIZE];
+    UNICODE_STRING str;
+    GUID guid;
+
+    RtlInitUnicodeString( &str, name );
+    if (!RtlGUIDFromString( &str, &guid ))
+    {
+        NET_LUID luid;
+        if (ConvertInterfaceGuidToLuid( &guid, &luid ) ||
+            ConvertInterfaceLuidToNameW( &luid, unix_nameW, ARRAY_SIZE(unix_nameW) )) return FALSE;
+
+        name = unix_nameW;
+    }
+    return WideCharToMultiByte( CP_UNIXCP, 0, name, -1, unix_name, len, NULL, NULL ) != 0;
+}
+
+static DBusMessage *dhcp4_config_request( const WCHAR *adapter )
+{
+    static const char *device = "org.freedesktop.NetworkManager.Device";
+    static const char *dhcp4_config = "Dhcp4Config";
+    char iface[IF_NAMESIZE];
+    DBusMessage *request, *reply;
+    DBusMessageIter iter;
+    DBusError error;
+    const char *path = NULL;
+
+    if (!map_adapter_name( adapter, iface, sizeof(iface) )) return NULL;
+    if (!(reply = device_by_iface_request( iface ))) return NULL;
+
+    p_dbus_message_iter_init( reply, &iter );
+    if (p_dbus_message_iter_get_arg_type( &iter ) == DBUS_TYPE_OBJECT_PATH) p_dbus_message_iter_get_basic( &iter, &path );
+    p_dbus_message_unref( reply );
+    if (!path) return NULL;
+
+    request = p_dbus_message_new_method_call( "org.freedesktop.NetworkManager", path,
+                                              "org.freedesktop.DBus.Properties", "Get" );
+    if (!request) return NULL;
+
+    p_dbus_message_iter_init_append( request, &iter );
+    p_dbus_message_iter_append_basic( &iter, DBUS_TYPE_STRING, &device );
+    p_dbus_message_iter_append_basic( &iter, DBUS_TYPE_STRING, &dhcp4_config );
+
+    p_dbus_error_init( &error );
+    reply = p_dbus_connection_send_with_reply_and_block( get_dhcp_connection(), request, -1, &error );
+    p_dbus_message_unref( request );
+    if (!reply)
+    {
+        WARN( "failed: %s\n", error.message );
+        p_dbus_error_free( &error );
+        return NULL;
+    }
+
+    p_dbus_error_free( &error );
+    return reply;
+}
+
+static DBusMessage *dhcp4_config_options_request( const WCHAR *adapter )
+{
+    static const char *dhcp4_config = "org.freedesktop.NetworkManager.DHCP4Config";
+    static const char *options = "Options";
+    DBusMessage *request, *reply;
+    DBusMessageIter iter, sub;
+    DBusError error;
+    const char *path = NULL;
+
+    if (!(reply = dhcp4_config_request( adapter ))) return NULL;
+
+    p_dbus_message_iter_init( reply, &iter );
+    if (p_dbus_message_iter_get_arg_type( &iter ) == DBUS_TYPE_VARIANT)
+    {
+        p_dbus_message_iter_recurse( &iter, &sub );
+        p_dbus_message_iter_get_basic( &sub, &path );
+    }
+    if (!path)
+    {
+        p_dbus_message_unref( reply );
+        return NULL;
+    }
+
+    request = p_dbus_message_new_method_call( "org.freedesktop.NetworkManager", path,
+                                              "org.freedesktop.DBus.Properties", "Get" );
+    p_dbus_message_unref( reply );
+    if (!request) return NULL;
+
+    p_dbus_message_iter_init_append( request, &iter );
+    p_dbus_message_iter_append_basic( &iter, DBUS_TYPE_STRING, &dhcp4_config );
+    p_dbus_message_iter_append_basic( &iter, DBUS_TYPE_STRING, &options );
+
+    p_dbus_error_init( &error );
+    reply = p_dbus_connection_send_with_reply_and_block( get_dhcp_connection(), request, -1, &error );
+    p_dbus_message_unref( request );
+    if (!reply)
+    {
+        p_dbus_error_free( &error );
+        return NULL;
+    }
+
+    p_dbus_error_free( &error );
+    return reply;
+}
+
+static const char *dhcp4_config_option_next_dict_entry( DBusMessageIter *iter, DBusMessageIter *variant )
+{
+    DBusMessageIter sub;
+    const char *name;
+
+    if (p_dbus_message_iter_get_arg_type( iter ) != DBUS_TYPE_DICT_ENTRY) return NULL;
+    p_dbus_message_iter_recurse( iter, &sub );
+    p_dbus_message_iter_next( iter );
+    p_dbus_message_iter_get_basic( &sub, &name );
+    p_dbus_message_iter_next( &sub );
+    p_dbus_message_iter_recurse( &sub, variant );
+    return name;
+}
+
+static DBusMessage *dhcp4_config_option_request( const WCHAR *adapter, const char *option, const char **value )
+{
+    DBusMessage *reply;
+    DBusMessageIter iter, variant;
+    const char *name;
+
+    if (!(reply = dhcp4_config_options_request( adapter ))) return NULL;
+
+    *value = NULL;
+    p_dbus_message_iter_init( reply, &iter );
+    if (p_dbus_message_iter_get_arg_type( &iter ) == DBUS_TYPE_VARIANT)
+    {
+        p_dbus_message_iter_recurse( &iter, &iter );
+        if (p_dbus_message_iter_get_arg_type( &iter ) == DBUS_TYPE_ARRAY)
+        {
+            p_dbus_message_iter_recurse( &iter, &iter );
+            while ((name = dhcp4_config_option_next_dict_entry( &iter, &variant )))
+            {
+                if (!strcmp( name, option ))
+                {
+                    p_dbus_message_iter_get_basic( &variant, value );
+                    break;
+                }
+            }
+        }
+    }
+
+    return reply;
+}
+
+static const char *map_option( ULONG option )
+{
+    switch (option)
+    {
+    case OPTION_SUBNET_MASK:         return "subnet_mask";
+    case OPTION_ROUTER_ADDRESS:      return "next_server";
+    case OPTION_HOST_NAME:           return "host_name";
+    case OPTION_DOMAIN_NAME:         return "domain_name";
+    case OPTION_BROADCAST_ADDRESS:   return "broadcast_address";
+    case OPTION_MSFT_IE_PROXY:       return "wpad";
+    default:
+        FIXME( "unhandled option %u\n", option );
+        return "";
+    }
+}
+
+ULONG get_dhcp_request_param( const WCHAR *adapter, struct mountmgr_dhcp_request_param *param, char *buf, ULONG offset,
+                              ULONG size )
+{
+    DBusMessage *reply;
+    const char *value;
+    ULONG ret = 0;
+
+    param->offset = param->size = 0;
+
+    if (!(reply = dhcp4_config_option_request( adapter, map_option(param->id), &value ))) return 0;
+
+    switch (param->id)
+    {
+    case OPTION_SUBNET_MASK:
+    case OPTION_ROUTER_ADDRESS:
+    case OPTION_BROADCAST_ADDRESS:
+    {
+        IN_ADDR *ptr = (IN_ADDR *)(buf + offset);
+        if (value && size >= sizeof(IN_ADDR) && !RtlIpv4StringToAddressA( value, TRUE, NULL, ptr ))
+        {
+            param->offset = offset;
+            param->size   = sizeof(*ptr);
+            TRACE( "returning %08x\n", *(DWORD *)ptr );
+        }
+        ret = sizeof(*ptr);
+        break;
+    }
+    case OPTION_HOST_NAME:
+    case OPTION_DOMAIN_NAME:
+    case OPTION_MSFT_IE_PROXY:
+    {
+        char *ptr = buf + offset;
+        int len = value ? strlen( value ) : 0;
+        if (len && size >= len)
+        {
+            memcpy( ptr, value, len );
+            param->offset = offset;
+            param->size   = len;
+            TRACE( "returning %s\n", debugstr_an(ptr, len) );
+        }
+        ret = len;
+        break;
+    }
+    default:
+        FIXME( "option %u not supported\n", param->id );
+        break;
+    }
+
+    p_dbus_message_unref( reply );
+    return ret;
+}
+
 #else  /* SONAME_LIBDBUS_1 */
 
 void initialize_dbus(void)
diff --git a/dlls/mountmgr.sys/mountmgr.c b/dlls/mountmgr.sys/mountmgr.c
index 2f43a227dc..bc2b776a92 100644
--- a/dlls/mountmgr.sys/mountmgr.c
+++ b/dlls/mountmgr.sys/mountmgr.c
@@ -359,6 +359,35 @@ done:
     return status;
 }
 
+/* implementation of IOCTL_MOUNTMGR_QUERY_DHCP_REQUEST_PARAMS */
+static NTSTATUS query_dhcp_request_params( void *buff, SIZE_T insize,
+                                           SIZE_T outsize, IO_STATUS_BLOCK *iosb )
+{
+    struct mountmgr_dhcp_request_params *query = buff;
+    ULONG i, offset;
+
+    /* sanity checks */
+    if (FIELD_OFFSET(struct mountmgr_dhcp_request_params, params[query->count]) > insize ||
+        !memchrW( query->adapter, 0, ARRAY_SIZE(query->adapter) )) return STATUS_INVALID_PARAMETER;
+    for (i = 0; i < query->count; i++)
+        if (query->params[i].offset + query->params[i].size > insize) return STATUS_INVALID_PARAMETER;
+
+    offset = FIELD_OFFSET(struct mountmgr_dhcp_request_params, params[query->count]);
+    for (i = 0; i < query->count; i++)
+    {
+        offset += get_dhcp_request_param( query->adapter, &query->params[i], buff, offset, outsize - offset );
+        if (offset > outsize)
+        {
+            if (offset >= sizeof(query->size)) query->size = offset;
+            iosb->Information = sizeof(query->size);
+            return STATUS_MORE_ENTRIES;
+        }
+    }
+
+    iosb->Information = offset;
+    return STATUS_SUCCESS;
+}
+
 /* handler for ioctls on the mount manager device */
 static NTSTATUS WINAPI mountmgr_ioctl( DEVICE_OBJECT *device, IRP *irp )
 {
@@ -403,6 +432,17 @@ static NTSTATUS WINAPI mountmgr_ioctl( DEVICE_OBJECT *device, IRP *irp )
                                                    irpsp->Parameters.DeviceIoControl.OutputBufferLength,
                                                    &irp->IoStatus );
         break;
+    case IOCTL_MOUNTMGR_QUERY_DHCP_REQUEST_PARAMS:
+        if (irpsp->Parameters.DeviceIoControl.InputBufferLength < sizeof(struct mountmgr_dhcp_request_params))
+        {
+            irp->IoStatus.u.Status = STATUS_INVALID_PARAMETER;
+            break;
+        }
+        irp->IoStatus.u.Status = query_dhcp_request_params( irp->AssociatedIrp.SystemBuffer,
+                                                            irpsp->Parameters.DeviceIoControl.InputBufferLength,
+                                                            irpsp->Parameters.DeviceIoControl.OutputBufferLength,
+                                                            &irp->IoStatus );
+        break;
     default:
         FIXME( "ioctl %x not supported\n", irpsp->Parameters.DeviceIoControl.IoControlCode );
         irp->IoStatus.u.Status = STATUS_NOT_SUPPORTED;
diff --git a/dlls/mountmgr.sys/mountmgr.h b/dlls/mountmgr.sys/mountmgr.h
index 79f72a3c83..95386a44f8 100644
--- a/dlls/mountmgr.sys/mountmgr.h
+++ b/dlls/mountmgr.sys/mountmgr.h
@@ -70,3 +70,6 @@ extern struct mount_point *add_volume_mount_point( DEVICE_OBJECT *device, UNICOD
                                                    const GUID *guid ) DECLSPEC_HIDDEN;
 extern void delete_mount_point( struct mount_point *mount ) DECLSPEC_HIDDEN;
 extern void set_mount_point_id( struct mount_point *mount, const void *id, unsigned int id_len ) DECLSPEC_HIDDEN;
+
+extern ULONG get_dhcp_request_param( const WCHAR *adapter, struct mountmgr_dhcp_request_param *param, char *buf,
+                                     ULONG offset, ULONG size ) DECLSPEC_HIDDEN;
diff --git a/include/ddk/mountmgr.h b/include/ddk/mountmgr.h
index fc3199c5ca..cb5822bf3d 100644
--- a/include/ddk/mountmgr.h
+++ b/include/ddk/mountmgr.h
@@ -61,6 +61,27 @@ struct mountmgr_unix_drive
     USHORT device_offset;
 };
 
+#define IOCTL_MOUNTMGR_QUERY_DHCP_REQUEST_PARAMS CTL_CODE(MOUNTMGRCONTROLTYPE, 64, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+struct mountmgr_dhcp_request_param
+{
+    ULONG id;
+    ULONG offset;
+    ULONG size;
+};
+
+#ifndef IF_MAX_STRING_SIZE
+#define IF_MAX_STRING_SIZE 256
+#endif
+
+struct mountmgr_dhcp_request_params
+{
+    ULONG size;
+    ULONG count;
+    WCHAR adapter[IF_MAX_STRING_SIZE + 1];
+    struct mountmgr_dhcp_request_param params[1];
+};
+
 #endif
 
 typedef struct _MOUNTMGR_CREATE_POINT_INPUT
-- 
2.20.1




More information about the wine-devel mailing list