如何获取物理网卡的MAC地址信息

 

以下代码枚举所有LANA号码,执行复位(NCBREST)和适配器状态(NCBASTAT)。

 #include <windows.h>
   #include <wincon.h>
   #include <stdlib.h>
   #include <stdio.h>
   #include <time.h>

   typedef struct _ASTAT_
   {

      ADAPTER_STATUS adapt;
      NAME_BUFFER    NameBuff [30];

   }ASTAT, * PASTAT;

   ASTAT Adapter;

   void main (void)
   {
      NCB Ncb;
      UCHAR uRetCode;
      char NetName[50];
      LANA_ENUM   lenum;
      int      i;

      memset( &Ncb, 0, sizeof(Ncb) );
      Ncb.ncb_command = NCBENUM;
      Ncb.ncb_buffer = (UCHAR *)&lenum;
      Ncb.ncb_length = sizeof(lenum);
      uRetCode = Netbios( &Ncb );
      printf( "The NCBENUM return code is: 0x%x \n", uRetCode );

      for(i=0; i < lenum.length ;i++)
      {
          memset( &Ncb, 0, sizeof(Ncb) );
          Ncb.ncb_command = NCBRESET;
          Ncb.ncb_lana_num = lenum.lana[i];

          uRetCode = Netbios( &Ncb );
          printf( "The NCBRESET on LANA %d return code is: 0x%x \n",
                  lenum.lana[i], uRetCode );

          memset( &Ncb, 0, sizeof (Ncb) );
          Ncb.ncb_command = NCBASTAT;
          Ncb.ncb_lana_num = lenum.lana[i];

          strcpy( Ncb.ncb_callname,  "*               " );
          Ncb.ncb_buffer = (char *) &Adapter;
          Ncb.ncb_length = sizeof(Adapter);

          uRetCode = Netbios( &Ncb );
          printf( "The NCBASTAT on LANA %d return code is: 0x%x \n",
                  lenum.lana[i], uRetCode );
          if ( uRetCode == 0 )
          {
             printf( "The Ethernet Number on LANA %d is:
                     %02x%02x%02x%02x%02x%02x\n",
            lenum.lana[i],
                  Adapter.adapt.adapter_address[0],
                  Adapter.adapt.adapter_address[1],
                  Adapter.adapt.adapter_address[2],
                  Adapter.adapt.adapter_address[3],
                  Adapter.adapt.adapter_address[4],
                  Adapter.adapt.adapter_address[5] );
          }
       }

   }

        众所周知,一个网卡对应唯一MAC地址,对一些应用程序来说,获取网卡MAC地址有时是必要的,使用VC提供的netbios网络编程接口可以方便获取网卡MAC地址。

        netbios中所用的函数声明、常数等等均是在头文件nb30.h内定义的,若想使用netbios,须连接的库是netapi32.lib。调用netbios函数时,使用uRetCode = netbios(&ncb)语句,其入口参数&ncb为指向一网络控制块(NCB)的指针。在该NCB结构中,包含了为执行一个netbios命令相应需预先准备(在调用前)或命令执行结果(在调用后)的全部信息,在调用netbios函数前要先预置好该NCB结构中的一些有关字段;返回码uRetCode正常时应为0,返回的具体结果会包含在NCB结构的一些字段中。

NCB结构的定义如下: 

typedef struct _NCB{

UCHAR ncb_command;   //用于指定要执行的NetBIOS命令, 一些常见的NetBIOS命令如附表所示

UCHAR ncb_retcode;       //用于指定操作的返回代码,若返回值为0,就表示操作成功

UCHAR ncb_lsn;              //对应一个本地会话编号,成功的执行了一次NCBCALL或NCBLISTEN命令后,                                           //函数会返回一个会话编号

UCHAR ncb_num;           //用于知道本地名字的编号,伴随NCBADDNAME或NCBADDGRNAME命令的                                           //每一次调用,都会返回一个新的编号

PUCHAR ncb_buffer;       //指向数据缓冲区,发送时该缓冲区包含了要送出去的实际数据,接收时的接收

                                       //数据则为从NetBIOS函数返回的数据;对其他命令来说,如NCBENUM,缓冲                                          //区便是预定义的结构LANA_ENUM 

WORD ncb_length;         //指定缓冲区的长度,以字节数为单位,接收时NetBios会将该值设为收到的字节

                                       //数,若指定的缓冲区不够大,NetBIOS就会返回NRC_BUFLEND错误

UCHAR ncb_callname[NCBNAMSZ]; //用于指定远程应用的名字

UCHAR ncb_name[NCBNAMSZ]; //用于指定应用程序已知的名字

UCHAR ncb_rto;              //规定接收操作时的会话超时(以0.5秒为单位) 

UCHAR ncb_sto;             //规定发送操作时的会话超时(以0.5秒为单位) 

viod (CALLBACK *ncb_post) (struct _NCB *); //异步命令完成后,调用的后处理程序地址

UCHAR ncb_lana_num; //指定LAN Adapter编号

UCHAR ncb_cmd_cplt; //用于指定操作的返回代码,异步操作进行期间,Netbios会将这个值设为

                                     //NRC_PENDING 

UCHAR ncb_reserve[10]; //保留,必须为0 

HANDLE ncb_event; //事件对象的句柄,netbios函数返回非0值时会发信号给事件

}NCB, *PNCB; 

 

