天天看點

linux擷取網線插拔狀态的實作linux擷取網線插拔狀态的實作 總結:

linux擷取網線插拔狀态的實作

1、對于基于linux2.4核心的uclinux系統如何實作在應用層監控網線插拔狀态?

2、硬體環境:IPS100(ARM7TDMI)

3、實作過程

由于linux下的ifconfig指令就能夠實作在應用層監控網線插拔狀态,例如當網線連接配接正常時,使用ifconfig eth0指令,列印的資訊中會有RUNNING,而拔掉網線後,再使用ifconfig eth0指令,RUNNING就不見了。是以,實作Linux應用層監控網線插入狀态就相當于自己寫一個ifconfig函數。

基于這個思路,首先參考ifconfig的源碼,可以參考linux自身提供的ifconfig的源碼(linux提供的有ifconfig.c函數),也可以在網上查找。首先找到linux自身提供的ifconfig.c函數,既然ifconfig通過RUNNING來判斷網絡的通斷的狀況的,首先找到RUNNING的出處,搜尋一下發現這句話,

If(ptr->flags &IFF_RUNNIG)
{
Printf(__("RUNNING"));
}
           

以這個為切入點,層層向上找,分别是被些函數調用,最後我們進入了main函數(這是理所當然的),在這裡的到RUNNING→ife_print()→if_pirint()→main().。先看ife_prinf()函數,這裡沒有和核心通信,這時我們再看if_print()函數,這裡剛好有和核心通信的函數,

else {                       
        struct interface *ife;

        ife = lookup_interface(ifname);
        res = do_if_fetch(ife);
        if (res >= 0)
            ife_print(ife);
    }
           

    這時需要看到lookup_interface(ifname)和do_if_fetch(ife)的原型,由于頭檔案很多,我沒辦法知道這兩個函數在那個頭檔案中,是以幹脆在網上找到這兩個函數的原型,我們找到了一篇ifconfing源碼分析的文章,http://viscar.blog.sohu.com/2574772.html,這裡面找到了函數原型,我們看到 do_if_fetch()函數裡面又調用了if_fetch()函數,太好了,這個函數正是我們所需要的,在這裡面有個很重要的函數ioctl(),ioctl用于向裝置發送控制和配置指令,驅動程式可以接收ioctl的資料,并傳回資料,ioctl的原型為

    ioctl(int d, int cmd, ......),

d是某個裝置的檔案描述符,cmd是ioctl的指令,可變參數取決于cmd,是指向變量或結構體的指針。

這裡面用到的裝置檔案描述符skfd = socket(AF_INET,SOCK_DGRAM,0);這是一個套接字,作用是打開一個網絡通訊端口,成功的話傳回skfd,相當于一個檔案描述符。

   有了這些之後我們就可以寫一個自己的簡潔版的ifconfig函數了,現在ubuntu10.04上編寫代碼,代碼裡面的ioctl函數這樣寫ioctl(skfd, SIOCGIFFLAGS, &ifr) ,其中SIOCGIGGLAGS表示得到sock i/o的flags,這時因為,RUNNIGN的條件是ptr->flags &IFF_RUNNING 是否為真,代碼裡面直接展現eth0,函數為strcpy(ifr.ifr_name, “eth0”);完整的代碼如下:

(以下代碼在ubuntu10.04下運作通過)

#include "icconst.h"
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#include <string.h>
#include <stdio.h>
#include "net_detect.h"
 
int net_detect(char* net_name)
{
int skfd = 0;
struct ifreq ifr;
 
skfd = socket(AF_INET, SOCK_DGRAM, 0);
if(skfd < 0)
{
printf("%s:%d Open socket error!\n", __FILE__, __LINE__);
return -1;
}
 
strcpy(ifr.ifr_name, net_name);
 
if(ioctl(skfd, SIOCGIFFLAGS, &ifr) <0 )
{
printf("%s:%d IOCTL error!\n", __FILE__, __LINE__);
printf("Maybe ethernet inferface %s is not valid!", ifr.ifr_name);
close(skfd);
return -1;
}
 
if(ifr.ifr_flags & IFF_RUNNING)
{
printf("%s is running :)\n", ifr.ifr_name);
}
else
{
printf("%s is not running :(\n", ifr.ifr_name);
}
           
if(ioctl(skfd,SIOCGIFADDR,&ifr)<0)
{
  printf("SIOCGIFADDRIOCTL error!\n");
  close(skfd);
  return-1;
}
printf("ipaddr :[%s]\n",inet_ntoa(((structsockaddr_in*)&(ifr.ifr_addr))->sin_addr));
if(ioctl(skfd,SIOCGIFHWADDR,&ifr)<0)
{
  printf("SIOCGIFHWADDRIOCTL error!\n");
  close(skfd);
  return-1;
}
printf("macaddr: %02x:%02x:%02x:%02x:%02x:%02x\n"
    (unsignedchar)ifr.ifr_hwaddr.sa_data[0],
    (unsignedchar)ifr.ifr_hwaddr.sa_data[1],
    (unsignedchar)ifr.ifr_hwaddr.sa_data[2],
    (unsignedchar)ifr.ifr_hwaddr.sa_data[3],
    (unsignedchar)ifr.ifr_hwaddr.sa_data[4],
    (unsignedchar)ifr.ifr_hwaddr.sa_data[5]  );
/*************************************************************************************************************************************/
close(skfd);
 
return 0;
}
           

代碼裡面的struct ifreq 是一個裝置請求的結構體,在<linux/if.h>中定義,SIOCGIFFLAGS使用了ifreq結構,

  在ubuntu10.04環境下編譯之後,運作#./a.out eth0  即可實作網線插拔的監控。

這時把代碼加到uclinux下運作,發現并不能實作ubuntu的效果,這是為什麼呢?

初步分析原因,可能是在驅動程式中沒有将插拔狀态的資訊通知核心,是以我們使用ioctl實際上不能獲得核心網絡裝置的狀态的資訊。我們在《linux裝置驅動程式這本書上》看到有兩個函數剛好做這件事情:

Void netif_carrier_off(struct net_device*dev);
Void netif_carrier_on(struct net_device*dev);
           

當驅動檢測到裝置沒有連接配接好,可以調用netif_carrier_off通知核心這一事情;當裝置再次連接配接好時,調用netif_carrier_on通知核心現在連接配接好了。

現在我們将這兩個函數分别加到驅動程式中,放到監控網線插拔狀态的位置,再在unlinux中插拔網線時,會在序列槽終端列印出相應的狀态資訊,這時的狀态資訊完全是在應用層實作的。

 總結:

多看看linux一些指令實作的代碼和linux一些開源的軟體非常有好處,他們的代碼寫的很美,值得學習!