52 #define _snprintf StringCbPrintfA
65 static const char *StripPcapPrefix(
const char *pcap_dev)
67 return strchr(pcap_dev,
'{');
75 uint32_t Win32GetAdaptersAddresses(IP_ADAPTER_ADDRESSES **pif_info_list)
78 IP_ADAPTER_ADDRESSES *if_info_list;
81 err = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, NULL, &size);
82 if (err != ERROR_BUFFER_OVERFLOW) {
85 if_info_list =
SCMalloc((
size_t)size);
86 if (if_info_list == NULL) {
87 return ERROR_NOT_ENOUGH_MEMORY;
89 err = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, if_info_list, &size);
90 if (err != NO_ERROR) {
95 *pif_info_list = if_info_list;
99 uint32_t Win32FindAdapterAddresses(IP_ADAPTER_ADDRESSES *if_info_list,
100 const char *adapter_name,
101 IP_ADAPTER_ADDRESSES **pif_info)
103 DWORD ret = NO_ERROR;
104 adapter_name = StripPcapPrefix(adapter_name);
107 for (IP_ADAPTER_ADDRESSES *current = if_info_list; current != NULL;
108 current = current->Next) {
111 if (strncmp(adapter_name, current->AdapterName, strlen(adapter_name)) ==
119 if (*pif_info == NULL) {
120 ret = ERROR_NOT_FOUND;
126 #if NTDDI_VERSION < NTDDI_VISTA
128 int GetIfaceMTUWin32(
const char *pcap_dev) {
return 0; }
129 int GetGlobalMTUWin32(
void) {
return 0; }
131 int GetIfaceOffloadingWin32(
const char *ifname,
int csum,
int other)
133 SCLogWarning(
"Suricata not targeted for Windows Vista or "
134 "higher. Network offload interrogation not "
138 int DisableIfaceOffloadingWin32(
LiveDevice *ldev,
int csum,
int other)
140 SCLogWarning(
"Suricata not targeted for Windows Vista or "
141 "higher. Network offload interrogation not "
145 int RestoreIfaceOffloadingWin32(
LiveDevice *ldev)
147 SCLogWarning(
"Suricata not targeted for Windows Vista or "
148 "higher. Network offload interrogation not "
155 static HMODULE wmiutils_dll = NULL;
160 static HMODULE WmiUtils(
void)
162 if (wmiutils_dll == NULL) {
164 LoadLibraryA(
"C:\\Windows\\System32\\wbem\\wmiutils.dll");
173 static BSTR utob(uint64_t ui)
176 _ui64tow(ui, buf, 10);
177 return SysAllocString(buf);
186 const char *Win32GetErrorString(DWORD error_code, HMODULE ext_module)
188 char *error_string = NULL;
191 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS;
192 if (ext_module != NULL) {
193 flags |= FORMAT_MESSAGE_FROM_HMODULE;
195 flags |= FORMAT_MESSAGE_FROM_SYSTEM;
198 FormatMessageA(
flags, ext_module, error_code, 0, (LPTSTR)&error_string, 0,
201 if (error_string == NULL) {
205 error_string[strlen(error_string) - 2] = 0;
214 static void _Win32HResultLog(
SCLogLevel level, HRESULT hr,
const char *file,
215 const char *
function,
const int line)
217 const char *err_str = Win32GetErrorString(hr, WmiUtils());
218 SCLog(level, file,
function, line,
"HRESULT: %s (0x%08" PRIx32
")", err_str,
220 LocalFree((LPVOID)err_str);
223 #define Win32HResultLogDebug(hr) \
224 _Win32HResultLog(SC_LOG_DEBUG, (hr), __FILE__, __FUNCTION__, __LINE__)
226 #define Win32HResultLogDebug(hr)
232 #define WbemLogDebug(hr) (_WbemLogDebug)((hr), __FILE__, __FUNCTION__, __LINE__)
234 static void _WbemLogDebug(HRESULT hr,
const char *file,
const char *
function,
238 IErrorInfo *err_info;
239 BSTR err_description;
240 char *err_description_mb = NULL;
242 _Win32HResultLog(
SC_LOG_DEBUG, hr, file,
function, line);
244 GetErrorInfo(0, &err_info);
246 err_info->lpVtbl->GetDescription(err_info, &err_description))) {
251 err_description_mb =
SCMalloc(SysStringLen(err_description) + 1);
253 if (err_description_mb == NULL) {
259 err_description_mb[SysStringLen(err_description)] = 0;
260 wcstombs(err_description_mb, err_description,
261 SysStringLen(err_description));
268 SCFree(err_description_mb);
269 SysFreeString(err_description);
276 int GetIfaceMTUWin32(
const char *pcap_dev)
278 DWORD err = NO_ERROR;
282 IP_ADAPTER_ADDRESSES *if_info_list = NULL, *if_info = NULL;
283 err = Win32GetAdaptersAddresses(&if_info_list);
284 if (err != NO_ERROR) {
288 err = Win32FindAdapterAddresses(if_info_list, pcap_dev, &if_info);
289 if (err != NO_ERROR) {
300 const char *errbuf = Win32GetErrorString(err, WmiUtils());
301 SCLogWarning(
"Failure when trying to get MTU via syscall for '%s': %s "
303 pcap_dev, errbuf, (uint32_t)err);
304 LocalFree((LPVOID)errbuf);
306 SCLogInfo(
"Found an MTU of %d for '%s'", mtu, pcap_dev);
315 int GetGlobalMTUWin32(
void)
319 DWORD err = NO_ERROR;
320 IP_ADAPTER_ADDRESSES *if_info_list = NULL;
323 err = Win32GetAdaptersAddresses(&if_info_list);
324 if (err != NO_ERROR) {
329 IP_ADAPTER_ADDRESSES *if_info = NULL;
330 for (if_info = if_info_list; if_info != NULL; if_info = if_info->Next) {
332 if (if_info->Mtu == (uint32_t)-1) {
337 mtu = max(mtu, if_info->Mtu);
342 SCLogInfo(
"Found a global MTU of %" PRIu32, mtu);
348 const char *errbuf = NULL;
349 FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
350 FORMAT_MESSAGE_IGNORE_INSERTS,
351 NULL, err, 0, (LPTSTR)&errbuf, 0, NULL);
353 SCLogWarning(
"Failure when trying to get global MTU via syscall: %s (%" PRId32
")", errbuf,
359 #define ReleaseObject(objptr) \
361 if ((objptr) != NULL) { \
362 (objptr)->lpVtbl->Release(objptr); \
367 typedef enum Win32TcpOffloadFlags_ {
368 WIN32_TCP_OFFLOAD_FLAG_NONE = 0,
369 WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4RX = 1,
370 WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4TX = 1 << 1,
371 WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6RX = 1 << 2,
372 WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6TX = 1 << 3,
373 WIN32_TCP_OFFLOAD_FLAG_LSOV1_IP4 = 1 << 4,
374 WIN32_TCP_OFFLOAD_FLAG_LSOV2_IP4 = 1 << 5,
375 WIN32_TCP_OFFLOAD_FLAG_LSOV2_IP6 = 1 << 6,
378 WIN32_TCP_OFFLOAD_FLAG_CSUM = WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4RX |
379 WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4TX |
380 WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6RX |
381 WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6TX,
382 WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4 = WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4RX |
383 WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4TX,
384 WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6 = WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6RX |
385 WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6TX,
386 WIN32_TCP_OFFLOAD_FLAG_LSO = WIN32_TCP_OFFLOAD_FLAG_LSOV1_IP4 |
387 WIN32_TCP_OFFLOAD_FLAG_LSOV2_IP4 |
388 WIN32_TCP_OFFLOAD_FLAG_LSOV2_IP6,
389 } Win32TcpOffloadFlags;
391 typedef struct ComInstance_ {
392 IWbemLocator *locator;
393 IWbemServices *services;
399 static HRESULT ComInstanceInit(ComInstance *instance, LPCWSTR resource)
403 instance->locator = NULL;
404 instance->services = NULL;
406 BSTR resource_bstr = SysAllocString(resource);
407 if (resource_bstr == NULL) {
408 hr = HRESULT_FROM_WIN32(E_OUTOFMEMORY);
414 hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
420 SCLogWarning(
"COM CoInitializeEx failed: 0x%" PRIx32, (uint32_t)hr);
423 hr = CoInitializeSecurity(
424 NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT,
425 RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
427 SCLogWarning(
"COM CoInitializeSecurity failed: 0x%" PRIx32, (uint32_t)hr);
433 hr = CoCreateInstance(&CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER,
434 &IID_IWbemLocator, (LPVOID *)&instance->locator);
436 SCLogWarning(
"COM CoCreateInstance failed: 0x%" PRIx32, (uint32_t)hr);
439 hr = instance->locator->lpVtbl->ConnectServer(
440 instance->locator, resource_bstr, NULL, NULL, NULL, 0, NULL, NULL,
441 &instance->services);
443 SCLogWarning(
"COM ConnectServer failed: 0x%" PRIx32, (uint32_t)hr);
448 SysFreeString(resource_bstr);
456 static void ComInstanceRelease(ComInstance *instance)
458 if (instance == NULL) {
461 ReleaseObject(instance->services);
462 ReleaseObject(instance->locator);
468 static HRESULT GetWbemClass(ComInstance *instance, LPCWSTR
name,
469 IWbemClassObject **p_class)
471 HRESULT hr = WBEM_S_NO_ERROR;
472 BSTR name_bstr = NULL;
474 if (instance == NULL ||
name == NULL || p_class == NULL ||
476 hr = HRESULT_FROM_WIN32(E_INVALIDARG);
477 Win32HResultLogDebug(hr);
482 name_bstr = SysAllocString(
name);
483 if (name_bstr == NULL) {
484 hr = HRESULT_FROM_WIN32(E_OUTOFMEMORY);
490 hr = instance->services->lpVtbl->GetObject(instance->services, name_bstr,
491 WBEM_FLAG_RETURN_WBEM_COMPLETE,
492 NULL, p_class, NULL);
495 SCLogWarning(
"WMI GetObject failed: 0x%" PRIx32, (uint32_t)hr);
500 SysFreeString(name_bstr);
508 static HRESULT GetWbemClassInstance(ComInstance *instance, LPCWSTR
name,
509 IWbemClassObject **p_instance)
511 HRESULT hr = WBEM_S_NO_ERROR;
513 IWbemClassObject *
class = NULL;
515 hr = GetWbemClass(instance,
name, &
class);
516 if (hr != WBEM_S_NO_ERROR) {
520 hr =
class->lpVtbl->SpawnInstance(
class, 0, p_instance);
521 if (hr != WBEM_S_NO_ERROR) {
523 SCLogWarning(
"WMI SpawnInstance failed: 0x%" PRIx32, (uint32_t)hr);
531 typedef struct WbemMethod_ {
532 ComInstance *com_instance;
536 IWbemClassObject *in_params, *out_params;
542 static HRESULT GetWbemMethod(ComInstance *com_instance, LPCWSTR class_name,
543 LPCWSTR method_name, WbemMethod *method)
546 IWbemClassObject *
class = NULL;
548 method->com_instance = com_instance;
550 BSTR class_name_bstr = SysAllocString(class_name);
551 if (class_name_bstr == NULL) {
552 hr = HRESULT_FROM_WIN32(E_OUTOFMEMORY);
556 method->method_name = SysAllocString(method_name);
557 if (method->method_name == NULL) {
558 hr = HRESULT_FROM_WIN32(E_OUTOFMEMORY);
564 hr = GetWbemClass(com_instance, class_name, &
class);
565 if (hr != WBEM_S_NO_ERROR) {
570 hr =
class->lpVtbl->GetMethod(
class, method_name, 0, &method->in_params,
571 &method->out_params);
572 if (hr != WBEM_S_NO_ERROR) {
574 SCLogWarning(
"WMI GetMethod failed: 0x%" PRIx32, (uint32_t)hr);
579 ReleaseObject(
class);
581 SysFreeString(class_name_bstr);
589 static void WbemMethodRelease(WbemMethod *method)
591 if (method == NULL) {
594 ReleaseObject(method->in_params);
595 ReleaseObject(method->out_params);
597 SysFreeString(method->method_name);
600 typedef struct WbemMethodCall_ {
605 IWbemClassObject *in_params;
611 static HRESULT GetWbemMethodCall(WbemMethod *method, LPCWSTR instance_path,
612 WbemMethodCall *call)
616 call->method = method;
617 call->instance_path = SysAllocString(instance_path);
618 if (call->instance_path == NULL) {
619 hr = HRESULT_FROM_WIN32(E_OUTOFMEMORY);
620 SCLogWarning(
"Failed to allocate BSTR: 0x%" PRIx32, (uint32_t)hr);
625 hr = method->in_params->lpVtbl->SpawnInstance(method->in_params, 0,
629 SCLogWarning(
"WMI SpawnInstance failed on in_params: 0x%" PRIx32, (uint32_t)hr);
640 static void WbemMethodCallRelease(WbemMethodCall *call)
645 ReleaseObject(call->in_params);
647 SysFreeString(call->instance_path);
653 static HRESULT WbemMethodCallExec(WbemMethodCall *call,
654 IWbemClassObject **p_out_params)
658 hr = call->method->com_instance->services->lpVtbl->ExecMethod(
659 call->method->com_instance->services, call->instance_path,
660 call->method->method_name, 0, NULL, call->in_params, p_out_params,
662 if (hr != WBEM_S_NO_ERROR) {
664 SCLogDebug(
"WMI ExecMethod failed: 0x%" PRIx32, (uint32_t)hr);
675 static HRESULT WbemGetSubObject(IWbemClassObject *
object, LPCWSTR property_name,
676 IWbemClassObject **sub_object)
681 VariantInit(&out_var);
682 hr =
object->lpVtbl->Get(
object, property_name, 0, &out_var, NULL, NULL);
683 if (hr != WBEM_S_NO_ERROR) {
687 IUnknown *unknown = V_UNKNOWN(&out_var);
688 hr = unknown->lpVtbl->QueryInterface(unknown, &IID_IWbemClassObject,
689 (
void **)sub_object);
691 SCLogWarning(
"WMI QueryInterface (IWbemClassObject) failed: 0x%" PRIx32, (uint32_t)hr);
696 VariantClear(&out_var);
703 static HRESULT GetEncapsulation(IWbemClassObject *
object, LPCWSTR category,
704 LPCWSTR subcategory, ULONG *encapsulation)
706 HRESULT hr = WBEM_S_NO_ERROR;
708 IWbemClassObject *category_object = NULL;
709 IWbemClassObject *subcategory_object = NULL;
712 VariantInit(&out_var);
715 hr = WbemGetSubObject(
object, category, &category_object);
716 if (hr != WBEM_S_NO_ERROR) {
721 hr = WbemGetSubObject(category_object, subcategory, &subcategory_object);
722 if (hr != WBEM_S_NO_ERROR) {
725 hr = subcategory_object->lpVtbl->Get(subcategory_object, L
"Encapsulation",
726 0, &out_var, NULL, NULL);
727 if (hr != WBEM_S_NO_ERROR) {
730 *encapsulation = V_UI4(&out_var);
733 VariantClear(&out_var);
734 ReleaseObject(subcategory_object);
735 ReleaseObject(category_object);
739 static HRESULT GetIUnknown(IWbemClassObject *
object, IUnknown **p_unknown)
741 HRESULT hr = WBEM_S_NO_ERROR;
743 if (
object == NULL || p_unknown == NULL || *p_unknown != NULL) {
744 hr = HRESULT_FROM_WIN32(E_INVALIDARG);
745 Win32HResultLogDebug(hr);
749 hr =
object->lpVtbl->QueryInterface(
object, &IID_IUnknown,
752 SCLogWarning(
"WMI QueryInterface (IUnknown) failed: 0x%" PRIx32, (uint32_t)hr);
760 static HRESULT BuildNdisObjectHeader(ComInstance *instance, uint8_t
type,
761 uint8_t revision, uint16_t size,
762 IWbemClassObject **p_ndis_object_header)
764 HRESULT hr = WBEM_S_NO_ERROR;
766 if (instance == NULL || p_ndis_object_header == NULL ||
767 *p_ndis_object_header != NULL) {
769 hr = HRESULT_FROM_WIN32(E_INVALIDARG);
770 Win32HResultLogDebug(hr);
775 hr = GetWbemClassInstance(instance, L
"MSNdis_ObjectHeader",
776 p_ndis_object_header);
777 if (hr != WBEM_S_NO_ERROR) {
781 VARIANT param_variant;
782 VariantInit(¶m_variant);
783 IWbemClassObject *ndis_object_header = *p_ndis_object_header;
786 V_VT(¶m_variant) = VT_UI1;
787 V_UI1(¶m_variant) =
type;
788 hr = ndis_object_header->lpVtbl->Put(ndis_object_header, L
"Type", 0,
790 VariantClear(¶m_variant);
791 if (hr != WBEM_S_NO_ERROR) {
796 V_VT(¶m_variant) = VT_UI1;
797 V_UI1(¶m_variant) = revision;
798 hr = ndis_object_header->lpVtbl->Put(ndis_object_header, L
"Revision", 0,
800 VariantClear(¶m_variant);
801 if (hr != WBEM_S_NO_ERROR) {
808 V_VT(¶m_variant) = VT_I4;
809 V_I4(¶m_variant) = size;
810 hr = ndis_object_header->lpVtbl->Put(ndis_object_header, L
"Size", 0,
812 VariantClear(¶m_variant);
813 if (hr != WBEM_S_NO_ERROR) {
822 static HRESULT BuildNdisWmiMethodHeader(ComInstance *instance,
823 uint64_t net_luid, uint32_t port_number,
824 uint64_t request_id, uint32_t timeout,
825 IWbemClassObject **p_ndis_method_header)
827 HRESULT hr = WBEM_S_NO_ERROR;
829 IWbemClassObject *ndis_object_header = NULL;
831 if (instance == NULL || p_ndis_method_header == NULL ||
832 *p_ndis_method_header != NULL) {
834 hr = HRESULT_FROM_WIN32(E_INVALIDARG);
835 Win32HResultLogDebug(hr);
840 hr = GetWbemClassInstance(instance, L
"MSNdis_WmiMethodHeader",
841 p_ndis_method_header);
842 if (hr != WBEM_S_NO_ERROR) {
846 VARIANT param_variant;
847 VariantInit(¶m_variant);
850 hr = BuildNdisObjectHeader(instance, NDIS_WMI_OBJECT_TYPE_METHOD,
851 NDIS_WMI_METHOD_HEADER_REVISION_1, 0xFFFF,
852 &ndis_object_header);
853 if (hr != WBEM_S_NO_ERROR) {
856 V_VT(¶m_variant) = VT_UNKNOWN;
857 V_UNKNOWN(¶m_variant) = NULL;
858 hr = GetIUnknown(ndis_object_header, &V_UNKNOWN(¶m_variant));
859 if (hr != WBEM_S_NO_ERROR) {
863 IWbemClassObject *ndis_method_header = *p_ndis_method_header;
866 hr = ndis_method_header->lpVtbl->Put(ndis_method_header, L
"Header", 0,
868 VariantClear(¶m_variant);
869 if (hr != WBEM_S_NO_ERROR) {
874 V_VT(¶m_variant) = VT_BSTR;
875 V_BSTR(¶m_variant) = utob(net_luid);
876 hr = ndis_method_header->lpVtbl->Put(ndis_method_header, L
"NetLuid", 0,
878 VariantClear(¶m_variant);
879 if (hr != WBEM_S_NO_ERROR) {
884 V_VT(¶m_variant) = VT_BSTR;
885 V_BSTR(¶m_variant) = utob((uint64_t)port_number);
886 hr = ndis_method_header->lpVtbl->Put(ndis_method_header, L
"PortNumber", 0,
888 VariantClear(¶m_variant);
889 if (hr != WBEM_S_NO_ERROR) {
894 V_VT(¶m_variant) = VT_BSTR;
895 V_BSTR(¶m_variant) = utob(request_id);
896 hr = ndis_method_header->lpVtbl->Put(ndis_method_header, L
"RequestId", 0,
898 VariantClear(¶m_variant);
899 if (hr != WBEM_S_NO_ERROR) {
904 V_VT(¶m_variant) = VT_BSTR;
905 V_BSTR(¶m_variant) = utob((uint64_t)timeout);
906 hr = ndis_method_header->lpVtbl->Put(ndis_method_header, L
"Timeout", 0,
908 VariantClear(¶m_variant);
909 if (hr != WBEM_S_NO_ERROR) {
914 V_VT(¶m_variant) = VT_BSTR;
915 V_BSTR(¶m_variant) = utob((uint64_t)0);
916 hr = ndis_method_header->lpVtbl->Put(ndis_method_header, L
"Padding", 0,
918 VariantClear(¶m_variant);
919 if (hr != WBEM_S_NO_ERROR) {
925 ReleaseObject(ndis_object_header);
933 static HRESULT GetNdisOffload(LPCWSTR if_description, uint32_t *offload_flags)
937 ComInstance instance = {};
938 WbemMethod method = {};
939 WbemMethodCall call = {};
941 IWbemClassObject *ndis_method_header = NULL;
942 IWbemClassObject *out_params = NULL;
943 IWbemClassObject *ndis_offload = NULL;
945 if (if_description == NULL) {
947 hr = HRESULT_FROM_WIN32(E_INVALIDARG);
951 LPCWSTR class_name = L
"MSNdis_TcpOffloadCurrentConfig";
952 LPCWSTR instance_name_fmt = L
"%s=\"%s\"";
953 size_t n_chars = wcslen(class_name) + wcslen(if_description) +
954 wcslen(instance_name_fmt);
955 LPWSTR instance_name =
SCMalloc((n_chars + 1) *
sizeof(
wchar_t));
956 if (instance_name == NULL) {
957 SCLogWarning(
"Failed to allocate buffer for instance path");
960 instance_name[n_chars] = 0;
961 hr = StringCchPrintfW(instance_name, n_chars, instance_name_fmt, class_name,
964 SCLogWarning(
"Failed to format WMI class instance name: 0x%" PRIx32, (uint32_t)hr);
968 LPCWSTR method_name = L
"WmiQueryCurrentOffloadConfig";
971 hr = ComInstanceInit(&instance, L
"ROOT\\WMI");
977 hr = GetWbemMethod(&instance, class_name, method_name, &method);
983 hr = GetWbemMethodCall(&method, instance_name, &call);
990 VARIANT param_variant;
991 VariantInit(¶m_variant);
994 hr = BuildNdisWmiMethodHeader(&instance, 0, 0, 0, 5, &ndis_method_header);
995 if (hr != WBEM_S_NO_ERROR) {
998 V_VT(¶m_variant) = VT_UNKNOWN;
999 V_UNKNOWN(¶m_variant) = NULL;
1000 hr = GetIUnknown(ndis_method_header, &V_UNKNOWN(¶m_variant));
1001 if (hr != WBEM_S_NO_ERROR) {
1006 hr = call.in_params->lpVtbl->Put(call.in_params, L
"Header", 0,
1008 VariantClear(¶m_variant);
1009 if (hr != WBEM_S_NO_ERROR) {
1015 hr = WbemMethodCallExec(&call, &out_params);
1017 size_t if_description_len = wcslen(if_description);
1018 char *if_description_ansi =
SCMalloc(if_description_len + 1);
1019 if (if_description_ansi == NULL) {
1020 SCLogWarning(
"Failed to allocate buffer for interface description");
1023 if_description_ansi[if_description_len] = 0;
1024 wcstombs(if_description_ansi, if_description, if_description_len);
1025 SCLogInfo(
"Obtaining offload state failed, device \"%s\" may not "
1026 "support offload. Error: 0x%" PRIx32,
1027 if_description_ansi, (uint32_t)hr);
1028 SCFree(if_description_ansi);
1029 Win32HResultLogDebug(hr);
1034 hr = WbemGetSubObject(out_params, L
"Offload", &ndis_offload);
1035 if (hr != WBEM_S_NO_ERROR) {
1038 ULONG encapsulation = 0;
1041 hr = GetEncapsulation(ndis_offload, L
"Checksum", L
"IPv4Receive",
1043 if (hr != WBEM_S_NO_ERROR) {
1047 if (encapsulation != 0) {
1048 *offload_flags |= WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4RX;
1050 hr = GetEncapsulation(ndis_offload, L
"Checksum", L
"IPv4Transmit",
1052 if (hr != WBEM_S_NO_ERROR) {
1056 if (encapsulation != 0) {
1057 *offload_flags |= WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4TX;
1059 hr = GetEncapsulation(ndis_offload, L
"Checksum", L
"IPv6Receive",
1061 if (hr != WBEM_S_NO_ERROR) {
1065 if (encapsulation != 0) {
1066 *offload_flags |= WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6RX;
1068 hr = GetEncapsulation(ndis_offload, L
"Checksum", L
"IPv6Transmit",
1070 if (hr != WBEM_S_NO_ERROR) {
1074 if (encapsulation != 0) {
1075 *offload_flags |= WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6TX;
1079 hr = GetEncapsulation(ndis_offload, L
"LsoV1", L
"WmiIPv4", &encapsulation);
1080 if (hr != WBEM_S_NO_ERROR) {
1084 if (encapsulation != 0) {
1085 *offload_flags |= WIN32_TCP_OFFLOAD_FLAG_LSOV1_IP4;
1089 hr = GetEncapsulation(ndis_offload, L
"LsoV2", L
"WmiIPv4", &encapsulation);
1090 if (hr != WBEM_S_NO_ERROR) {
1094 if (encapsulation != 0) {
1095 *offload_flags |= WIN32_TCP_OFFLOAD_FLAG_LSOV2_IP4;
1097 hr = GetEncapsulation(ndis_offload, L
"LsoV2", L
"WmiIPv6", &encapsulation);
1098 if (hr != WBEM_S_NO_ERROR) {
1102 if (encapsulation != 0) {
1103 *offload_flags |= WIN32_TCP_OFFLOAD_FLAG_LSOV2_IP6;
1107 ReleaseObject(ndis_method_header);
1108 ReleaseObject(ndis_offload);
1109 ReleaseObject(out_params);
1111 WbemMethodCallRelease(&call);
1112 WbemMethodRelease(&method);
1113 ComInstanceRelease(&instance);
1118 int GetIfaceOffloadingWin32(
const char *pcap_dev,
int csum,
int other)
1120 SCLogDebug(
"Querying offloading for device %s", pcap_dev);
1122 DWORD err = NO_ERROR;
1124 uint32_t offload_flags = 0;
1127 IP_ADAPTER_ADDRESSES *if_info_list = NULL, *if_info = NULL;
1128 err = Win32GetAdaptersAddresses(&if_info_list);
1129 if (err != NO_ERROR) {
1133 err = Win32FindAdapterAddresses(if_info_list, pcap_dev, &if_info);
1134 if (err != NO_ERROR) {
1138 LPWSTR if_description = if_info->Description;
1141 err = GetNdisOffload(if_description, &offload_flags);
1145 }
else if (offload_flags != 0) {
1147 if ((offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM) != 0) {
1152 if ((offload_flags & WIN32_TCP_OFFLOAD_FLAG_LSO) != 0) {
1159 SCLogPerf(
"NIC offloading on %s: Checksum IPv4 Rx: %d Tx: %d IPv6 "
1160 "Rx: %d Tx: %d LSOv1 IPv4: %d LSOv2 IPv4: %d IPv6: %d",
1162 (offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4RX) != 0,
1163 (offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4TX) != 0,
1164 (offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6RX) != 0,
1165 (offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6TX) != 0,
1166 (offload_flags & WIN32_TCP_OFFLOAD_FLAG_LSOV1_IP4) != 0,
1167 (offload_flags & WIN32_TCP_OFFLOAD_FLAG_LSOV2_IP4) != 0,
1168 (offload_flags & WIN32_TCP_OFFLOAD_FLAG_LSOV2_IP6) != 0);
1170 SCLogWarning(
"NIC offloading on %s: Checksum IPv4 Rx: %d Tx: %d IPv6 "
1171 "Rx: %d Tx: %d LSOv1 IPv4: %d LSOv2 IPv4: %d IPv6: %d",
1172 pcap_dev, (offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4RX) != 0,
1173 (offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4TX) != 0,
1174 (offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6RX) != 0,
1175 (offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6TX) != 0,
1176 (offload_flags & WIN32_TCP_OFFLOAD_FLAG_LSOV1_IP4) != 0,
1177 (offload_flags & WIN32_TCP_OFFLOAD_FLAG_LSOV2_IP4) != 0,
1178 (offload_flags & WIN32_TCP_OFFLOAD_FLAG_LSOV2_IP6) != 0);
1183 const char *err_str = Win32GetErrorString(err, WmiUtils());
1184 SCLogWarning(
"Failure when trying to get feature via syscall for '%s': "
1185 "%s (0x%08" PRIx32
")",
1186 pcap_dev, err_str, (uint32_t)err);
1187 LocalFree((LPVOID)err_str);
1196 BuildNdisTcpOffloadParameters(ComInstance *instance, uint32_t offload_flags,
1198 IWbemClassObject **p_ndis_tcp_offload_parameters)
1200 HRESULT hr = WBEM_S_NO_ERROR;
1202 IWbemClassObject *ndis_object_header = NULL;
1204 if (instance == NULL || p_ndis_tcp_offload_parameters == NULL ||
1205 *p_ndis_tcp_offload_parameters != NULL) {
1207 hr = HRESULT_FROM_WIN32(E_INVALIDARG);
1208 Win32HResultLogDebug(hr);
1213 hr = GetWbemClassInstance(instance, L
"MSNdis_TcpOffloadParameters",
1214 p_ndis_tcp_offload_parameters);
1215 if (hr != WBEM_S_NO_ERROR) {
1219 VARIANT param_variant;
1220 VariantInit(¶m_variant);
1223 hr = BuildNdisObjectHeader(instance, NDIS_OBJECT_TYPE_DEFAULT,
1224 NDIS_OFFLOAD_PARAMETERS_REVISION_1,
1225 NDIS_SIZEOF_OFFLOAD_PARAMETERS_REVISION_1,
1226 &ndis_object_header);
1227 if (hr != WBEM_S_NO_ERROR) {
1230 V_VT(¶m_variant) = VT_UNKNOWN;
1231 V_UNKNOWN(¶m_variant) = NULL;
1232 hr = GetIUnknown(ndis_object_header, &V_UNKNOWN(¶m_variant));
1233 if (hr != WBEM_S_NO_ERROR) {
1237 IWbemClassObject *ndis_tcp_offload_parameters =
1238 *p_ndis_tcp_offload_parameters;
1241 hr = ndis_tcp_offload_parameters->lpVtbl->Put(
1242 ndis_tcp_offload_parameters, L
"Header", 0, ¶m_variant, 0);
1243 VariantClear(¶m_variant);
1244 if (hr != WBEM_S_NO_ERROR) {
1245 Win32HResultLogDebug(hr);
1250 V_VT(¶m_variant) = VT_BSTR;
1251 V_BSTR(¶m_variant) = utob(NDIS_OFFLOAD_PARAMETERS_NO_CHANGE);
1252 if (!enable && (offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4) != 0) {
1254 V_BSTR(¶m_variant) = utob(NDIS_OFFLOAD_PARAMETERS_TX_RX_DISABLED);
1255 }
else if ((offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4) ==
1256 WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4) {
1258 V_BSTR(¶m_variant) = utob(NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED);
1259 }
else if ((offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4RX) != 0) {
1261 V_BSTR(¶m_variant) =
1262 utob(NDIS_OFFLOAD_PARAMETERS_RX_ENABLED_TX_DISABLED);
1263 }
else if ((offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4TX) != 0) {
1265 V_BSTR(¶m_variant) =
1266 utob(NDIS_OFFLOAD_PARAMETERS_TX_ENABLED_RX_DISABLED);
1268 hr = ndis_tcp_offload_parameters->lpVtbl->Put(
1269 ndis_tcp_offload_parameters, L
"IPv4Checksum", 0, ¶m_variant, 0);
1270 if (hr != WBEM_S_NO_ERROR) {
1274 hr = ndis_tcp_offload_parameters->lpVtbl->Put(ndis_tcp_offload_parameters,
1275 L
"TCPIPv4Checksum", 0,
1277 if (hr != WBEM_S_NO_ERROR) {
1281 hr = ndis_tcp_offload_parameters->lpVtbl->Put(ndis_tcp_offload_parameters,
1282 L
"UDPIPv4Checksum", 0,
1284 if (hr != WBEM_S_NO_ERROR) {
1288 VariantClear(¶m_variant);
1291 V_VT(¶m_variant) = VT_BSTR;
1292 V_BSTR(¶m_variant) = utob(NDIS_OFFLOAD_PARAMETERS_NO_CHANGE);
1293 if (!enable && (offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6) != 0) {
1295 V_BSTR(¶m_variant) = utob(NDIS_OFFLOAD_PARAMETERS_TX_RX_DISABLED);
1296 }
else if ((offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6) ==
1297 WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6) {
1299 V_BSTR(¶m_variant) = utob(NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED);
1300 }
else if ((offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6RX) != 0) {
1302 V_BSTR(¶m_variant) =
1303 utob(NDIS_OFFLOAD_PARAMETERS_RX_ENABLED_TX_DISABLED);
1304 }
else if ((offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6TX) != 0) {
1306 V_BSTR(¶m_variant) =
1307 utob(NDIS_OFFLOAD_PARAMETERS_TX_ENABLED_RX_DISABLED);
1309 hr = ndis_tcp_offload_parameters->lpVtbl->Put(ndis_tcp_offload_parameters,
1310 L
"TCPIPv6Checksum", 0,
1312 if (hr != WBEM_S_NO_ERROR) {
1316 hr = ndis_tcp_offload_parameters->lpVtbl->Put(ndis_tcp_offload_parameters,
1317 L
"UDPIPv6Checksum", 0,
1319 if (hr != WBEM_S_NO_ERROR) {
1323 VariantClear(¶m_variant);
1326 V_VT(¶m_variant) = VT_BSTR;
1327 V_BSTR(¶m_variant) = utob(NDIS_OFFLOAD_PARAMETERS_NO_CHANGE);
1328 if ((offload_flags & WIN32_TCP_OFFLOAD_FLAG_LSOV1_IP4) != 0) {
1330 V_BSTR(¶m_variant) =
1331 utob(NDIS_OFFLOAD_PARAMETERS_LSOV1_ENABLED);
1333 V_BSTR(¶m_variant) =
1334 utob(NDIS_OFFLOAD_PARAMETERS_LSOV1_DISABLED);
1337 hr = ndis_tcp_offload_parameters->lpVtbl->Put(
1338 ndis_tcp_offload_parameters, L
"LsoV1", 0, ¶m_variant, 0);
1339 if (hr != WBEM_S_NO_ERROR) {
1343 VariantClear(¶m_variant);
1346 V_VT(¶m_variant) = VT_BSTR;
1347 V_BSTR(¶m_variant) = utob(NDIS_OFFLOAD_PARAMETERS_NO_CHANGE);
1348 if ((offload_flags & WIN32_TCP_OFFLOAD_FLAG_LSOV2_IP4) != 0) {
1350 V_BSTR(¶m_variant) =
1351 utob(NDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED);
1353 V_BSTR(¶m_variant) =
1354 utob(NDIS_OFFLOAD_PARAMETERS_LSOV2_DISABLED);
1357 hr = ndis_tcp_offload_parameters->lpVtbl->Put(
1358 ndis_tcp_offload_parameters, L
"LsoV2IPv4", 0, ¶m_variant, 0);
1359 if (hr != WBEM_S_NO_ERROR) {
1363 VariantClear(¶m_variant);
1366 V_VT(¶m_variant) = VT_BSTR;
1367 V_BSTR(¶m_variant) = utob(NDIS_OFFLOAD_PARAMETERS_NO_CHANGE);
1368 if ((offload_flags & WIN32_TCP_OFFLOAD_FLAG_LSOV2_IP6) != 0) {
1370 V_BSTR(¶m_variant) =
1371 utob(NDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED);
1373 V_BSTR(¶m_variant) =
1374 utob(NDIS_OFFLOAD_PARAMETERS_LSOV2_DISABLED);
1377 hr = ndis_tcp_offload_parameters->lpVtbl->Put(
1378 ndis_tcp_offload_parameters, L
"LsoV2IPv6", 0, ¶m_variant, 0);
1379 if (hr != WBEM_S_NO_ERROR) {
1383 VariantClear(¶m_variant);
1386 V_VT(¶m_variant) = VT_BSTR;
1387 V_BSTR(¶m_variant) = utob(NDIS_OFFLOAD_PARAMETERS_NO_CHANGE);
1388 hr = ndis_tcp_offload_parameters->lpVtbl->Put(
1389 ndis_tcp_offload_parameters, L
"IPSec", 0, ¶m_variant, 0);
1390 if (hr != WBEM_S_NO_ERROR) {
1394 hr = ndis_tcp_offload_parameters->lpVtbl->Put(ndis_tcp_offload_parameters,
1395 L
"TcpConnectionIPv4", 0,
1397 if (hr != WBEM_S_NO_ERROR) {
1401 hr = ndis_tcp_offload_parameters->lpVtbl->Put(ndis_tcp_offload_parameters,
1402 L
"TcpConnectionIPv6", 0,
1404 if (hr != WBEM_S_NO_ERROR) {
1408 hr = ndis_tcp_offload_parameters->lpVtbl->Put(
1409 ndis_tcp_offload_parameters, L
"Flags", 0, ¶m_variant, 0);
1410 if (hr != WBEM_S_NO_ERROR) {
1417 VariantClear(¶m_variant);
1422 static HRESULT SetNdisOffload(LPCWSTR if_description, uint32_t offload_flags,
1427 ComInstance instance = {};
1428 WbemMethod method = {};
1429 WbemMethodCall call = {};
1432 IWbemClassObject *ndis_method_header = NULL;
1434 IWbemClassObject *ndis_tcp_offload_parameters = NULL;
1436 if (if_description == NULL) {
1438 return E_INVALIDARG;
1441 LPCWSTR class_name = L
"MSNdis_SetTcpOffloadParameters";
1442 LPCWSTR instance_name_fmt = L
"%s=\"%s\"";
1443 size_t n_chars = wcslen(class_name) + wcslen(if_description) +
1444 wcslen(instance_name_fmt);
1445 LPWSTR instance_name =
SCMalloc((n_chars + 1) *
sizeof(
wchar_t));
1446 if (instance_name == NULL) {
1447 SCLogWarning(
"Failed to allocate buffer for instance path");
1450 instance_name[n_chars] = 0;
1451 hr = StringCchPrintfW(instance_name, n_chars, instance_name_fmt, class_name,
1454 SCLogWarning(
"Failed to format WMI class instance name: 0x%" PRIx32, (uint32_t)hr);
1459 LPCWSTR method_name = L
"WmiSetTcpOffloadParameters";
1462 hr = ComInstanceInit(&instance, L
"ROOT\\WMI");
1468 hr = GetWbemMethod(&instance, class_name, method_name, &method);
1474 hr = GetWbemMethodCall(&method, instance_name, &call);
1481 VARIANT param_variant;
1482 VariantInit(¶m_variant);
1485 hr = BuildNdisWmiMethodHeader(&instance, 0, 0, 0, 5, &ndis_method_header);
1486 if (hr != WBEM_S_NO_ERROR) {
1490 V_VT(¶m_variant) = VT_UNKNOWN;
1491 V_UNKNOWN(¶m_variant) = NULL;
1492 hr = GetIUnknown(ndis_method_header, &V_UNKNOWN(¶m_variant));
1493 if (hr != WBEM_S_NO_ERROR) {
1496 hr = call.in_params->lpVtbl->Put(call.in_params, L
"MethodHeader", 0,
1498 VariantClear(¶m_variant);
1499 if (hr != WBEM_S_NO_ERROR) {
1500 Win32HResultLogDebug(hr);
1505 hr = BuildNdisTcpOffloadParameters(&instance, offload_flags, enable,
1506 &ndis_tcp_offload_parameters);
1507 if (hr != WBEM_S_NO_ERROR) {
1511 V_VT(¶m_variant) = VT_UNKNOWN;
1512 V_UNKNOWN(¶m_variant) = NULL;
1513 hr = GetIUnknown(ndis_tcp_offload_parameters, &V_UNKNOWN(¶m_variant));
1514 if (hr != WBEM_S_NO_ERROR) {
1517 hr = call.in_params->lpVtbl->Put(call.in_params, L
"TcpOffloadParameters", 0,
1519 VariantClear(¶m_variant);
1520 if (hr != WBEM_S_NO_ERROR) {
1521 Win32HResultLogDebug(hr);
1526 hr = WbemMethodCallExec(&call, NULL);
1528 Win32HResultLogDebug(hr);
1533 ReleaseObject(ndis_tcp_offload_parameters);
1534 ReleaseObject(ndis_method_header);
1536 WbemMethodCallRelease(&call);
1537 WbemMethodRelease(&method);
1538 ComInstanceRelease(&instance);
1543 int DisableIfaceOffloadingWin32(
LiveDevice *ldev,
int csum,
int other)
1545 SCLogDebug(
"Disabling offloading for device %s", ldev->
dev);
1548 DWORD err = NO_ERROR;
1549 uint32_t offload_flags = 0;
1556 IP_ADAPTER_ADDRESSES *if_info_list = NULL, *if_info = NULL;
1557 err = Win32GetAdaptersAddresses(&if_info_list);
1558 if (err != NO_ERROR) {
1562 err = Win32FindAdapterAddresses(if_info_list, ldev->
dev, &if_info);
1563 if (err != NO_ERROR) {
1567 LPWSTR if_description = if_info->Description;
1569 err = GetNdisOffload(if_description, &offload_flags);
1576 offload_flags &= ~WIN32_TCP_OFFLOAD_FLAG_CSUM;
1579 offload_flags &= ~WIN32_TCP_OFFLOAD_FLAG_LSO;
1582 err = SetNdisOffload(if_description, offload_flags, 0);
1594 int RestoreIfaceOffloadingWin32(
LiveDevice *ldev)
1599 DWORD err = NO_ERROR;
1606 IP_ADAPTER_ADDRESSES *if_info_list = NULL, *if_info = NULL;
1607 err = Win32GetAdaptersAddresses(&if_info_list);
1608 if (err != NO_ERROR) {
1612 err = Win32FindAdapterAddresses(if_info_list, ldev->
dev, &if_info);
1613 if (err != NO_ERROR) {
1617 LPWSTR if_description = if_info->Description;
1619 err = SetNdisOffload(if_description, ldev->
offload_orig, 1);
1634 static int Win32TestStripPcapPrefix(
void)
1638 const char *name1 =
"\\Device\\NPF_{D4A32435-1BA7-4008-93A6-1518AA4BBD9B}";
1639 const char *expect_name1 =
"{D4A32435-1BA7-4008-93A6-1518AA4BBD9B}";
1641 const char *name2 =
"{D4A32435-1BA7-4008-93A6-1518AA4BBD9B}";
1642 const char *expect_name2 =
"{D4A32435-1BA7-4008-93A6-1518AA4BBD9B}";
1644 result &= (strncmp(expect_name1, StripPcapPrefix(name1),
1645 strlen(expect_name1)) == 0);
1647 result &= (strncmp(expect_name2, StripPcapPrefix(name2),
1648 strlen(expect_name2)) == 0);
1654 void Win32SyscallRegisterTests(
void)
1657 UtRegisterTest(
"Win32TestStripPcapPrefix", Win32TestStripPcapPrefix);