ifconfig工具与驱动交互解析(ioctl)

这篇具有很好参考价值的文章主要介绍了ifconfig工具与驱动交互解析(ioctl)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Linux ifconfig(network interfaces configuring)

  • Linux ifconfig命令用于显示或设置网络设备。ifconfig可设置网络设备的状态,或是显示目前的设置。
  • 同netstat一样,ifconfig源码也位于net-tools中。
  • 源码位于net-tools工具包中,这是linux网络的基本工具包,此外还有arp,hostname,route等命令。

PS

此文章不考虑ifconfig的具体功能介绍,而是侧重与驱动和内核的交互,下面简单描述下该工具的使用实例,并且代码并不包含对于ifconfig的标准实现,仅是注重实现过程。

实例

$ ifconfig
eth0      Link encap:Ethernet  HWaddr 00:0c:29:e7:65:70
          inet addr:192.168.101.128  Bcast:192.168.101.255  Mask:255.255.255.0
          inet6 addr: fe80::20c:29ff:fee7:6570/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:17080658 errors:73 dropped:2 overruns:0 frame:0
          TX packets:17346739 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:4038046913 (4.0 GB)  TX bytes:2731849230 (2.7 GB)
          Interrupt:19 Base address:0x2000

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:58049 errors:0 dropped:0 overruns:0 frame:0
          TX packets:58049 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:5540611 (5.5 MB)  TX bytes:5540611 (5.5 MB)

启动关闭指定网卡

# ifconfig eth0 down
# ifconfig eth0 up

用ifconfig修改MAC地址

# ifconfig eth0 down //关闭网卡
# ifconfig eth0 hw ether 00:AA:BB:CC:DD:EE //修改MAC地址
# ifconfig eth0 up //启动网卡

配置IP地址

# ifconfig eth0 192.168.1.56 
//给eth0网卡配置IP地址
# ifconfig eth0 192.168.1.56 netmask 255.255.255.0 
// 给eth0网卡配置IP地址,并加上子掩码
# ifconfig eth0 192.168.1.56 netmask 255.255.255.0 broadcast 192.168.1.255
// 给eth0网卡配置IP地址,加上子掩码,加上个广播地址

启用和关闭ARP协议

# ifconfig eth0 arp  //开启
# ifconfig eth0 -arp  //关闭

/proc/net/dev

$ cat /proc/net/dev
Inter-|   Receive                                                |  Transmit
 face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
    lo: 5558739   58239    0    0    0     0          0         0  5558739   58239    0    0    0     0       0          0
  eth0: 4038107838 17081103   73    2    0     0          0         0 2731895950 17347146    0    0    0     0       0          0
  • 这里列出了所有网络设备的其属性状态和收发包情况。ifconfig会open这个设备查找匹配信息。

那知道了如何使用该工具,那么具体是怎么实现的呢???
就到了下面的源码分析

代码分析

先来个简单的查看信息,如下是获取ip的流程

  1. 先通过ioctl获得本地所有接口的信息,并保存在ifconf中
  2. 再从ifconf中取出每一个ifreq中表示ip地址的信息

分析一:(获取ip地址)
接下来我们只需要从一个一个的接口信息获取ip地址信息即可。

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <linux/if.h>

 
int main()
{
    int i=0;
    int sockfd;
    struct ifconf ifconf;
    unsigned char buf[512];
    struct ifreq *ifreq;
    //初始化ifconf
    ifconf.ifc_len = 512;
    ifconf.ifc_buf = buf;
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0))<0)
    {
        exit(1);
    }
    ioctl(sockfd, SIOCGIFCONF, &ifconf); //获取所有接口信息
    //接下来一个一个的获取IP地址
    ifreq = (struct ifreq*)buf;
    for (i=(ifconf.ifc_len/sizeof (struct ifreq)); i>0; i--)
    {
        // if(ifreq->ifr_flags == AF_INET){ //for ipv4
        printf("name = [%s]\n" , ifreq->ifr_name);
        printf("local addr = [%s]\n" ,inet_ntoa(((struct sockaddr_in*)&(ifreq->ifr_addr))->sin_addr));
        ifreq++;
// }
    }
return 0;

