52 #define _snprintf StringCbPrintfA
67 static const char *StripPcapPrefix(
const char *pcap_dev)
69 return strchr(pcap_dev,
'{');
77 uint32_t Win32GetAdaptersAddresses(IP_ADAPTER_ADDRESSES **pif_info_list)
80 IP_ADAPTER_ADDRESSES *if_info_list;
83 err = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, NULL, &size);
84 if (err != ERROR_BUFFER_OVERFLOW) {
87 if_info_list =
SCMalloc((
size_t)size);
88 if (if_info_list == NULL) {
89 return ERROR_NOT_ENOUGH_MEMORY;
91 err = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, if_info_list, &size);
92 if (err != NO_ERROR) {
97 *pif_info_list = if_info_list;
101 uint32_t Win32FindAdapterAddresses(IP_ADAPTER_ADDRESSES *if_info_list,
102 const char *adapter_name,
103 IP_ADAPTER_ADDRESSES **pif_info)
105 DWORD ret = NO_ERROR;
106 adapter_name = StripPcapPrefix(adapter_name);
109 for (IP_ADAPTER_ADDRESSES *current = if_info_list; current != NULL;
110 current = current->Next) {
113 if (strncmp(adapter_name, current->AdapterName, strlen(adapter_name)) ==
121 if (*pif_info == NULL) {
122 ret = ERROR_NOT_FOUND;
128 #if NTDDI_VERSION < NTDDI_VISTA
130 int GetIfaceMTUWin32(
const char *pcap_dev) {
return 0; }
131 int GetGlobalMTUWin32(
void) {
return 0; }
133 int GetIfaceOffloadingWin32(
const char *ifname,
int csum,
int other)
136 "higher. Network offload interrogation not "
140 int DisableIfaceOffloadingWin32(
LiveDevice *ldev,
int csum,
int other)
143 "higher. Network offload interrogation not "
147 int RestoreIfaceOffloadingWin32(
LiveDevice *ldev)
150 "higher. Network offload interrogation not "
157 static HMODULE wmiutils_dll = NULL;
162 static HMODULE WmiUtils(
void)
164 if (wmiutils_dll == NULL) {
166 LoadLibraryA(
"C:\\Windows\\System32\\wbem\\wmiutils.dll");
175 static BSTR utob(uint64_t ui)
178 _ui64tow(ui, buf, 10);
179 return SysAllocString(buf);
188 const char *Win32GetErrorString(DWORD error_code, HMODULE ext_module)
190 char *error_string = NULL;
193 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS;
194 if (ext_module != NULL) {
195 flags |= FORMAT_MESSAGE_FROM_HMODULE;
197 flags |= FORMAT_MESSAGE_FROM_SYSTEM;
200 FormatMessageA(
flags, ext_module, error_code, 0, (LPTSTR)&error_string, 0,
203 if (error_string == NULL) {
207 error_string[strlen(error_string) - 2] = 0;
216 static void _Win32HResultLog(
SCLogLevel level, HRESULT hr,
const char *file,
217 const char *
function,
const int line)
219 const char *err_str = Win32GetErrorString(hr, WmiUtils());
220 SCLog(level, file,
function, line,
"HRESULT: %s (0x%08" PRIx32
")", err_str,
222 LocalFree((LPVOID)err_str);
225 #define Win32HResultLogDebug(hr) \
226 _Win32HResultLog(SC_LOG_DEBUG, (hr), __FILE__, __FUNCTION__, __LINE__)
228 #define Win32HResultLogDebug(hr)
234 #define WbemLogDebug(hr) (_WbemLogDebug)((hr), __FILE__, __FUNCTION__, __LINE__)
236 static void _WbemLogDebug(HRESULT hr,
const char *file,
const char *
function,
240 IErrorInfo *err_info;
241 BSTR err_description;
242 char *err_description_mb = NULL;
244 _Win32HResultLog(
SC_LOG_DEBUG, hr, file,
function, line);
246 GetErrorInfo(0, &err_info);
248 err_info->lpVtbl->GetDescription(err_info, &err_description))) {
253 err_description_mb =
SCMalloc(SysStringLen(err_description) + 1);
255 if (err_description_mb == NULL) {
261 err_description_mb[SysStringLen(err_description)] = 0;
262 wcstombs(err_description_mb, err_description,
263 SysStringLen(err_description));
270 SCFree(err_description_mb);
271 SysFreeString(err_description);
278 int GetIfaceMTUWin32(
const char *pcap_dev)
280 DWORD err = NO_ERROR;
284 IP_ADAPTER_ADDRESSES *if_info_list = NULL, *if_info = NULL;
285 err = Win32GetAdaptersAddresses(&if_info_list);
286 if (err != NO_ERROR) {
290 err = Win32FindAdapterAddresses(if_info_list, pcap_dev, &if_info);
291 if (err != NO_ERROR) {
302 const char *errbuf = Win32GetErrorString(err, WmiUtils());
304 "Failure when trying to get MTU via syscall for '%s': %s "
306 pcap_dev, errbuf, (uint32_t)err);
307 LocalFree((LPVOID)errbuf);
309 SCLogInfo(
"Found an MTU of %d for '%s'", mtu, pcap_dev);
318 int GetGlobalMTUWin32()
322 DWORD err = NO_ERROR;
323 IP_ADAPTER_ADDRESSES *if_info_list = NULL;
326 err = Win32GetAdaptersAddresses(&if_info_list);
327 if (err != NO_ERROR) {
332 IP_ADAPTER_ADDRESSES *if_info = NULL;
333 for (if_info = if_info_list; if_info != NULL; if_info = if_info->Next) {
335 if (if_info->Mtu == (uint32_t)-1) {
340 mtu = max(mtu, if_info->Mtu);
345 SCLogInfo(
"Found a global MTU of %" PRIu32, mtu);
351 const char *errbuf = NULL;
352 FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
353 FORMAT_MESSAGE_IGNORE_INSERTS,
354 NULL, err, 0, (LPTSTR)&errbuf, 0, NULL);
358 "Failure when trying to get global MTU via syscall: %s (%" PRId32
360 errbuf, (uint32_t)err);
365 #define ReleaseObject(objptr) \
367 if ((objptr) != NULL) { \
368 (objptr)->lpVtbl->Release(objptr); \
373 typedef enum Win32TcpOffloadFlags_ {
374 WIN32_TCP_OFFLOAD_FLAG_NONE = 0,
375 WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4RX = 1,
376 WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4TX = 1 << 1,
377 WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6RX = 1 << 2,
378 WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6TX = 1 << 3,
379 WIN32_TCP_OFFLOAD_FLAG_LSOV1_IP4 = 1 << 4,
380 WIN32_TCP_OFFLOAD_FLAG_LSOV2_IP4 = 1 << 5,
381 WIN32_TCP_OFFLOAD_FLAG_LSOV2_IP6 = 1 << 6,
384 WIN32_TCP_OFFLOAD_FLAG_CSUM = WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4RX |
385 WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4TX |
386 WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6RX |
387 WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6TX,
388 WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4 = WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4RX |
389 WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4TX,
390 WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6 = WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6RX |
391 WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6TX,
392 WIN32_TCP_OFFLOAD_FLAG_LSO = WIN32_TCP_OFFLOAD_FLAG_LSOV1_IP4 |
393 WIN32_TCP_OFFLOAD_FLAG_LSOV2_IP4 |
394 WIN32_TCP_OFFLOAD_FLAG_LSOV2_IP6,
395 } Win32TcpOffloadFlags;
397 typedef struct ComInstance_ {
398 IWbemLocator *locator;
399 IWbemServices *services;
405 static HRESULT ComInstanceInit(ComInstance *instance, LPCWSTR resource)
409 instance->locator = NULL;
410 instance->services = NULL;
412 BSTR resource_bstr = SysAllocString(resource);
413 if (resource_bstr == NULL) {
414 hr = HRESULT_FROM_WIN32(E_OUTOFMEMORY);
420 hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
427 "COM CoInitializeEx failed: 0x%" PRIx32, (uint32_t)hr);
430 hr = CoInitializeSecurity(
431 NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT,
432 RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
435 "COM CoInitializeSecurity failed: 0x%" PRIx32,
442 hr = CoCreateInstance(&CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER,
443 &IID_IWbemLocator, (LPVOID *)&instance->locator);
449 hr = instance->locator->lpVtbl->ConnectServer(
450 instance->locator, resource_bstr, NULL, NULL, NULL, 0, NULL, NULL,
451 &instance->services);
459 SysFreeString(resource_bstr);
467 static void ComInstanceRelease(ComInstance *instance)
469 if (instance == NULL) {
472 ReleaseObject(instance->services);
473 ReleaseObject(instance->locator);
479 static HRESULT GetWbemClass(ComInstance *instance, LPCWSTR name,
480 IWbemClassObject **p_class)
482 HRESULT hr = WBEM_S_NO_ERROR;
483 BSTR name_bstr = NULL;
485 if (instance == NULL || name == NULL || p_class == NULL ||
487 hr = HRESULT_FROM_WIN32(E_INVALIDARG);
488 Win32HResultLogDebug(hr);
493 name_bstr = SysAllocString(name);
494 if (name_bstr == NULL) {
495 hr = HRESULT_FROM_WIN32(E_OUTOFMEMORY);
501 hr = instance->services->lpVtbl->GetObject(instance->services, name_bstr,
502 WBEM_FLAG_RETURN_WBEM_COMPLETE,
503 NULL, p_class, NULL);
512 SysFreeString(name_bstr);
520 static HRESULT GetWbemClassInstance(ComInstance *instance, LPCWSTR name,
521 IWbemClassObject **p_instance)
523 HRESULT hr = WBEM_S_NO_ERROR;
525 IWbemClassObject *
class = NULL;
527 hr = GetWbemClass(instance, name, &
class);
528 if (hr != WBEM_S_NO_ERROR) {
532 hr =
class->lpVtbl->SpawnInstance(
class, 0, p_instance);
533 if (hr != WBEM_S_NO_ERROR) {
544 typedef struct WbemMethod_ {
545 ComInstance *com_instance;
549 IWbemClassObject *in_params, *out_params;
555 static HRESULT GetWbemMethod(ComInstance *com_instance, LPCWSTR class_name,
556 LPCWSTR method_name, WbemMethod *method)
559 IWbemClassObject *
class = NULL;
561 method->com_instance = com_instance;
563 BSTR class_name_bstr = SysAllocString(class_name);
564 if (class_name_bstr == NULL) {
565 hr = HRESULT_FROM_WIN32(E_OUTOFMEMORY);
569 method->method_name = SysAllocString(method_name);
570 if (method->method_name == NULL) {
571 hr = HRESULT_FROM_WIN32(E_OUTOFMEMORY);
577 hr = GetWbemClass(com_instance, class_name, &
class);
578 if (hr != WBEM_S_NO_ERROR) {
583 hr =
class->lpVtbl->GetMethod(
class, method_name, 0, &method->in_params,
584 &method->out_params);
585 if (hr != WBEM_S_NO_ERROR) {
593 ReleaseObject(
class);
595 SysFreeString(class_name_bstr);
603 static void WbemMethodRelease(WbemMethod *method)
605 if (method == NULL) {
608 ReleaseObject(method->in_params);
609 ReleaseObject(method->out_params);
611 SysFreeString(method->method_name);
614 typedef struct WbemMethodCall_ {
619 IWbemClassObject *in_params;
625 static HRESULT GetWbemMethodCall(WbemMethod *method, LPCWSTR instance_path,
626 WbemMethodCall *call)
630 call->method = method;
631 call->instance_path = SysAllocString(instance_path);
632 if (call->instance_path == NULL) {
633 hr = HRESULT_FROM_WIN32(E_OUTOFMEMORY);
640 hr = method->in_params->lpVtbl->SpawnInstance(method->in_params, 0,
645 "WMI SpawnInstance failed on in_params: 0x%" PRIx32,
657 static void WbemMethodCallRelease(WbemMethodCall *call)
662 ReleaseObject(call->in_params);
664 SysFreeString(call->instance_path);
670 static HRESULT WbemMethodCallExec(WbemMethodCall *call,
671 IWbemClassObject **p_out_params)
675 hr = call->method->com_instance->services->lpVtbl->ExecMethod(
676 call->method->com_instance->services, call->instance_path,
677 call->method->method_name, 0, NULL, call->in_params, p_out_params,
679 if (hr != WBEM_S_NO_ERROR) {
681 SCLogDebug(
"WMI ExecMethod failed: 0x%" PRIx32, (uint32_t)hr);
692 static HRESULT WbemGetSubObject(IWbemClassObject *
object, LPCWSTR property_name,
693 IWbemClassObject **sub_object)
698 VariantInit(&out_var);
699 hr =
object->lpVtbl->Get(
object, property_name, 0, &out_var, NULL, NULL);
700 if (hr != WBEM_S_NO_ERROR) {
704 IUnknown *unknown = V_UNKNOWN(&out_var);
705 hr = unknown->lpVtbl->QueryInterface(unknown, &IID_IWbemClassObject,
706 (
void **)sub_object);
709 "WMI QueryInterface (IWbemClassObject) failed: 0x%" PRIx32,
715 VariantClear(&out_var);
722 static HRESULT GetEncapsulation(IWbemClassObject *
object, LPCWSTR category,
723 LPCWSTR subcategory, ULONG *encapsulation)
725 HRESULT hr = WBEM_S_NO_ERROR;
727 IWbemClassObject *category_object = NULL;
728 IWbemClassObject *subcategory_object = NULL;
731 VariantInit(&out_var);
734 hr = WbemGetSubObject(
object, category, &category_object);
735 if (hr != WBEM_S_NO_ERROR) {
740 hr = WbemGetSubObject(category_object, subcategory, &subcategory_object);
741 if (hr != WBEM_S_NO_ERROR) {
744 hr = subcategory_object->lpVtbl->Get(subcategory_object, L
"Encapsulation",
745 0, &out_var, NULL, NULL);
746 if (hr != WBEM_S_NO_ERROR) {
749 *encapsulation = V_UI4(&out_var);
752 VariantClear(&out_var);
753 ReleaseObject(subcategory_object);
754 ReleaseObject(category_object);
758 static HRESULT GetIUnknown(IWbemClassObject *
object, IUnknown **p_unknown)
760 HRESULT hr = WBEM_S_NO_ERROR;
762 if (
object == NULL || p_unknown == NULL || *p_unknown != NULL) {
763 hr = HRESULT_FROM_WIN32(E_INVALIDARG);
764 Win32HResultLogDebug(hr);
768 hr =
object->lpVtbl->QueryInterface(
object, &IID_IUnknown,
772 "WMI QueryInterface (IUnknown) failed: 0x%" PRIx32,
781 static HRESULT BuildNdisObjectHeader(ComInstance *instance, uint8_t
type,
782 uint8_t revision, uint16_t size,
783 IWbemClassObject **p_ndis_object_header)
785 HRESULT hr = WBEM_S_NO_ERROR;
787 if (instance == NULL || p_ndis_object_header == NULL ||
788 *p_ndis_object_header != NULL) {
790 hr = HRESULT_FROM_WIN32(E_INVALIDARG);
791 Win32HResultLogDebug(hr);
796 hr = GetWbemClassInstance(instance, L
"MSNdis_ObjectHeader",
797 p_ndis_object_header);
798 if (hr != WBEM_S_NO_ERROR) {
802 VARIANT param_variant;
803 VariantInit(¶m_variant);
804 IWbemClassObject *ndis_object_header = *p_ndis_object_header;
807 V_VT(¶m_variant) = VT_UI1;
808 V_UI1(¶m_variant) =
type;
809 hr = ndis_object_header->lpVtbl->Put(ndis_object_header, L
"Type", 0,
811 VariantClear(¶m_variant);
812 if (hr != WBEM_S_NO_ERROR) {
817 V_VT(¶m_variant) = VT_UI1;
818 V_UI1(¶m_variant) = revision;
819 hr = ndis_object_header->lpVtbl->Put(ndis_object_header, L
"Revision", 0,
821 VariantClear(¶m_variant);
822 if (hr != WBEM_S_NO_ERROR) {
829 V_VT(¶m_variant) = VT_I4;
830 V_I4(¶m_variant) = size;
831 hr = ndis_object_header->lpVtbl->Put(ndis_object_header, L
"Size", 0,
833 VariantClear(¶m_variant);
834 if (hr != WBEM_S_NO_ERROR) {
843 static HRESULT BuildNdisWmiMethodHeader(ComInstance *instance,
844 uint64_t net_luid, uint32_t port_number,
845 uint64_t request_id, uint32_t timeout,
846 IWbemClassObject **p_ndis_method_header)
848 HRESULT hr = WBEM_S_NO_ERROR;
850 IWbemClassObject *ndis_object_header = NULL;
852 if (instance == NULL || p_ndis_method_header == NULL ||
853 *p_ndis_method_header != NULL) {
855 hr = HRESULT_FROM_WIN32(E_INVALIDARG);
856 Win32HResultLogDebug(hr);
861 hr = GetWbemClassInstance(instance, L
"MSNdis_WmiMethodHeader",
862 p_ndis_method_header);
863 if (hr != WBEM_S_NO_ERROR) {
867 VARIANT param_variant;
868 VariantInit(¶m_variant);
871 hr = BuildNdisObjectHeader(instance, NDIS_WMI_OBJECT_TYPE_METHOD,
872 NDIS_WMI_METHOD_HEADER_REVISION_1, 0xFFFF,
873 &ndis_object_header);
874 if (hr != WBEM_S_NO_ERROR) {
877 V_VT(¶m_variant) = VT_UNKNOWN;
878 V_UNKNOWN(¶m_variant) = NULL;
879 hr = GetIUnknown(ndis_object_header, &V_UNKNOWN(¶m_variant));
880 if (hr != WBEM_S_NO_ERROR) {
884 IWbemClassObject *ndis_method_header = *p_ndis_method_header;
887 hr = ndis_method_header->lpVtbl->Put(ndis_method_header, L
"Header", 0,
889 VariantClear(¶m_variant);
890 if (hr != WBEM_S_NO_ERROR) {
895 V_VT(¶m_variant) = VT_BSTR;
896 V_BSTR(¶m_variant) = utob(net_luid);
897 hr = ndis_method_header->lpVtbl->Put(ndis_method_header, L
"NetLuid", 0,
899 VariantClear(¶m_variant);
900 if (hr != WBEM_S_NO_ERROR) {
905 V_VT(¶m_variant) = VT_BSTR;
906 V_BSTR(¶m_variant) = utob((uint64_t)port_number);
907 hr = ndis_method_header->lpVtbl->Put(ndis_method_header, L
"PortNumber", 0,
909 VariantClear(¶m_variant);
910 if (hr != WBEM_S_NO_ERROR) {
915 V_VT(¶m_variant) = VT_BSTR;
916 V_BSTR(¶m_variant) = utob(request_id);
917 hr = ndis_method_header->lpVtbl->Put(ndis_method_header, L
"RequestId", 0,
919 VariantClear(¶m_variant);
920 if (hr != WBEM_S_NO_ERROR) {
925 V_VT(¶m_variant) = VT_BSTR;
926 V_BSTR(¶m_variant) = utob((uint64_t)timeout);
927 hr = ndis_method_header->lpVtbl->Put(ndis_method_header, L
"Timeout", 0,
929 VariantClear(¶m_variant);
930 if (hr != WBEM_S_NO_ERROR) {
935 V_VT(¶m_variant) = VT_BSTR;
936 V_BSTR(¶m_variant) = utob((uint64_t)0);
937 hr = ndis_method_header->lpVtbl->Put(ndis_method_header, L
"Padding", 0,
939 VariantClear(¶m_variant);
940 if (hr != WBEM_S_NO_ERROR) {
946 ReleaseObject(ndis_object_header);
954 static HRESULT GetNdisOffload(LPCWSTR if_description, uint32_t *offload_flags)
958 ComInstance instance = {};
959 WbemMethod method = {};
960 WbemMethodCall call = {};
962 IWbemClassObject *ndis_method_header = NULL;
963 IWbemClassObject *out_params = NULL;
964 IWbemClassObject *ndis_offload = NULL;
966 if (if_description == NULL) {
968 hr = HRESULT_FROM_WIN32(E_INVALIDARG);
972 LPCWSTR class_name = L
"MSNdis_TcpOffloadCurrentConfig";
973 LPCWSTR instance_name_fmt = L
"%s=\"%s\"";
974 size_t n_chars = wcslen(class_name) + wcslen(if_description) +
975 wcslen(instance_name_fmt);
976 LPWSTR instance_name =
SCMalloc((n_chars + 1) *
sizeof(
wchar_t));
977 if (instance_name == NULL) {
979 "Failed to allocate buffer for instance path");
982 instance_name[n_chars] = 0;
983 hr = StringCchPrintfW(instance_name, n_chars, instance_name_fmt, class_name,
987 "Failed to format WMI class instance name: 0x%" PRIx32,
992 LPCWSTR method_name = L
"WmiQueryCurrentOffloadConfig";
995 hr = ComInstanceInit(&instance, L
"ROOT\\WMI");
1001 hr = GetWbemMethod(&instance, class_name, method_name, &method);
1007 hr = GetWbemMethodCall(&method, instance_name, &call);
1014 VARIANT param_variant;
1015 VariantInit(¶m_variant);
1018 hr = BuildNdisWmiMethodHeader(&instance, 0, 0, 0, 5, &ndis_method_header);
1019 if (hr != WBEM_S_NO_ERROR) {
1022 V_VT(¶m_variant) = VT_UNKNOWN;
1023 V_UNKNOWN(¶m_variant) = NULL;
1024 hr = GetIUnknown(ndis_method_header, &V_UNKNOWN(¶m_variant));
1025 if (hr != WBEM_S_NO_ERROR) {
1030 hr = call.in_params->lpVtbl->Put(call.in_params, L
"Header", 0,
1032 VariantClear(¶m_variant);
1033 if (hr != WBEM_S_NO_ERROR) {
1039 hr = WbemMethodCallExec(&call, &out_params);
1041 size_t if_description_len = wcslen(if_description);
1042 char *if_description_ansi =
SCMalloc(if_description_len + 1);
1043 if (if_description_ansi == NULL) {
1045 "Failed to allocate buffer for interface description");
1048 if_description_ansi[if_description_len] = 0;
1049 wcstombs(if_description_ansi, if_description, if_description_len);
1050 SCLogInfo(
"Obtaining offload state failed, device \"%s\" may not "
1051 "support offload. Error: 0x%" PRIx32,
1052 if_description_ansi, (uint32_t)hr);
1053 SCFree(if_description_ansi);
1054 Win32HResultLogDebug(hr);
1059 hr = WbemGetSubObject(out_params, L
"Offload", &ndis_offload);
1060 if (hr != WBEM_S_NO_ERROR) {
1063 ULONG encapsulation = 0;
1066 hr = GetEncapsulation(ndis_offload, L
"Checksum", L
"IPv4Receive",
1068 if (hr != WBEM_S_NO_ERROR) {
1072 if (encapsulation != 0) {
1073 *offload_flags |= WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4RX;
1075 hr = GetEncapsulation(ndis_offload, L
"Checksum", L
"IPv4Transmit",
1077 if (hr != WBEM_S_NO_ERROR) {
1081 if (encapsulation != 0) {
1082 *offload_flags |= WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4TX;
1084 hr = GetEncapsulation(ndis_offload, L
"Checksum", L
"IPv6Receive",
1086 if (hr != WBEM_S_NO_ERROR) {
1090 if (encapsulation != 0) {
1091 *offload_flags |= WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6RX;
1093 hr = GetEncapsulation(ndis_offload, L
"Checksum", L
"IPv6Transmit",
1095 if (hr != WBEM_S_NO_ERROR) {
1099 if (encapsulation != 0) {
1100 *offload_flags |= WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6TX;
1104 hr = GetEncapsulation(ndis_offload, L
"LsoV1", L
"WmiIPv4", &encapsulation);
1105 if (hr != WBEM_S_NO_ERROR) {
1109 if (encapsulation != 0) {
1110 *offload_flags |= WIN32_TCP_OFFLOAD_FLAG_LSOV1_IP4;
1114 hr = GetEncapsulation(ndis_offload, L
"LsoV2", L
"WmiIPv4", &encapsulation);
1115 if (hr != WBEM_S_NO_ERROR) {
1119 if (encapsulation != 0) {
1120 *offload_flags |= WIN32_TCP_OFFLOAD_FLAG_LSOV2_IP4;
1122 hr = GetEncapsulation(ndis_offload, L
"LsoV2", L
"WmiIPv6", &encapsulation);
1123 if (hr != WBEM_S_NO_ERROR) {
1127 if (encapsulation != 0) {
1128 *offload_flags |= WIN32_TCP_OFFLOAD_FLAG_LSOV2_IP6;
1132 ReleaseObject(ndis_method_header);
1133 ReleaseObject(ndis_offload);
1134 ReleaseObject(out_params);
1136 WbemMethodCallRelease(&call);
1137 WbemMethodRelease(&method);
1138 ComInstanceRelease(&instance);
1143 int GetIfaceOffloadingWin32(
const char *pcap_dev,
int csum,
int other)
1145 SCLogDebug(
"Querying offloading for device %s", pcap_dev);
1147 DWORD err = NO_ERROR;
1149 uint32_t offload_flags = 0;
1152 IP_ADAPTER_ADDRESSES *if_info_list = NULL, *if_info = NULL;
1153 err = Win32GetAdaptersAddresses(&if_info_list);
1154 if (err != NO_ERROR) {
1158 err = Win32FindAdapterAddresses(if_info_list, pcap_dev, &if_info);
1159 if (err != NO_ERROR) {
1163 LPWSTR if_description = if_info->Description;
1166 err = GetNdisOffload(if_description, &offload_flags);
1170 }
else if (offload_flags != 0) {
1172 if ((offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM) != 0) {
1177 if ((offload_flags & WIN32_TCP_OFFLOAD_FLAG_LSO) != 0) {
1184 SCLogPerf(
"NIC offloading on %s: Checksum IPv4 Rx: %d Tx: %d IPv6 "
1185 "Rx: %d Tx: %d LSOv1 IPv4: %d LSOv2 IPv4: %d IPv6: %d",
1187 (offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4RX) != 0,
1188 (offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4TX) != 0,
1189 (offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6RX) != 0,
1190 (offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6TX) != 0,
1191 (offload_flags & WIN32_TCP_OFFLOAD_FLAG_LSOV1_IP4) != 0,
1192 (offload_flags & WIN32_TCP_OFFLOAD_FLAG_LSOV2_IP4) != 0,
1193 (offload_flags & WIN32_TCP_OFFLOAD_FLAG_LSOV2_IP6) != 0);
1196 "NIC offloading on %s: Checksum IPv4 Rx: %d Tx: %d IPv6 "
1197 "Rx: %d Tx: %d LSOv1 IPv4: %d LSOv2 IPv4: %d IPv6: %d",
1199 (offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4RX) != 0,
1200 (offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4TX) != 0,
1201 (offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6RX) != 0,
1202 (offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6TX) != 0,
1203 (offload_flags & WIN32_TCP_OFFLOAD_FLAG_LSOV1_IP4) != 0,
1204 (offload_flags & WIN32_TCP_OFFLOAD_FLAG_LSOV2_IP4) != 0,
1205 (offload_flags & WIN32_TCP_OFFLOAD_FLAG_LSOV2_IP6) != 0);
1210 const char *err_str = Win32GetErrorString(err, WmiUtils());
1212 "Failure when trying to get feature via syscall for '%s': "
1213 "%s (0x%08" PRIx32
")",
1214 pcap_dev, err_str, (uint32_t)err);
1215 LocalFree((LPVOID)err_str);
1224 BuildNdisTcpOffloadParameters(ComInstance *instance, uint32_t offload_flags,
1226 IWbemClassObject **p_ndis_tcp_offload_parameters)
1228 HRESULT hr = WBEM_S_NO_ERROR;
1230 IWbemClassObject *ndis_object_header = NULL;
1232 if (instance == NULL || p_ndis_tcp_offload_parameters == NULL ||
1233 *p_ndis_tcp_offload_parameters != NULL) {
1235 hr = HRESULT_FROM_WIN32(E_INVALIDARG);
1236 Win32HResultLogDebug(hr);
1241 hr = GetWbemClassInstance(instance, L
"MSNdis_TcpOffloadParameters",
1242 p_ndis_tcp_offload_parameters);
1243 if (hr != WBEM_S_NO_ERROR) {
1247 VARIANT param_variant;
1248 VariantInit(¶m_variant);
1251 hr = BuildNdisObjectHeader(instance, NDIS_OBJECT_TYPE_DEFAULT,
1252 NDIS_OFFLOAD_PARAMETERS_REVISION_1,
1253 NDIS_SIZEOF_OFFLOAD_PARAMETERS_REVISION_1,
1254 &ndis_object_header);
1255 if (hr != WBEM_S_NO_ERROR) {
1258 V_VT(¶m_variant) = VT_UNKNOWN;
1259 V_UNKNOWN(¶m_variant) = NULL;
1260 hr = GetIUnknown(ndis_object_header, &V_UNKNOWN(¶m_variant));
1261 if (hr != WBEM_S_NO_ERROR) {
1265 IWbemClassObject *ndis_tcp_offload_parameters =
1266 *p_ndis_tcp_offload_parameters;
1269 hr = ndis_tcp_offload_parameters->lpVtbl->Put(
1270 ndis_tcp_offload_parameters, L
"Header", 0, ¶m_variant, 0);
1271 VariantClear(¶m_variant);
1272 if (hr != WBEM_S_NO_ERROR) {
1273 Win32HResultLogDebug(hr);
1278 V_VT(¶m_variant) = VT_BSTR;
1279 V_BSTR(¶m_variant) = utob(NDIS_OFFLOAD_PARAMETERS_NO_CHANGE);
1280 if (!enable && (offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4) != 0) {
1282 V_BSTR(¶m_variant) = utob(NDIS_OFFLOAD_PARAMETERS_TX_RX_DISABLED);
1283 }
else if ((offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4) ==
1284 WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4) {
1286 V_BSTR(¶m_variant) = utob(NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED);
1287 }
else if ((offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4RX) != 0) {
1289 V_BSTR(¶m_variant) =
1290 utob(NDIS_OFFLOAD_PARAMETERS_RX_ENABLED_TX_DISABLED);
1291 }
else if ((offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4TX) != 0) {
1293 V_BSTR(¶m_variant) =
1294 utob(NDIS_OFFLOAD_PARAMETERS_TX_ENABLED_RX_DISABLED);
1296 hr = ndis_tcp_offload_parameters->lpVtbl->Put(
1297 ndis_tcp_offload_parameters, L
"IPv4Checksum", 0, ¶m_variant, 0);
1298 if (hr != WBEM_S_NO_ERROR) {
1302 hr = ndis_tcp_offload_parameters->lpVtbl->Put(ndis_tcp_offload_parameters,
1303 L
"TCPIPv4Checksum", 0,
1305 if (hr != WBEM_S_NO_ERROR) {
1309 hr = ndis_tcp_offload_parameters->lpVtbl->Put(ndis_tcp_offload_parameters,
1310 L
"UDPIPv4Checksum", 0,
1312 if (hr != WBEM_S_NO_ERROR) {
1316 VariantClear(¶m_variant);
1319 V_VT(¶m_variant) = VT_BSTR;
1320 V_BSTR(¶m_variant) = utob(NDIS_OFFLOAD_PARAMETERS_NO_CHANGE);
1321 if (!enable && (offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6) != 0) {
1323 V_BSTR(¶m_variant) = utob(NDIS_OFFLOAD_PARAMETERS_TX_RX_DISABLED);
1324 }
else if ((offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6) ==
1325 WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6) {
1327 V_BSTR(¶m_variant) = utob(NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED);
1328 }
else if ((offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6RX) != 0) {
1330 V_BSTR(¶m_variant) =
1331 utob(NDIS_OFFLOAD_PARAMETERS_RX_ENABLED_TX_DISABLED);
1332 }
else if ((offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6TX) != 0) {
1334 V_BSTR(¶m_variant) =
1335 utob(NDIS_OFFLOAD_PARAMETERS_TX_ENABLED_RX_DISABLED);
1337 hr = ndis_tcp_offload_parameters->lpVtbl->Put(ndis_tcp_offload_parameters,
1338 L
"TCPIPv6Checksum", 0,
1340 if (hr != WBEM_S_NO_ERROR) {
1344 hr = ndis_tcp_offload_parameters->lpVtbl->Put(ndis_tcp_offload_parameters,
1345 L
"UDPIPv6Checksum", 0,
1347 if (hr != WBEM_S_NO_ERROR) {
1351 VariantClear(¶m_variant);
1354 V_VT(¶m_variant) = VT_BSTR;
1355 V_BSTR(¶m_variant) = utob(NDIS_OFFLOAD_PARAMETERS_NO_CHANGE);
1356 if ((offload_flags & WIN32_TCP_OFFLOAD_FLAG_LSOV1_IP4) != 0) {
1358 V_BSTR(¶m_variant) =
1359 utob(NDIS_OFFLOAD_PARAMETERS_LSOV1_ENABLED);
1361 V_BSTR(¶m_variant) =
1362 utob(NDIS_OFFLOAD_PARAMETERS_LSOV1_DISABLED);
1365 hr = ndis_tcp_offload_parameters->lpVtbl->Put(
1366 ndis_tcp_offload_parameters, L
"LsoV1", 0, ¶m_variant, 0);
1367 if (hr != WBEM_S_NO_ERROR) {
1371 VariantClear(¶m_variant);
1374 V_VT(¶m_variant) = VT_BSTR;
1375 V_BSTR(¶m_variant) = utob(NDIS_OFFLOAD_PARAMETERS_NO_CHANGE);
1376 if ((offload_flags & WIN32_TCP_OFFLOAD_FLAG_LSOV2_IP4) != 0) {
1378 V_BSTR(¶m_variant) =
1379 utob(NDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED);
1381 V_BSTR(¶m_variant) =
1382 utob(NDIS_OFFLOAD_PARAMETERS_LSOV2_DISABLED);
1385 hr = ndis_tcp_offload_parameters->lpVtbl->Put(
1386 ndis_tcp_offload_parameters, L
"LsoV2IPv4", 0, ¶m_variant, 0);
1387 if (hr != WBEM_S_NO_ERROR) {
1391 VariantClear(¶m_variant);
1394 V_VT(¶m_variant) = VT_BSTR;
1395 V_BSTR(¶m_variant) = utob(NDIS_OFFLOAD_PARAMETERS_NO_CHANGE);
1396 if ((offload_flags & WIN32_TCP_OFFLOAD_FLAG_LSOV2_IP6) != 0) {
1398 V_BSTR(¶m_variant) =
1399 utob(NDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED);
1401 V_BSTR(¶m_variant) =
1402 utob(NDIS_OFFLOAD_PARAMETERS_LSOV2_DISABLED);
1405 hr = ndis_tcp_offload_parameters->lpVtbl->Put(
1406 ndis_tcp_offload_parameters, L
"LsoV2IPv6", 0, ¶m_variant, 0);
1407 if (hr != WBEM_S_NO_ERROR) {
1411 VariantClear(¶m_variant);
1414 V_VT(¶m_variant) = VT_BSTR;
1415 V_BSTR(¶m_variant) = utob(NDIS_OFFLOAD_PARAMETERS_NO_CHANGE);
1416 hr = ndis_tcp_offload_parameters->lpVtbl->Put(
1417 ndis_tcp_offload_parameters, L
"IPSec", 0, ¶m_variant, 0);
1418 if (hr != WBEM_S_NO_ERROR) {
1422 hr = ndis_tcp_offload_parameters->lpVtbl->Put(ndis_tcp_offload_parameters,
1423 L
"TcpConnectionIPv4", 0,
1425 if (hr != WBEM_S_NO_ERROR) {
1429 hr = ndis_tcp_offload_parameters->lpVtbl->Put(ndis_tcp_offload_parameters,
1430 L
"TcpConnectionIPv6", 0,
1432 if (hr != WBEM_S_NO_ERROR) {
1436 hr = ndis_tcp_offload_parameters->lpVtbl->Put(
1437 ndis_tcp_offload_parameters, L
"Flags", 0, ¶m_variant, 0);
1438 if (hr != WBEM_S_NO_ERROR) {
1445 VariantClear(¶m_variant);
1450 static HRESULT SetNdisOffload(LPCWSTR if_description, uint32_t offload_flags,
1455 ComInstance instance = {};
1456 WbemMethod method = {};
1457 WbemMethodCall call = {};
1460 IWbemClassObject *ndis_method_header = NULL;
1462 IWbemClassObject *ndis_tcp_offload_parameters = NULL;
1464 if (if_description == NULL) {
1466 return E_INVALIDARG;
1469 LPCWSTR class_name = L
"MSNdis_SetTcpOffloadParameters";
1470 LPCWSTR instance_name_fmt = L
"%s=\"%s\"";
1471 size_t n_chars = wcslen(class_name) + wcslen(if_description) +
1472 wcslen(instance_name_fmt);
1473 LPWSTR instance_name =
SCMalloc((n_chars + 1) *
sizeof(
wchar_t));
1474 if (instance_name == NULL) {
1476 "Failed to allocate buffer for instance path");
1479 instance_name[n_chars] = 0;
1480 hr = StringCchPrintfW(instance_name, n_chars, instance_name_fmt, class_name,
1484 "Failed to format WMI class instance name: 0x%" PRIx32,
1490 LPCWSTR method_name = L
"WmiSetTcpOffloadParameters";
1493 hr = ComInstanceInit(&instance, L
"ROOT\\WMI");
1499 hr = GetWbemMethod(&instance, class_name, method_name, &method);
1505 hr = GetWbemMethodCall(&method, instance_name, &call);
1512 VARIANT param_variant;
1513 VariantInit(¶m_variant);
1516 hr = BuildNdisWmiMethodHeader(&instance, 0, 0, 0, 5, &ndis_method_header);
1517 if (hr != WBEM_S_NO_ERROR) {
1521 V_VT(¶m_variant) = VT_UNKNOWN;
1522 V_UNKNOWN(¶m_variant) = NULL;
1523 hr = GetIUnknown(ndis_method_header, &V_UNKNOWN(¶m_variant));
1524 if (hr != WBEM_S_NO_ERROR) {
1527 hr = call.in_params->lpVtbl->Put(call.in_params, L
"MethodHeader", 0,
1529 VariantClear(¶m_variant);
1530 if (hr != WBEM_S_NO_ERROR) {
1531 Win32HResultLogDebug(hr);
1536 hr = BuildNdisTcpOffloadParameters(&instance, offload_flags, enable,
1537 &ndis_tcp_offload_parameters);
1538 if (hr != WBEM_S_NO_ERROR) {
1542 V_VT(¶m_variant) = VT_UNKNOWN;
1543 V_UNKNOWN(¶m_variant) = NULL;
1544 hr = GetIUnknown(ndis_tcp_offload_parameters, &V_UNKNOWN(¶m_variant));
1545 if (hr != WBEM_S_NO_ERROR) {
1548 hr = call.in_params->lpVtbl->Put(call.in_params, L
"TcpOffloadParameters", 0,
1550 VariantClear(¶m_variant);
1551 if (hr != WBEM_S_NO_ERROR) {
1552 Win32HResultLogDebug(hr);
1557 hr = WbemMethodCallExec(&call, NULL);
1559 Win32HResultLogDebug(hr);
1564 ReleaseObject(ndis_tcp_offload_parameters);
1565 ReleaseObject(ndis_method_header);
1567 WbemMethodCallRelease(&call);
1568 WbemMethodRelease(&method);
1569 ComInstanceRelease(&instance);
1574 int DisableIfaceOffloadingWin32(
LiveDevice *ldev,
int csum,
int other)
1576 SCLogDebug(
"Disabling offloading for device %s", ldev->
dev);
1579 DWORD err = NO_ERROR;
1580 uint32_t offload_flags = 0;
1587 IP_ADAPTER_ADDRESSES *if_info_list = NULL, *if_info = NULL;
1588 err = Win32GetAdaptersAddresses(&if_info_list);
1589 if (err != NO_ERROR) {
1593 err = Win32FindAdapterAddresses(if_info_list, ldev->
dev, &if_info);
1594 if (err != NO_ERROR) {
1598 LPWSTR if_description = if_info->Description;
1600 err = GetNdisOffload(if_description, &offload_flags);
1607 offload_flags &= ~WIN32_TCP_OFFLOAD_FLAG_CSUM;
1610 offload_flags &= ~WIN32_TCP_OFFLOAD_FLAG_LSO;
1613 err = SetNdisOffload(if_description, offload_flags, 0);
1625 int RestoreIfaceOffloadingWin32(
LiveDevice *ldev)
1630 DWORD err = NO_ERROR;
1637 IP_ADAPTER_ADDRESSES *if_info_list = NULL, *if_info = NULL;
1638 err = Win32GetAdaptersAddresses(&if_info_list);
1639 if (err != NO_ERROR) {
1643 err = Win32FindAdapterAddresses(if_info_list, ldev->
dev, &if_info);
1644 if (err != NO_ERROR) {
1648 LPWSTR if_description = if_info->Description;
1650 err = SetNdisOffload(if_description, ldev->
offload_orig, 1);
1665 static int Win32TestStripPcapPrefix(
void)
1669 const char *name1 =
"\\Device\\NPF_{D4A32435-1BA7-4008-93A6-1518AA4BBD9B}";
1670 const char *expect_name1 =
"{D4A32435-1BA7-4008-93A6-1518AA4BBD9B}";
1672 const char *name2 =
"{D4A32435-1BA7-4008-93A6-1518AA4BBD9B}";
1673 const char *expect_name2 =
"{D4A32435-1BA7-4008-93A6-1518AA4BBD9B}";
1675 result &= (strncmp(expect_name1, StripPcapPrefix(name1),
1676 strlen(expect_name1)) == 0);
1678 result &= (strncmp(expect_name2, StripPcapPrefix(name2),
1679 strlen(expect_name2)) == 0);
1685 void Win32SyscallRegisterTests()
1688 UtRegisterTest(
"Win32TestStripPcapPrefix", Win32TestStripPcapPrefix);