From c9f63f57b96254315984d604af0a0216c6bf5026 Mon Sep 17 00:00:00 2001 From: Thomas Faber Date: Sat, 3 May 2014 12:53:58 +0000 Subject: [PATCH] [NETAPI32] - Import recent fixes and new stubs from Wine - Note that Wine is using Samba's libnetapi to implement many functions these days (not included here), so it may be worth having a look at porting that work to ROS. CORE-8160 #resolve svn path=/trunk/; revision=63128 --- reactos/dll/win32/netapi32/nbcmdqueue.h | 12 +-- reactos/dll/win32/netapi32/nbnamecache.h | 8 +- reactos/dll/win32/netapi32/nbt.c | 36 ++++---- reactos/dll/win32/netapi32/netapi32.c | 109 +++++++++++------------ reactos/dll/win32/netapi32/netapi32.h | 1 + reactos/dll/win32/netapi32/netapi32.spec | 10 +-- reactos/dll/win32/netapi32/netbios.c | 47 +++++++++- reactos/dll/win32/netapi32/netbios.h | 20 ++--- reactos/dll/win32/netapi32/wksta.c | 28 ++---- 9 files changed, 151 insertions(+), 120 deletions(-) diff --git a/reactos/dll/win32/netapi32/nbcmdqueue.h b/reactos/dll/win32/netapi32/nbcmdqueue.h index 8bd45b1e0be..debe7832daa 100644 --- a/reactos/dll/win32/netapi32/nbcmdqueue.h +++ b/reactos/dll/win32/netapi32/nbcmdqueue.h @@ -25,12 +25,12 @@ struct NBCmdQueue; /* Allocates a new command queue from heap. */ -struct NBCmdQueue *NBCmdQueueCreate(HANDLE heap); +struct NBCmdQueue *NBCmdQueueCreate(HANDLE heap) DECLSPEC_HIDDEN; /* Adds ncb to queue. Assumes queue is not NULL, and ncb is not already in the * queue. If ncb is already in the queue, returns NRC_TOOMANY. */ -UCHAR NBCmdQueueAdd(struct NBCmdQueue *queue, PNCB ncb); +UCHAR NBCmdQueueAdd(struct NBCmdQueue *queue, PNCB ncb) DECLSPEC_HIDDEN; /* Cancels the given ncb. Blocks until the command completes. Implicitly * removes ncb from the queue. Assumes queue and ncb are not NULL, and that @@ -39,23 +39,23 @@ UCHAR NBCmdQueueAdd(struct NBCmdQueue *queue, PNCB ncb); * completed before it could be cancelled, and various other return values for * different failures. */ -UCHAR NBCmdQueueCancel(struct NBCmdQueue *queue, PNCB ncb); +UCHAR NBCmdQueueCancel(struct NBCmdQueue *queue, PNCB ncb) DECLSPEC_HIDDEN; /* Sets the return code of the given ncb, and implicitly removes the command * from the queue. Assumes queue and ncb are not NULL, and that ncb has been * added to queue previously. * Returns NRC_GOODRET on success. */ -UCHAR NBCmdQueueComplete(struct NBCmdQueue *queue, PNCB ncb, UCHAR retcode); +UCHAR NBCmdQueueComplete(struct NBCmdQueue *queue, PNCB ncb, UCHAR retcode) DECLSPEC_HIDDEN; /* Cancels all pending commands in the queue (useful for a RESET or a shutdown). * Returns when all commands have been completed. */ -UCHAR NBCmdQueueCancelAll(struct NBCmdQueue *queue); +UCHAR NBCmdQueueCancelAll(struct NBCmdQueue *queue) DECLSPEC_HIDDEN; /* Frees all memory associated with the queue. Blocks until all commands * pending in the queue have been completed. */ -void NBCmdQueueDestroy(struct NBCmdQueue *queue); +void NBCmdQueueDestroy(struct NBCmdQueue *queue) DECLSPEC_HIDDEN; #endif /* __NBCMDQUEUE_H__ */ diff --git a/reactos/dll/win32/netapi32/nbnamecache.h b/reactos/dll/win32/netapi32/nbnamecache.h index bfdbb33abbe..3a36953f770 100644 --- a/reactos/dll/win32/netapi32/nbnamecache.h +++ b/reactos/dll/win32/netapi32/nbnamecache.h @@ -45,7 +45,7 @@ typedef struct _NBNameCacheEntry /* Allocates a new name cache from heap, and sets the expire time on new * entries to entryExpireTimeMS after a cache entry is added. */ -struct NBNameCache *NBNameCacheCreate(HANDLE heap, DWORD entryExpireTimeMS); +struct NBNameCache *NBNameCacheCreate(HANDLE heap, DWORD entryExpireTimeMS) DECLSPEC_HIDDEN; /* Adds an entry to the cache. The entry is assumed to have been allocated * from the same heap as the name cache; the name cache will own the entry @@ -54,14 +54,14 @@ struct NBNameCache *NBNameCacheCreate(HANDLE heap, DWORD entryExpireTimeMS); * same name was in the cache, the entry is replaced. Returns TRUE on success * or FALSE on failure. */ -BOOL NBNameCacheAddEntry(struct NBNameCache *cache, NBNameCacheEntry *entry); +BOOL NBNameCacheAddEntry(struct NBNameCache *cache, NBNameCacheEntry *entry) DECLSPEC_HIDDEN; /* Finds the entry with name name in the cache and returns a pointer to it, or * NULL if it isn't found. */ const NBNameCacheEntry *NBNameCacheFindEntry(struct NBNameCache *cache, - const UCHAR name[NCBNAMSZ]); + const UCHAR name[NCBNAMSZ]) DECLSPEC_HIDDEN; -void NBNameCacheDestroy(struct NBNameCache *cache); +void NBNameCacheDestroy(struct NBNameCache *cache) DECLSPEC_HIDDEN; #endif /* ndef __WINE_NBNAMECACHE_H */ diff --git a/reactos/dll/win32/netapi32/nbt.c b/reactos/dll/win32/netapi32/nbt.c index d0ae2853b49..ba68e7206da 100644 --- a/reactos/dll/win32/netapi32/nbt.c +++ b/reactos/dll/win32/netapi32/nbt.c @@ -289,7 +289,7 @@ static UCHAR NetBTWaitForNameResponse(const NetBTAdapter *adapter, SOCKET fd, if (fd == INVALID_SOCKET) return NRC_BADDR; if (!answerCallback) return NRC_BADDR; - while (!found && ret == NRC_GOODRET && (now = GetTickCount()) < waitUntil) + while (!found && ret == NRC_GOODRET && (int)((now = GetTickCount()) - waitUntil) < 0) { DWORD msToWait = waitUntil - now; struct fd_set fds; @@ -399,9 +399,8 @@ static BOOL NetBTFindNameAnswerCallback(void *pVoid, WORD answerCount, { if (queryData->cacheEntry == NULL) { - queryData->cacheEntry = HeapAlloc( - GetProcessHeap(), 0, sizeof(NBNameCacheEntry) + - (answerCount - 1) * sizeof(DWORD)); + queryData->cacheEntry = HeapAlloc(GetProcessHeap(), 0, + FIELD_OFFSET(NBNameCacheEntry, addresses[answerCount])); if (queryData->cacheEntry) queryData->cacheEntry->numAddresses = 0; else @@ -533,8 +532,8 @@ static UCHAR NetBTinetResolve(const UCHAR name[NCBNAMSZ], if (addr != INADDR_NONE) { - *cacheEntry = HeapAlloc(GetProcessHeap(), - 0, sizeof(NBNameCacheEntry)); + *cacheEntry = HeapAlloc(GetProcessHeap(), 0, + FIELD_OFFSET(NBNameCacheEntry, addresses[1])); if (*cacheEntry) { memcpy((*cacheEntry)->name, name, NCBNAMSZ); @@ -558,9 +557,8 @@ static UCHAR NetBTinetResolve(const UCHAR name[NCBNAMSZ], ; if (host->h_addr_list && host->h_addr_list[0]) { - *cacheEntry = HeapAlloc( - GetProcessHeap(), 0, sizeof(NBNameCacheEntry) + - (i - 1) * sizeof(DWORD)); + *cacheEntry = HeapAlloc(GetProcessHeap(), 0, + FIELD_OFFSET(NBNameCacheEntry, addresses[i])); if (*cacheEntry) { memcpy((*cacheEntry)->name, name, NCBNAMSZ); @@ -569,7 +567,7 @@ static UCHAR NetBTinetResolve(const UCHAR name[NCBNAMSZ], (*cacheEntry)->numAddresses = i; for (i = 0; i < (*cacheEntry)->numAddresses; i++) (*cacheEntry)->addresses[i] = - (DWORD)host->h_addr_list[i]; + *(DWORD*)host->h_addr_list[i]; } else ret = NRC_OSRESNOTAV; @@ -995,7 +993,7 @@ static UCHAR NetBTCall(void *adapt, PNCB ncb, void **sess) setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)); } - if (ncb->ncb_rto > 0) + if (ncb->ncb_sto > 0) { timeout = ncb->ncb_sto * 500; setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, @@ -1489,13 +1487,17 @@ void NetBTInit(void) NetBTNameEncode */ char *ptr, *lenPtr; - for (ptr = gScopeID + 1; ptr - gScopeID < sizeof(gScopeID) && *ptr; ) + for (ptr = gScopeID + 1, lenPtr = gScopeID; ptr - gScopeID < sizeof(gScopeID) && *ptr; ++ptr) { - for (lenPtr = ptr - 1, *lenPtr = 0; - ptr - gScopeID < sizeof(gScopeID) && *ptr && *ptr != '.'; - ptr++) - *lenPtr += 1; - ptr++; + if (*ptr == '.') + { + lenPtr = ptr; + *lenPtr = 0; + } + else + { + ++*lenPtr; + } } } if (RegQueryValueExW(hKey, CacheTimeoutW, NULL, NULL, diff --git a/reactos/dll/win32/netapi32/netapi32.c b/reactos/dll/win32/netapi32/netapi32.c index d81953d4a97..5c0b947803c 100644 --- a/reactos/dll/win32/netapi32/netapi32.c +++ b/reactos/dll/win32/netapi32/netapi32.c @@ -20,9 +20,7 @@ #include -WINE_DEFAULT_DEBUG_CHANNEL(netbios); - -static HMODULE NETAPI32_hModule; +WINE_DEFAULT_DEBUG_CHANNEL(netapi32); BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { @@ -30,18 +28,14 @@ BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) switch (fdwReason) { case DLL_PROCESS_ATTACH: - { DisableThreadLibraryCalls(hinstDLL); - NETAPI32_hModule = hinstDLL; NetBIOSInit(); NetBTInit(); break; - } case DLL_PROCESS_DETACH: - { + if (lpvReserved) break; NetBIOSShutdown(); break; - } } return TRUE; @@ -83,10 +77,28 @@ NET_API_STATUS WINAPI NetServerEnumEx( LMCSTR domain, LMCSTR FirstNameToReturn) { - FIXME("Stub (%s %d %p %d %p %p %d %s %p)\n", debugstr_w(ServerName), - Level, Bufptr, PrefMaxlen, EntriesRead, totalentries, servertype, - debugstr_w(domain), debugstr_w(FirstNameToReturn)); - + FIXME("Stub (%s %d %p %d %p %p %d %s %s)\n", + debugstr_w(ServerName), Level, Bufptr, PrefMaxlen, EntriesRead, totalentries, + servertype, debugstr_w(domain), debugstr_w(FirstNameToReturn)); + + return ERROR_NO_BROWSER_SERVERS_FOUND; +} + +/************************************************************ + * NetServerDiskEnum (NETAPI32.@) + */ +NET_API_STATUS WINAPI NetServerDiskEnum( + LMSTR ServerName, + DWORD Level, + LPBYTE *Bufptr, + DWORD PrefMaxlen, + LPDWORD EntriesRead, + LPDWORD totalentries, + LPDWORD Resume_Handle) +{ + FIXME("Stub (%s %d %p %d %p %p %p)\n", debugstr_w(ServerName), + Level, Bufptr, PrefMaxlen, EntriesRead, totalentries, Resume_Handle); + return ERROR_NO_BROWSER_SERVERS_FOUND; } @@ -162,51 +174,6 @@ NET_API_STATUS WINAPI NetStatisticsGet(LMSTR server, LMSTR service, return NERR_InternalError; } -DWORD WINAPI NetpNetBiosStatusToApiStatus(DWORD nrc) -{ - DWORD ret; - - switch (nrc) - { - case NRC_GOODRET: - ret = NO_ERROR; - break; - case NRC_NORES: - ret = NERR_NoNetworkResource; - break; - case NRC_DUPNAME: - ret = NERR_AlreadyExists; - break; - case NRC_NAMTFUL: - ret = NERR_TooManyNames; - break; - case NRC_ACTSES: - ret = NERR_DeleteLater; - break; - case NRC_REMTFUL: - ret = ERROR_REM_NOT_LIST; - break; - case NRC_NOCALL: - ret = NERR_NameNotFound; - break; - case NRC_NOWILD: - ret = ERROR_INVALID_PARAMETER; - break; - case NRC_INUSE: - ret = NERR_DuplicateName; - break; - case NRC_NAMERR: - ret = ERROR_INVALID_PARAMETER; - break; - case NRC_NAMCONF: - ret = NERR_DuplicateName; - break; - default: - ret = NERR_NetworkError; - } - return ret; -} - NET_API_STATUS WINAPI NetpNtStatusToApiStatus(NTSTATUS Status) @@ -242,3 +209,31 @@ NET_API_STATUS WINAPI NetUseEnum(LMSTR server, DWORD level, LPBYTE* bufptr, DWOR entriesread, totalentries, resumehandle); return ERROR_NOT_SUPPORTED; } + +NET_API_STATUS WINAPI NetScheduleJobAdd(LPCWSTR server, LPBYTE bufptr, LPDWORD jobid) +{ + FIXME("stub (%s, %p, %p)\n", debugstr_w(server), bufptr, jobid); + return NERR_Success; +} + +NET_API_STATUS WINAPI NetScheduleJobDel(LPCWSTR server, DWORD minjobid, DWORD maxjobid) +{ + FIXME("stub (%s, %d, %d)\n", debugstr_w(server), minjobid, maxjobid); + return NERR_Success; +} + +NET_API_STATUS WINAPI NetScheduleJobEnum(LPCWSTR server, LPBYTE* bufptr, DWORD prefmaxsize, LPDWORD entriesread, + LPDWORD totalentries, LPDWORD resumehandle) +{ + FIXME("stub (%s, %p, %d, %p, %p, %p)\n", debugstr_w(server), bufptr, prefmaxsize, entriesread, totalentries, resumehandle); + *entriesread = 0; + *totalentries = 0; + return NERR_Success; +} + +NET_API_STATUS WINAPI NetUseGetInfo(LMSTR server, LMSTR name, DWORD level, LPBYTE *bufptr) +{ + FIXME("stub (%p, %p, %d, %p)\n", server, name, level, bufptr); + return ERROR_NOT_SUPPORTED; + +} diff --git a/reactos/dll/win32/netapi32/netapi32.h b/reactos/dll/win32/netapi32/netapi32.h index c33f9336eb0..722e333e911 100644 --- a/reactos/dll/win32/netapi32/netapi32.h +++ b/reactos/dll/win32/netapi32/netapi32.h @@ -19,6 +19,7 @@ #include #include +#include #define NTOS_MODE_USER #include diff --git a/reactos/dll/win32/netapi32/netapi32.spec b/reactos/dll/win32/netapi32/netapi32.spec index 66f9a5d0e16..f9556c5b48b 100644 --- a/reactos/dll/win32/netapi32/netapi32.spec +++ b/reactos/dll/win32/netapi32/netapi32.spec @@ -201,13 +201,13 @@ @ stub NetReplImportDirLock @ stub NetReplImportDirUnlock @ stub NetReplSetInfo -@ stub NetScheduleJobAdd -@ stub NetScheduleJobDel -@ stub NetScheduleJobEnum +@ stdcall NetScheduleJobAdd(wstr ptr ptr) +@ stdcall NetScheduleJobDel(wstr long long) +@ stdcall NetScheduleJobEnum(wstr ptr long ptr ptr ptr) @ stub NetScheduleJobGetInfo @ stub NetServerComputerNameAdd @ stub NetServerComputerNameDel -@ stub NetServerDiskEnum +@ stdcall NetServerDiskEnum(wstr long ptr long ptr ptr ptr) @ stdcall NetServerEnum(wstr long ptr long ptr ptr long wstr ptr) @ stdcall NetServerEnumEx(wstr long ptr long ptr ptr long wstr wstr) @ stdcall NetServerGetInfo(wstr long ptr) @@ -238,7 +238,7 @@ @ stdcall NetUseAdd(wstr long ptr ptr) @ stub NetUseDel @ stdcall NetUseEnum(wstr long ptr long ptr ptr ptr) -@ stub NetUseGetInfo +@ stdcall NetUseGetInfo(ptr ptr long ptr) @ stdcall NetUserAdd(wstr long ptr ptr) @ stdcall NetUserChangePassword(wstr wstr wstr wstr) @ stdcall NetUserDel(wstr wstr) diff --git a/reactos/dll/win32/netapi32/netbios.c b/reactos/dll/win32/netapi32/netbios.c index 8cb1e63c1ea..5bfe4476061 100644 --- a/reactos/dll/win32/netapi32/netbios.c +++ b/reactos/dll/win32/netapi32/netbios.c @@ -49,7 +49,7 @@ typedef struct _NetBIOSSession * is not NULL, the adapter is considered valid. (transport is a pointer to * an entry in a NetBIOSTransportTableEntry.) data has data for the callers of * NetBIOSEnumAdapters to be able to see. The lana is repeated there, even - * though I don't use it internally--it's for transports to use reenabling + * though I don't use it internally--it's for transports to use re-enabling * adapters using NetBIOSEnableAdapter. */ typedef struct _NetBIOSAdapter @@ -858,3 +858,48 @@ UCHAR WINAPI Netbios(PNCB ncb) TRACE("returning 0x%02x\n", ret); return ret; } + +DWORD WINAPI NetpNetBiosStatusToApiStatus(DWORD nrc) +{ + DWORD ret; + + switch (nrc) + { + case NRC_GOODRET: + ret = NO_ERROR; + break; + case NRC_NORES: + ret = NERR_NoNetworkResource; + break; + case NRC_DUPNAME: + ret = NERR_AlreadyExists; + break; + case NRC_NAMTFUL: + ret = NERR_TooManyNames; + break; + case NRC_ACTSES: + ret = NERR_DeleteLater; + break; + case NRC_REMTFUL: + ret = ERROR_REM_NOT_LIST; + break; + case NRC_NOCALL: + ret = NERR_NameNotFound; + break; + case NRC_NOWILD: + ret = ERROR_INVALID_PARAMETER; + break; + case NRC_INUSE: + ret = NERR_DuplicateName; + break; + case NRC_NAMERR: + ret = ERROR_INVALID_PARAMETER; + break; + case NRC_NAMCONF: + ret = NERR_DuplicateName; + break; + default: + ret = NERR_NetworkError; + } + return ret; +} diff --git a/reactos/dll/win32/netapi32/netbios.h b/reactos/dll/win32/netapi32/netbios.h index b211af28b10..76499848ad7 100644 --- a/reactos/dll/win32/netapi32/netbios.h +++ b/reactos/dll/win32/netapi32/netbios.h @@ -26,8 +26,8 @@ * Public functions */ -void NetBIOSInit(void); -void NetBIOSShutdown(void); +void NetBIOSInit(void) DECLSPEC_HIDDEN; +void NetBIOSShutdown(void) DECLSPEC_HIDDEN; struct _NetBIOSTransport; @@ -35,7 +35,7 @@ struct _NetBIOSTransport; * a unique id (the transport_id of ACTION_HEADER, for example) and an * implementation. Returns TRUE on success, and FALSE on failure. */ -BOOL NetBIOSRegisterTransport(ULONG id, struct _NetBIOSTransport *transport); +BOOL NetBIOSRegisterTransport(ULONG id, struct _NetBIOSTransport *transport) DECLSPEC_HIDDEN; /* Registers an adapter with the given transport and ifIndex with NetBIOS. * ifIndex is an interface index usable by the IpHlpApi. ifIndex is not @@ -45,21 +45,21 @@ BOOL NetBIOSRegisterTransport(ULONG id, struct _NetBIOSTransport *transport); * FIXME: need functions for retrieving the name and hardware index, rather * than assuming a correlation with IpHlpApi. */ -BOOL NetBIOSRegisterAdapter(ULONG transport, DWORD ifIndex, void *adapter); +BOOL NetBIOSRegisterAdapter(ULONG transport, DWORD ifIndex, void *adapter) DECLSPEC_HIDDEN; /* During enumeration, all adapters from your transport are disabled - * internally. If an adapter is still valid, reenable it with this function. + * internally. If an adapter is still valid, re-enable it with this function. * Adapters you don't enable will have their transport's NetBIOSCleanupAdapter * function (see below) called on them, and will be removed from the table. * (This is to deal with lack of plug-and-play--sorry.) */ -void NetBIOSEnableAdapter(UCHAR lana); +void NetBIOSEnableAdapter(UCHAR lana) DECLSPEC_HIDDEN; /* Gets a quick count of the number of NetBIOS adapters. Not guaranteed not * to change from one call to the next, depending on what's been enumerated * lately. See also NetBIOSEnumAdapters. */ -UCHAR NetBIOSNumAdapters(void); +UCHAR NetBIOSNumAdapters(void) DECLSPEC_HIDDEN; typedef struct _NetBIOSAdapterImpl { UCHAR lana; @@ -78,7 +78,7 @@ typedef BOOL (*NetBIOSEnumAdaptersCallback)(UCHAR totalLANAs, UCHAR lanaIndex, * Your callback should return FALSE if it no longer wishes to be called. */ void NetBIOSEnumAdapters(ULONG transport, NetBIOSEnumAdaptersCallback cb, - void *closure); + void *closure) DECLSPEC_HIDDEN; /* Hangs up the session identified in the NCB; the NCB need not be a NCBHANGUP. * Will result in the transport's hangup function being called, so release any @@ -86,7 +86,7 @@ void NetBIOSEnumAdapters(ULONG transport, NetBIOSEnumAdaptersCallback cb, * This function is intended for use by a transport, if the session is closed * by some error in the transport layer. */ -void NetBIOSHangupSession(const NCB *ncb); +void NetBIOSHangupSession(const NCB *ncb) DECLSPEC_HIDDEN; /** * Functions a transport implementation must implement @@ -172,6 +172,6 @@ typedef struct _NetBIOSTransport /* Not defined by MS, so make my own private define: */ #define TRANSPORT_NBT "MNBT" -void NetBTInit(void); +void NetBTInit(void) DECLSPEC_HIDDEN; #endif /* ndef __WINE_NETBIOS_H__ */ diff --git a/reactos/dll/win32/netapi32/wksta.c b/reactos/dll/win32/netapi32/wksta.c index 4cef46cd02e..4e5d8d6e128 100644 --- a/reactos/dll/win32/netapi32/wksta.c +++ b/reactos/dll/win32/netapi32/wksta.c @@ -30,29 +30,17 @@ WINE_DEFAULT_DEBUG_CHANNEL(netapi32); * * Checks whether the server name indicates local machine. */ -BOOL NETAPI_IsLocalComputer(LMCSTR ServerName) +DECLSPEC_HIDDEN BOOL NETAPI_IsLocalComputer( LMCSTR name ) { - if (!ServerName) - { - return TRUE; - } - else if (ServerName[0] == '\0') - return TRUE; - else - { - DWORD dwSize = MAX_COMPUTERNAME_LENGTH + 1; - BOOL Result; - LPWSTR buf; + WCHAR buf[MAX_COMPUTERNAME_LENGTH + 1]; + DWORD size = sizeof(buf) / sizeof(buf[0]); + BOOL ret; - NetApiBufferAllocate(dwSize * sizeof(WCHAR), (LPVOID *) &buf); - Result = GetComputerNameW(buf, &dwSize); - if (Result && (ServerName[0] == '\\') && (ServerName[1] == '\\')) - ServerName += 2; - Result = Result && !lstrcmpW(ServerName, buf); - NetApiBufferFree(buf); + if (!name || !name[0]) return TRUE; - return Result; - } + ret = GetComputerNameW( buf, &size ); + if (ret && name[0] == '\\' && name[1] == '\\') name += 2; + return ret && !strcmpiW( name, buf ); } static void wprint_mac(WCHAR* buffer, int len, const MIB_IFROW *ifRow)