执行结果

ifconfig_achieve$ ./ifconfig_wlan_ip.o
name = [lo]
local addr = [127.0.0.1]
name = [ens33]
local addr = [192.168.101.137]

解析:

  • ifc_len:表示用来存放所有接口信息的缓冲区长度
  • ifc_buf:表示存放接口信息的缓冲区
  • 用ioctl获得本地ip地址时要用到两个结构体ifconf和ifreq,我们需要在程序开始时对ifconf的ifc_len和ifc_buf进行初始化
  • 使用ioctl获取所有接口信息,完成后ifc_len内存放实际获得的接口信息总长度
    并且信息被存放在ifc_buf中。
  • struct ifconf:通常是用来保存所有接口信息的
  • struct ifreq:这个结构定义在include/net/if.h,用来配置ip地址,激活接口,配置MTU等接口信息的
  • 想要获取当前网口网线插入状态,需要用到ifreq结构体,获取网卡的信息,然后socket结合网卡驱动的ioctl,就可以得到与网线插入状态相关的数据。

简单部分罗列下上面的结构体:

//ifconf通常是用来保存所有接口信息的
struct ifconf
{
    int ifc_len; /* size of buffer */
    union
    {
        char *ifcu_buf; /* input from user->kernel*/
        struct ifreq *ifcu_req; /* return from kernel->user*/
    } ifc_ifcu;
};
#define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */
#define ifc_req ifc_ifcu.ifcu_req /* array of structures */
 
//ifreq用来保存某个接口的信息
struct ifreq 
{
    char ifr_name[IFNAMSIZ];
    union {
        struct sockaddr ifru_addr;
        struct sockaddr ifru_dstaddr;
        struct sockaddr ifru_broadaddr;
        short ifru_flags;
        int ifru_metric;
        caddr_t ifru_data;
    } ifr_ifru;
};
#define ifr_addr ifr_ifru.ifru_addr
#define ifr_dstaddr ifr_ifru.ifru_dstaddr
#define ifr_broadaddr ifr_ifru.ifru_broadaddr

分析二(获取基础信息,并更改设置ip)

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <linux/if.h>
#include <string.h>

#define INTERFACE "ens33"


void port_status(unsigned int flags)  
    { 
        if(flags & IFF_UP)    
        {  
            printf("is up\n");        
        }  
        if(flags & IFF_BROADCAST)     
        {  
            printf("is broadcast\n");     
        }  
        if(flags & IFF_LOOPBACK)      
        {  
            printf("is loop back\n");     
        }  
        if(flags & IFF_POINTOPOINT)   
        {  
            printf("is point to point\n");    
        }  
        if(flags & IFF_RUNNING)   
        {  
            printf("is running\n");   
        }  
        if(flags & IFF_PROMISC)   
        {  
            printf("is promisc\n");   
        }  
    }  

