參考網路資料,經整理驗證ok.
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#include <string.h>
#include <stdio.h>
int net_detect(char* net_name)
{
int skfd = 0;
struct ifreq ifr;
struct sockaddr_in *pAddr = NULL;
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("SIOCGIFADDR IOCTL error!\n");
close(skfd);
return -1;
}
pAddr = (struct sockaddr_in *)&(ifr.ifr_addr);
printf("ip addr :[%s]\n", inet_ntoa(pAddr->sin_addr));
if(ioctl(skfd,SIOCGIFHWADDR,&ifr)<0)
{
printf("SIOCGIFHWADDR IOCTL error!\n");
close(skfd);
return -1;
}
printf("mac addr: %02x:%02x:%02x:%02x:%02x:%02x\n",
(unsigned char)ifr.ifr_hwaddr.sa_data[0],
(unsigned char)ifr.ifr_hwaddr.sa_data[1],
(unsigned char)ifr.ifr_hwaddr.sa_data[2],
(unsigned char)ifr.ifr_hwaddr.sa_data[3],
(unsigned char)ifr.ifr_hwaddr.sa_data[4],
(unsigned char)ifr.ifr_hwaddr.sa_data[5]);
close(skfd);
return 0;
}
void main()
{
net_detect("eth0");
}
參考網路資料:
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”);完整的代碼如下:
(以下代碼在ubuntu 10.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);
}
/*****************以下為識別ip地址,mac地址***************************************/
if(ioctl(skfd,SIOCGIFADDR,&ifr)<0)
{
printf("SIOCGIFADDR IOCTL error!\n");
close(skfd);
return -1;
}
printf("ip addr :[%s]\n",inet_ntoa(((struct sockaddr_in*)&(ifr.ifr_addr))->sin_addr));
if(ioctl(skfd,SIOCGIFHWADDR,&ifr)<0)
{
printf("SIOCGIFHWADDR IOCTL error!\n");
close(skfd);
return -1;
}
printf("mac addr: %02x:%02x:%02x:%02x:%02x:%02x\n"
(unsigned char)ifr.ifr_hwaddr.sa_data[0],
(unsigned char)ifr.ifr_hwaddr.sa_data[1],
(unsigned char)ifr.ifr_hwaddr.sa_data[2],
(unsigned char)ifr.ifr_hwaddr.sa_data[3],
(unsigned char)ifr.ifr_hwaddr.sa_data[4],
(unsigned char)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中插拔網線時,會在串口終端列印出相應的狀態資訊,這時的狀態資訊完全是在應用程式層實現的。
4.參考文檔:uclinux核心網路驅動源碼和ifconfig的源碼
《linux裝置驅動程式》