IFF_UP 和 IFF_RUNNING 的差別在哪?就實際功用而言,兩者都代表了網路裝置是否正常啟用,但是更仔細觀察可以發現拔除網路線時會造成 IFF_RUNNING 的改變,至於 IFF_UP 不會因插拔網路線而有任何變化
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <linux/if.h>
#include <linux/sockios.h>
#include <linux/ethtool.h>
#define SLEEP_TIME (1000*1000)
typedef struct nic_t
{
char if_name[5];
int status;
int old_status;
}nic;
void init_daemon(void);
int get_netlink_status(const char *if_name);
void auto_up_down_eth(nic* pnic);
void auto_route_eth(nic* pnic);
void init_nic(nic* pnic, const char* if_name)
{
memset(pnic, 0, sizeof(nic));
strcpy(pnic->if_name, if_name);
}
int main(int argc, char* argv[])
{
init_daemon();
if(getuid() != 0)
{
fprintf(stderr, "Netlink Status Check Need Root Power.\n");
return 1;
}
nic eth[2];
init_nic(ð[0], "eth0");
init_nic(ð[1], "eth1");
while(1)
{
auto_up_down_eth(eth);
auto_up_down_eth(eth+1);
//auto_route_eth(eth);
//auto_route_eth(eth+1);
//get_netlink_status("eth1");
usleep(SLEEP_TIME);
}
return 0;
}
#define IFCONFIG_CMD "ifconfig %s %s"
void ifconfig_cmd(const char* if_name, int up_down)
{
char cmd[48];
sprintf(cmd, IFCONFIG_CMD, if_name, up_down==1?"up":"down");
system(cmd);
}
#define LINK_UP "up"
#define LINK_DOWN "down"
void auto_up_down_eth(nic* pnic)
{
pnic->status = get_netlink_status(pnic->if_name);
if(pnic->status!=pnic->old_status)
{
printf("%s Net link status: %s\n", pnic->if_name, pnic->status==1?"up":"down");
ifconfig_cmd(pnic->if_name, pnic->status);
pnic->old_status = pnic->status;
}
}
#define ROUTE_DEL_CMD "route del -net %s netmask %s dev %s"
//route del -net 192.168.3.0 netmask 255.255.255.0 dev eth1
void route_del_cmd(const char* if_name, int up_down)
{
char cmd[48];
sprintf(cmd, "./delroute.sh %s", if_name);
if(up_down!=1)
{
system(cmd);
}
}
void auto_route_eth(nic* pnic)
{
pnic->status = get_netlink_status(pnic->if_name);
if(pnic->status!=pnic->old_status)
{
printf("%s Net link status: %s\n", pnic->if_name, pnic->status==1?"up":"down");
route_del_cmd(pnic->if_name, pnic->status);
pnic->old_status = pnic->status;
}
}
// if_name like "ath0", "eth0". Notice: call this function
// need root privilege.
// return value:
// -1 -- error , details can check errno
// 1 -- interface link up
// 0 -- interface link down.
#if 1
int get_netlink_status(const char *if_name)
{
int skfd;
struct ifreq ifr;
struct ethtool_value edata;
edata.cmd = ETHTOOL_GLINK;
edata.data = 0;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name) - 1);
ifr.ifr_data = (char *) &edata;
if (( skfd = socket( AF_INET, SOCK_DGRAM, 0 )) == 0)
return -1;
if(ioctl( skfd, SIOCETHTOOL, &ifr ) == -1)
{
close(skfd);
return -1;
}
close(skfd);
return edata.data;
}
#else
int get_netlink_status(const char *if_name)
{
struct ifreq ifr;
int sockfd;
int ret = 0;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
bzero(&ifr, sizeof(ifr));
strcpy(ifr.ifr_name, if_name);
ioctl(sockfd, SIOCGIFFLAGS, &ifr);
/*
ifr_flags 的各項旗標和說明:
IFF_UP 裝置正在運作
IFF_BROADCAST 有效的廣播位址
IFF_DEBUG Debug 標誌
IFF_LOOPBACK 這是 Loopback 裝置
IFF_POINTOPOINT 這是點到點的網路裝置介面
IFF_RUNNING 資源已分配
IFF_NOARP 無arp協議,沒有設置第二層目的地址
IFF_PROMISC 介面為雜湊(promiscuous)模式
IFF_NOTRAILERS 避免使用 trailer
IFF_ALLMULTI 接收所有群組廣播(multicast)封包資料
IFF_MASTER 主負載平衡群(bundle)
IFF_SLAVE 從負載平衡群(bundle)
IFF_MULTICAST 支持群組廣播(multicast)
IFF_PORTSEL 可以通過 ifmap 選擇 media 類型
IFF_AUTOMEDIA 自動選擇 media
IFF_DYNAMIC 裝置介面關閉時丟棄地址
*/
if (ifr.ifr_flags & IFF_UP)
{
printf("%s is IFF_UP!\n", if_name);
ret = 1;
}
else
{
printf("%s is !IFF_UP!\n", if_name);
ret = 0;
}
if (ifr.ifr_flags & IFF_RUNNING)
{
printf("%s is IFF_RUNNING!\n", if_name);
}
else
{
printf("%s is !IFF_RUNNING!\n", if_name);
}
close(sockfd);
return ret;
}
#endif
#include <unistd.h>
#include <signal.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
void init_daemon(void)
{
int pid;
int i;
if(pid=fork())
exit(0);//是父进程,结束父进程
else if(pid< 0)
exit(1);//fork失败,退出
//是第一子进程,后台继续执行
setsid();//第一子进程成为新的会话组长和进程组长
//并与控制终端分离
if(pid=fork())
exit(0);//是第一子进程,结束第一子进程
else if(pid< 0)
exit(1);//fork失败,退出
//是第二子进程,继续
//第二子进程不再是会话组长
for(i=0;i< NOFILE;++i)//关闭打开的文件描述符
close(i);
//linzhming add:这个我们不需要
chdir("/tmp");//改变工作目录到/tmp
umask(0);//重设文件创建掩模
return;
}