int main()
{
        int fd;
        struct ifreq buf[5];    //这个结构定义在/usr/include/net/if.h,用来配置和获取ip地址,掩码,MTU等接口信息的。 ifreq用来保存某个接口的信息 
        struct ifconf ifc;  //ifconf通常是用来保存所有接口信息的
        int ret = 0,i=0,j=0;      
        ifc.ifc_len = sizeof(buf);  
        ifc.ifc_buf = (caddr_t) buf;  
        uint32_t ip = 0x8165a8c0;//192.168.101.129
        struct sockaddr_in sin;
        if ((fd = socket(AF_INET, SOCK_DGRAM, 0))<0)
        {
        perror("socket" );
        exit(1);
        }
        else
        printf("----------fd:%d-----------\n",fd);
         
        ret = ioctl(fd, SIOCGIFCONF, (char*)&ifc);  
        if(ret)  
        {  
            printf("get if config info failed");  
            return -1;  
        }  
    for (i=(ifc.ifc_len/sizeof (struct ifreq)); i>0; i--)
    {
        printf("--------------name = [%s]------------\n" , buf[j].ifr_name);
        if(strcmp(buf[j].ifr_name,"ens33")==0)
        {
        printf("--------------ens33网卡---------------\n");
        strncpy(buf[j].ifr_name, INTERFACE, 5);
        memset(&sin, 0, sizeof(struct sockaddr));
        sin.sin_family = AF_INET;
        sin.sin_addr.s_addr = ip;
        memcpy(&buf[j].ifr_addr, &sin, sizeof(struct sockaddr));
        ret = ioctl(fd, SIOCSIFADDR, (char*)&buf[j]);
        if(ret)  
        continue;      
        }
        ret = ioctl(fd, SIOCGIFADDR, (char*)&buf[j]);  
            if(ret)  
                continue;
        printf("----------local addr = [%s]----------\n" ,inet_ntoa(((struct sockaddr_in*)&(buf[j].ifr_addr))->sin_addr));

        ret = ioctl(fd, SIOCGIFFLAGS, (char*)&buf[j]);  
            if(ret)  
                continue;  
        port_status(buf[j].ifr_flags);
        printf("--------------ifr_flags = [%d]------------\n" , buf[j].ifr_flags);

        ret = ioctl(fd, SIOCGIFMTU, (char*)&buf[j]);  
        if(ret)  
           continue;
        printf("-------mtu:%d----------\n",(unsigned int)(buf[j].ifr_ifru.ifru_mtu));
         /* 获取当前网卡的mac 命令cat /sys/class/net/eth0/address*/  
            ret = ioctl(fd, SIOCGIFHWADDR, (char*)&buf[j]);  
            if(ret)  
                continue;
        printf("%02x:%02x:%02x:%02x:%02x:%02x\n\n",  
                (unsigned char)buf[j].ifr_hwaddr.sa_data[0],  
                (unsigned char)buf[j].ifr_hwaddr.sa_data[1],  
                (unsigned char)buf[j].ifr_hwaddr.sa_data[2],  
                (unsigned char)buf[j].ifr_hwaddr.sa_data[3],  
                (unsigned char)buf[j].ifr_hwaddr.sa_data[4],  
                (unsigned char)buf[j].ifr_hwaddr.sa_data[5]  
                );
        j++;
        

    }
    close(fd);
return 0;
}

运行结果

./ifconfig_wlan.o
----------fd:3-----------
--------------name = [lo]------------
----------local addr = [127.0.0.1]----------
is up
is loop back
is running
--------------ifr_flags = [73]------------
-------mtu:65536----------
00:00:00:00:00:00

--------------name = [ens33]------------
--------------ens33网卡---------------
----------local addr = [192.168.101.129]----------
is up
is broadcast
is running
--------------ifr_flags = [4163]------------
-------mtu:1500----------
00:0c:29:24:11:8b

注意:
通过

gcc  ifconfig_wlan.c  -o ifconfig_wlan.o

命令编译出来的可执行文件本身是无法直接执行的,debug如下:

strace ./ifconfig_wlan.o

失败 log:
ifconfig工具与驱动交互解析(ioctl)
是由于编译的可执行文件权限不足导致ioctl设置失败,如下是解决流程:


 1. gcc ifconfig_wlan_information.c -o ifconfig_wlan_information.o
 2. sudo cp ifconfig_wlan_information.o ifconfig_wlan.o
 3. sudo chmod u+s ifconfig_wlan.o
 4. strace ./ifconfig_wlan.o

如下为再次执行后的结果:
ifconfig工具与驱动交互解析(ioctl)

结语

如上主要讲的是设置和获取,希望能够抛砖引玉,让大家学到更多文章来源地址https://www.toymoban.com/news/detail-472184.html