nb30.h中还定义了另外一个很重要的结构LANA_ENUM,当主机中有两块以上网卡时,使用NCB命令NCBENUM后(该命令只能在Windows NT/2000/XP中使用),该结构中会含有返回的网卡数目及其索引,该结构的定义如下:

typedef struct LANA_ENUM { 

UCHAR length; 

UCHAR lana [MAX_LANA]; 

} LANA_ENUM, *PLANA_ENUM;

其中:lana [MAX_LANA]定义了一个存放所有网卡信息的数组,length表示该数组的长度,即为本机所带网卡的个数。此外,我们还要定义一个描述网卡的结构ASTAT,其中使用了结构ADAPTER_STATUS(也由

nb30.h定义):

typedef struct { 

ADAPTER_STATUS adapt; 

NAME_BUFFER NameBuff[30]; 

} ASTAT; 

其中的ADAPTER_STATUS结构为

typedef struct _ADAPTER_STATUS { 

UCHAR adapter_address[6]; //网卡MAC地址

UCHAR rev_major; 

UCHAR reserved0; 

UCHAR adapter_type; 

UCHAR rev_minor; 

WORD duration; 

WORD frmr_recv; 

WORD frmr_xmit; 

WORD iframe_recv_err; 

WORD xmit_aborts; 

DWORD xmit_success; 

DWORD recv_success; 

WORD iframe_xmit_err; 

WORD recv_buff_unavail; 

WORD t1_timeouts; 

WORD ti_timeouts; 

DWORD eserved1; 

WORD free_ncbs; 

WORD max_cfg_ncbs; 

WORD max_ncbs; 

WORD xmit_buf_unavail; 

WORD max_dgram_size; 

WORD pending_sess; 

WORD max_cfg_sess; 

WORD max_sess; 

WORD max_sess_pkt_size; 

WORD name_count; 

} ADAPTER_STATUS, *PADAPTER_STATUS; 

在调用netbios NCBASTAT命令前,我们可将指向ADAPTER_STATUS结构的指针值赋给缓冲区指针ncb.ncb_buffer,

ASTAT Adapter; 

ncb.ncb_buffer = (unsigned char *) &Adapter; //两个指针指向同一个地方

ncb.ncb_length = sizeof(Adapter); // 设置ncb_buffer缓冲区长度

这样在执行NCBASTAT命令后,由于ncb.ncb_buffer指针所指的缓冲区中为命令执行后网卡返回的统计结果(其中包含MAC网卡地址),我们使用与其同一地址的ADAPTER_STATUS结构的adapter_address[6]字段便可取出网卡地址。

几点说明:

1.由于ncb_command字段用于指定要执行的netbios命令,所以总是在执行一个netbios命令之前设置该

ncb_command字段。例如:

(1)我们要获取当前计算机有多少个网卡,则可用以下一段代码来实现:

NCB ncb; 

UCHAR uRetCode = Netbios(&ncb); 

int num; //标识网卡个数

num = lana_enum.length; 

(2)对网卡进行初始化可用以下代码实现:

memset(&ncb, 0, sizeof(ncb)); 

ncb.ncb_command = NCBRESET; 

ncb.ncb_lana_num = 0; 

uRetCode = Netbios(&ncb ); 

(3)查询网卡包括MAC地址等在内的信息可用以下代码实现:

memset(&ncb, 0, sizeof(ncb)); 

ncb.ncb_command = NCBASTAT; 

ncb.ncb_lana_num = 0; 

sNetBiosName ="*";

FillMemory(ncb.ncb_callname, NCBNAMSZ - 1, 0x20); 

strcpy((char *)ncb.ncb_callname, (LPCTSTR) sNetBiosName); 

ncb.ncb_callname[sNetBiosName.GetLength()] = 0x20; 

ncb.ncb_callname[NCBNAMSZ] = 0x0; 

ASTAT Adapter; 

ncb.ncb_buffer = (unsigned char *) &Adapter; 

ncb.ncb_length = sizeof(Adapter); 

uRetCode = Netbios(&ncb);

转载于:https://my.oschina.net/SecCode/blog/1540079

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值