Use iphlpapi to enumerate LAN adapters.

Add names to NetBIOS transports, and eliminates loopback adapters from
enumerated LAN adapters.
oldstable
Juan Lang 2003-06-16 01:23:20 +00:00 committed by Alexandre Julliard
parent 9d5295f5bd
commit c5e856a300
4 changed files with 172 additions and 201 deletions

View File

@ -4,7 +4,7 @@ TOPOBJDIR = ../..
SRCDIR = @srcdir@
VPATH = @srcdir@
MODULE = netapi32.dll
IMPORTS = advapi32 kernel32
IMPORTS = iphlpapi advapi32 kernel32
LDDLLFLAGS = @LDDLLFLAGS@
SYMBOLFILE = $(MODULE).tmp.o

View File

@ -20,6 +20,7 @@
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
@ -33,183 +34,73 @@
#include "winerror.h"
#include "nb30.h"
#include "lmcons.h"
#ifdef HAVE_SYS_FILE_H
# include <sys/file.h>
#endif
#ifdef HAVE_SYS_IOCTL_H
# include <sys/ioctl.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h>
#endif
#ifdef HAVE_SYS_SOCKIO_H
# include <sys/sockio.h>
#endif
#ifdef HAVE_NET_IF_H
# include <net/if.h>
#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
# ifndef max
# define max(a,b) ((a) > (b) ? (a) : (b))
# endif
# define ifreq_size(i) max(sizeof(struct ifreq),\
sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
# else
# define ifreq_size(i) sizeof(struct ifreq)
# endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
#include "iphlpapi.h"
WINE_DEFAULT_DEBUG_CHANNEL(netbios);
HMODULE NETAPI32_hModule = 0;
struct NetBiosAdapter
{
int valid;
unsigned char address[6];
};
static struct NetBiosAdapter NETBIOS_Adapter[MAX_LANA];
# ifdef SIOCGIFHWADDR
int get_hw_address(int sd, struct ifreq *ifr, unsigned char *address)
{
if (ioctl(sd, SIOCGIFHWADDR, ifr) < 0)
return -1;
memcpy(address, (unsigned char *)&ifr->ifr_hwaddr.sa_data, 6);
return 0;
}
# else
# ifdef SIOCGENADDR
int get_hw_address(int sd, struct ifreq *ifr, unsigned char *address)
{
if (ioctl(sd, SIOCGENADDR, ifr) < 0)
return -1;
memcpy(address, (unsigned char *) ifr->ifr_enaddr, 6);
return 0;
}
# else
int get_hw_address(int sd, struct ifreq *ifr, unsigned char *address)
{
return -1;
}
# endif /* SIOCGENADDR */
# endif /* SIOCGIFHWADDR */
int enum_hw(void)
{
int ret = 0;
#ifdef HAVE_NET_IF_H
int sd;
struct ifreq ifr, *ifrp;
struct ifconf ifc;
unsigned char buf[1024];
int i, ofs;
/* BSD 4.4 defines the size of an ifreq to be
* max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
* However, under earlier systems, sa_len isn't present, so
* the size is just sizeof(struct ifreq)
*/
sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
if (sd < 0)
return NRC_OPENERROR;
memset(buf, 0, sizeof(buf));
ifc.ifc_len = sizeof(buf);
ifc.ifc_buf = buf;
/* get the ifconf interface */
if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0)
{
close(sd);
return NRC_OPENERROR;
}
/* loop through the interfaces, looking for a valid one */
/* n = ifc.ifc_len; */
ofs = 0;
for (i = 0; i < ifc.ifc_len; i++)
{
unsigned char *a = NETBIOS_Adapter[i].address;
ifrp = (struct ifreq *)((char *)ifc.ifc_buf+ofs);
strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ);
/* try to get the address for this interface */
if(get_hw_address(sd, &ifr, a)==0)
{
/* make sure it's not blank */
/* if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5])
continue; */
TRACE("Found valid adapter %d at %02x:%02x:%02x:%02x:%02x:%02x\n", i,
a[0],a[1],a[2],a[3],a[4],a[5]);
NETBIOS_Adapter[i].valid = TRUE;
ret++;
}
ofs += ifreq_size(ifr);
}
close(sd);
TRACE("found %d adapters\n",ret);
#endif /* HAVE_NET_IF_H */
return ret;
}
void wprint_mac(WCHAR* buffer, int index)
{
int i;
unsigned char val;
for (i = 0; i<6; i++)
{
val = NETBIOS_Adapter[index].address[i];
if ((val >>4) >9)
buffer[2*i] = (WCHAR)((val >>4) + 'A' - 10);
else
buffer[2*i] = (WCHAR)((val >>4) + '0');
if ((val & 0xf ) >9)
buffer[2*i+1] = (WCHAR)((val & 0xf) + 'A' - 10);
else
buffer[2*i+1] = (WCHAR)((val & 0xf) + '0');
}
buffer[12]=(WCHAR)0;
}
static UCHAR NETBIOS_Enum(PNCB ncb)
{
int i;
LANA_ENUM *lanas = (PLANA_ENUM) ncb->ncb_buffer;
DWORD apiReturn, size = 0;
PMIB_IFTABLE table;
UCHAR ret;
TRACE("NCBENUM\n");
lanas->length = 0;
for (i = 0; i < enum_hw(); i++)
{
lanas->lana[lanas->length] = i;
lanas->length++;
}
return NRC_GOODRET;
apiReturn = GetIfTable(NULL, &size, FALSE);
if (apiReturn != NO_ERROR)
{
table = (PMIB_IFTABLE)malloc(size);
if (table)
{
apiReturn = GetIfTable(table, &size, FALSE);
if (apiReturn == NO_ERROR)
{
lanas->length = 0;
for (i = 0; i < table->dwNumEntries && lanas->length < MAX_LANA;
i++)
{
if (table->table[i].dwType != MIB_IF_TYPE_LOOPBACK)
{
lanas->lana[lanas->length] = table->table[i].dwIndex;
lanas->length++;
}
}
ret = NRC_GOODRET;
}
else
ret = NRC_SYSTEM;
free(table);
}
else
ret = NRC_NORESOURCES;
}
else
ret = NRC_SYSTEM;
return ret;
}
static UCHAR NETBIOS_Astat(PNCB ncb)
{
struct NetBiosAdapter *nad = &NETBIOS_Adapter[ncb->ncb_lana_num];
PADAPTER_STATUS astat = (PADAPTER_STATUS) ncb->ncb_buffer;
MIB_IFROW row;
TRACE("NCBASTAT (Adapter %d)\n", ncb->ncb_lana_num);
if(!nad->valid)
return NRC_INVADDRESS;
memset(astat, 0, sizeof astat);
memcpy(astat->adapter_address, nad->address, sizeof astat->adapter_address);
row.dwIndex = ncb->ncb_lana_num;
if (GetIfEntry(&row) != NO_ERROR)
return NRC_INVADDRESS;
/* doubt anyone cares, but why not.. */
if (row.dwType == MIB_IF_TYPE_TOKENRING)
astat->adapter_type = 0xff;
else
astat->adapter_type = 0xfe; /* for Ethernet */
return NRC_GOODRET;
}
@ -241,9 +132,16 @@ BOOL WINAPI Netbios(PNCB pncb)
{
case NCBRESET:
FIXME("NCBRESET adapter %d\n",pncb->ncb_lana_num);
if( (pncb->ncb_lana_num < MAX_LANA ) &&
NETBIOS_Adapter[pncb->ncb_lana_num].valid)
ret = NRC_GOODRET;
if(pncb->ncb_lana_num < MAX_LANA )
{
MIB_IFROW row;
row.dwIndex = pncb->ncb_lana_num;
if (GetIfEntry(&row) != NO_ERROR)
ret = NRC_GOODRET;
else
ret = NRC_ILLCMD; /* NetBIOS emulator not found */
}
else
ret = NRC_ILLCMD; /* NetBIOS emulator not found */
break;

View File

@ -18,12 +18,14 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdlib.h>
#include "winbase.h"
#include "nb30.h"
#include "lmcons.h"
#include "lmapibuf.h"
#include "lmerr.h"
#include "lmwksta.h"
#include "iphlpapi.h"
#include "winerror.h"
#include "winternl.h"
#include "ntsecapi.h"
@ -59,8 +61,53 @@ BOOL NETAPI_IsLocalComputer(LPCWSTR ServerName)
}
}
int enum_hw(void);
void wprint_mac(WCHAR* buffer, int index);
static void wprint_mac(WCHAR* buffer, PIP_ADAPTER_INFO adapter)
{
if (adapter != NULL)
{
int i;
unsigned char val;
for (i = 0; i<max(adapter->AddressLength, 6); i++)
{
val = adapter->Address[i];
if ((val >>4) >9)
buffer[2*i] = (WCHAR)((val >>4) + 'A' - 10);
else
buffer[2*i] = (WCHAR)((val >>4) + '0');
if ((val & 0xf ) >9)
buffer[2*i+1] = (WCHAR)((val & 0xf) + 'A' - 10);
else
buffer[2*i+1] = (WCHAR)((val & 0xf) + '0');
}
buffer[12]=(WCHAR)0;
}
else
buffer[0] = 0;
}
#define TRANSPORT_NAME_HEADER "\\Device\\NetBT_Tcpip_"
#define TRANSPORT_NAME_LEN \
(sizeof(TRANSPORT_NAME_HEADER) + MAX_ADAPTER_NAME_LENGTH)
static void wprint_name(WCHAR *buffer, int len, PIP_ADAPTER_INFO adapter)
{
WCHAR *ptr;
const char *name;
if (!buffer)
return;
if (!adapter)
return;
for (ptr = buffer, name = TRANSPORT_NAME_HEADER; *name && ptr < buffer + len;
ptr++, name++)
*ptr = *name;
for (name = adapter->AdapterName; name && *name && ptr < buffer + len;
ptr++, name++)
*ptr = *name;
*ptr = '\0';
}
NET_API_STATUS WINAPI
NetWkstaTransportEnum(LPCWSTR ServerName, DWORD level, LPBYTE* pbuf,
@ -84,49 +131,73 @@ NetWkstaTransportEnum(LPCWSTR ServerName, DWORD level, LPBYTE* pbuf,
switch (level)
{
case 0: /* transport info */
{
PWKSTA_TRANSPORT_INFO_0 ti;
int i,size_needed,n_adapt = enum_hw();
if (n_adapt == 0)
case 0: /* transport info */
{
PWKSTA_TRANSPORT_INFO_0 ti;
int i,size_needed,n_adapt;
DWORD apiReturn, adaptInfoSize = 0;
PIP_ADAPTER_INFO info, ptr;
apiReturn = GetAdaptersInfo(NULL, &adaptInfoSize);
if (apiReturn == ERROR_NO_DATA)
return ERROR_NETWORK_UNREACHABLE;
if (!read_entries)
return STATUS_ACCESS_VIOLATION;
if (!total_entries || !pbuf)
return RPC_X_NULL_REF_POINTER;
size_needed = n_adapt * (sizeof(WKSTA_TRANSPORT_INFO_0)
* 13 * sizeof (WCHAR));
if (prefmaxlen == MAX_PREFERRED_LENGTH)
NetApiBufferAllocate( size_needed, (LPVOID *) pbuf);
else
{
if (size_needed > prefmaxlen)
return ERROR_MORE_DATA;
NetApiBufferAllocate(prefmaxlen,
(LPVOID *) pbuf);
}
for (i = 0; i <n_adapt; i++)
{
ti = (PWKSTA_TRANSPORT_INFO_0)
((PBYTE) *pbuf + i * sizeof(WKSTA_TRANSPORT_INFO_0));
ti->wkti0_quality_of_service=0;
ti->wkti0_number_of_vcs=0;
ti->wkti0_transport_name=NULL;
ti->wkti0_transport_address= (LPWSTR)
((PBYTE )*pbuf + n_adapt* sizeof(WKSTA_TRANSPORT_INFO_0)
+ i * 13 * sizeof (WCHAR));
ti->wkti0_wan_ish=TRUE; /*TCPIP/NETBIOS Protocoll*/
wprint_mac(ti->wkti0_transport_address,i);
TRACE("%d of %d:ti at %p transport_address at %p %s\n",i,n_adapt,
ti, ti->wkti0_transport_address, debugstr_w(ti->wkti0_transport_address));
}
info = (PIP_ADAPTER_INFO)malloc(adaptInfoSize);
apiReturn = GetAdaptersInfo(info, &adaptInfoSize);
if (apiReturn != NO_ERROR)
{
free(info);
return apiReturn;
}
for (n_adapt = 0, ptr = info; ptr; ptr = ptr->Next)
n_adapt++;
size_needed = n_adapt * (sizeof(WKSTA_TRANSPORT_INFO_0)
+ n_adapt * TRANSPORT_NAME_LEN * sizeof (WCHAR)
+ n_adapt * 13 * sizeof (WCHAR));
if (prefmaxlen == MAX_PREFERRED_LENGTH)
NetApiBufferAllocate( size_needed, (LPVOID *) pbuf);
else
{
if (size_needed > prefmaxlen)
{
free(info);
return ERROR_MORE_DATA;
}
NetApiBufferAllocate(prefmaxlen,
(LPVOID *) pbuf);
}
for (i = 0, ptr = info; ptr; ptr = ptr->Next, i++)
{
ti = (PWKSTA_TRANSPORT_INFO_0)
((PBYTE) *pbuf + i * sizeof(WKSTA_TRANSPORT_INFO_0));
ti->wkti0_quality_of_service=0;
ti->wkti0_number_of_vcs=0;
ti->wkti0_transport_name= (LPWSTR)
((PBYTE )*pbuf +
n_adapt * sizeof(WKSTA_TRANSPORT_INFO_0)
+ i * TRANSPORT_NAME_LEN * sizeof (WCHAR));
wprint_name(ti->wkti0_transport_name,TRANSPORT_NAME_LEN, ptr);
ti->wkti0_transport_address= (LPWSTR)
((PBYTE )*pbuf +
n_adapt * sizeof(WKSTA_TRANSPORT_INFO_0) +
n_adapt * TRANSPORT_NAME_LEN * sizeof (WCHAR)
+ i * 13 * sizeof (WCHAR));
ti->wkti0_wan_ish=TRUE; /*TCPIP/NETBIOS Protocoll*/
wprint_mac(ti->wkti0_transport_address, ptr);
TRACE("%d of %d:ti at %p transport_address at %p %s\n",i,n_adapt,
ti, ti->wkti0_transport_address, debugstr_w(ti->wkti0_transport_address));
}
*read_entries = n_adapt;
*total_entries = n_adapt;
if(hresume) *hresume= 0;
break;
}
free(info);
if(hresume) *hresume= 0;
break;
}
default:
ERR("Invalid level %ld is specified\n", level);
return ERROR_INVALID_LEVEL;

View File

@ -100,9 +100,11 @@ typedef struct _LANA_ENUM
#define NRC_ILLCMD 0x03
#define NRC_CMDTMO 0x05
#define NRC_INCOMP 0x06
#define NRC_NORESOURCES 0x38
#define NRC_INVADDRESS 0x39
#define NRC_PENDING 0xff
#define NRC_OPENERROR 0x3f
#define NRC_SYSTEM 0x40
#ifdef __cplusplus
}