This is my first patch so I hope I got everything right.
Signed-off-by: Kenth Andersson <ke...@eastmark.net> --- configure | 2 +- qga/commands-win32.c | 267 ++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 266 insertions(+), 3 deletions(-) diff --git a/configure b/configure index 862f6d2..1d2aeae 100755 --- a/configure +++ b/configure @@ -717,7 +717,7 @@ EOF sysconfdir="\${prefix}" local_statedir= confsuffix="" - libs_qga="-lws2_32 -lwinmm -lpowrprof $libs_qga" + libs_qga="-lws2_32 -lwinmm -lpowrprof -liphlpapi $libs_qga" fi werror="" diff --git a/qga/commands-win32.c b/qga/commands-win32.c index 3bcbeae..e084573 100644 --- a/qga/commands-win32.c +++ b/qga/commands-win32.c @@ -14,6 +14,9 @@ #include <glib.h> #include <wtypes.h> #include <powrprof.h> +#include <winsock2.h> +#include <iphlpapi.h> +#include <ws2tcpip.h> #include "qga/guest-agent-core.h" #include "qga/vss-win32.h" #include "qga-qmp-commands.h" @@ -359,10 +362,270 @@ void qmp_guest_suspend_hybrid(Error **errp) error_set(errp, QERR_UNSUPPORTED); } +static int get_prefix(PIP_ADAPTER_PREFIX prefix, + LPSOCKADDR sockaddr, int socklen) +{ + PIP_ADAPTER_PREFIX p = prefix; + + for (; p != NULL; p = p->Next) + { + if (sockaddr->sa_family == p->Address.lpSockaddr->sa_family) + { + int num_bytes = p->PrefixLength / 8; + int i = 0; + char* src = 0; + char* dst = 0; + int remaining_bits = 0; + + if (sockaddr->sa_family == AF_INET) + { + struct sockaddr_in* sin = (struct sockaddr_in*)sockaddr; + src = (char*)sin->sin_addr.s_addr; + } + else if (sockaddr->sa_family == AF_INET6) + { + struct sockaddr_in6* sin = (struct sockaddr_in6*)sockaddr; + src = (char*)sin->sin6_addr.s6_addr; + } + if (prefix->Address.lpSockaddr->sa_family == AF_INET) + { + struct sockaddr_in* sin = + (struct sockaddr_in*)prefix->Address.lpSockaddr; + dst = (char*)sin->sin_addr.s_addr; + } + else if (prefix->Address.lpSockaddr->sa_family == AF_INET6) + { + struct sockaddr_in6* sin = + (struct sockaddr_in6*)prefix->Address.lpSockaddr; + dst = (char*)sin->sin6_addr.s6_addr; + } + if ((src == 0) || (dst == 0)) + { + continue; + } + + for (; i < num_bytes; ++i) + { + if (src[i] != dst[i]) + { + continue; + } + } + + remaining_bits = p->PrefixLength % 8; + + if (remaining_bits != 0) + { + unsigned char mask = 0xff << (8 - remaining_bits); + int i = num_bytes; + + if ((src[i] & mask) != (dst[i] & mask)) + { + continue; + } + } + + return p->PrefixLength; + } + } + return 0; +} + + + GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp) { - error_set(errp, QERR_UNSUPPORTED); - return NULL; + GuestNetworkInterfaceList *head = NULL, *curr_item = NULL; + DWORD ret_val = 0; + + /* Startup WinSock32 */ + WORD ws_version_requested = MAKEWORD(2, 2); + WSADATA ws_data; + WSAStartup(ws_version_requested, &ws_data); + + + PIP_ADAPTER_ADDRESSES adapter_addresses = NULL; + PIP_ADAPTER_ADDRESSES current_adapter_address = NULL; + PIP_ADAPTER_UNICAST_ADDRESS adapter_unicast_address = NULL; + + unsigned long bufLen = sizeof(IP_ADAPTER_ADDRESSES); + + /* Allocate adapter address list */ + adapter_addresses = (IP_ADAPTER_ADDRESSES*) + HeapAlloc(GetProcessHeap(), 0, sizeof(IP_ADAPTER_ADDRESSES)); + if (adapter_addresses == NULL) { + goto cleanup; + } + + /* Get adapter adresses and if it doesn't fit in adapter_addresses + * we will realloc */ + if (GetAdaptersAddresses(AF_UNSPEC, + GAA_FLAG_INCLUDE_PREFIX, + NULL, + adapter_addresses, &bufLen) == + ERROR_BUFFER_OVERFLOW) { + + HeapFree(GetProcessHeap(), 0, adapter_addresses); + + adapter_addresses = (IP_ADAPTER_ADDRESSES*) + HeapAlloc(GetProcessHeap(), 0, bufLen); + + if (adapter_addresses == NULL) { + goto cleanup; + } + } + + /* Get adapter address list */ + if ((ret_val = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, + NULL, + adapter_addresses, &bufLen)) == NO_ERROR) { + + /* Iterate all adapter addresses */ + + current_adapter_address = adapter_addresses; + + while (current_adapter_address) { + /* Check if this adapter is up and running */ + + if ((current_adapter_address->OperStatus == IfOperStatusUp) && + ((current_adapter_address->IfType == IF_TYPE_ETHERNET_CSMACD) || + (current_adapter_address->IfType == IF_TYPE_IEEE80211) || + (current_adapter_address->IfType == + IF_TYPE_SOFTWARE_LOOPBACK))) { + + int len = 0; + char* temp_description = 0; + + GuestNetworkInterfaceList* interface_list = + g_malloc0(sizeof(*interface_list)); + if (interface_list == NULL) { + goto cleanup; + } + + interface_list->value = g_malloc0(sizeof(*interface_list->value)); + if (interface_list->value == NULL) { + g_free(interface_list); + goto cleanup; + } + + len = wcslen(current_adapter_address->Description) + 1; + temp_description = g_malloc0(len); + if (temp_description == NULL) { + g_free(interface_list->value); + g_free(interface_list); + goto cleanup; + } + + wcstombs(temp_description, + current_adapter_address->Description, + len); + interface_list->value->name = g_strdup(temp_description); + g_free(temp_description); + + if (curr_item == NULL) { + head = curr_item = interface_list; + } else { + curr_item->next = interface_list; + curr_item = interface_list; + } + + /* Format MAC address */ + interface_list->value->hardware_address = + g_strdup_printf("%02x:%02x:%02x:%02x:%02x:%02x", + (int) current_adapter_address->PhysicalAddress[0], + (int) current_adapter_address->PhysicalAddress[1], + (int) current_adapter_address->PhysicalAddress[2], + (int) current_adapter_address->PhysicalAddress[3], + (int) current_adapter_address->PhysicalAddress[4], + (int) current_adapter_address->PhysicalAddress[5]); + + + interface_list->value->has_hardware_address = true; + + /* Iterate all unicast addresses of this adapter */ + GuestIpAddressList **address_list = + &interface_list->value->ip_addresses; + + GuestIpAddressList *address_item = NULL; + + adapter_unicast_address = + current_adapter_address->FirstUnicastAddress; + + while (adapter_unicast_address) { + SOCKET_ADDRESS* saddr = &adapter_unicast_address->Address; + int socklen = 0; + char buffer[50]; + DWORD len = 50; + + /* Allocate an address item */ + address_item = g_malloc0(sizeof(*address_item)); + if (address_item == NULL) { + goto cleanup; + } + address_item->value = + g_malloc0(sizeof(*address_item->value)); + + if (address_item->value == NULL) { + g_free(address_item); + goto cleanup; + } + + /* Is this IPv4 or IPv6 */ + if (saddr->lpSockaddr->sa_family == AF_INET) { + address_item->value->ip_address_type = + GUEST_IP_ADDRESS_TYPE_IPV4; + socklen = sizeof(struct sockaddr_in); + } else if (saddr->lpSockaddr->sa_family == AF_INET6) { + address_item->value->ip_address_type = + GUEST_IP_ADDRESS_TYPE_IPV6; + socklen = sizeof(struct sockaddr_in6); + } + + /* Temporary buffer to hold human readable address */ + WSAAddressToString(saddr->lpSockaddr, + socklen, NULL, buffer, &len); + buffer[len] = 0; + address_item->value->ip_address = g_strdup(buffer); + + /* Get the prefix for this address */ + address_item->value->prefix = + get_prefix(current_adapter_address->FirstPrefix, + saddr->lpSockaddr, socklen); + + /* Add this address to the end of the address list */ + while (*address_list && (*address_list)->next) { + address_list = &(*address_list)->next; + } + + if (!*address_list) { + *address_list = address_item; + } else { + (*address_list)->next = address_item; + } + + /* Jump to next address */ + adapter_unicast_address = adapter_unicast_address->Next; + } + interface_list->value->has_ip_addresses = true; + + } + + /* Jump to next adapter */ + current_adapter_address = current_adapter_address->Next; + } + } + +cleanup: + + /* Free the adapter list */ + if (adapter_addresses != NULL) { + HeapFree(GetProcessHeap(), 0, adapter_addresses); + } + + /* Cleanup WinSock32 */ + WSACleanup(); + + return head; } int64_t qmp_guest_get_time(Error **errp) -- 1.8.5.2 (Apple Git-48)