ifconfig调用过程

copy from :https://blog.csdn.net/liangdsing/article/details/70159314

ifconfig命令是可以查看当前网络设备信息,在openwrt环境中,ifconfig源码位于busybox文件夹下

找到入口函数ifconfig_main,位于ifconfig.c文件中

int ifconfig_main(int argc UNUSED_PARAM, char **argv)
{
struct ifreq ifr;
struct sockaddr_in sai;
#if ENABLE_FEATURE_IFCONFIG_HW
struct sockaddr sa;
#endif
const struct arg1opt *a1op;
const struct options *op;
int sockfd; /* socket fd we use to manipulate stuff with */
int selector;
#if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS
unsigned int mask;
unsigned int did_flags;
unsigned int sai_hostname, sai_netmask;
#else
unsigned char mask;
unsigned char did_flags;
#endif
char *p;
/*char host[128];*/
const char *host = NULL; /* make gcc happy */

did_flags = 0;
#if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS
sai_hostname = 0;
sai_netmask = 0;
#endif

/* skip argv[0] */
++argv;

#if ENABLE_FEATURE_IFCONFIG_STATUS
if (argv[0] && (argv[0][0] == '-' && argv[0][1] == 'a' && !argv[0][2])) {
interface_opt_a = 1;
++argv;
}
#endif

if (!argv[0] || !argv[1]) { /* one or no args */
#if ENABLE_FEATURE_IFCONFIG_STATUS
return display_interfaces(argv[0] /* can be NULL */);
#else
bb_error_msg_and_die("no support for status display");
#endif
}

若未配置任何信息则进入下面函数


int FAST_FUNC display_interfaces(char *ifname)
{
int status;

status = if_print(ifname);

return (status < 0); /* status < 0 == 1 -- error */
}
若提供端口名字则查看对应名字的设备端口信息
static int if_print(char *ifname)
{
struct interface *ife;
int res;

if (!ifname) {
/*res = for_all_interfaces(do_if_print, &interface_opt_a);*/
if (!int_list && (if_readlist() < 0))
return -1;
for (ife = int_list; ife; ife = ife->next) {
int err = do_if_print(ife); /*, &interface_opt_a);*/
if (err)
return err;
}
return 0;
}
ife = lookup_interface(ifname);
res = do_if_fetch(ife);
if (res >= 0)
ife_print(ife);
return res;
}


读取设备名称信息,首先从proc文件系统读取,若失败,则通过ioctl读取内核内的设备信息
static int if_readlist(void)
{
int err = if_readlist_proc(NULL);
/* Needed in order to get ethN:M aliases */
if (!err)
err = if_readconf();
return err;
}

之后更新这些设备名称从通过ioctl从内核中读取详细信息
static int if_fetch(struct interface *ife)
{
struct ifreq ifr;
char *ifname = ife->name;
int skfd;

skfd = xsocket(AF_INET, SOCK_DGRAM, 0);

strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) {
close(skfd);
return -1;
}
ife->flags = ifr.ifr_flags;

strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
memset(ife->hwaddr, 0, 32);
if (ioctl(skfd, SIOCGIFHWADDR, &ifr) >= 0)
memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8);

ife->type = ifr.ifr_hwaddr.sa_family;

strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
ife->metric = 0;
if (ioctl(skfd, SIOCGIFMETRIC, &ifr) >= 0)
ife->metric = ifr.ifr_metric;

strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
ife->mtu = 0;
if (ioctl(skfd, SIOCGIFMTU, &ifr) >= 0)
ife->mtu = ifr.ifr_mtu;

memset(&ife->map, 0, sizeof(struct ifmap));
#ifdef SIOCGIFMAP
strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
if (ioctl(skfd, SIOCGIFMAP, &ifr) == 0)
ife->map = ifr.ifr_map;
#endif

#ifdef HAVE_TXQUEUELEN
strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
ife->tx_queue_len = -1; /* unknown value */
if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) >= 0)
ife->tx_queue_len = ifr.ifr_qlen;
#else
ife->tx_queue_len = -1; /* unknown value */
#endif

strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
ifr.ifr_addr.sa_family = AF_INET;
memset(&ife->addr, 0, sizeof(struct sockaddr));
if (ioctl(skfd, SIOCGIFADDR, &ifr) == 0) {
ife->has_ip = 1;
ife->addr = ifr.ifr_addr;
strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
memset(&ife->dstaddr, 0, sizeof(struct sockaddr));
if (ioctl(skfd, SIOCGIFDSTADDR, &ifr) >= 0)
ife->dstaddr = ifr.ifr_dstaddr;

strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
memset(&ife->broadaddr, 0, sizeof(struct sockaddr));
if (ioctl(skfd, SIOCGIFBRDADDR, &ifr) >= 0)
ife->broadaddr = ifr.ifr_broadaddr;

strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
memset(&ife->netmask, 0, sizeof(struct sockaddr));
if (ioctl(skfd, SIOCGIFNETMASK, &ifr) >= 0)
ife->netmask = ifr.ifr_netmask;
}

close(skfd);
return 0;
}
用的是ioctl方法。
下面是内核部分解析,解析SIOCGIFFLAGS的的调用过程

ioctl(skfd, SIOCGIFFLAGS, &ifr)
内核部分进入的函数是sock_ioctl,位于socket。

static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg)
{
struct socket *sock;
struct sock *sk;
void __user *argp = (void __user *)arg;
int pid, err;
struct net *net;

sock = file->private_data;
sk = sock->sk;
net = sock_net(sk);
if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) {
err = dev_ioctl(net, cmd, argp);
} else
#ifdef CONFIG_WEXT_CORE
if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {
err = dev_ioctl(net, cmd, argp);
} else
#endif

进入dev_ioctl函数

int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg)
{
struct ifreq ifr;
int ret;
char *colon;

/* One special case: SIOCGIFCONF takes ifconf argument
and requires shared lock, because it sleeps writing
to user space.
*/

if (cmd == SIOCGIFCONF) {//ifconfig
rtnl_lock();
ret = dev_ifconf(net, (char __user *) arg);
rtnl_unlock();
return ret;
}

static int dev_ifconf(struct net *net, char __user *arg)
{
struct ifconf ifc;
struct net_device *dev;
char __user *pos;
int len;
int total;
int i;

/*
* Fetch the caller's info block.
*/

if (copy_from_user(&ifc, arg, sizeof(struct ifconf)))
return -EFAULT;

pos = ifc.ifc_buf;
len = ifc.ifc_len;

/*
* Loop over the interfaces, and write an info block for each.
*/

total = 0;
for_each_netdev(net, dev) {
for (i = 0; i < NPROTO; i++) {
if (gifconf_list[i]) {//inet_gifconf
int done;
if (!pos)
done = gifconf_list[i](dev, NULL, 0);
else
done = gifconf_list[i](dev, pos + total,
len - total);
if (done < 0)
return -EFAULT;
total += done;
}
}
}

遍历&(net)->dev_base_head链表上的net_device
————————————————
版权声明:本文为CSDN博主「东升」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/liangdsing/java/article/details/70159314

猜你喜欢

转载自www.cnblogs.com/Oude/p/12608336.html
今日推荐