Message ID | 20160813010606.13668-1-aserdean@cloudbasesolutions.com |
---|---|
State | Superseded |
Delegated to: | Guru Shetty |
Headers | show |
Sorry for the delay in the review. Acked-by: Sairam Venugopal <vsairam@vmware.com> On 8/12/16, 6:06 PM, "Alin Serdean" <aserdean@cloudbasesolutions.com> wrote: >This patch updates the following commands in the vswitch: >ovs-vsctl add-br br-test >ovs-vsctl del-br br-test > >ovs-vsctl add-br br-test: > This command will now create an internal port on the MSFT virtual >switch > using the WMI interface from Msvm_VirtualEthernetSwitchManagementService > leveraging the method AddResourceSettings. > Before creating the actual port, the switch will be queried to see if >there > is not a port already created (good for restarts when restarting the > vswitch daemon). If there is a port defined it will return success and >log > a message. > After checking if the port already exists the command will also verify > if the forwarding extension (windows datapath) is enabled and on a >single > switch. If it is not activated or if it is activated on multiple >switches > it will return an error and a message will be logged. > After the port was created on the switch, we will disable the adapter >on > the host and rename to the corresponding OVS bridge name for >consistency. > The user will enable and set the values he wants after creation. > >ovs-vsctl del-br br-test > This command will remove an internal port on the MSFT virtual switch > using the Msvm_VirtualEthernetSwitchManagementService class and >executing > the method RemoveResourceSettings. > >Both commands will be blocking until the WMI job is finished, this allows >us >to guarantee that the ports are created and their name are set before >issuing >a netlink message to the windows datapath. > >This patch also includes helpers for normal WMI retrievals and >initializations. >Appveyor and documentation has been modified to include the libraries >needed >for COM objects. > >This patch was tested individually using IMallocSpy and CRT heap checks >to ensure no new memory leaks are introduced. > >Tested on the following OS's: >Windows 2012 and Windows 2012r2 > >Signed-off-by: Alin Gabriel Serdean <aserdean@cloudbasesolutions.com> >Acked-by: Paul Boca <pboca@cloudbasesolutions.com> >--- >v4: address comments (sanitize input, short refactor) > use full stop on comments > update coding style >v3: rebase, add acked >v2: Address comments. Rebase >--- > appveyor.yml | 2 +- > lib/automake.mk | 4 +- > lib/dpif-netlink.c | 21 + > lib/wmi.c | 1276 >++++++++++++++++++++++++++++++++++++++++++++++++++++ > lib/wmi.h | 51 +++ > 5 files changed, 1352 insertions(+), 2 deletions(-) > create mode 100644 lib/wmi.c > create mode 100644 lib/wmi.h > >diff --git a/appveyor.yml b/appveyor.yml >index 0fd003b..1061df6 100644 >--- a/appveyor.yml >+++ b/appveyor.yml >@@ -41,5 +41,5 @@ build_script: > - C:\MinGW\msys\1.0\bin\bash -lc "cp >/c/pthreads-win32/Pre-built.2/dll/x86/*.dll /c/openvswitch/." > - C:\MinGW\msys\1.0\bin\bash -lc "mv /bin/link.exe /bin/link_copy.exe" > - C:\MinGW\msys\1.0\bin\bash -lc "cd /c/openvswitch && ./boot.sh" >-- C:\MinGW\msys\1.0\bin\bash -lc "cd /c/openvswitch && ./configure >CC=build-aux/cccl LD=\"`which link`\" LIBS=\"-lws2_32 -liphlpapi\" >--with-pthread=C:/pthreads-win32/Pre-built.2 >--with-openssl=C:/OpenSSL-Win32 --with-vstudiotarget=\"Debug\"" >+- C:\MinGW\msys\1.0\bin\bash -lc "cd /c/openvswitch && ./configure >CC=build-aux/cccl LD=\"`which link`\" LIBS=\"-lws2_32 -liphlpapi >-lwbemuuid -lole32 -loleaut32\" >--with-pthread=C:/pthreads-win32/Pre-built.2 >--with-openssl=C:/OpenSSL-Win32 --with-vstudiotarget=\"Debug\"" > - C:\MinGW\msys\1.0\bin\bash -lc "cd /c/openvswitch && make" >diff --git a/lib/automake.mk b/lib/automake.mk >index 2faaeac..99bbdc0 100644 >--- a/lib/automake.mk >+++ b/lib/automake.mk >@@ -387,7 +387,9 @@ lib_libopenvswitch_la_SOURCES += \ > lib/netlink-notifier.h \ > lib/netlink-protocol.h \ > lib/netlink-socket.c \ >- lib/netlink-socket.h >+ lib/netlink-socket.h \ >+ lib/wmi.c \ >+ lib/wmi.h > endif > > if HAVE_POSIX_AIO >diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c >index a39faa2..c8b0e37 100644 >--- a/lib/dpif-netlink.c >+++ b/lib/dpif-netlink.c >@@ -58,6 +58,7 @@ > > VLOG_DEFINE_THIS_MODULE(dpif_netlink); > #ifdef _WIN32 >+#include "wmi.h" > enum { WINDOWS = 1 }; > #else > enum { WINDOWS = 0 }; >@@ -849,6 +850,16 @@ dpif_netlink_port_add__(struct dpif_netlink *dpif, >struct netdev *netdev, > #endif > } > >+#ifdef _WIN32 >+ if (request.type == OVS_VPORT_TYPE_INTERNAL) { >+ if (!create_wmi_port(name)){ >+ VLOG_ERR("Could not create wmi internal port with name:%s", >name); >+ vport_del_socksp(dpif, socksp); >+ return EINVAL; >+ }; >+ } >+#endif >+ > tnl_cfg = netdev_get_tunnel_config(netdev); > if (tnl_cfg && (tnl_cfg->dst_port != 0 || tnl_cfg->exts)) { > ofpbuf_use_stack(&options, options_stub, sizeof options_stub); >@@ -940,6 +951,16 @@ dpif_netlink_port_del__(struct dpif_netlink *dpif, >odp_port_t port_no) > vport.cmd = OVS_VPORT_CMD_DEL; > vport.dp_ifindex = dpif->dp_ifindex; > vport.port_no = port_no; >+#ifdef _WIN32 >+ struct dpif_port temp_dpif_port; >+ dpif_netlink_port_query__(dpif, port_no, NULL, &temp_dpif_port); >+ if (!strcmp(temp_dpif_port.type, "internal")) { >+ if (!delete_wmi_port(temp_dpif_port.name)){ >+ VLOG_ERR("Could not delete wmi port with name: %s", >+ temp_dpif_port.name); >+ }; >+ } >+#endif > error = dpif_netlink_vport_transact(&vport, NULL, NULL); > > vport_del_channels(dpif, port_no); >diff --git a/lib/wmi.c b/lib/wmi.c >new file mode 100644 >index 0000000..67f0873 >--- /dev/null >+++ b/lib/wmi.c >@@ -0,0 +1,1276 @@ >+/* >+ * Copyright (c) 2016 Cloudbase Solutions Srl >+ * >+ * Licensed under the Apache License, Version 2.0 (the "License"); >+ * you may not use this file except in compliance with the License. >+ * You may obtain a copy of the License at >+ * >+ * >https://urldefense.proofpoint.com/v2/url?u=http-3A__www.apache.org_license >s_LICENSE-2D2.0&d=CwIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-YihVMNtXt-uEs&r=D >cruz40PROJ40ROzSpxyQSLw6fcrOWpJgEcEmNR3JEQ&m=1NgcutJOUfLwjikmUhz6W0zVXDR35 >T75FV8sqiZ8ki8&s=6YJXIuUkmHpuGcJw64GoPVKdYVnqhnBsGxStg7axmxs&e= >+ * >+ * Unless required by applicable law or agreed to in writing, software >+ * distributed under the License is distributed on an "AS IS" BASIS, >+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or >implied. >+ * See the License for the specific language governing permissions and >+ * limitations under the License. >+ */ >+ >+#include <config.h> >+#include "wmi.h" >+#include <stdlib.h> >+#include <stdio.h> >+#include <tchar.h> >+#include <Windows.h> >+#include "openvswitch/vlog.h" >+ >+VLOG_DEFINE_THIS_MODULE(wmi); >+ >+/* WMI Job values. */ >+enum job_status >+{ >+ job_starting = 3, >+ job_running = 4, >+ job_completed = 7, >+ job_wait = 4096 >+}; >+ >+static char * >+sanitize_port_name(char *name) >+{ >+ char *p1, *p2; >+ p1 = p2 = name; >+ >+ while (*p1) { >+ if ((*p1) == '\'' || (*p1) == '\"') { >+ p1++; >+ } else { >+ *p2 = *p1; >+ p2++; >+ p1++; >+ } >+ } >+ *p2 = '\0'; >+ return name; >+} >+ >+/* This function will output the appropriate message for a given >HRESULT.*/ >+static void >+get_hres_error(HRESULT hres) >+{ >+ char *error_msg = NULL; >+ >+ if (FACILITY_WINDOWS == HRESULT_FACILITY(hres)) { >+ hres = HRESULT_CODE(hres); >+ } >+ >+ VLOG_ERR("%s", ovs_format_message(hres)); >+} >+ >+static boolean >+check_return_value(HRESULT hres) >+{ >+ if (FAILED(hres)) { >+ get_hres_error(hres); >+ return false; >+ } >+ >+ return true; >+} >+ >+static HRESULT >+get_variant_value(IWbemClassObject *pcls_obj, wchar_t *field_name, >+ VARIANT *value) >+{ >+ HRESULT hres; >+ >+ VariantInit(value); >+ >+ hres = pcls_obj->lpVtbl->Get(pcls_obj, field_name, 0, value, 0, 0); >+ >+ if (FAILED(hres)) { >+ VariantClear(value); >+ } >+ >+ return hres; >+} >+ >+/* This function retrieves the uint16_t value from a given class object >with >+ * the field name field_name. */ >+static HRESULT >+get_uint16_t_value(IWbemClassObject *pcls_obj, wchar_t *field_name, >+ uint16_t *value) >+{ >+ VARIANT vt_prop; >+ HRESULT hres = get_variant_value(pcls_obj, field_name, &vt_prop); >+ *value = V_UI2(&vt_prop); >+ >+ return hres; >+} >+ >+/* This function retrieves the unsigned int values from a given class >object >+ * with the field name field_name. */ >+static HRESULT >+get_uint_value(IWbemClassObject *pcls_obj, wchar_t *field_name, >+ unsigned int *value) >+{ >+ VARIANT vt_prop; >+ HRESULT hres = get_variant_value(pcls_obj, field_name, &vt_prop); >+ *value = V_UI4(&vt_prop); >+ >+ return hres; >+} >+ >+/* This function retrieves the unsigned short value from a given class >object >+ * with the field name field_name. */ >+static HRESULT >+get_ushort_value(IWbemClassObject *pcls_obj, wchar_t *field_name, >+ unsigned short *value) >+{ >+ VARIANT vt_prop; >+ HRESULT hres = get_variant_value(pcls_obj, field_name, &vt_prop); >+ *value = V_UI2(&vt_prop); >+ >+ return hres; >+} >+ >+/* This function retrieves the BSTR value from a given class object with >+ * the field name field_name, to a preallocated destination dest and >with the >+ * maximum length max_dest_lgth. */ >+static HRESULT >+get_str_value(IWbemClassObject *pcls_obj, wchar_t *field_name, wchar_t >*dest, >+ int max_dest_lgth) >+{ >+ VARIANT vt_prop; >+ HRESULT hres = get_variant_value(pcls_obj, field_name, &vt_prop); >+ >+ if (wcscpy_s(dest, max_dest_lgth, vt_prop.bstrVal)) { >+ VariantClear(&vt_prop); >+ VLOG_WARN("get_str_value, wcscpy_s failed :%s", >ovs_strerror(errno)); >+ return WBEM_E_FAILED; >+ } >+ >+ VariantClear(&vt_prop); >+ return S_OK; >+} >+ >+/* This function waits for a WMI job to finish and retrieves the error >code >+ * if the job failed */ >+static HRESULT >+wait_for_job(IWbemServices *psvc, wchar_t *job_path) >+{ >+ IWbemClassObject *pcls_obj = NULL; >+ HRESULT retval = 0; >+ uint16_t job_state = 0; >+ uint16_t error = 0; >+ >+ do { >+ if(!check_return_value(psvc->lpVtbl->GetObject(psvc, job_path, >0, NULL, >+ &pcls_obj, >NULL))) { >+ retval = WBEM_E_FAILED; >+ break; >+ } >+ >+ retval = get_uint16_t_value(pcls_obj, L"JobState", &job_state); >+ if (FAILED(retval)) { >+ break; >+ } >+ >+ if (job_state == job_starting || job_state == job_running) { >+ Sleep(200); >+ } else if (job_state == job_completed) { >+ break; >+ } else { >+ /* Error occurred. */ >+ retval = get_uint16_t_value(pcls_obj, L"ErrorCode", &error); >+ if (FAILED(retval)) { >+ break; >+ } >+ VLOG_WARN("Job failed with error: %d", error); >+ retval = WBEM_E_FAILED;; >+ break; >+ } >+ >+ if (pcls_obj != NULL) { >+ pcls_obj->lpVtbl->Release(pcls_obj); >+ pcls_obj = NULL; >+ } >+ } while(TRUE); >+ >+ if (pcls_obj != NULL) { >+ pcls_obj->lpVtbl->Release(pcls_obj); >+ pcls_obj = NULL; >+ } >+ >+ return retval; >+} >+ >+/* This function will initialize DCOM retrieving the WMI locator's ploc >and >+ * the context associated to it. */ >+static boolean >+initialize_wmi(IWbemLocator **ploc, IWbemContext **pcontext) >+{ >+ HRESULT hres = 0; >+ >+ /* Initialize COM. */ >+ hres = CoInitialize(NULL); >+ >+ if (FAILED(hres)) { >+ return false; >+ } >+ >+ /* Initialize COM security. */ >+ hres = CoInitializeSecurity(NULL, >+ -1, >+ NULL, >+ NULL, >+ RPC_C_AUTHN_LEVEL_DEFAULT, >+ RPC_C_IMP_LEVEL_IMPERSONATE, >+ NULL, >+ EOAC_NONE, >+ NULL); >+ >+ if (FAILED(hres)) { >+ return false; >+ } >+ >+ /* Fill context. */ >+ hres = CoCreateInstance(&CLSID_WbemContext, >+ NULL, >+ CLSCTX_INPROC_SERVER, >+ &IID_IWbemContext, >+ (void**)pcontext); >+ >+ if (FAILED(hres)) { >+ return false; >+ } >+ >+ fill_context(*pcontext); >+ >+ /* Initialize locator's (ploc) to WMI. */ >+ hres = CoCreateInstance(&CLSID_WbemLocator, >+ NULL, >+ CLSCTX_INPROC_SERVER, >+ &IID_IWbemLocator, >+ (LPVOID *)ploc); >+ >+ if (FAILED(hres)) { >+ return false; >+ } >+ >+ return true; >+} >+ >+/* This function connects the WMI locator's ploc to a given WMI provider >+ * defined in server and also sets the required security levels for a >local >+ * connection to it. */ >+static boolean >+connect_set_security(IWbemLocator *ploc, IWbemContext *pcontext, >+ wchar_t *server, IWbemServices **psvc) >+{ >+ HRESULT hres = 0; >+ >+ /* Connect to server. */ >+ hres = ploc->lpVtbl->ConnectServer(ploc, >+ server, >+ NULL, >+ NULL, >+ 0, >+ 0, >+ 0, >+ pcontext, >+ psvc); >+ >+ if (FAILED(hres)) { >+ return false; >+ } >+ >+ /* Set security levels. */ >+ hres = CoSetProxyBlanket((IUnknown *) *psvc, >+ RPC_C_AUTHN_WINNT, >+ RPC_C_AUTHZ_NONE, >+ NULL, >+ RPC_C_AUTHN_LEVEL_CALL, >+ RPC_C_IMP_LEVEL_IMPERSONATE, >+ NULL, >+ EOAC_NONE); >+ >+ if (FAILED(hres)) { >+ return false; >+ } >+ >+ return true; >+} >+ >+/* This function retrieves the first class object of a given enumeration >+ * outputted by a query and fails if it could not retrieve the object or >there >+ * was no object to retrieve */ >+static boolean >+get_first_element(IEnumWbemClassObject *penumerate, >+ IWbemClassObject **pcls_obj) >+{ >+ unsigned long retval = 0; >+ >+ if (penumerate == NULL) { >+ VLOG_WARN("Enumeration Class Object is NULL. Cannot get the >first" >+ "object"); >+ return false; >+ } >+ >+ HRESULT hres = penumerate->lpVtbl->Next(penumerate, WBEM_INFINITE, 1, >+ pcls_obj, &retval); >+ >+ >+ if (!check_return_value(hres) || retval == 0) { >+ return false; >+ } >+ >+ return true; >+} >+ >+/* This function is a wrapper that transforms a char * into a wchar_t * >*/ >+static boolean >+tranform_wide(char *name, wchar_t *wide_name) >+{ >+ unsigned long size = strlen(name) + 1; >+ long long ret = 0; >+ >+ if (wide_name == NULL) { >+ VLOG_WARN("Provided wide string is NULL"); >+ return false; >+ } >+ >+ ret = mbstowcs(wide_name, name, size); >+ >+ if (ret == -1) { >+ VLOG_WARN("Invalid multibyte character is encountered"); >+ return false; >+ } else if (ret == size) { >+ VLOG_WARN("Returned wide string not NULL terminated"); >+ return false; >+ } >+ >+ return true; >+} >+ >+/* This function will delete a switch internal port with a given name as >input >+ * executing "RemoveResourceSettings" as per documentation: >+ * >https://urldefense.proofpoint.com/v2/url?u=https-3A__msdn.microsoft.com_en >-2Dus_library_hh850277-2528v-3Dvs.85-2529.aspx&d=CwIGaQ&c=Sqcl0Ez6M0X8aeM6 >7LKIiDJAXVeAw-YihVMNtXt-uEs&r=Dcruz40PROJ40ROzSpxyQSLw6fcrOWpJgEcEmNR3JEQ& >m=1NgcutJOUfLwjikmUhz6W0zVXDR35T75FV8sqiZ8ki8&s=tLEsQhF14PQ5LahGIKh2T8Z5h- >JPdlzvoU3ecWYc9hg&e= >+ * allocating the data and populating the needed fields to execute the >+ * method */ >+boolean >+delete_wmi_port(char *name) >+{ >+ HRESULT hres = 0; >+ boolean retval = true; >+ >+ IWbemLocator *ploc = NULL; >+ IWbemServices *psvc = NULL; >+ IWbemContext *pcontext = NULL; >+ IWbemClassObject *pclass_instance = NULL; >+ IWbemClassObject *pinput_params = NULL; >+ IWbemClassObject *pcls_obj = NULL; >+ IWbemClassObject *pout_params = NULL; >+ IEnumWbemClassObject *penumerate = NULL; >+ >+ sanitize_port_name(name); >+ VARIANT vt_prop; >+ VARIANT variant_array; >+ wchar_t *wide_name = NULL; >+ VariantInit(&vt_prop); >+ VariantInit(&variant_array); >+ >+ LONG count[1]; >+ SAFEARRAY* psa = SafeArrayCreateVector(VT_BSTR, 0, 1); >+ if (psa == NULL) { >+ VLOG_WARN("Could not allocate memory for a SAFEARRAY"); >+ retval = false; >+ goto error; >+ } >+ >+ if (!initialize_wmi(&ploc, &pcontext)) { >+ VLOG_WARN("Could not initialize DCOM"); >+ retval = false; >+ goto error; >+ } >+ >+ if (!connect_set_security(ploc, pcontext, >L"Root\\Virtualization\\v2", >+ &psvc)) { >+ VLOG_WARN("Could not connect and set security for >virtualization"); >+ retval = false; >+ goto error; >+ } >+ >+ >+ /* Get the port with the element name equal to the name input. */ >+ wchar_t internal_port_query[2048] = L"SELECT * from " >+ L"Msvm_EthernetPortAllocationSettingData WHERE ElementName = >\"" ; >+ >+ wide_name = malloc((strlen(name) + 1) * sizeof(wchar_t)); >+ if (wide_name == NULL) { >+ VLOG_WARN("Could not allocate memory for wide string"); >+ retval = false; >+ goto error; >+ } >+ >+ if (!tranform_wide(name, wide_name)) { >+ retval = false; >+ goto error; >+ } >+ wcscat_s(internal_port_query, sizeof(internal_port_query), >wide_name); >+ >+ wcscat_s(internal_port_query, sizeof(internal_port_query), L"\""); >+ >+ hres = psvc->lpVtbl->ExecQuery(psvc, >+ L"WQL", >+ internal_port_query, >+ WBEM_FLAG_FORWARD_ONLY | >+ WBEM_FLAG_RETURN_IMMEDIATELY, >+ NULL, >+ &penumerate); >+ >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ >+ /* Get the element path on the switch which will be deleted. */ >+ if (!get_first_element(penumerate, &pcls_obj)) { >+ retval = false; >+ goto error; >+ } >+ penumerate->lpVtbl->Release(penumerate); >+ penumerate = NULL; >+ >+ hres = pcls_obj->lpVtbl->Get(pcls_obj, L"__PATH", 0, &vt_prop, 0, 0); >+ >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ pcls_obj->lpVtbl->Release(pcls_obj); >+ pcls_obj = NULL; >+ >+ /* Get the class object and the parameters it can have. */ >+ hres = psvc->lpVtbl->GetObject(psvc, >+ L"Msvm_VirtualEthernetSwitchManagementService", 0, NULL, >&pcls_obj, >+ NULL); >+ >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ >+ hres = pcls_obj->lpVtbl->GetMethod(pcls_obj, >L"RemoveResourceSettings", 0, >+ &pinput_params, NULL); >+ >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ pcls_obj->lpVtbl->Release(pcls_obj); >+ pcls_obj = NULL; >+ >+ hres = pinput_params->lpVtbl->SpawnInstance(pinput_params, 0, >+ &pclass_instance); >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ >+ count[0] = 0; >+ >+ hres = SafeArrayPutElement(psa, count, vt_prop.bstrVal); >+ >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ >+ VariantClear(&vt_prop); >+ VariantInit(&vt_prop); >+ variant_array.vt = VT_ARRAY | VT_BSTR; >+ variant_array.parray = psa; >+ >+ hres = pclass_instance->lpVtbl->Put(pclass_instance, >L"ResourceSettings", 0, >+ &variant_array, 0); >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ >+ /* Get the object of the Msvm_VirtualEthernetSwitchManagementService >which >+ * we need to invoke the port deletion. */ >+ hres = psvc->lpVtbl->ExecQuery(psvc, >+ L"WQL", >+ L"SELECT * FROM " >+ >L"Msvm_VirtualEthernetSwitchManagementService", >+ WBEM_FLAG_FORWARD_ONLY | >+ WBEM_FLAG_RETURN_IMMEDIATELY, >+ NULL, >+ &penumerate); >+ >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ >+ if (!get_first_element(penumerate, &pcls_obj)) { >+ retval = false; >+ goto error; >+ } >+ penumerate->lpVtbl->Release(penumerate); >+ penumerate = NULL; >+ >+ hres = pcls_obj->lpVtbl->Get(pcls_obj, L"__PATH", 0, &vt_prop, 0, 0); >+ >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ >+ pcls_obj->lpVtbl->Release(pcls_obj); >+ pcls_obj = NULL; >+ >+ /* Invoke the delete port method. */ >+ hres = psvc->lpVtbl->ExecMethod(psvc, vt_prop.bstrVal, >+ L"RemoveResourceSettings", 0, >+ pcontext, pclass_instance, >&pout_params, >+ NULL); >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ VariantClear(&vt_prop); >+ VariantInit(&vt_prop); >+ >+ hres = pout_params->lpVtbl->Get(pout_params, L"ReturnValue", 0, >+ &vt_prop, NULL, 0); >+ >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ >+ unsigned int retvalue = 0; >+ hres = get_uint_value(pout_params, L"ReturnValue", &retvalue); >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ >+ if (retvalue != 0 && retvalue != job_wait) { >+ retval = false; >+ goto error; >+ } >+ >+ if (retvalue == job_wait) { >+ WCHAR job_path[2048]; >+ hres = get_str_value(pout_params, L"Job", job_path, >+ sizeof(job_path) / sizeof(WCHAR)); >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ hres = wait_for_job(psvc, job_path); >+ if (FAILED(hres)) { >+ retval = false; >+ } >+ } >+ >+error: >+ VariantClear(&vt_prop); >+ >+ if (pcontext != NULL) { >+ pcontext->lpVtbl->Release(pcontext); >+ pcontext = NULL; >+ } >+ if (psa != NULL) { >+ SafeArrayDestroy(psa); >+ psa = NULL; >+ } >+ if (pcls_obj != NULL) { >+ pcls_obj->lpVtbl->Release(pcls_obj); >+ pcls_obj = NULL; >+ } >+ if (wide_name != NULL) { >+ free(wide_name); >+ wide_name = NULL; >+ } >+ if (!retval) { >+ get_hres_error(hres); >+ } >+ if (pinput_params != NULL) { >+ pinput_params->lpVtbl->Release(pinput_params); >+ pinput_params = NULL; >+ } >+ if (pout_params != NULL) { >+ pout_params->lpVtbl->Release(pout_params); >+ pout_params = NULL; >+ } >+ if (psvc != NULL) { >+ psvc->lpVtbl->Release(psvc); >+ psvc = NULL; >+ } >+ if (ploc != NULL) { >+ ploc->lpVtbl->Release(ploc); >+ ploc = NULL; >+ } >+ if (pclass_instance != NULL) { >+ pclass_instance->lpVtbl->Release(pclass_instance); >+ pclass_instance = NULL; >+ } >+ if (penumerate != NULL) { >+ penumerate->lpVtbl->Release(penumerate); >+ penumerate = NULL; >+ } >+ >+ CoUninitialize(); >+ return retval; >+} >+ >+/* This function will create an internal port on the switch given a >given name >+ * executing the method AddResourceSettings as per documentation: >+ * >https://urldefense.proofpoint.com/v2/url?u=https-3A__msdn.microsoft.com_en >-2Dus_library_hh850019-2528v-3Dvs.85-2529.aspx&d=CwIGaQ&c=Sqcl0Ez6M0X8aeM6 >7LKIiDJAXVeAw-YihVMNtXt-uEs&r=Dcruz40PROJ40ROzSpxyQSLw6fcrOWpJgEcEmNR3JEQ& >m=1NgcutJOUfLwjikmUhz6W0zVXDR35T75FV8sqiZ8ki8&s=KtkOaMFPsRkI7S8YEFN7XDLQgu >UWKnLJ-moHTsCF8Mo&e= . >+ * It will verify if the port is already defined, in which case it will >use >+ * the specific port, and if the forwarding extension "Open vSwitch >Extension" >+ * is enabled and running only on a single switch. >+ * After the port is created and bound to the switch we will disable the >+ * created net adapter and rename it to match the OVS bridge name .*/ >+boolean >+create_wmi_port(char *name) { >+ HRESULT hres = 0; >+ boolean retval = true; >+ >+ BSTR text_object_string = NULL; >+ >+ IWbemLocator *ploc = NULL; >+ IWbemContext *pcontext = NULL; >+ IWbemServices *psvc = NULL; >+ IEnumWbemClassObject *penumerate = NULL; >+ IWbemClassObject *default_settings_data = NULL; >+ IWbemClassObject *default_system = NULL; >+ IWbemClassObject *pcls_obj = NULL; >+ IWbemClassObject *pclass = NULL; >+ IWbemClassObject *pinput_params = NULL; >+ IWbemClassObject *pclass_instance = NULL; >+ IWbemObjectTextSrc *text_object = NULL; >+ IWbemClassObject *pout_params = NULL; >+ >+ wchar_t *wide_name = NULL; >+ VARIANT vt_prop; >+ VARIANT switch_setting_path; >+ VARIANT new_name; >+ SAFEARRAY *psa = SafeArrayCreateVector(VT_BSTR, 0, 1); >+ VARIANT variant_array; >+ LONG count[1]; >+ >+ VariantInit(&vt_prop); >+ VariantInit(&switch_setting_path); >+ sanitize_port_name(name); >+ >+ if (psa == NULL) { >+ VLOG_WARN("Could not allocate memory for a SAFEARRAY"); >+ retval = false; >+ goto error; >+ } >+ >+ if (!initialize_wmi(&ploc, &pcontext)) { >+ VLOG_WARN("Could not initialize DCOM"); >+ retval = false; >+ goto error; >+ } >+ >+ if (!connect_set_security(ploc, pcontext, >L"Root\\Virtualization\\v2", >+ &psvc)) { >+ VLOG_WARN("Could not connect and set security for >virtualization"); >+ retval = false; >+ goto error; >+ } >+ >+ /* Check if the element already exists on the switch. */ >+ wchar_t internal_port_query[2048] = L"SELECT * FROM " >+ L"Msvm_InternalEthernetPort WHERE ElementName = \""; >+ >+ wide_name = malloc((strlen(name) + 1) * sizeof(wchar_t)); >+ if (wide_name == NULL) { >+ VLOG_WARN("Could not allocate memory for wide string"); >+ retval = false; >+ goto error; >+ } >+ >+ if (!tranform_wide(name, wide_name)) { >+ retval = false; >+ goto error; >+ } >+ wcscat_s(internal_port_query, sizeof(internal_port_query), >wide_name); >+ >+ wcscat_s(internal_port_query, sizeof(internal_port_query), L"\""); >+ hres = psvc->lpVtbl->ExecQuery(psvc, >+ L"WQL", >+ internal_port_query, >+ WBEM_FLAG_FORWARD_ONLY | >+ WBEM_FLAG_RETURN_IMMEDIATELY, >+ NULL, >+ &penumerate); >+ >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ >+ if (get_first_element(penumerate, &pcls_obj)) { >+ VLOG_WARN("Port with name: %s already defined on the switch", >name); >+ goto error; >+ } >+ penumerate->lpVtbl->Release(penumerate); >+ penumerate = NULL; >+ >+ /* Check if the extension is enabled and running. Also check if the >+ * the extension is enabled on more than one switch. */ >+ hres = psvc->lpVtbl->ExecQuery(psvc, >+ L"WQL", >+ L"SELECT * " >+ L"FROM Msvm_EthernetSwitchExtension " >+ L"WHERE " >+ L"ElementName=\"Open vSwitch >Extension\" " >+ L"AND EnabledState=2 " >+ L"AND HealthState=5", >+ WBEM_FLAG_FORWARD_ONLY | >+ WBEM_FLAG_RETURN_IMMEDIATELY, >+ NULL, >+ &penumerate); >+ >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ >+ if (!get_first_element(penumerate, &pcls_obj)) { >+ VLOG_WARN("Open vSwitch Extension is not enabled on any switch"); >+ retval = false; >+ goto error; >+ } >+ wcscpy_s(internal_port_query, sizeof(internal_port_query), >+ L"SELECT * FROM Msvm_VirtualEthernetSwitch WHERE Name = >\""); >+ >+ hres = pcls_obj->lpVtbl->Get(pcls_obj, L"SystemName", 0, >+ &vt_prop, 0, 0); >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ >+ wcscat_s(internal_port_query, sizeof(internal_port_query), >+ vt_prop.bstrVal); >+ >+ VariantClear(&vt_prop); >+ pcls_obj->lpVtbl->Release(pcls_obj); >+ pcls_obj = NULL; >+ >+ if (get_first_element(penumerate, &pcls_obj)) { >+ VLOG_WARN("The extension is activated on more than one switch, " >+ "aborting operation. Please activate the extension on >a " >+ "single switch"); >+ retval = false; >+ goto error; >+ } >+ penumerate->lpVtbl->Release(penumerate); >+ penumerate = NULL; >+ if (pcls_obj != NULL) { >+ pcls_obj->lpVtbl->Release(pcls_obj); >+ pcls_obj = NULL; >+ } >+ >+ /* Get the switch object on which the extension is activated. */ >+ wcscat_s(internal_port_query, sizeof(internal_port_query), L"\""); >+ hres = psvc->lpVtbl->ExecQuery(psvc, >+ L"WQL", >+ internal_port_query, >+ WBEM_FLAG_FORWARD_ONLY | >+ WBEM_FLAG_RETURN_IMMEDIATELY, >+ NULL, >+ &penumerate); >+ >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ >+ if (!get_first_element(penumerate, &pcls_obj)) { >+ VLOG_WARN("Could not get the switch object on which the >extension is" >+ "activated"); >+ retval = false; >+ goto error; >+ } >+ penumerate->lpVtbl->Release(penumerate); >+ penumerate = NULL; >+ >+ hres = pcls_obj->lpVtbl->Get(pcls_obj, L"ElementName", 0, &vt_prop, >0, 0); >+ >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ >+ wcscpy_s(internal_port_query, sizeof(internal_port_query), >+ L"SELECT * FROM Msvm_VirtualEthernetSwitchSettingData WHERE >" >+ L"ElementName = \""); >+ >+ wcscat_s(internal_port_query, sizeof(internal_port_query), >+ vt_prop.bstrVal); >+ VariantClear(&vt_prop); >+ >+ hres = pcls_obj->lpVtbl->Get(pcls_obj, L"Name", 0, &vt_prop, 0, 0); >+ >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ pcls_obj->lpVtbl->Release(pcls_obj); >+ pcls_obj = NULL; >+ >+ wcscat_s(internal_port_query, sizeof(internal_port_query), >+ L"\" AND VirtualSystemIdentifier = \""); >+ wcscat_s(internal_port_query, sizeof(internal_port_query), >+ vt_prop.bstrVal); >+ wcscat_s(internal_port_query, sizeof(internal_port_query), >+ L"\" AND InstanceID = \"Microsoft:"); >+ wcscat_s(internal_port_query, sizeof(internal_port_query), >+ vt_prop.bstrVal); >+ wcscat_s(internal_port_query, sizeof(internal_port_query), >+ L"\" AND Caption = \"Virtual Ethernet Switch Settings\" AND >" >+ L"VirtualSystemType = \"DMTF:Virtual Ethernet Switch\""); >+ >+ VariantClear(&vt_prop); >+ >+ /* Retrieve the Msvm_VirtualEthernetSwitchSettingData pinned to the >switch >+ * object on which the extension is activated. */ >+ hres = psvc->lpVtbl->ExecQuery(psvc, >+ L"WQL", >+ internal_port_query, >+ WBEM_FLAG_FORWARD_ONLY | >+ WBEM_FLAG_RETURN_IMMEDIATELY, >+ NULL, >+ &penumerate); >+ >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ >+ if (!get_first_element(penumerate, &pcls_obj)) { >+ VLOG_WARN("Could not get the first " >+ "Msvm_VirtualEthernetSwitchSettingData object"); >+ retval = false; >+ goto error; >+ } >+ penumerate->lpVtbl->Release(penumerate); >+ penumerate = NULL; >+ >+ hres = pcls_obj->lpVtbl->Get(pcls_obj, L"__PATH", 0, >&switch_setting_path, >+ 0, 0); >+ >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ pcls_obj->lpVtbl->Release(pcls_obj); >+ pcls_obj = NULL; >+ >+ /* Retrieve a default allocation port. This object will be later >filled >+ * with optional data to create an switch internal port. */ >+ hres = psvc->lpVtbl->ExecQuery(psvc, >+ L"WQL", >+ L"SELECT * FROM " >+ >L"Msvm_EthernetPortAllocationSettingData " >+ L"WHERE InstanceID LIKE >'%%%%\\\\Default' " >+ L"AND ResourceSubType = " >+ L"'Microsoft:Hyper-V:Ethernet >Connection'", >+ WBEM_FLAG_FORWARD_ONLY | >+ WBEM_FLAG_RETURN_IMMEDIATELY, >+ NULL, >+ &penumerate); >+ >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ >+ if (!get_first_element(penumerate, &default_settings_data)) { >+ VLOG_WARN("Could not retrieve default allocation port object"); >+ retval = false; >+ goto error; >+ } >+ penumerate->lpVtbl->Release(penumerate); >+ penumerate = NULL; >+ >+ /* Retrieve the default computer system on which the port allocation >will >+ * be hosted. */ >+ hres = psvc->lpVtbl->ExecQuery(psvc, >+ L"WQL", >+ L"SELECT * FROM Msvm_ComputerSystem >WHERE " >+ L"Description = \"Microsoft Hosting " >+ L"Computer System\"", >+ WBEM_FLAG_FORWARD_ONLY | >+ WBEM_FLAG_RETURN_IMMEDIATELY, >+ NULL, >+ &penumerate); >+ >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ >+ if (!get_first_element(penumerate, &default_system)) { >+ VLOG_WARN("Could not retrieve default computer system object"); >+ retval = false; >+ goto error; >+ } >+ >+ hres = default_system->lpVtbl->Get(default_system, L"__PATH", >+ 0, &vt_prop, 0, 0); >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ penumerate->lpVtbl->Release(penumerate); >+ penumerate = NULL; >+ >+ count[0] = 0; >+ hres = SafeArrayPutElement(psa, count, vt_prop.bstrVal); >+ >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ >+ VariantClear(&vt_prop); >+ variant_array.vt = VT_ARRAY | VT_BSTR; >+ variant_array.parray = psa; >+ hres = default_settings_data->lpVtbl->Put(default_settings_data, >+ L"HostResource", 0, >+ &variant_array, 0); >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ >+ hres = psvc->lpVtbl->GetObject(psvc, >+ >L"Msvm_VirtualEthernetSwitchManagementService", >+ 0, NULL, &pclass, NULL); >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ >+ hres = pclass->lpVtbl->GetMethod(pclass, L"AddResourceSettings", 0, >+ &pinput_params, NULL); >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ >+ hres = pinput_params->lpVtbl->SpawnInstance(pinput_params, 0, >+ &pclass_instance); >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ >+ /* Store the switch setting path retrieved above in the affected >+ * configuration field of the class instance. */ >+ hres = pclass_instance->lpVtbl->Put(pclass_instance, >+ L"AffectedConfiguration", 0, >+ &switch_setting_path, 0); >+ >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ >+ /* Store the port name in the ElementName field of the default >allocation >+ * data. */ >+ vt_prop.vt = VT_BSTR; >+ vt_prop.bstrVal = SysAllocString(wide_name); >+ hres = default_settings_data->lpVtbl->Put(default_settings_data, >+ L"ElementName", 0, >+ &vt_prop, 0); >+ VariantClear(&vt_prop); >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ >+ /* Retrieve and store the serialized data of the modified default >switch >+ * settings data. */ >+ hres = CoCreateInstance(&CLSID_WbemObjectTextSrc, >+ NULL, >+ CLSCTX_INPROC_SERVER, >+ &IID_IWbemObjectTextSrc, >+ (void**)&text_object); >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ >+ hres = text_object->lpVtbl->GetText(text_object, 0, >+ default_settings_data, >+ WMI_OBJ_TEXT_WMI_DTD_2_0, >+ pcontext, >+ &text_object_string); >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ hres = SafeArrayDestroy(psa); >+ if (FAILED(hres)) { >+ VLOG_WARN("Could not clear the data of the array"); >+ retval = false; >+ goto error; >+ } >+ >+ psa = SafeArrayCreateVector(VT_BSTR, 0, 1); >+ >+ if (psa == NULL) { >+ VLOG_WARN("Could not allocate memory for a SAFEARRAY"); >+ retval = false; >+ goto error; >+ } >+ >+ count[0] = 0; >+ variant_array.parray = psa; >+ hres = SafeArrayPutElement(psa, count, text_object_string); >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ hres = pclass_instance->lpVtbl->Put(pclass_instance, >L"ResourceSettings", >+ 0, &variant_array, 0); >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ >+ /* Get the object of the switch service. */ >+ hres = psvc->lpVtbl->ExecQuery(psvc, >+ L"WQL", >+ L"SELECT * FROM " >+ >L"Msvm_VirtualEthernetSwitchManagementService", >+ WBEM_FLAG_FORWARD_ONLY | >+ WBEM_FLAG_RETURN_IMMEDIATELY, >+ NULL, >+ &penumerate); >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ >+ if (!get_first_element(penumerate, &pcls_obj)) { >+ VLOG_WARN("Could not get the object of the switch service"); >+ retval = false; >+ goto error; >+ } >+ penumerate->lpVtbl->Release(penumerate); >+ penumerate = NULL; >+ >+ hres = pcls_obj->lpVtbl->Get(pcls_obj, L"__PATH", 0, &vt_prop, 0, 0); >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ pcls_obj->lpVtbl->Release(pcls_obj); >+ pcls_obj = NULL; >+ >+ /* Try to add the port to the switch. */ >+ hres = psvc->lpVtbl->ExecMethod(psvc, vt_prop.bstrVal, >+ L"AddResourceSettings", 0, >+ pcontext, pclass_instance, >&pout_params, >+ NULL); >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ >+ unsigned int retvalue = 0; >+ hres = get_uint_value(pout_params, L"ReturnValue", &retvalue); >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ >+ if (retvalue != 0 && retvalue != job_wait) { >+ retval = false; >+ goto error; >+ } >+ >+ if (retvalue == job_wait) { >+ WCHAR job_path[2048]; >+ hres = get_str_value(pout_params, L"Job", job_path, >+ sizeof(job_path) / sizeof(WCHAR)); >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ hres = wait_for_job(psvc, job_path); >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ } >+ >+ pclass->lpVtbl->Release(pclass); >+ pclass = NULL; >+ pclass_instance->lpVtbl->Release(pclass_instance); >+ pclass_instance = NULL; >+ pinput_params->lpVtbl->Release(pinput_params); >+ pinput_params = NULL; >+ psvc->lpVtbl->Release(psvc); >+ psvc = NULL; >+ VariantClear(&vt_prop); >+ >+ if (!connect_set_security(ploc, pcontext, L"Root\\StandardCimv2", >+ &psvc)) { >+ VLOG_WARN("Could not connect and set security for CIM"); >+ retval = false; >+ goto error; >+ } >+ >+ wcscpy_s(internal_port_query, sizeof(internal_port_query), >+ L"SELECT * FROM MSFT_NetAdapter WHERE Name LIKE '%%"); >+ wcscat_s(internal_port_query, sizeof(internal_port_query), >wide_name); >+ wcscat_s(internal_port_query, sizeof(internal_port_query), L"%%'"); >+ >+ /* Get the object with the port name equal to name on the CIM. */ >+ hres = psvc->lpVtbl->ExecQuery(psvc, >+ L"WQL", >+ internal_port_query, >+ WBEM_FLAG_FORWARD_ONLY | >+ WBEM_FLAG_RETURN_IMMEDIATELY, >+ NULL, >+ &penumerate); >+ >+ if (!get_first_element(penumerate, &pcls_obj)) { >+ VLOG_WARN("Element name: %s not found in CIM", name); >+ retval = false; >+ goto error; >+ } >+ penumerate->lpVtbl->Release(penumerate); >+ penumerate = NULL; >+ pcls_obj->lpVtbl->Get(pcls_obj, L"__PATH", 0, &vt_prop, 0, 0); >+ pcls_obj->lpVtbl->Release(pcls_obj); >+ pcls_obj = NULL; >+ >+ /* Disable the adapter with port name equal with name. */ >+ hres = psvc->lpVtbl->ExecMethod(psvc, vt_prop.bstrVal, L"Disable", 0, >+ pcontext, NULL, NULL, NULL); >+ >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ >+ hres = psvc->lpVtbl->GetObject(psvc, L"MSFT_NetAdapter", 0, NULL, >&pclass, >+ NULL); >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ >+ hres = pclass->lpVtbl->GetMethod(pclass, L"Rename", 0, >&pinput_params, >+ NULL); >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ >+ hres = pinput_params->lpVtbl->SpawnInstance(pinput_params, 0, >+ &pclass_instance); >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ >+ VariantInit(&new_name); >+ new_name.vt = VT_BSTR; >+ new_name.bstrVal = wide_name; >+ hres = pclass_instance->lpVtbl->Put(pclass_instance, L"NewName", 0, >+ &new_name, 0); >+ if (FAILED(hres)) { >+ retval = false; >+ goto error; >+ } >+ hres = psvc->lpVtbl->ExecMethod(psvc, vt_prop.bstrVal, L"Rename", 0, >+ pcontext, pclass_instance, NULL, >NULL); >+ if (FAILED(hres)) { >+ retval = false; >+ } >+ >+error: >+ if (text_object_string != NULL) { >+ SysFreeString(text_object_string); >+ text_object_string = NULL; >+ } >+ if (psa != NULL) { >+ SafeArrayDestroy(psa); >+ psa = NULL; >+ } >+ if (ploc != NULL) { >+ ploc->lpVtbl->Release(ploc); >+ ploc = NULL; >+ } >+ if (pcontext != NULL) { >+ pcontext->lpVtbl->Release(pcontext); >+ pcontext = NULL; >+ } >+ if (psvc != NULL) { >+ psvc->lpVtbl->Release(psvc); >+ psvc = NULL; >+ } >+ if (penumerate != NULL) { >+ penumerate->lpVtbl->Release(penumerate); >+ penumerate = NULL; >+ } >+ if (default_settings_data != NULL) { >+ default_settings_data->lpVtbl->Release(default_settings_data); >+ default_settings_data = NULL; >+ } >+ if (default_system != NULL) { >+ default_system->lpVtbl->Release(default_system); >+ default_system = NULL; >+ } >+ if (pcls_obj != NULL) { >+ pcls_obj->lpVtbl->Release(pcls_obj); >+ pcls_obj = NULL; >+ } >+ if (pclass != NULL) { >+ pclass->lpVtbl->Release(pclass); >+ pclass = NULL; >+ } >+ if (pinput_params != NULL) { >+ pinput_params->lpVtbl->Release(pinput_params); >+ pinput_params = NULL; >+ } >+ if (pclass_instance != NULL) { >+ pclass_instance->lpVtbl->Release(pclass_instance); >+ pclass_instance = NULL; >+ } >+ if (text_object != NULL) { >+ text_object->lpVtbl->Release(text_object); >+ text_object = NULL; >+ } >+ if (pout_params != NULL) { >+ pout_params->lpVtbl->Release(pout_params); >+ pout_params = NULL; >+ } >+ if (wide_name != NULL) { >+ free(wide_name); >+ wide_name = NULL; >+ } >+ VariantClear(&vt_prop); >+ VariantClear(&switch_setting_path); >+ >+ if (!retval) { >+ get_hres_error(hres); >+ } >+ CoUninitialize(); >+ return retval; >+} >diff --git a/lib/wmi.h b/lib/wmi.h >new file mode 100644 >index 0000000..28910e7 >--- /dev/null >+++ b/lib/wmi.h >@@ -0,0 +1,51 @@ >+/* >+ * Copyright (c) 2016 Cloudbase Solutions Srl >+ * >+ * Licensed under the Apache License, Version 2.0 (the "License"); >+ * you may not use this file except in compliance with the License. >+ * You may obtain a copy of the License at >+ * >+ * >https://urldefense.proofpoint.com/v2/url?u=http-3A__www.apache.org_license >s_LICENSE-2D2.0&d=CwIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-YihVMNtXt-uEs&r=D >cruz40PROJ40ROzSpxyQSLw6fcrOWpJgEcEmNR3JEQ&m=1NgcutJOUfLwjikmUhz6W0zVXDR35 >T75FV8sqiZ8ki8&s=6YJXIuUkmHpuGcJw64GoPVKdYVnqhnBsGxStg7axmxs&e= >+ * >+ * Unless required by applicable law or agreed to in writing, software >+ * distributed under the License is distributed on an "AS IS" BASIS, >+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or >implied. >+ * See the License for the specific language governing permissions and >+ * limitations under the License. >+ */ >+ >+#ifndef WMI_H >+#define WMI_H 1 >+ >+#include <windefs.h> >+#include <Wbemidl.h> >+ >+static inline void fill_context(IWbemContext *pContext) >+{ >+ VARIANT var; >+ >+ /* IncludeQualifiers. */ >+ VariantInit(&var); >+ var.vt = VT_BOOL; >+ var.boolVal = VARIANT_TRUE; >+ pContext->lpVtbl->SetValue(pContext, L"IncludeQualifiers", 0, &var); >+ VariantClear(&var); >+ >+ VariantInit(&var); >+ var.vt = VT_I4; >+ var.lVal = 0; >+ pContext->lpVtbl->SetValue(pContext, L"PathLevel", 0, &var); >+ VariantClear(&var); >+ >+ /* ExcludeSystemProperties. */ >+ VariantInit(&var); >+ var.vt = VT_BOOL; >+ var.boolVal = VARIANT_FALSE; >+ pContext->lpVtbl->SetValue(pContext, L"ExcludeSystemProperties", 0, >&var); >+ VariantClear(&var); >+} >+ >+boolean create_wmi_port(char *name); >+boolean delete_wmi_port(char *name); >+ >+#endif /* wmi.h */ >-- >2.9.2.windows.1 > >_______________________________________________ >dev mailing list >dev@openvswitch.org >https://urldefense.proofpoint.com/v2/url?u=http-3A__openvswitch.org_mailma >n_listinfo_dev&d=CwIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-YihVMNtXt-uEs&r=Dc >ruz40PROJ40ROzSpxyQSLw6fcrOWpJgEcEmNR3JEQ&m=1NgcutJOUfLwjikmUhz6W0zVXDR35T >75FV8sqiZ8ki8&s=YMq7EI4iHIjlQKCYB1Lil7Pq3-80pelN7ZKYA4JvBb4&e=
On 10 October 2016 at 15:47, Sairam Venugopal <vsairam@vmware.com> wrote: > Sorry for the delay in the review. > > Acked-by: Sairam Venugopal <vsairam@vmware.com> > There is a v5 of this series. Would you mind looking at that. > > > > On 8/12/16, 6:06 PM, "Alin Serdean" <aserdean@cloudbasesolutions.com> > wrote: > > >This patch updates the following commands in the vswitch: > >ovs-vsctl add-br br-test > >ovs-vsctl del-br br-test > > > >ovs-vsctl add-br br-test: > > This command will now create an internal port on the MSFT virtual > >switch > > using the WMI interface from Msvm_VirtualEthernetSwitchManagemen > tService > > leveraging the method AddResourceSettings. > > Before creating the actual port, the switch will be queried to see if > >there > > is not a port already created (good for restarts when restarting the > > vswitch daemon). If there is a port defined it will return success and > >log > > a message. > > After checking if the port already exists the command will also verify > > if the forwarding extension (windows datapath) is enabled and on a > >single > > switch. If it is not activated or if it is activated on multiple > >switches > > it will return an error and a message will be logged. > > After the port was created on the switch, we will disable the adapter > >on > > the host and rename to the corresponding OVS bridge name for > >consistency. > > The user will enable and set the values he wants after creation. > > > >ovs-vsctl del-br br-test > > This command will remove an internal port on the MSFT virtual switch > > using the Msvm_VirtualEthernetSwitchManagementService class and > >executing > > the method RemoveResourceSettings. > > > >Both commands will be blocking until the WMI job is finished, this allows > >us > >to guarantee that the ports are created and their name are set before > >issuing > >a netlink message to the windows datapath. > > > >This patch also includes helpers for normal WMI retrievals and > >initializations. > >Appveyor and documentation has been modified to include the libraries > >needed > >for COM objects. > > > >This patch was tested individually using IMallocSpy and CRT heap checks > >to ensure no new memory leaks are introduced. > > > >Tested on the following OS's: > >Windows 2012 and Windows 2012r2 > > > >Signed-off-by: Alin Gabriel Serdean <aserdean@cloudbasesolutions.com> > >Acked-by: Paul Boca <pboca@cloudbasesolutions.com> > >--- > >v4: address comments (sanitize input, short refactor) > > use full stop on comments > > update coding style > >v3: rebase, add acked > >v2: Address comments. Rebase > >--- > > appveyor.yml | 2 +- > > lib/automake.mk | 4 +- > > lib/dpif-netlink.c | 21 + > > lib/wmi.c | 1276 > >++++++++++++++++++++++++++++++++++++++++++++++++++++ > > lib/wmi.h | 51 +++ > > 5 files changed, 1352 insertions(+), 2 deletions(-) > > create mode 100644 lib/wmi.c > > create mode 100644 lib/wmi.h > > > >diff --git a/appveyor.yml b/appveyor.yml > >index 0fd003b..1061df6 100644 > >--- a/appveyor.yml > >+++ b/appveyor.yml > >@@ -41,5 +41,5 @@ build_script: > > - C:\MinGW\msys\1.0\bin\bash -lc "cp > >/c/pthreads-win32/Pre-built.2/dll/x86/*.dll /c/openvswitch/." > > - C:\MinGW\msys\1.0\bin\bash -lc "mv /bin/link.exe /bin/link_copy.exe" > > - C:\MinGW\msys\1.0\bin\bash -lc "cd /c/openvswitch && ./boot.sh" > >-- C:\MinGW\msys\1.0\bin\bash -lc "cd /c/openvswitch && ./configure > >CC=build-aux/cccl LD=\"`which link`\" LIBS=\"-lws2_32 -liphlpapi\" > >--with-pthread=C:/pthreads-win32/Pre-built.2 > >--with-openssl=C:/OpenSSL-Win32 --with-vstudiotarget=\"Debug\"" > >+- C:\MinGW\msys\1.0\bin\bash -lc "cd /c/openvswitch && ./configure > >CC=build-aux/cccl LD=\"`which link`\" LIBS=\"-lws2_32 -liphlpapi > >-lwbemuuid -lole32 -loleaut32\" > >--with-pthread=C:/pthreads-win32/Pre-built.2 > >--with-openssl=C:/OpenSSL-Win32 --with-vstudiotarget=\"Debug\"" > > - C:\MinGW\msys\1.0\bin\bash -lc "cd /c/openvswitch && make" > >diff --git a/lib/automake.mk b/lib/automake.mk > >index 2faaeac..99bbdc0 100644 > >--- a/lib/automake.mk > >+++ b/lib/automake.mk > >@@ -387,7 +387,9 @@ lib_libopenvswitch_la_SOURCES += \ > > lib/netlink-notifier.h \ > > lib/netlink-protocol.h \ > > lib/netlink-socket.c \ > >- lib/netlink-socket.h > >+ lib/netlink-socket.h \ > >+ lib/wmi.c \ > >+ lib/wmi.h > > endif > > > > if HAVE_POSIX_AIO > >diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c > >index a39faa2..c8b0e37 100644 > >--- a/lib/dpif-netlink.c > >+++ b/lib/dpif-netlink.c > >@@ -58,6 +58,7 @@ > > > > VLOG_DEFINE_THIS_MODULE(dpif_netlink); > > #ifdef _WIN32 > >+#include "wmi.h" > > enum { WINDOWS = 1 }; > > #else > > enum { WINDOWS = 0 }; > >@@ -849,6 +850,16 @@ dpif_netlink_port_add__(struct dpif_netlink *dpif, > >struct netdev *netdev, > > #endif > > } > > > >+#ifdef _WIN32 > >+ if (request.type == OVS_VPORT_TYPE_INTERNAL) { > >+ if (!create_wmi_port(name)){ > >+ VLOG_ERR("Could not create wmi internal port with name:%s", > >name); > >+ vport_del_socksp(dpif, socksp); > >+ return EINVAL; > >+ }; > >+ } > >+#endif > >+ > > tnl_cfg = netdev_get_tunnel_config(netdev); > > if (tnl_cfg && (tnl_cfg->dst_port != 0 || tnl_cfg->exts)) { > > ofpbuf_use_stack(&options, options_stub, sizeof options_stub); > >@@ -940,6 +951,16 @@ dpif_netlink_port_del__(struct dpif_netlink *dpif, > >odp_port_t port_no) > > vport.cmd = OVS_VPORT_CMD_DEL; > > vport.dp_ifindex = dpif->dp_ifindex; > > vport.port_no = port_no; > >+#ifdef _WIN32 > >+ struct dpif_port temp_dpif_port; > >+ dpif_netlink_port_query__(dpif, port_no, NULL, &temp_dpif_port); > >+ if (!strcmp(temp_dpif_port.type, "internal")) { > >+ if (!delete_wmi_port(temp_dpif_port.name)){ > >+ VLOG_ERR("Could not delete wmi port with name: %s", > >+ temp_dpif_port.name); > >+ }; > >+ } > >+#endif > > error = dpif_netlink_vport_transact(&vport, NULL, NULL); > > > > vport_del_channels(dpif, port_no); > >diff --git a/lib/wmi.c b/lib/wmi.c > >new file mode 100644 > >index 0000000..67f0873 > >--- /dev/null > >+++ b/lib/wmi.c > >@@ -0,0 +1,1276 @@ > >+/* > >+ * Copyright (c) 2016 Cloudbase Solutions Srl > >+ * > >+ * Licensed under the Apache License, Version 2.0 (the "License"); > >+ * you may not use this file except in compliance with the License. > >+ * You may obtain a copy of the License at > >+ * > >+ * > >https://urldefense.proofpoint.com/v2/url?u=http- > 3A__www.apache.org_license > >s_LICENSE-2D2.0&d=CwIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw- > YihVMNtXt-uEs&r=D > >cruz40PROJ40ROzSpxyQSLw6fcrOWpJgEcEmNR3JEQ&m= > 1NgcutJOUfLwjikmUhz6W0zVXDR35 > >T75FV8sqiZ8ki8&s=6YJXIuUkmHpuGcJw64GoPVKdYVnqhnBsGxStg7axmxs&e= > >+ * > >+ * Unless required by applicable law or agreed to in writing, software > >+ * distributed under the License is distributed on an "AS IS" BASIS, > >+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or > >implied. > >+ * See the License for the specific language governing permissions and > >+ * limitations under the License. > >+ */ > >+ > >+#include <config.h> > >+#include "wmi.h" > >+#include <stdlib.h> > >+#include <stdio.h> > >+#include <tchar.h> > >+#include <Windows.h> > >+#include "openvswitch/vlog.h" > >+ > >+VLOG_DEFINE_THIS_MODULE(wmi); > >+ > >+/* WMI Job values. */ > >+enum job_status > >+{ > >+ job_starting = 3, > >+ job_running = 4, > >+ job_completed = 7, > >+ job_wait = 4096 > >+}; > >+ > >+static char * > >+sanitize_port_name(char *name) > >+{ > >+ char *p1, *p2; > >+ p1 = p2 = name; > >+ > >+ while (*p1) { > >+ if ((*p1) == '\'' || (*p1) == '\"') { > >+ p1++; > >+ } else { > >+ *p2 = *p1; > >+ p2++; > >+ p1++; > >+ } > >+ } > >+ *p2 = '\0'; > >+ return name; > >+} > >+ > >+/* This function will output the appropriate message for a given > >HRESULT.*/ > >+static void > >+get_hres_error(HRESULT hres) > >+{ > >+ char *error_msg = NULL; > >+ > >+ if (FACILITY_WINDOWS == HRESULT_FACILITY(hres)) { > >+ hres = HRESULT_CODE(hres); > >+ } > >+ > >+ VLOG_ERR("%s", ovs_format_message(hres)); > >+} > >+ > >+static boolean > >+check_return_value(HRESULT hres) > >+{ > >+ if (FAILED(hres)) { > >+ get_hres_error(hres); > >+ return false; > >+ } > >+ > >+ return true; > >+} > >+ > >+static HRESULT > >+get_variant_value(IWbemClassObject *pcls_obj, wchar_t *field_name, > >+ VARIANT *value) > >+{ > >+ HRESULT hres; > >+ > >+ VariantInit(value); > >+ > >+ hres = pcls_obj->lpVtbl->Get(pcls_obj, field_name, 0, value, 0, 0); > >+ > >+ if (FAILED(hres)) { > >+ VariantClear(value); > >+ } > >+ > >+ return hres; > >+} > >+ > >+/* This function retrieves the uint16_t value from a given class object > >with > >+ * the field name field_name. */ > >+static HRESULT > >+get_uint16_t_value(IWbemClassObject *pcls_obj, wchar_t *field_name, > >+ uint16_t *value) > >+{ > >+ VARIANT vt_prop; > >+ HRESULT hres = get_variant_value(pcls_obj, field_name, &vt_prop); > >+ *value = V_UI2(&vt_prop); > >+ > >+ return hres; > >+} > >+ > >+/* This function retrieves the unsigned int values from a given class > >object > >+ * with the field name field_name. */ > >+static HRESULT > >+get_uint_value(IWbemClassObject *pcls_obj, wchar_t *field_name, > >+ unsigned int *value) > >+{ > >+ VARIANT vt_prop; > >+ HRESULT hres = get_variant_value(pcls_obj, field_name, &vt_prop); > >+ *value = V_UI4(&vt_prop); > >+ > >+ return hres; > >+} > >+ > >+/* This function retrieves the unsigned short value from a given class > >object > >+ * with the field name field_name. */ > >+static HRESULT > >+get_ushort_value(IWbemClassObject *pcls_obj, wchar_t *field_name, > >+ unsigned short *value) > >+{ > >+ VARIANT vt_prop; > >+ HRESULT hres = get_variant_value(pcls_obj, field_name, &vt_prop); > >+ *value = V_UI2(&vt_prop); > >+ > >+ return hres; > >+} > >+ > >+/* This function retrieves the BSTR value from a given class object with > >+ * the field name field_name, to a preallocated destination dest and > >with the > >+ * maximum length max_dest_lgth. */ > >+static HRESULT > >+get_str_value(IWbemClassObject *pcls_obj, wchar_t *field_name, wchar_t > >*dest, > >+ int max_dest_lgth) > >+{ > >+ VARIANT vt_prop; > >+ HRESULT hres = get_variant_value(pcls_obj, field_name, &vt_prop); > >+ > >+ if (wcscpy_s(dest, max_dest_lgth, vt_prop.bstrVal)) { > >+ VariantClear(&vt_prop); > >+ VLOG_WARN("get_str_value, wcscpy_s failed :%s", > >ovs_strerror(errno)); > >+ return WBEM_E_FAILED; > >+ } > >+ > >+ VariantClear(&vt_prop); > >+ return S_OK; > >+} > >+ > >+/* This function waits for a WMI job to finish and retrieves the error > >code > >+ * if the job failed */ > >+static HRESULT > >+wait_for_job(IWbemServices *psvc, wchar_t *job_path) > >+{ > >+ IWbemClassObject *pcls_obj = NULL; > >+ HRESULT retval = 0; > >+ uint16_t job_state = 0; > >+ uint16_t error = 0; > >+ > >+ do { > >+ if(!check_return_value(psvc->lpVtbl->GetObject(psvc, job_path, > >0, NULL, > >+ &pcls_obj, > >NULL))) { > >+ retval = WBEM_E_FAILED; > >+ break; > >+ } > >+ > >+ retval = get_uint16_t_value(pcls_obj, L"JobState", &job_state); > >+ if (FAILED(retval)) { > >+ break; > >+ } > >+ > >+ if (job_state == job_starting || job_state == job_running) { > >+ Sleep(200); > >+ } else if (job_state == job_completed) { > >+ break; > >+ } else { > >+ /* Error occurred. */ > >+ retval = get_uint16_t_value(pcls_obj, L"ErrorCode", &error); > >+ if (FAILED(retval)) { > >+ break; > >+ } > >+ VLOG_WARN("Job failed with error: %d", error); > >+ retval = WBEM_E_FAILED;; > >+ break; > >+ } > >+ > >+ if (pcls_obj != NULL) { > >+ pcls_obj->lpVtbl->Release(pcls_obj); > >+ pcls_obj = NULL; > >+ } > >+ } while(TRUE); > >+ > >+ if (pcls_obj != NULL) { > >+ pcls_obj->lpVtbl->Release(pcls_obj); > >+ pcls_obj = NULL; > >+ } > >+ > >+ return retval; > >+} > >+ > >+/* This function will initialize DCOM retrieving the WMI locator's ploc > >and > >+ * the context associated to it. */ > >+static boolean > >+initialize_wmi(IWbemLocator **ploc, IWbemContext **pcontext) > >+{ > >+ HRESULT hres = 0; > >+ > >+ /* Initialize COM. */ > >+ hres = CoInitialize(NULL); > >+ > >+ if (FAILED(hres)) { > >+ return false; > >+ } > >+ > >+ /* Initialize COM security. */ > >+ hres = CoInitializeSecurity(NULL, > >+ -1, > >+ NULL, > >+ NULL, > >+ RPC_C_AUTHN_LEVEL_DEFAULT, > >+ RPC_C_IMP_LEVEL_IMPERSONATE, > >+ NULL, > >+ EOAC_NONE, > >+ NULL); > >+ > >+ if (FAILED(hres)) { > >+ return false; > >+ } > >+ > >+ /* Fill context. */ > >+ hres = CoCreateInstance(&CLSID_WbemContext, > >+ NULL, > >+ CLSCTX_INPROC_SERVER, > >+ &IID_IWbemContext, > >+ (void**)pcontext); > >+ > >+ if (FAILED(hres)) { > >+ return false; > >+ } > >+ > >+ fill_context(*pcontext); > >+ > >+ /* Initialize locator's (ploc) to WMI. */ > >+ hres = CoCreateInstance(&CLSID_WbemLocator, > >+ NULL, > >+ CLSCTX_INPROC_SERVER, > >+ &IID_IWbemLocator, > >+ (LPVOID *)ploc); > >+ > >+ if (FAILED(hres)) { > >+ return false; > >+ } > >+ > >+ return true; > >+} > >+ > >+/* This function connects the WMI locator's ploc to a given WMI provider > >+ * defined in server and also sets the required security levels for a > >local > >+ * connection to it. */ > >+static boolean > >+connect_set_security(IWbemLocator *ploc, IWbemContext *pcontext, > >+ wchar_t *server, IWbemServices **psvc) > >+{ > >+ HRESULT hres = 0; > >+ > >+ /* Connect to server. */ > >+ hres = ploc->lpVtbl->ConnectServer(ploc, > >+ server, > >+ NULL, > >+ NULL, > >+ 0, > >+ 0, > >+ 0, > >+ pcontext, > >+ psvc); > >+ > >+ if (FAILED(hres)) { > >+ return false; > >+ } > >+ > >+ /* Set security levels. */ > >+ hres = CoSetProxyBlanket((IUnknown *) *psvc, > >+ RPC_C_AUTHN_WINNT, > >+ RPC_C_AUTHZ_NONE, > >+ NULL, > >+ RPC_C_AUTHN_LEVEL_CALL, > >+ RPC_C_IMP_LEVEL_IMPERSONATE, > >+ NULL, > >+ EOAC_NONE); > >+ > >+ if (FAILED(hres)) { > >+ return false; > >+ } > >+ > >+ return true; > >+} > >+ > >+/* This function retrieves the first class object of a given enumeration > >+ * outputted by a query and fails if it could not retrieve the object or > >there > >+ * was no object to retrieve */ > >+static boolean > >+get_first_element(IEnumWbemClassObject *penumerate, > >+ IWbemClassObject **pcls_obj) > >+{ > >+ unsigned long retval = 0; > >+ > >+ if (penumerate == NULL) { > >+ VLOG_WARN("Enumeration Class Object is NULL. Cannot get the > >first" > >+ "object"); > >+ return false; > >+ } > >+ > >+ HRESULT hres = penumerate->lpVtbl->Next(penumerate, WBEM_INFINITE, > 1, > >+ pcls_obj, &retval); > >+ > >+ > >+ if (!check_return_value(hres) || retval == 0) { > >+ return false; > >+ } > >+ > >+ return true; > >+} > >+ > >+/* This function is a wrapper that transforms a char * into a wchar_t * > >*/ > >+static boolean > >+tranform_wide(char *name, wchar_t *wide_name) > >+{ > >+ unsigned long size = strlen(name) + 1; > >+ long long ret = 0; > >+ > >+ if (wide_name == NULL) { > >+ VLOG_WARN("Provided wide string is NULL"); > >+ return false; > >+ } > >+ > >+ ret = mbstowcs(wide_name, name, size); > >+ > >+ if (ret == -1) { > >+ VLOG_WARN("Invalid multibyte character is encountered"); > >+ return false; > >+ } else if (ret == size) { > >+ VLOG_WARN("Returned wide string not NULL terminated"); > >+ return false; > >+ } > >+ > >+ return true; > >+} > >+ > >+/* This function will delete a switch internal port with a given name as > >input > >+ * executing "RemoveResourceSettings" as per documentation: > >+ * > >https://urldefense.proofpoint.com/v2/url?u=https- > 3A__msdn.microsoft.com_en > >-2Dus_library_hh850277-2528v-3Dvs.85-2529.aspx&d=CwIGaQ&c= > Sqcl0Ez6M0X8aeM6 > >7LKIiDJAXVeAw-YihVMNtXt-uEs&r=Dcruz40PROJ40ROzSpxyQSLw6fcrOW > pJgEcEmNR3JEQ& > >m=1NgcutJOUfLwjikmUhz6W0zVXDR35T75FV8sqiZ8ki8&s= > tLEsQhF14PQ5LahGIKh2T8Z5h- > >JPdlzvoU3ecWYc9hg&e= > >+ * allocating the data and populating the needed fields to execute the > >+ * method */ > >+boolean > >+delete_wmi_port(char *name) > >+{ > >+ HRESULT hres = 0; > >+ boolean retval = true; > >+ > >+ IWbemLocator *ploc = NULL; > >+ IWbemServices *psvc = NULL; > >+ IWbemContext *pcontext = NULL; > >+ IWbemClassObject *pclass_instance = NULL; > >+ IWbemClassObject *pinput_params = NULL; > >+ IWbemClassObject *pcls_obj = NULL; > >+ IWbemClassObject *pout_params = NULL; > >+ IEnumWbemClassObject *penumerate = NULL; > >+ > >+ sanitize_port_name(name); > >+ VARIANT vt_prop; > >+ VARIANT variant_array; > >+ wchar_t *wide_name = NULL; > >+ VariantInit(&vt_prop); > >+ VariantInit(&variant_array); > >+ > >+ LONG count[1]; > >+ SAFEARRAY* psa = SafeArrayCreateVector(VT_BSTR, 0, 1); > >+ if (psa == NULL) { > >+ VLOG_WARN("Could not allocate memory for a SAFEARRAY"); > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ if (!initialize_wmi(&ploc, &pcontext)) { > >+ VLOG_WARN("Could not initialize DCOM"); > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ if (!connect_set_security(ploc, pcontext, > >L"Root\\Virtualization\\v2", > >+ &psvc)) { > >+ VLOG_WARN("Could not connect and set security for > >virtualization"); > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ > >+ /* Get the port with the element name equal to the name input. */ > >+ wchar_t internal_port_query[2048] = L"SELECT * from " > >+ L"Msvm_EthernetPortAllocationSettingData WHERE ElementName = > >\"" ; > >+ > >+ wide_name = malloc((strlen(name) + 1) * sizeof(wchar_t)); > >+ if (wide_name == NULL) { > >+ VLOG_WARN("Could not allocate memory for wide string"); > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ if (!tranform_wide(name, wide_name)) { > >+ retval = false; > >+ goto error; > >+ } > >+ wcscat_s(internal_port_query, sizeof(internal_port_query), > >wide_name); > >+ > >+ wcscat_s(internal_port_query, sizeof(internal_port_query), L"\""); > >+ > >+ hres = psvc->lpVtbl->ExecQuery(psvc, > >+ L"WQL", > >+ internal_port_query, > >+ WBEM_FLAG_FORWARD_ONLY | > >+ WBEM_FLAG_RETURN_IMMEDIATELY, > >+ NULL, > >+ &penumerate); > >+ > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ /* Get the element path on the switch which will be deleted. */ > >+ if (!get_first_element(penumerate, &pcls_obj)) { > >+ retval = false; > >+ goto error; > >+ } > >+ penumerate->lpVtbl->Release(penumerate); > >+ penumerate = NULL; > >+ > >+ hres = pcls_obj->lpVtbl->Get(pcls_obj, L"__PATH", 0, &vt_prop, 0, > 0); > >+ > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ pcls_obj->lpVtbl->Release(pcls_obj); > >+ pcls_obj = NULL; > >+ > >+ /* Get the class object and the parameters it can have. */ > >+ hres = psvc->lpVtbl->GetObject(psvc, > >+ L"Msvm_VirtualEthernetSwitchManagementService", 0, NULL, > >&pcls_obj, > >+ NULL); > >+ > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ hres = pcls_obj->lpVtbl->GetMethod(pcls_obj, > >L"RemoveResourceSettings", 0, > >+ &pinput_params, NULL); > >+ > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ pcls_obj->lpVtbl->Release(pcls_obj); > >+ pcls_obj = NULL; > >+ > >+ hres = pinput_params->lpVtbl->SpawnInstance(pinput_params, 0, > >+ &pclass_instance); > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ count[0] = 0; > >+ > >+ hres = SafeArrayPutElement(psa, count, vt_prop.bstrVal); > >+ > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ VariantClear(&vt_prop); > >+ VariantInit(&vt_prop); > >+ variant_array.vt = VT_ARRAY | VT_BSTR; > >+ variant_array.parray = psa; > >+ > >+ hres = pclass_instance->lpVtbl->Put(pclass_instance, > >L"ResourceSettings", 0, > >+ &variant_array, 0); > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ /* Get the object of the Msvm_VirtualEthernetSwitchManagementService > >which > >+ * we need to invoke the port deletion. */ > >+ hres = psvc->lpVtbl->ExecQuery(psvc, > >+ L"WQL", > >+ L"SELECT * FROM " > >+ > >L"Msvm_VirtualEthernetSwitchManagementService", > >+ WBEM_FLAG_FORWARD_ONLY | > >+ WBEM_FLAG_RETURN_IMMEDIATELY, > >+ NULL, > >+ &penumerate); > >+ > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ if (!get_first_element(penumerate, &pcls_obj)) { > >+ retval = false; > >+ goto error; > >+ } > >+ penumerate->lpVtbl->Release(penumerate); > >+ penumerate = NULL; > >+ > >+ hres = pcls_obj->lpVtbl->Get(pcls_obj, L"__PATH", 0, &vt_prop, 0, > 0); > >+ > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ pcls_obj->lpVtbl->Release(pcls_obj); > >+ pcls_obj = NULL; > >+ > >+ /* Invoke the delete port method. */ > >+ hres = psvc->lpVtbl->ExecMethod(psvc, vt_prop.bstrVal, > >+ L"RemoveResourceSettings", 0, > >+ pcontext, pclass_instance, > >&pout_params, > >+ NULL); > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ VariantClear(&vt_prop); > >+ VariantInit(&vt_prop); > >+ > >+ hres = pout_params->lpVtbl->Get(pout_params, L"ReturnValue", 0, > >+ &vt_prop, NULL, 0); > >+ > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ unsigned int retvalue = 0; > >+ hres = get_uint_value(pout_params, L"ReturnValue", &retvalue); > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ if (retvalue != 0 && retvalue != job_wait) { > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ if (retvalue == job_wait) { > >+ WCHAR job_path[2048]; > >+ hres = get_str_value(pout_params, L"Job", job_path, > >+ sizeof(job_path) / sizeof(WCHAR)); > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ hres = wait_for_job(psvc, job_path); > >+ if (FAILED(hres)) { > >+ retval = false; > >+ } > >+ } > >+ > >+error: > >+ VariantClear(&vt_prop); > >+ > >+ if (pcontext != NULL) { > >+ pcontext->lpVtbl->Release(pcontext); > >+ pcontext = NULL; > >+ } > >+ if (psa != NULL) { > >+ SafeArrayDestroy(psa); > >+ psa = NULL; > >+ } > >+ if (pcls_obj != NULL) { > >+ pcls_obj->lpVtbl->Release(pcls_obj); > >+ pcls_obj = NULL; > >+ } > >+ if (wide_name != NULL) { > >+ free(wide_name); > >+ wide_name = NULL; > >+ } > >+ if (!retval) { > >+ get_hres_error(hres); > >+ } > >+ if (pinput_params != NULL) { > >+ pinput_params->lpVtbl->Release(pinput_params); > >+ pinput_params = NULL; > >+ } > >+ if (pout_params != NULL) { > >+ pout_params->lpVtbl->Release(pout_params); > >+ pout_params = NULL; > >+ } > >+ if (psvc != NULL) { > >+ psvc->lpVtbl->Release(psvc); > >+ psvc = NULL; > >+ } > >+ if (ploc != NULL) { > >+ ploc->lpVtbl->Release(ploc); > >+ ploc = NULL; > >+ } > >+ if (pclass_instance != NULL) { > >+ pclass_instance->lpVtbl->Release(pclass_instance); > >+ pclass_instance = NULL; > >+ } > >+ if (penumerate != NULL) { > >+ penumerate->lpVtbl->Release(penumerate); > >+ penumerate = NULL; > >+ } > >+ > >+ CoUninitialize(); > >+ return retval; > >+} > >+ > >+/* This function will create an internal port on the switch given a > >given name > >+ * executing the method AddResourceSettings as per documentation: > >+ * > >https://urldefense.proofpoint.com/v2/url?u=https- > 3A__msdn.microsoft.com_en > >-2Dus_library_hh850019-2528v-3Dvs.85-2529.aspx&d=CwIGaQ&c= > Sqcl0Ez6M0X8aeM6 > >7LKIiDJAXVeAw-YihVMNtXt-uEs&r=Dcruz40PROJ40ROzSpxyQSLw6fcrOW > pJgEcEmNR3JEQ& > >m=1NgcutJOUfLwjikmUhz6W0zVXDR35T75FV8sqiZ8ki8&s= > KtkOaMFPsRkI7S8YEFN7XDLQgu > >UWKnLJ-moHTsCF8Mo&e= . > >+ * It will verify if the port is already defined, in which case it will > >use > >+ * the specific port, and if the forwarding extension "Open vSwitch > >Extension" > >+ * is enabled and running only on a single switch. > >+ * After the port is created and bound to the switch we will disable the > >+ * created net adapter and rename it to match the OVS bridge name .*/ > >+boolean > >+create_wmi_port(char *name) { > >+ HRESULT hres = 0; > >+ boolean retval = true; > >+ > >+ BSTR text_object_string = NULL; > >+ > >+ IWbemLocator *ploc = NULL; > >+ IWbemContext *pcontext = NULL; > >+ IWbemServices *psvc = NULL; > >+ IEnumWbemClassObject *penumerate = NULL; > >+ IWbemClassObject *default_settings_data = NULL; > >+ IWbemClassObject *default_system = NULL; > >+ IWbemClassObject *pcls_obj = NULL; > >+ IWbemClassObject *pclass = NULL; > >+ IWbemClassObject *pinput_params = NULL; > >+ IWbemClassObject *pclass_instance = NULL; > >+ IWbemObjectTextSrc *text_object = NULL; > >+ IWbemClassObject *pout_params = NULL; > >+ > >+ wchar_t *wide_name = NULL; > >+ VARIANT vt_prop; > >+ VARIANT switch_setting_path; > >+ VARIANT new_name; > >+ SAFEARRAY *psa = SafeArrayCreateVector(VT_BSTR, 0, 1); > >+ VARIANT variant_array; > >+ LONG count[1]; > >+ > >+ VariantInit(&vt_prop); > >+ VariantInit(&switch_setting_path); > >+ sanitize_port_name(name); > >+ > >+ if (psa == NULL) { > >+ VLOG_WARN("Could not allocate memory for a SAFEARRAY"); > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ if (!initialize_wmi(&ploc, &pcontext)) { > >+ VLOG_WARN("Could not initialize DCOM"); > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ if (!connect_set_security(ploc, pcontext, > >L"Root\\Virtualization\\v2", > >+ &psvc)) { > >+ VLOG_WARN("Could not connect and set security for > >virtualization"); > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ /* Check if the element already exists on the switch. */ > >+ wchar_t internal_port_query[2048] = L"SELECT * FROM " > >+ L"Msvm_InternalEthernetPort WHERE ElementName = \""; > >+ > >+ wide_name = malloc((strlen(name) + 1) * sizeof(wchar_t)); > >+ if (wide_name == NULL) { > >+ VLOG_WARN("Could not allocate memory for wide string"); > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ if (!tranform_wide(name, wide_name)) { > >+ retval = false; > >+ goto error; > >+ } > >+ wcscat_s(internal_port_query, sizeof(internal_port_query), > >wide_name); > >+ > >+ wcscat_s(internal_port_query, sizeof(internal_port_query), L"\""); > >+ hres = psvc->lpVtbl->ExecQuery(psvc, > >+ L"WQL", > >+ internal_port_query, > >+ WBEM_FLAG_FORWARD_ONLY | > >+ WBEM_FLAG_RETURN_IMMEDIATELY, > >+ NULL, > >+ &penumerate); > >+ > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ if (get_first_element(penumerate, &pcls_obj)) { > >+ VLOG_WARN("Port with name: %s already defined on the switch", > >name); > >+ goto error; > >+ } > >+ penumerate->lpVtbl->Release(penumerate); > >+ penumerate = NULL; > >+ > >+ /* Check if the extension is enabled and running. Also check if the > >+ * the extension is enabled on more than one switch. */ > >+ hres = psvc->lpVtbl->ExecQuery(psvc, > >+ L"WQL", > >+ L"SELECT * " > >+ L"FROM Msvm_EthernetSwitchExtension " > >+ L"WHERE " > >+ L"ElementName=\"Open vSwitch > >Extension\" " > >+ L"AND EnabledState=2 " > >+ L"AND HealthState=5", > >+ WBEM_FLAG_FORWARD_ONLY | > >+ WBEM_FLAG_RETURN_IMMEDIATELY, > >+ NULL, > >+ &penumerate); > >+ > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ if (!get_first_element(penumerate, &pcls_obj)) { > >+ VLOG_WARN("Open vSwitch Extension is not enabled on any switch"); > >+ retval = false; > >+ goto error; > >+ } > >+ wcscpy_s(internal_port_query, sizeof(internal_port_query), > >+ L"SELECT * FROM Msvm_VirtualEthernetSwitch WHERE Name = > >\""); > >+ > >+ hres = pcls_obj->lpVtbl->Get(pcls_obj, L"SystemName", 0, > >+ &vt_prop, 0, 0); > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ wcscat_s(internal_port_query, sizeof(internal_port_query), > >+ vt_prop.bstrVal); > >+ > >+ VariantClear(&vt_prop); > >+ pcls_obj->lpVtbl->Release(pcls_obj); > >+ pcls_obj = NULL; > >+ > >+ if (get_first_element(penumerate, &pcls_obj)) { > >+ VLOG_WARN("The extension is activated on more than one switch, " > >+ "aborting operation. Please activate the extension on > >a " > >+ "single switch"); > >+ retval = false; > >+ goto error; > >+ } > >+ penumerate->lpVtbl->Release(penumerate); > >+ penumerate = NULL; > >+ if (pcls_obj != NULL) { > >+ pcls_obj->lpVtbl->Release(pcls_obj); > >+ pcls_obj = NULL; > >+ } > >+ > >+ /* Get the switch object on which the extension is activated. */ > >+ wcscat_s(internal_port_query, sizeof(internal_port_query), L"\""); > >+ hres = psvc->lpVtbl->ExecQuery(psvc, > >+ L"WQL", > >+ internal_port_query, > >+ WBEM_FLAG_FORWARD_ONLY | > >+ WBEM_FLAG_RETURN_IMMEDIATELY, > >+ NULL, > >+ &penumerate); > >+ > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ if (!get_first_element(penumerate, &pcls_obj)) { > >+ VLOG_WARN("Could not get the switch object on which the > >extension is" > >+ "activated"); > >+ retval = false; > >+ goto error; > >+ } > >+ penumerate->lpVtbl->Release(penumerate); > >+ penumerate = NULL; > >+ > >+ hres = pcls_obj->lpVtbl->Get(pcls_obj, L"ElementName", 0, &vt_prop, > >0, 0); > >+ > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ wcscpy_s(internal_port_query, sizeof(internal_port_query), > >+ L"SELECT * FROM Msvm_VirtualEthernetSwitchSettingData WHERE > >" > >+ L"ElementName = \""); > >+ > >+ wcscat_s(internal_port_query, sizeof(internal_port_query), > >+ vt_prop.bstrVal); > >+ VariantClear(&vt_prop); > >+ > >+ hres = pcls_obj->lpVtbl->Get(pcls_obj, L"Name", 0, &vt_prop, 0, 0); > >+ > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ pcls_obj->lpVtbl->Release(pcls_obj); > >+ pcls_obj = NULL; > >+ > >+ wcscat_s(internal_port_query, sizeof(internal_port_query), > >+ L"\" AND VirtualSystemIdentifier = \""); > >+ wcscat_s(internal_port_query, sizeof(internal_port_query), > >+ vt_prop.bstrVal); > >+ wcscat_s(internal_port_query, sizeof(internal_port_query), > >+ L"\" AND InstanceID = \"Microsoft:"); > >+ wcscat_s(internal_port_query, sizeof(internal_port_query), > >+ vt_prop.bstrVal); > >+ wcscat_s(internal_port_query, sizeof(internal_port_query), > >+ L"\" AND Caption = \"Virtual Ethernet Switch Settings\" AND > >" > >+ L"VirtualSystemType = \"DMTF:Virtual Ethernet Switch\""); > >+ > >+ VariantClear(&vt_prop); > >+ > >+ /* Retrieve the Msvm_VirtualEthernetSwitchSettingData pinned to the > >switch > >+ * object on which the extension is activated. */ > >+ hres = psvc->lpVtbl->ExecQuery(psvc, > >+ L"WQL", > >+ internal_port_query, > >+ WBEM_FLAG_FORWARD_ONLY | > >+ WBEM_FLAG_RETURN_IMMEDIATELY, > >+ NULL, > >+ &penumerate); > >+ > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ if (!get_first_element(penumerate, &pcls_obj)) { > >+ VLOG_WARN("Could not get the first " > >+ "Msvm_VirtualEthernetSwitchSettingData object"); > >+ retval = false; > >+ goto error; > >+ } > >+ penumerate->lpVtbl->Release(penumerate); > >+ penumerate = NULL; > >+ > >+ hres = pcls_obj->lpVtbl->Get(pcls_obj, L"__PATH", 0, > >&switch_setting_path, > >+ 0, 0); > >+ > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ pcls_obj->lpVtbl->Release(pcls_obj); > >+ pcls_obj = NULL; > >+ > >+ /* Retrieve a default allocation port. This object will be later > >filled > >+ * with optional data to create an switch internal port. */ > >+ hres = psvc->lpVtbl->ExecQuery(psvc, > >+ L"WQL", > >+ L"SELECT * FROM " > >+ > >L"Msvm_EthernetPortAllocationSettingData " > >+ L"WHERE InstanceID LIKE > >'%%%%\\\\Default' " > >+ L"AND ResourceSubType = " > >+ L"'Microsoft:Hyper-V:Ethernet > >Connection'", > >+ WBEM_FLAG_FORWARD_ONLY | > >+ WBEM_FLAG_RETURN_IMMEDIATELY, > >+ NULL, > >+ &penumerate); > >+ > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ if (!get_first_element(penumerate, &default_settings_data)) { > >+ VLOG_WARN("Could not retrieve default allocation port object"); > >+ retval = false; > >+ goto error; > >+ } > >+ penumerate->lpVtbl->Release(penumerate); > >+ penumerate = NULL; > >+ > >+ /* Retrieve the default computer system on which the port allocation > >will > >+ * be hosted. */ > >+ hres = psvc->lpVtbl->ExecQuery(psvc, > >+ L"WQL", > >+ L"SELECT * FROM Msvm_ComputerSystem > >WHERE " > >+ L"Description = \"Microsoft Hosting " > >+ L"Computer System\"", > >+ WBEM_FLAG_FORWARD_ONLY | > >+ WBEM_FLAG_RETURN_IMMEDIATELY, > >+ NULL, > >+ &penumerate); > >+ > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ if (!get_first_element(penumerate, &default_system)) { > >+ VLOG_WARN("Could not retrieve default computer system object"); > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ hres = default_system->lpVtbl->Get(default_system, L"__PATH", > >+ 0, &vt_prop, 0, 0); > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ penumerate->lpVtbl->Release(penumerate); > >+ penumerate = NULL; > >+ > >+ count[0] = 0; > >+ hres = SafeArrayPutElement(psa, count, vt_prop.bstrVal); > >+ > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ VariantClear(&vt_prop); > >+ variant_array.vt = VT_ARRAY | VT_BSTR; > >+ variant_array.parray = psa; > >+ hres = default_settings_data->lpVtbl->Put(default_settings_data, > >+ L"HostResource", 0, > >+ &variant_array, 0); > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ hres = psvc->lpVtbl->GetObject(psvc, > >+ > >L"Msvm_VirtualEthernetSwitchManagementService", > >+ 0, NULL, &pclass, NULL); > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ hres = pclass->lpVtbl->GetMethod(pclass, L"AddResourceSettings", 0, > >+ &pinput_params, NULL); > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ hres = pinput_params->lpVtbl->SpawnInstance(pinput_params, 0, > >+ &pclass_instance); > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ /* Store the switch setting path retrieved above in the affected > >+ * configuration field of the class instance. */ > >+ hres = pclass_instance->lpVtbl->Put(pclass_instance, > >+ L"AffectedConfiguration", 0, > >+ &switch_setting_path, 0); > >+ > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ /* Store the port name in the ElementName field of the default > >allocation > >+ * data. */ > >+ vt_prop.vt = VT_BSTR; > >+ vt_prop.bstrVal = SysAllocString(wide_name); > >+ hres = default_settings_data->lpVtbl->Put(default_settings_data, > >+ L"ElementName", 0, > >+ &vt_prop, 0); > >+ VariantClear(&vt_prop); > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ /* Retrieve and store the serialized data of the modified default > >switch > >+ * settings data. */ > >+ hres = CoCreateInstance(&CLSID_WbemObjectTextSrc, > >+ NULL, > >+ CLSCTX_INPROC_SERVER, > >+ &IID_IWbemObjectTextSrc, > >+ (void**)&text_object); > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ hres = text_object->lpVtbl->GetText(text_object, 0, > >+ default_settings_data, > >+ WMI_OBJ_TEXT_WMI_DTD_2_0, > >+ pcontext, > >+ &text_object_string); > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ hres = SafeArrayDestroy(psa); > >+ if (FAILED(hres)) { > >+ VLOG_WARN("Could not clear the data of the array"); > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ psa = SafeArrayCreateVector(VT_BSTR, 0, 1); > >+ > >+ if (psa == NULL) { > >+ VLOG_WARN("Could not allocate memory for a SAFEARRAY"); > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ count[0] = 0; > >+ variant_array.parray = psa; > >+ hres = SafeArrayPutElement(psa, count, text_object_string); > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ hres = pclass_instance->lpVtbl->Put(pclass_instance, > >L"ResourceSettings", > >+ 0, &variant_array, 0); > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ /* Get the object of the switch service. */ > >+ hres = psvc->lpVtbl->ExecQuery(psvc, > >+ L"WQL", > >+ L"SELECT * FROM " > >+ > >L"Msvm_VirtualEthernetSwitchManagementService", > >+ WBEM_FLAG_FORWARD_ONLY | > >+ WBEM_FLAG_RETURN_IMMEDIATELY, > >+ NULL, > >+ &penumerate); > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ if (!get_first_element(penumerate, &pcls_obj)) { > >+ VLOG_WARN("Could not get the object of the switch service"); > >+ retval = false; > >+ goto error; > >+ } > >+ penumerate->lpVtbl->Release(penumerate); > >+ penumerate = NULL; > >+ > >+ hres = pcls_obj->lpVtbl->Get(pcls_obj, L"__PATH", 0, &vt_prop, 0, > 0); > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ pcls_obj->lpVtbl->Release(pcls_obj); > >+ pcls_obj = NULL; > >+ > >+ /* Try to add the port to the switch. */ > >+ hres = psvc->lpVtbl->ExecMethod(psvc, vt_prop.bstrVal, > >+ L"AddResourceSettings", 0, > >+ pcontext, pclass_instance, > >&pout_params, > >+ NULL); > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ unsigned int retvalue = 0; > >+ hres = get_uint_value(pout_params, L"ReturnValue", &retvalue); > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ if (retvalue != 0 && retvalue != job_wait) { > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ if (retvalue == job_wait) { > >+ WCHAR job_path[2048]; > >+ hres = get_str_value(pout_params, L"Job", job_path, > >+ sizeof(job_path) / sizeof(WCHAR)); > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ hres = wait_for_job(psvc, job_path); > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ } > >+ > >+ pclass->lpVtbl->Release(pclass); > >+ pclass = NULL; > >+ pclass_instance->lpVtbl->Release(pclass_instance); > >+ pclass_instance = NULL; > >+ pinput_params->lpVtbl->Release(pinput_params); > >+ pinput_params = NULL; > >+ psvc->lpVtbl->Release(psvc); > >+ psvc = NULL; > >+ VariantClear(&vt_prop); > >+ > >+ if (!connect_set_security(ploc, pcontext, L"Root\\StandardCimv2", > >+ &psvc)) { > >+ VLOG_WARN("Could not connect and set security for CIM"); > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ wcscpy_s(internal_port_query, sizeof(internal_port_query), > >+ L"SELECT * FROM MSFT_NetAdapter WHERE Name LIKE '%%"); > >+ wcscat_s(internal_port_query, sizeof(internal_port_query), > >wide_name); > >+ wcscat_s(internal_port_query, sizeof(internal_port_query), L"%%'"); > >+ > >+ /* Get the object with the port name equal to name on the CIM. */ > >+ hres = psvc->lpVtbl->ExecQuery(psvc, > >+ L"WQL", > >+ internal_port_query, > >+ WBEM_FLAG_FORWARD_ONLY | > >+ WBEM_FLAG_RETURN_IMMEDIATELY, > >+ NULL, > >+ &penumerate); > >+ > >+ if (!get_first_element(penumerate, &pcls_obj)) { > >+ VLOG_WARN("Element name: %s not found in CIM", name); > >+ retval = false; > >+ goto error; > >+ } > >+ penumerate->lpVtbl->Release(penumerate); > >+ penumerate = NULL; > >+ pcls_obj->lpVtbl->Get(pcls_obj, L"__PATH", 0, &vt_prop, 0, 0); > >+ pcls_obj->lpVtbl->Release(pcls_obj); > >+ pcls_obj = NULL; > >+ > >+ /* Disable the adapter with port name equal with name. */ > >+ hres = psvc->lpVtbl->ExecMethod(psvc, vt_prop.bstrVal, L"Disable", 0, > >+ pcontext, NULL, NULL, NULL); > >+ > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ hres = psvc->lpVtbl->GetObject(psvc, L"MSFT_NetAdapter", 0, NULL, > >&pclass, > >+ NULL); > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ hres = pclass->lpVtbl->GetMethod(pclass, L"Rename", 0, > >&pinput_params, > >+ NULL); > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ hres = pinput_params->lpVtbl->SpawnInstance(pinput_params, 0, > >+ &pclass_instance); > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ > >+ VariantInit(&new_name); > >+ new_name.vt = VT_BSTR; > >+ new_name.bstrVal = wide_name; > >+ hres = pclass_instance->lpVtbl->Put(pclass_instance, L"NewName", 0, > >+ &new_name, 0); > >+ if (FAILED(hres)) { > >+ retval = false; > >+ goto error; > >+ } > >+ hres = psvc->lpVtbl->ExecMethod(psvc, vt_prop.bstrVal, L"Rename", 0, > >+ pcontext, pclass_instance, NULL, > >NULL); > >+ if (FAILED(hres)) { > >+ retval = false; > >+ } > >+ > >+error: > >+ if (text_object_string != NULL) { > >+ SysFreeString(text_object_string); > >+ text_object_string = NULL; > >+ } > >+ if (psa != NULL) { > >+ SafeArrayDestroy(psa); > >+ psa = NULL; > >+ } > >+ if (ploc != NULL) { > >+ ploc->lpVtbl->Release(ploc); > >+ ploc = NULL; > >+ } > >+ if (pcontext != NULL) { > >+ pcontext->lpVtbl->Release(pcontext); > >+ pcontext = NULL; > >+ } > >+ if (psvc != NULL) { > >+ psvc->lpVtbl->Release(psvc); > >+ psvc = NULL; > >+ } > >+ if (penumerate != NULL) { > >+ penumerate->lpVtbl->Release(penumerate); > >+ penumerate = NULL; > >+ } > >+ if (default_settings_data != NULL) { > >+ default_settings_data->lpVtbl->Release(default_settings_data); > >+ default_settings_data = NULL; > >+ } > >+ if (default_system != NULL) { > >+ default_system->lpVtbl->Release(default_system); > >+ default_system = NULL; > >+ } > >+ if (pcls_obj != NULL) { > >+ pcls_obj->lpVtbl->Release(pcls_obj); > >+ pcls_obj = NULL; > >+ } > >+ if (pclass != NULL) { > >+ pclass->lpVtbl->Release(pclass); > >+ pclass = NULL; > >+ } > >+ if (pinput_params != NULL) { > >+ pinput_params->lpVtbl->Release(pinput_params); > >+ pinput_params = NULL; > >+ } > >+ if (pclass_instance != NULL) { > >+ pclass_instance->lpVtbl->Release(pclass_instance); > >+ pclass_instance = NULL; > >+ } > >+ if (text_object != NULL) { > >+ text_object->lpVtbl->Release(text_object); > >+ text_object = NULL; > >+ } > >+ if (pout_params != NULL) { > >+ pout_params->lpVtbl->Release(pout_params); > >+ pout_params = NULL; > >+ } > >+ if (wide_name != NULL) { > >+ free(wide_name); > >+ wide_name = NULL; > >+ } > >+ VariantClear(&vt_prop); > >+ VariantClear(&switch_setting_path); > >+ > >+ if (!retval) { > >+ get_hres_error(hres); > >+ } > >+ CoUninitialize(); > >+ return retval; > >+} > >diff --git a/lib/wmi.h b/lib/wmi.h > >new file mode 100644 > >index 0000000..28910e7 > >--- /dev/null > >+++ b/lib/wmi.h > >@@ -0,0 +1,51 @@ > >+/* > >+ * Copyright (c) 2016 Cloudbase Solutions Srl > >+ * > >+ * Licensed under the Apache License, Version 2.0 (the "License"); > >+ * you may not use this file except in compliance with the License. > >+ * You may obtain a copy of the License at > >+ * > >+ * > >https://urldefense.proofpoint.com/v2/url?u=http- > 3A__www.apache.org_license > >s_LICENSE-2D2.0&d=CwIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw- > YihVMNtXt-uEs&r=D > >cruz40PROJ40ROzSpxyQSLw6fcrOWpJgEcEmNR3JEQ&m= > 1NgcutJOUfLwjikmUhz6W0zVXDR35 > >T75FV8sqiZ8ki8&s=6YJXIuUkmHpuGcJw64GoPVKdYVnqhnBsGxStg7axmxs&e= > >+ * > >+ * Unless required by applicable law or agreed to in writing, software > >+ * distributed under the License is distributed on an "AS IS" BASIS, > >+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or > >implied. > >+ * See the License for the specific language governing permissions and > >+ * limitations under the License. > >+ */ > >+ > >+#ifndef WMI_H > >+#define WMI_H 1 > >+ > >+#include <windefs.h> > >+#include <Wbemidl.h> > >+ > >+static inline void fill_context(IWbemContext *pContext) > >+{ > >+ VARIANT var; > >+ > >+ /* IncludeQualifiers. */ > >+ VariantInit(&var); > >+ var.vt = VT_BOOL; > >+ var.boolVal = VARIANT_TRUE; > >+ pContext->lpVtbl->SetValue(pContext, L"IncludeQualifiers", 0, &var); > >+ VariantClear(&var); > >+ > >+ VariantInit(&var); > >+ var.vt = VT_I4; > >+ var.lVal = 0; > >+ pContext->lpVtbl->SetValue(pContext, L"PathLevel", 0, &var); > >+ VariantClear(&var); > >+ > >+ /* ExcludeSystemProperties. */ > >+ VariantInit(&var); > >+ var.vt = VT_BOOL; > >+ var.boolVal = VARIANT_FALSE; > >+ pContext->lpVtbl->SetValue(pContext, L"ExcludeSystemProperties", 0, > >&var); > >+ VariantClear(&var); > >+} > >+ > >+boolean create_wmi_port(char *name); > >+boolean delete_wmi_port(char *name); > >+ > >+#endif /* wmi.h */ > >-- > >2.9.2.windows.1 > > > >_______________________________________________ > >dev mailing list > >dev@openvswitch.org > >https://urldefense.proofpoint.com/v2/url?u=http- > 3A__openvswitch.org_mailma > >n_listinfo_dev&d=CwIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw- > YihVMNtXt-uEs&r=Dc > >ruz40PROJ40ROzSpxyQSLw6fcrOWpJgEcEmNR3JEQ&m= > 1NgcutJOUfLwjikmUhz6W0zVXDR35T > >75FV8sqiZ8ki8&s=YMq7EI4iHIjlQKCYB1Lil7Pq3-80pelN7ZKYA4JvBb4&e= > > _______________________________________________ > dev mailing list > dev@openvswitch.org > http://openvswitch.org/mailman/listinfo/dev >
diff --git a/appveyor.yml b/appveyor.yml index 0fd003b..1061df6 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -41,5 +41,5 @@ build_script: - C:\MinGW\msys\1.0\bin\bash -lc "cp /c/pthreads-win32/Pre-built.2/dll/x86/*.dll /c/openvswitch/." - C:\MinGW\msys\1.0\bin\bash -lc "mv /bin/link.exe /bin/link_copy.exe" - C:\MinGW\msys\1.0\bin\bash -lc "cd /c/openvswitch && ./boot.sh" -- C:\MinGW\msys\1.0\bin\bash -lc "cd /c/openvswitch && ./configure CC=build-aux/cccl LD=\"`which link`\" LIBS=\"-lws2_32 -liphlpapi\" --with-pthread=C:/pthreads-win32/Pre-built.2 --with-openssl=C:/OpenSSL-Win32 --with-vstudiotarget=\"Debug\"" +- C:\MinGW\msys\1.0\bin\bash -lc "cd /c/openvswitch && ./configure CC=build-aux/cccl LD=\"`which link`\" LIBS=\"-lws2_32 -liphlpapi -lwbemuuid -lole32 -loleaut32\" --with-pthread=C:/pthreads-win32/Pre-built.2 --with-openssl=C:/OpenSSL-Win32 --with-vstudiotarget=\"Debug\"" - C:\MinGW\msys\1.0\bin\bash -lc "cd /c/openvswitch && make" diff --git a/lib/automake.mk b/lib/automake.mk index 2faaeac..99bbdc0 100644 --- a/lib/automake.mk +++ b/lib/automake.mk @@ -387,7 +387,9 @@ lib_libopenvswitch_la_SOURCES += \ lib/netlink-notifier.h \ lib/netlink-protocol.h \ lib/netlink-socket.c \ - lib/netlink-socket.h + lib/netlink-socket.h \ + lib/wmi.c \ + lib/wmi.h endif if HAVE_POSIX_AIO diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c index a39faa2..c8b0e37 100644 --- a/lib/dpif-netlink.c +++ b/lib/dpif-netlink.c @@ -58,6 +58,7 @@ VLOG_DEFINE_THIS_MODULE(dpif_netlink); #ifdef _WIN32 +#include "wmi.h" enum { WINDOWS = 1 }; #else enum { WINDOWS = 0 }; @@ -849,6 +850,16 @@ dpif_netlink_port_add__(struct dpif_netlink *dpif, struct netdev *netdev, #endif } +#ifdef _WIN32 + if (request.type == OVS_VPORT_TYPE_INTERNAL) { + if (!create_wmi_port(name)){ + VLOG_ERR("Could not create wmi internal port with name:%s", name); + vport_del_socksp(dpif, socksp); + return EINVAL; + }; + } +#endif + tnl_cfg = netdev_get_tunnel_config(netdev); if (tnl_cfg && (tnl_cfg->dst_port != 0 || tnl_cfg->exts)) { ofpbuf_use_stack(&options, options_stub, sizeof options_stub); @@ -940,6 +951,16 @@ dpif_netlink_port_del__(struct dpif_netlink *dpif, odp_port_t port_no) vport.cmd = OVS_VPORT_CMD_DEL; vport.dp_ifindex = dpif->dp_ifindex; vport.port_no = port_no; +#ifdef _WIN32 + struct dpif_port temp_dpif_port; + dpif_netlink_port_query__(dpif, port_no, NULL, &temp_dpif_port); + if (!strcmp(temp_dpif_port.type, "internal")) { + if (!delete_wmi_port(temp_dpif_port.name)){ + VLOG_ERR("Could not delete wmi port with name: %s", + temp_dpif_port.name); + }; + } +#endif error = dpif_netlink_vport_transact(&vport, NULL, NULL); vport_del_channels(dpif, port_no); diff --git a/lib/wmi.c b/lib/wmi.c new file mode 100644 index 0000000..67f0873 --- /dev/null +++ b/lib/wmi.c @@ -0,0 +1,1276 @@ +/* + * Copyright (c) 2016 Cloudbase Solutions Srl + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <config.h> +#include "wmi.h" +#include <stdlib.h> +#include <stdio.h> +#include <tchar.h> +#include <Windows.h> +#include "openvswitch/vlog.h" + +VLOG_DEFINE_THIS_MODULE(wmi); + +/* WMI Job values. */ +enum job_status +{ + job_starting = 3, + job_running = 4, + job_completed = 7, + job_wait = 4096 +}; + +static char * +sanitize_port_name(char *name) +{ + char *p1, *p2; + p1 = p2 = name; + + while (*p1) { + if ((*p1) == '\'' || (*p1) == '\"') { + p1++; + } else { + *p2 = *p1; + p2++; + p1++; + } + } + *p2 = '\0'; + return name; +} + +/* This function will output the appropriate message for a given HRESULT.*/ +static void +get_hres_error(HRESULT hres) +{ + char *error_msg = NULL; + + if (FACILITY_WINDOWS == HRESULT_FACILITY(hres)) { + hres = HRESULT_CODE(hres); + } + + VLOG_ERR("%s", ovs_format_message(hres)); +} + +static boolean +check_return_value(HRESULT hres) +{ + if (FAILED(hres)) { + get_hres_error(hres); + return false; + } + + return true; +} + +static HRESULT +get_variant_value(IWbemClassObject *pcls_obj, wchar_t *field_name, + VARIANT *value) +{ + HRESULT hres; + + VariantInit(value); + + hres = pcls_obj->lpVtbl->Get(pcls_obj, field_name, 0, value, 0, 0); + + if (FAILED(hres)) { + VariantClear(value); + } + + return hres; +} + +/* This function retrieves the uint16_t value from a given class object with + * the field name field_name. */ +static HRESULT +get_uint16_t_value(IWbemClassObject *pcls_obj, wchar_t *field_name, + uint16_t *value) +{ + VARIANT vt_prop; + HRESULT hres = get_variant_value(pcls_obj, field_name, &vt_prop); + *value = V_UI2(&vt_prop); + + return hres; +} + +/* This function retrieves the unsigned int values from a given class object + * with the field name field_name. */ +static HRESULT +get_uint_value(IWbemClassObject *pcls_obj, wchar_t *field_name, + unsigned int *value) +{ + VARIANT vt_prop; + HRESULT hres = get_variant_value(pcls_obj, field_name, &vt_prop); + *value = V_UI4(&vt_prop); + + return hres; +} + +/* This function retrieves the unsigned short value from a given class object + * with the field name field_name. */ +static HRESULT +get_ushort_value(IWbemClassObject *pcls_obj, wchar_t *field_name, + unsigned short *value) +{ + VARIANT vt_prop; + HRESULT hres = get_variant_value(pcls_obj, field_name, &vt_prop); + *value = V_UI2(&vt_prop); + + return hres; +} + +/* This function retrieves the BSTR value from a given class object with + * the field name field_name, to a preallocated destination dest and with the + * maximum length max_dest_lgth. */ +static HRESULT +get_str_value(IWbemClassObject *pcls_obj, wchar_t *field_name, wchar_t *dest, + int max_dest_lgth) +{ + VARIANT vt_prop; + HRESULT hres = get_variant_value(pcls_obj, field_name, &vt_prop); + + if (wcscpy_s(dest, max_dest_lgth, vt_prop.bstrVal)) { + VariantClear(&vt_prop); + VLOG_WARN("get_str_value, wcscpy_s failed :%s", ovs_strerror(errno)); + return WBEM_E_FAILED; + } + + VariantClear(&vt_prop); + return S_OK; +} + +/* This function waits for a WMI job to finish and retrieves the error code + * if the job failed */ +static HRESULT +wait_for_job(IWbemServices *psvc, wchar_t *job_path) +{ + IWbemClassObject *pcls_obj = NULL; + HRESULT retval = 0; + uint16_t job_state = 0; + uint16_t error = 0; + + do { + if(!check_return_value(psvc->lpVtbl->GetObject(psvc, job_path, 0, NULL, + &pcls_obj, NULL))) { + retval = WBEM_E_FAILED; + break; + } + + retval = get_uint16_t_value(pcls_obj, L"JobState", &job_state); + if (FAILED(retval)) { + break; + } + + if (job_state == job_starting || job_state == job_running) { + Sleep(200); + } else if (job_state == job_completed) { + break; + } else { + /* Error occurred. */ + retval = get_uint16_t_value(pcls_obj, L"ErrorCode", &error); + if (FAILED(retval)) { + break; + } + VLOG_WARN("Job failed with error: %d", error); + retval = WBEM_E_FAILED;; + break; + } + + if (pcls_obj != NULL) { + pcls_obj->lpVtbl->Release(pcls_obj); + pcls_obj = NULL; + } + } while(TRUE); + + if (pcls_obj != NULL) { + pcls_obj->lpVtbl->Release(pcls_obj); + pcls_obj = NULL; + } + + return retval; +} + +/* This function will initialize DCOM retrieving the WMI locator's ploc and + * the context associated to it. */ +static boolean +initialize_wmi(IWbemLocator **ploc, IWbemContext **pcontext) +{ + HRESULT hres = 0; + + /* Initialize COM. */ + hres = CoInitialize(NULL); + + if (FAILED(hres)) { + return false; + } + + /* Initialize COM security. */ + hres = CoInitializeSecurity(NULL, + -1, + NULL, + NULL, + RPC_C_AUTHN_LEVEL_DEFAULT, + RPC_C_IMP_LEVEL_IMPERSONATE, + NULL, + EOAC_NONE, + NULL); + + if (FAILED(hres)) { + return false; + } + + /* Fill context. */ + hres = CoCreateInstance(&CLSID_WbemContext, + NULL, + CLSCTX_INPROC_SERVER, + &IID_IWbemContext, + (void**)pcontext); + + if (FAILED(hres)) { + return false; + } + + fill_context(*pcontext); + + /* Initialize locator's (ploc) to WMI. */ + hres = CoCreateInstance(&CLSID_WbemLocator, + NULL, + CLSCTX_INPROC_SERVER, + &IID_IWbemLocator, + (LPVOID *)ploc); + + if (FAILED(hres)) { + return false; + } + + return true; +} + +/* This function connects the WMI locator's ploc to a given WMI provider + * defined in server and also sets the required security levels for a local + * connection to it. */ +static boolean +connect_set_security(IWbemLocator *ploc, IWbemContext *pcontext, + wchar_t *server, IWbemServices **psvc) +{ + HRESULT hres = 0; + + /* Connect to server. */ + hres = ploc->lpVtbl->ConnectServer(ploc, + server, + NULL, + NULL, + 0, + 0, + 0, + pcontext, + psvc); + + if (FAILED(hres)) { + return false; + } + + /* Set security levels. */ + hres = CoSetProxyBlanket((IUnknown *) *psvc, + RPC_C_AUTHN_WINNT, + RPC_C_AUTHZ_NONE, + NULL, + RPC_C_AUTHN_LEVEL_CALL, + RPC_C_IMP_LEVEL_IMPERSONATE, + NULL, + EOAC_NONE); + + if (FAILED(hres)) { + return false; + } + + return true; +} + +/* This function retrieves the first class object of a given enumeration + * outputted by a query and fails if it could not retrieve the object or there + * was no object to retrieve */ +static boolean +get_first_element(IEnumWbemClassObject *penumerate, + IWbemClassObject **pcls_obj) +{ + unsigned long retval = 0; + + if (penumerate == NULL) { + VLOG_WARN("Enumeration Class Object is NULL. Cannot get the first" + "object"); + return false; + } + + HRESULT hres = penumerate->lpVtbl->Next(penumerate, WBEM_INFINITE, 1, + pcls_obj, &retval); + + + if (!check_return_value(hres) || retval == 0) { + return false; + } + + return true; +} + +/* This function is a wrapper that transforms a char * into a wchar_t * */ +static boolean +tranform_wide(char *name, wchar_t *wide_name) +{ + unsigned long size = strlen(name) + 1; + long long ret = 0; + + if (wide_name == NULL) { + VLOG_WARN("Provided wide string is NULL"); + return false; + } + + ret = mbstowcs(wide_name, name, size); + + if (ret == -1) { + VLOG_WARN("Invalid multibyte character is encountered"); + return false; + } else if (ret == size) { + VLOG_WARN("Returned wide string not NULL terminated"); + return false; + } + + return true; +} + +/* This function will delete a switch internal port with a given name as input + * executing "RemoveResourceSettings" as per documentation: + * https://msdn.microsoft.com/en-us/library/hh850277%28v=vs.85%29.aspx + * allocating the data and populating the needed fields to execute the + * method */ +boolean +delete_wmi_port(char *name) +{ + HRESULT hres = 0; + boolean retval = true; + + IWbemLocator *ploc = NULL; + IWbemServices *psvc = NULL; + IWbemContext *pcontext = NULL; + IWbemClassObject *pclass_instance = NULL; + IWbemClassObject *pinput_params = NULL; + IWbemClassObject *pcls_obj = NULL; + IWbemClassObject *pout_params = NULL; + IEnumWbemClassObject *penumerate = NULL; + + sanitize_port_name(name); + VARIANT vt_prop; + VARIANT variant_array; + wchar_t *wide_name = NULL; + VariantInit(&vt_prop); + VariantInit(&variant_array); + + LONG count[1]; + SAFEARRAY* psa = SafeArrayCreateVector(VT_BSTR, 0, 1); + if (psa == NULL) { + VLOG_WARN("Could not allocate memory for a SAFEARRAY"); + retval = false; + goto error; + } + + if (!initialize_wmi(&ploc, &pcontext)) { + VLOG_WARN("Could not initialize DCOM"); + retval = false; + goto error; + } + + if (!connect_set_security(ploc, pcontext, L"Root\\Virtualization\\v2", + &psvc)) { + VLOG_WARN("Could not connect and set security for virtualization"); + retval = false; + goto error; + } + + + /* Get the port with the element name equal to the name input. */ + wchar_t internal_port_query[2048] = L"SELECT * from " + L"Msvm_EthernetPortAllocationSettingData WHERE ElementName = \"" ; + + wide_name = malloc((strlen(name) + 1) * sizeof(wchar_t)); + if (wide_name == NULL) { + VLOG_WARN("Could not allocate memory for wide string"); + retval = false; + goto error; + } + + if (!tranform_wide(name, wide_name)) { + retval = false; + goto error; + } + wcscat_s(internal_port_query, sizeof(internal_port_query), wide_name); + + wcscat_s(internal_port_query, sizeof(internal_port_query), L"\""); + + hres = psvc->lpVtbl->ExecQuery(psvc, + L"WQL", + internal_port_query, + WBEM_FLAG_FORWARD_ONLY | + WBEM_FLAG_RETURN_IMMEDIATELY, + NULL, + &penumerate); + + if (FAILED(hres)) { + retval = false; + goto error; + } + + /* Get the element path on the switch which will be deleted. */ + if (!get_first_element(penumerate, &pcls_obj)) { + retval = false; + goto error; + } + penumerate->lpVtbl->Release(penumerate); + penumerate = NULL; + + hres = pcls_obj->lpVtbl->Get(pcls_obj, L"__PATH", 0, &vt_prop, 0, 0); + + if (FAILED(hres)) { + retval = false; + goto error; + } + pcls_obj->lpVtbl->Release(pcls_obj); + pcls_obj = NULL; + + /* Get the class object and the parameters it can have. */ + hres = psvc->lpVtbl->GetObject(psvc, + L"Msvm_VirtualEthernetSwitchManagementService", 0, NULL, &pcls_obj, + NULL); + + if (FAILED(hres)) { + retval = false; + goto error; + } + + hres = pcls_obj->lpVtbl->GetMethod(pcls_obj, L"RemoveResourceSettings", 0, + &pinput_params, NULL); + + if (FAILED(hres)) { + retval = false; + goto error; + } + pcls_obj->lpVtbl->Release(pcls_obj); + pcls_obj = NULL; + + hres = pinput_params->lpVtbl->SpawnInstance(pinput_params, 0, + &pclass_instance); + if (FAILED(hres)) { + retval = false; + goto error; + } + + count[0] = 0; + + hres = SafeArrayPutElement(psa, count, vt_prop.bstrVal); + + if (FAILED(hres)) { + retval = false; + goto error; + } + + VariantClear(&vt_prop); + VariantInit(&vt_prop); + variant_array.vt = VT_ARRAY | VT_BSTR; + variant_array.parray = psa; + + hres = pclass_instance->lpVtbl->Put(pclass_instance, L"ResourceSettings", 0, + &variant_array, 0); + if (FAILED(hres)) { + retval = false; + goto error; + } + + /* Get the object of the Msvm_VirtualEthernetSwitchManagementService which + * we need to invoke the port deletion. */ + hres = psvc->lpVtbl->ExecQuery(psvc, + L"WQL", + L"SELECT * FROM " + L"Msvm_VirtualEthernetSwitchManagementService", + WBEM_FLAG_FORWARD_ONLY | + WBEM_FLAG_RETURN_IMMEDIATELY, + NULL, + &penumerate); + + if (FAILED(hres)) { + retval = false; + goto error; + } + + if (!get_first_element(penumerate, &pcls_obj)) { + retval = false; + goto error; + } + penumerate->lpVtbl->Release(penumerate); + penumerate = NULL; + + hres = pcls_obj->lpVtbl->Get(pcls_obj, L"__PATH", 0, &vt_prop, 0, 0); + + if (FAILED(hres)) { + retval = false; + goto error; + } + + pcls_obj->lpVtbl->Release(pcls_obj); + pcls_obj = NULL; + + /* Invoke the delete port method. */ + hres = psvc->lpVtbl->ExecMethod(psvc, vt_prop.bstrVal, + L"RemoveResourceSettings", 0, + pcontext, pclass_instance, &pout_params, + NULL); + if (FAILED(hres)) { + retval = false; + goto error; + } + VariantClear(&vt_prop); + VariantInit(&vt_prop); + + hres = pout_params->lpVtbl->Get(pout_params, L"ReturnValue", 0, + &vt_prop, NULL, 0); + + if (FAILED(hres)) { + retval = false; + goto error; + } + + unsigned int retvalue = 0; + hres = get_uint_value(pout_params, L"ReturnValue", &retvalue); + if (FAILED(hres)) { + retval = false; + goto error; + } + + if (retvalue != 0 && retvalue != job_wait) { + retval = false; + goto error; + } + + if (retvalue == job_wait) { + WCHAR job_path[2048]; + hres = get_str_value(pout_params, L"Job", job_path, + sizeof(job_path) / sizeof(WCHAR)); + if (FAILED(hres)) { + retval = false; + goto error; + } + hres = wait_for_job(psvc, job_path); + if (FAILED(hres)) { + retval = false; + } + } + +error: + VariantClear(&vt_prop); + + if (pcontext != NULL) { + pcontext->lpVtbl->Release(pcontext); + pcontext = NULL; + } + if (psa != NULL) { + SafeArrayDestroy(psa); + psa = NULL; + } + if (pcls_obj != NULL) { + pcls_obj->lpVtbl->Release(pcls_obj); + pcls_obj = NULL; + } + if (wide_name != NULL) { + free(wide_name); + wide_name = NULL; + } + if (!retval) { + get_hres_error(hres); + } + if (pinput_params != NULL) { + pinput_params->lpVtbl->Release(pinput_params); + pinput_params = NULL; + } + if (pout_params != NULL) { + pout_params->lpVtbl->Release(pout_params); + pout_params = NULL; + } + if (psvc != NULL) { + psvc->lpVtbl->Release(psvc); + psvc = NULL; + } + if (ploc != NULL) { + ploc->lpVtbl->Release(ploc); + ploc = NULL; + } + if (pclass_instance != NULL) { + pclass_instance->lpVtbl->Release(pclass_instance); + pclass_instance = NULL; + } + if (penumerate != NULL) { + penumerate->lpVtbl->Release(penumerate); + penumerate = NULL; + } + + CoUninitialize(); + return retval; +} + +/* This function will create an internal port on the switch given a given name + * executing the method AddResourceSettings as per documentation: + * https://msdn.microsoft.com/en-us/library/hh850019%28v=vs.85%29.aspx. + * It will verify if the port is already defined, in which case it will use + * the specific port, and if the forwarding extension "Open vSwitch Extension" + * is enabled and running only on a single switch. + * After the port is created and bound to the switch we will disable the + * created net adapter and rename it to match the OVS bridge name .*/ +boolean +create_wmi_port(char *name) { + HRESULT hres = 0; + boolean retval = true; + + BSTR text_object_string = NULL; + + IWbemLocator *ploc = NULL; + IWbemContext *pcontext = NULL; + IWbemServices *psvc = NULL; + IEnumWbemClassObject *penumerate = NULL; + IWbemClassObject *default_settings_data = NULL; + IWbemClassObject *default_system = NULL; + IWbemClassObject *pcls_obj = NULL; + IWbemClassObject *pclass = NULL; + IWbemClassObject *pinput_params = NULL; + IWbemClassObject *pclass_instance = NULL; + IWbemObjectTextSrc *text_object = NULL; + IWbemClassObject *pout_params = NULL; + + wchar_t *wide_name = NULL; + VARIANT vt_prop; + VARIANT switch_setting_path; + VARIANT new_name; + SAFEARRAY *psa = SafeArrayCreateVector(VT_BSTR, 0, 1); + VARIANT variant_array; + LONG count[1]; + + VariantInit(&vt_prop); + VariantInit(&switch_setting_path); + sanitize_port_name(name); + + if (psa == NULL) { + VLOG_WARN("Could not allocate memory for a SAFEARRAY"); + retval = false; + goto error; + } + + if (!initialize_wmi(&ploc, &pcontext)) { + VLOG_WARN("Could not initialize DCOM"); + retval = false; + goto error; + } + + if (!connect_set_security(ploc, pcontext, L"Root\\Virtualization\\v2", + &psvc)) { + VLOG_WARN("Could not connect and set security for virtualization"); + retval = false; + goto error; + } + + /* Check if the element already exists on the switch. */ + wchar_t internal_port_query[2048] = L"SELECT * FROM " + L"Msvm_InternalEthernetPort WHERE ElementName = \""; + + wide_name = malloc((strlen(name) + 1) * sizeof(wchar_t)); + if (wide_name == NULL) { + VLOG_WARN("Could not allocate memory for wide string"); + retval = false; + goto error; + } + + if (!tranform_wide(name, wide_name)) { + retval = false; + goto error; + } + wcscat_s(internal_port_query, sizeof(internal_port_query), wide_name); + + wcscat_s(internal_port_query, sizeof(internal_port_query), L"\""); + hres = psvc->lpVtbl->ExecQuery(psvc, + L"WQL", + internal_port_query, + WBEM_FLAG_FORWARD_ONLY | + WBEM_FLAG_RETURN_IMMEDIATELY, + NULL, + &penumerate); + + if (FAILED(hres)) { + retval = false; + goto error; + } + + if (get_first_element(penumerate, &pcls_obj)) { + VLOG_WARN("Port with name: %s already defined on the switch", name); + goto error; + } + penumerate->lpVtbl->Release(penumerate); + penumerate = NULL; + + /* Check if the extension is enabled and running. Also check if the + * the extension is enabled on more than one switch. */ + hres = psvc->lpVtbl->ExecQuery(psvc, + L"WQL", + L"SELECT * " + L"FROM Msvm_EthernetSwitchExtension " + L"WHERE " + L"ElementName=\"Open vSwitch Extension\" " + L"AND EnabledState=2 " + L"AND HealthState=5", + WBEM_FLAG_FORWARD_ONLY | + WBEM_FLAG_RETURN_IMMEDIATELY, + NULL, + &penumerate); + + if (FAILED(hres)) { + retval = false; + goto error; + } + + if (!get_first_element(penumerate, &pcls_obj)) { + VLOG_WARN("Open vSwitch Extension is not enabled on any switch"); + retval = false; + goto error; + } + wcscpy_s(internal_port_query, sizeof(internal_port_query), + L"SELECT * FROM Msvm_VirtualEthernetSwitch WHERE Name = \""); + + hres = pcls_obj->lpVtbl->Get(pcls_obj, L"SystemName", 0, + &vt_prop, 0, 0); + if (FAILED(hres)) { + retval = false; + goto error; + } + + wcscat_s(internal_port_query, sizeof(internal_port_query), + vt_prop.bstrVal); + + VariantClear(&vt_prop); + pcls_obj->lpVtbl->Release(pcls_obj); + pcls_obj = NULL; + + if (get_first_element(penumerate, &pcls_obj)) { + VLOG_WARN("The extension is activated on more than one switch, " + "aborting operation. Please activate the extension on a " + "single switch"); + retval = false; + goto error; + } + penumerate->lpVtbl->Release(penumerate); + penumerate = NULL; + if (pcls_obj != NULL) { + pcls_obj->lpVtbl->Release(pcls_obj); + pcls_obj = NULL; + } + + /* Get the switch object on which the extension is activated. */ + wcscat_s(internal_port_query, sizeof(internal_port_query), L"\""); + hres = psvc->lpVtbl->ExecQuery(psvc, + L"WQL", + internal_port_query, + WBEM_FLAG_FORWARD_ONLY | + WBEM_FLAG_RETURN_IMMEDIATELY, + NULL, + &penumerate); + + if (FAILED(hres)) { + retval = false; + goto error; + } + + if (!get_first_element(penumerate, &pcls_obj)) { + VLOG_WARN("Could not get the switch object on which the extension is" + "activated"); + retval = false; + goto error; + } + penumerate->lpVtbl->Release(penumerate); + penumerate = NULL; + + hres = pcls_obj->lpVtbl->Get(pcls_obj, L"ElementName", 0, &vt_prop, 0, 0); + + if (FAILED(hres)) { + retval = false; + goto error; + } + + wcscpy_s(internal_port_query, sizeof(internal_port_query), + L"SELECT * FROM Msvm_VirtualEthernetSwitchSettingData WHERE " + L"ElementName = \""); + + wcscat_s(internal_port_query, sizeof(internal_port_query), + vt_prop.bstrVal); + VariantClear(&vt_prop); + + hres = pcls_obj->lpVtbl->Get(pcls_obj, L"Name", 0, &vt_prop, 0, 0); + + if (FAILED(hres)) { + retval = false; + goto error; + } + pcls_obj->lpVtbl->Release(pcls_obj); + pcls_obj = NULL; + + wcscat_s(internal_port_query, sizeof(internal_port_query), + L"\" AND VirtualSystemIdentifier = \""); + wcscat_s(internal_port_query, sizeof(internal_port_query), + vt_prop.bstrVal); + wcscat_s(internal_port_query, sizeof(internal_port_query), + L"\" AND InstanceID = \"Microsoft:"); + wcscat_s(internal_port_query, sizeof(internal_port_query), + vt_prop.bstrVal); + wcscat_s(internal_port_query, sizeof(internal_port_query), + L"\" AND Caption = \"Virtual Ethernet Switch Settings\" AND " + L"VirtualSystemType = \"DMTF:Virtual Ethernet Switch\""); + + VariantClear(&vt_prop); + + /* Retrieve the Msvm_VirtualEthernetSwitchSettingData pinned to the switch + * object on which the extension is activated. */ + hres = psvc->lpVtbl->ExecQuery(psvc, + L"WQL", + internal_port_query, + WBEM_FLAG_FORWARD_ONLY | + WBEM_FLAG_RETURN_IMMEDIATELY, + NULL, + &penumerate); + + if (FAILED(hres)) { + retval = false; + goto error; + } + + if (!get_first_element(penumerate, &pcls_obj)) { + VLOG_WARN("Could not get the first " + "Msvm_VirtualEthernetSwitchSettingData object"); + retval = false; + goto error; + } + penumerate->lpVtbl->Release(penumerate); + penumerate = NULL; + + hres = pcls_obj->lpVtbl->Get(pcls_obj, L"__PATH", 0, &switch_setting_path, + 0, 0); + + if (FAILED(hres)) { + retval = false; + goto error; + } + pcls_obj->lpVtbl->Release(pcls_obj); + pcls_obj = NULL; + + /* Retrieve a default allocation port. This object will be later filled + * with optional data to create an switch internal port. */ + hres = psvc->lpVtbl->ExecQuery(psvc, + L"WQL", + L"SELECT * FROM " + L"Msvm_EthernetPortAllocationSettingData " + L"WHERE InstanceID LIKE '%%%%\\\\Default' " + L"AND ResourceSubType = " + L"'Microsoft:Hyper-V:Ethernet Connection'", + WBEM_FLAG_FORWARD_ONLY | + WBEM_FLAG_RETURN_IMMEDIATELY, + NULL, + &penumerate); + + if (FAILED(hres)) { + retval = false; + goto error; + } + + if (!get_first_element(penumerate, &default_settings_data)) { + VLOG_WARN("Could not retrieve default allocation port object"); + retval = false; + goto error; + } + penumerate->lpVtbl->Release(penumerate); + penumerate = NULL; + + /* Retrieve the default computer system on which the port allocation will + * be hosted. */ + hres = psvc->lpVtbl->ExecQuery(psvc, + L"WQL", + L"SELECT * FROM Msvm_ComputerSystem WHERE " + L"Description = \"Microsoft Hosting " + L"Computer System\"", + WBEM_FLAG_FORWARD_ONLY | + WBEM_FLAG_RETURN_IMMEDIATELY, + NULL, + &penumerate); + + if (FAILED(hres)) { + retval = false; + goto error; + } + + if (!get_first_element(penumerate, &default_system)) { + VLOG_WARN("Could not retrieve default computer system object"); + retval = false; + goto error; + } + + hres = default_system->lpVtbl->Get(default_system, L"__PATH", + 0, &vt_prop, 0, 0); + if (FAILED(hres)) { + retval = false; + goto error; + } + penumerate->lpVtbl->Release(penumerate); + penumerate = NULL; + + count[0] = 0; + hres = SafeArrayPutElement(psa, count, vt_prop.bstrVal); + + if (FAILED(hres)) { + retval = false; + goto error; + } + + VariantClear(&vt_prop); + variant_array.vt = VT_ARRAY | VT_BSTR; + variant_array.parray = psa; + hres = default_settings_data->lpVtbl->Put(default_settings_data, + L"HostResource", 0, + &variant_array, 0); + if (FAILED(hres)) { + retval = false; + goto error; + } + + hres = psvc->lpVtbl->GetObject(psvc, + L"Msvm_VirtualEthernetSwitchManagementService", + 0, NULL, &pclass, NULL); + if (FAILED(hres)) { + retval = false; + goto error; + } + + hres = pclass->lpVtbl->GetMethod(pclass, L"AddResourceSettings", 0, + &pinput_params, NULL); + if (FAILED(hres)) { + retval = false; + goto error; + } + + hres = pinput_params->lpVtbl->SpawnInstance(pinput_params, 0, + &pclass_instance); + if (FAILED(hres)) { + retval = false; + goto error; + } + + /* Store the switch setting path retrieved above in the affected + * configuration field of the class instance. */ + hres = pclass_instance->lpVtbl->Put(pclass_instance, + L"AffectedConfiguration", 0, + &switch_setting_path, 0); + + if (FAILED(hres)) { + retval = false; + goto error; + } + + /* Store the port name in the ElementName field of the default allocation + * data. */ + vt_prop.vt = VT_BSTR; + vt_prop.bstrVal = SysAllocString(wide_name); + hres = default_settings_data->lpVtbl->Put(default_settings_data, + L"ElementName", 0, + &vt_prop, 0); + VariantClear(&vt_prop); + if (FAILED(hres)) { + retval = false; + goto error; + } + + /* Retrieve and store the serialized data of the modified default switch + * settings data. */ + hres = CoCreateInstance(&CLSID_WbemObjectTextSrc, + NULL, + CLSCTX_INPROC_SERVER, + &IID_IWbemObjectTextSrc, + (void**)&text_object); + if (FAILED(hres)) { + retval = false; + goto error; + } + + hres = text_object->lpVtbl->GetText(text_object, 0, + default_settings_data, + WMI_OBJ_TEXT_WMI_DTD_2_0, + pcontext, + &text_object_string); + if (FAILED(hres)) { + retval = false; + goto error; + } + hres = SafeArrayDestroy(psa); + if (FAILED(hres)) { + VLOG_WARN("Could not clear the data of the array"); + retval = false; + goto error; + } + + psa = SafeArrayCreateVector(VT_BSTR, 0, 1); + + if (psa == NULL) { + VLOG_WARN("Could not allocate memory for a SAFEARRAY"); + retval = false; + goto error; + } + + count[0] = 0; + variant_array.parray = psa; + hres = SafeArrayPutElement(psa, count, text_object_string); + if (FAILED(hres)) { + retval = false; + goto error; + } + hres = pclass_instance->lpVtbl->Put(pclass_instance, L"ResourceSettings", + 0, &variant_array, 0); + if (FAILED(hres)) { + retval = false; + goto error; + } + + /* Get the object of the switch service. */ + hres = psvc->lpVtbl->ExecQuery(psvc, + L"WQL", + L"SELECT * FROM " + L"Msvm_VirtualEthernetSwitchManagementService", + WBEM_FLAG_FORWARD_ONLY | + WBEM_FLAG_RETURN_IMMEDIATELY, + NULL, + &penumerate); + if (FAILED(hres)) { + retval = false; + goto error; + } + + if (!get_first_element(penumerate, &pcls_obj)) { + VLOG_WARN("Could not get the object of the switch service"); + retval = false; + goto error; + } + penumerate->lpVtbl->Release(penumerate); + penumerate = NULL; + + hres = pcls_obj->lpVtbl->Get(pcls_obj, L"__PATH", 0, &vt_prop, 0, 0); + if (FAILED(hres)) { + retval = false; + goto error; + } + pcls_obj->lpVtbl->Release(pcls_obj); + pcls_obj = NULL; + + /* Try to add the port to the switch. */ + hres = psvc->lpVtbl->ExecMethod(psvc, vt_prop.bstrVal, + L"AddResourceSettings", 0, + pcontext, pclass_instance, &pout_params, + NULL); + if (FAILED(hres)) { + retval = false; + goto error; + } + + unsigned int retvalue = 0; + hres = get_uint_value(pout_params, L"ReturnValue", &retvalue); + if (FAILED(hres)) { + retval = false; + goto error; + } + + if (retvalue != 0 && retvalue != job_wait) { + retval = false; + goto error; + } + + if (retvalue == job_wait) { + WCHAR job_path[2048]; + hres = get_str_value(pout_params, L"Job", job_path, + sizeof(job_path) / sizeof(WCHAR)); + if (FAILED(hres)) { + retval = false; + goto error; + } + hres = wait_for_job(psvc, job_path); + if (FAILED(hres)) { + retval = false; + goto error; + } + } + + pclass->lpVtbl->Release(pclass); + pclass = NULL; + pclass_instance->lpVtbl->Release(pclass_instance); + pclass_instance = NULL; + pinput_params->lpVtbl->Release(pinput_params); + pinput_params = NULL; + psvc->lpVtbl->Release(psvc); + psvc = NULL; + VariantClear(&vt_prop); + + if (!connect_set_security(ploc, pcontext, L"Root\\StandardCimv2", + &psvc)) { + VLOG_WARN("Could not connect and set security for CIM"); + retval = false; + goto error; + } + + wcscpy_s(internal_port_query, sizeof(internal_port_query), + L"SELECT * FROM MSFT_NetAdapter WHERE Name LIKE '%%"); + wcscat_s(internal_port_query, sizeof(internal_port_query), wide_name); + wcscat_s(internal_port_query, sizeof(internal_port_query), L"%%'"); + + /* Get the object with the port name equal to name on the CIM. */ + hres = psvc->lpVtbl->ExecQuery(psvc, + L"WQL", + internal_port_query, + WBEM_FLAG_FORWARD_ONLY | + WBEM_FLAG_RETURN_IMMEDIATELY, + NULL, + &penumerate); + + if (!get_first_element(penumerate, &pcls_obj)) { + VLOG_WARN("Element name: %s not found in CIM", name); + retval = false; + goto error; + } + penumerate->lpVtbl->Release(penumerate); + penumerate = NULL; + pcls_obj->lpVtbl->Get(pcls_obj, L"__PATH", 0, &vt_prop, 0, 0); + pcls_obj->lpVtbl->Release(pcls_obj); + pcls_obj = NULL; + + /* Disable the adapter with port name equal with name. */ + hres = psvc->lpVtbl->ExecMethod(psvc, vt_prop.bstrVal, L"Disable", 0, + pcontext, NULL, NULL, NULL); + + if (FAILED(hres)) { + retval = false; + goto error; + } + + hres = psvc->lpVtbl->GetObject(psvc, L"MSFT_NetAdapter", 0, NULL, &pclass, + NULL); + if (FAILED(hres)) { + retval = false; + goto error; + } + + hres = pclass->lpVtbl->GetMethod(pclass, L"Rename", 0, &pinput_params, + NULL); + if (FAILED(hres)) { + retval = false; + goto error; + } + + hres = pinput_params->lpVtbl->SpawnInstance(pinput_params, 0, + &pclass_instance); + if (FAILED(hres)) { + retval = false; + goto error; + } + + VariantInit(&new_name); + new_name.vt = VT_BSTR; + new_name.bstrVal = wide_name; + hres = pclass_instance->lpVtbl->Put(pclass_instance, L"NewName", 0, + &new_name, 0); + if (FAILED(hres)) { + retval = false; + goto error; + } + hres = psvc->lpVtbl->ExecMethod(psvc, vt_prop.bstrVal, L"Rename", 0, + pcontext, pclass_instance, NULL, NULL); + if (FAILED(hres)) { + retval = false; + } + +error: + if (text_object_string != NULL) { + SysFreeString(text_object_string); + text_object_string = NULL; + } + if (psa != NULL) { + SafeArrayDestroy(psa); + psa = NULL; + } + if (ploc != NULL) { + ploc->lpVtbl->Release(ploc); + ploc = NULL; + } + if (pcontext != NULL) { + pcontext->lpVtbl->Release(pcontext); + pcontext = NULL; + } + if (psvc != NULL) { + psvc->lpVtbl->Release(psvc); + psvc = NULL; + } + if (penumerate != NULL) { + penumerate->lpVtbl->Release(penumerate); + penumerate = NULL; + } + if (default_settings_data != NULL) { + default_settings_data->lpVtbl->Release(default_settings_data); + default_settings_data = NULL; + } + if (default_system != NULL) { + default_system->lpVtbl->Release(default_system); + default_system = NULL; + } + if (pcls_obj != NULL) { + pcls_obj->lpVtbl->Release(pcls_obj); + pcls_obj = NULL; + } + if (pclass != NULL) { + pclass->lpVtbl->Release(pclass); + pclass = NULL; + } + if (pinput_params != NULL) { + pinput_params->lpVtbl->Release(pinput_params); + pinput_params = NULL; + } + if (pclass_instance != NULL) { + pclass_instance->lpVtbl->Release(pclass_instance); + pclass_instance = NULL; + } + if (text_object != NULL) { + text_object->lpVtbl->Release(text_object); + text_object = NULL; + } + if (pout_params != NULL) { + pout_params->lpVtbl->Release(pout_params); + pout_params = NULL; + } + if (wide_name != NULL) { + free(wide_name); + wide_name = NULL; + } + VariantClear(&vt_prop); + VariantClear(&switch_setting_path); + + if (!retval) { + get_hres_error(hres); + } + CoUninitialize(); + return retval; +} diff --git a/lib/wmi.h b/lib/wmi.h new file mode 100644 index 0000000..28910e7 --- /dev/null +++ b/lib/wmi.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2016 Cloudbase Solutions Srl + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WMI_H +#define WMI_H 1 + +#include <windefs.h> +#include <Wbemidl.h> + +static inline void fill_context(IWbemContext *pContext) +{ + VARIANT var; + + /* IncludeQualifiers. */ + VariantInit(&var); + var.vt = VT_BOOL; + var.boolVal = VARIANT_TRUE; + pContext->lpVtbl->SetValue(pContext, L"IncludeQualifiers", 0, &var); + VariantClear(&var); + + VariantInit(&var); + var.vt = VT_I4; + var.lVal = 0; + pContext->lpVtbl->SetValue(pContext, L"PathLevel", 0, &var); + VariantClear(&var); + + /* ExcludeSystemProperties. */ + VariantInit(&var); + var.vt = VT_BOOL; + var.boolVal = VARIANT_FALSE; + pContext->lpVtbl->SetValue(pContext, L"ExcludeSystemProperties", 0, &var); + VariantClear(&var); +} + +boolean create_wmi_port(char *name); +boolean delete_wmi_port(char *name); + +#endif /* wmi.h */