到了这里,关于ifconfig工具与驱动交互解析(ioctl)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Linux用户与内核空间交互—ioctl

    目录 简介 一、交互方法笔记与总结 二、ioctl 三、实战 1、头文件 2、应用程序 3、内核程序 4、 程序输出 用户空间与内核的交互方式,使用copy_from_user(), copy_to_user(). 除了这两种交互方式,内核还提供了其他高级的方式,对于写驱动来说很重要。有proc、sysfs、debugfs、netlink、

    2024年02月10日
    浏览(198)
  • linux驱动开发(四):ioctl()函数

    前文中我们介绍了应用程序通过使用虚拟文件系统VFS提供的接口,来控制字符驱动程序,完成字符驱动设备的open、close、read、write操作。但是如果我们想进行除此以外的其他操作,拓展一些file_operations给出的接口中没有的自定义功能,则需要使用到ioctl()函数。 首先,我们需

    2024年01月16日
    浏览(40)
  • linux tty 驱动之ioctls 函数

    在 struct tty_driver 中的 ioctl 函数被 tty 核心调用当 ioctl(2) 被在设备节点上 调用. 如果这个 tty 驱动不知道如何处理传递给它的 ioctl 值, 它应当返回 - ENOIOCTLCMD 来试图让 tty 核心实现一个通用的调用版本. 2.6 内核定义了大约 70 个不同的 tty ioctls, 可被用来发送给一个 tty 驱动. 大部

    2024年01月19日
    浏览(32)
  • linux驱动和应用的数据交互

    首先,我们需要规定一些命令码,这些命令码在应用程序和驱动程序中需要保持一致。应用程序只需向驱动程序下发一条指令码,用来通知它执行哪条命令。如何解读这条指令和怎么实现相关操作,就是驱动程序自己要做的事。 应用程序的接口函数为ioctl,参考官方文档,函

    2024年02月06日
    浏览(30)
  • 【Linux】应用与驱动交互及应用间数据交换

    1. 系统调用接口(System Calls): 应用程序可以通过系统调用,如 open(), read(), write(), ioctl(), 等来与设备驱动进行交互。这些调用最终会通过内核转发到相应的驱动函数。 2. 输入输出控制(ioctl): ioctl() 系统调用是一种特殊的系统调用,它提供了一个进行设备特定操作的方法。

    2024年01月21日
    浏览(75)
  • 深度长文 | 解析Apple Vision Pro 的3D功能与LiDAR工作场景,灵明光子ADS 6401 虚实交互的驱动引擎

    Apple Vision Pro 的 传感器分布 Apple Vision Pro目前公开出的产品形态包含众多传感器,以强化设备的深度信息感知能力,实现最佳的三维空间虚实结合效果。其中视觉传感器包括以下几类:RGB摄像头,红外摄像头,dToF激光雷达,结构光相机,以及鱼眼红外摄像头。 Apple Vision Pro正

    2024年02月15日
    浏览(42)
  • Linux驱动开发—最详细应用程序调用驱动程序解析

    Linux下进行驱动开发,完全将驱动程序与应用程序隔开,中间通过 C标准库函数 以及 系统调用 完成驱动层和应用层的数据交换。 驱动加载成功以后会在“/dev”目录下生成一个相应的文件,应用程序通过 对“/dev/xxx” (xxx 是具体的驱动文件名字) 的文件进行相应的操作 即可实

    2024年02月16日
    浏览(46)
  • 最全Linux驱动开发全流程详细解析(持续更新)

    驱动与底层硬件直接打交道,充当了硬件与应用软件中间的桥梁。 具体任务 读写设备寄存器(实现控制的方式) 完成设备的轮询、中断处理、DMA通信(CPU与外设通信的方式) 进行物理内存向虚拟内存的映射(在开启硬件MMU的情况下) 说明:设备驱动的两个任务方向 操作硬

    2024年02月03日
    浏览(49)
  • “Linux免除系统交互操作方法、expect自动化交互工具” 及 “SSH批量修改主机密码脚本”

    案例:为机器磁盘进行分区并实现挂载,免交互式操作,如何实现? 注意:有些命令的交互操作提示是不算在标准输出和错误输出中的,此时该方法不适用 注意:命令的交互操作提示是不算终端窗口的,此时该方法不适用 一. expect 简介 expect 工具是一个根据脚本与其他交互

    2024年02月08日
    浏览(56)
  • linux remoteproc驱动中elf解析函数实现分析

    在linux中存在的remoteproc的驱动中用到了很多elf解析的函数,比如 elf_size_of_phdr , elf_phdr_get_p_paddr 以及 elf_hdr_get_e_phnum 等等接口。当我们直接搜对应的函数时会发现无法找到其定义,其实这些函数的实现被定义在 drivers/remoteproc/remoteproc_elf_helpers.h 头文件中。 下面以ELF64为例 S

    2024年02月13日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包