socket ioctl函数

目录

1.ioctl函数简介

1.1 ioctl函数

1.2 ioctl常用命令

2.ioctl底层原理

3.ioctl常用示例

3.1 ioctl设置文件IO阻塞和非阻塞

3.2 ioctl获取接口列表

3.3 ioctl获取接口信息

3.4 ioctl获取和设置路由

3.5 ioctl获取和设置ARP表项


1.ioctl函数简介

1.1 ioctl函数

ioctl函数是内核开放给用户空间的一种通信机制,用户程序通过该机制可以和内核进行通信,实现一些定制或者扩展功能,用户可以注册自己的ioctl函数,完成用户特定的功能。

#include <sys/ioctl.h>

int ioctl(int fd, unsigned long request, ...);

参数:
fd:文件描述符
request:ioctl命令
...:命令参数

返回值:
成功:返回0
失败:返回-1,并设置errno

EBADF:无效文件描述符
EFAULT:arg指针指向不可访问内存空间
EINVAL:命令或命令参数无效
ENOTTY:fd没有指向一个字符设备,或者fd指向的字符设备不支持ioctl操作

1.2 ioctl常用命令

ioctl常见命令可以分为6大类:套接字,文件,接口,路由,ARP,流。表中只列出常见的一些命令,用户可以注册自己的命令,自己注册命令在Linux驱动开发中很常见。

 

2.ioctl底层原理

ioctl通过系统调用执行sys_ioctl函数,sys_ioctl会先去判断ioctl命令是否是通用命令,如果是通用命令则按照通用命令处理方式执行,如果不是通用命令,则会执行注册在文件描述符的ioctl函数,用户注册的ioctl函数就是通过这个机制完成调用。

 图 1

3.ioctl常用示例

3.1 ioctl设置文件IO阻塞和非阻塞

void set_block() {
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);

    int on = 1;
    //on:0(阻塞),1(非阻塞)
    int ret = ioctl(sockfd, FIONBIO, &on);
    if (ret) {
        perror("set block");
    }

    close(sockfd);
}

3.2 ioctl获取接口列表

void get_if_conf() {
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);

    struct ifconf conf;
#define MAX_IF_NUM (10)
    struct ifreq reqs[MAX_IF_NUM] = {0};
    conf.ifc_len = MAX_IF_NUM * sizeof(struct ifreq);
    conf.ifc_ifcu.ifcu_req = reqs;
    int ret = ioctl(sockfd, SIOCGIFCONF, &conf);
    if (ret) {
        perror("get if conf");
    }

    int  num = conf.ifc_len / sizeof(struct ifreq); //ifc_len会被内核修改为实际长度
    for (int i = 0; i < num; i++) {
        printf("if name:%s\n", reqs[i].ifr_ifrn.ifrn_name);
    }

    close(sockfd);
}

3.3 ioctl获取接口信息

void print_if_addr(const char *msg, void *data) {
    struct ifreq *req = (struct ifreq *)data;
    struct sockaddr_in *addr = ((struct sockaddr_in *)&(req->ifr_addr));
    printf("%s %s\n", msg, inet_ntoa(addr->sin_addr));
}
void print_if_flags(const char *msg, void *data) {
    struct ifreq *req = (struct ifreq *)data;
    printf("%s 0x%04x\n", msg, req->ifr_flags);
}
void print_if_dstaddr(const char *msg, void *data) {
    struct ifreq *req = (struct ifreq *)data;
    struct sockaddr_in *addr = ((struct sockaddr_in *)&(req->ifr_dstaddr));
    printf("%s %s\n", msg, inet_ntoa(addr->sin_addr));
}
void print_if_broadaddr(const char *msg, void *data) {
    struct ifreq *req = (struct ifreq *)data;
    struct sockaddr_in *addr = ((struct sockaddr_in *)&(req->ifr_broadaddr));
    printf("%s %s\n", msg, inet_ntoa(addr->sin_addr));
}
void print_if_netmask(const char *msg, void *data) {
    struct ifreq *req = (struct ifreq *)data;
    struct sockaddr_in *addr = ((struct sockaddr_in *)&(req->ifr_netmask));
    printf("%s %s\n", msg, inet_ntoa(addr->sin_addr));
}
void print_if_metric(const char *msg, void *data) {
    struct ifreq *req = (struct ifreq *)data;
    printf("%s %d\n", msg, req->ifr_metric);
}
void print_if_mtu(const char *msg, void *data) {
    struct ifreq *req = (struct ifreq *)data;
    printf("%s %d\n", msg, req->ifr_mtu);
}
void print_if_hwaddr(const char *msg, void *data) {
    struct ifreq *req = (struct ifreq *)data;
    struct sockaddr *addr = ((struct sockaddr*)&(req->ifr_hwaddr));
    printf("%s %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n", msg,
            addr->sa_data[0],
            addr->sa_data[1],
            addr->sa_data[2],
            addr->sa_data[3],
            addr->sa_data[4],
            addr->sa_data[5]);
}

void get_if_info() {
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);

    struct cmd_item {
        unsigned long cmd;
        char cmd_name[20];
        void (*print)(const char *msg, void *data);
    };
#define CMD_NUM (8)
    struct cmd_item cmd_list[CMD_NUM] =
    {
        {SIOCGIFADDR, "接口地址", print_if_addr},//获取接口地址
        {SIOCGIFFLAGS, "接口标识", print_if_flags}, //获取接口标志
        {SIOCGIFDSTADDR, "点对点地址", print_if_dstaddr}, //获取点对点地址
        {SIOCGIFBRDADDR, "广播地址", print_if_broadaddr}, //获取广播地址
        {SIOCGIFNETMASK, "子网掩码", print_if_netmask}, //获取子网掩码
        {SIOCGIFMETRIC, "接口测度", print_if_metric}, //获取接口测度
        {SIOCGIFMTU, "MTU", print_if_mtu}, //获取接口测度
        {SIOCGIFHWADDR, "硬件地址", print_if_hwaddr}, //获取接口测度
    };

    for (uint32_t i = 0; i < CMD_NUM; i++) {
        struct ifreq req = {0};
#define IF_NAME "ens33"
        memcpy(req.ifr_ifrn.ifrn_name, IF_NAME, strlen(IF_NAME));
        int ret = ioctl(sockfd, cmd_list[i].cmd, &req);
        if (ret) {
            printf("%s get %s info errno:%d(%s)\n", IF_NAME, cmd_list[i].cmd_name, errno, strerror(errno));
            continue;
        }
        if (cmd_list[i].print != NULL)
            cmd_list[i].print(cmd_list[i].cmd_name, &req);
    }
    close(sockfd);
}

3.4 ioctl获取和设置路由

void add_route() {
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);

#define GATEWAY "192.168.0.1"
#define DST "192.168.10.0"
#define GENMASK "255.255.255.0"
#define DEVNAME "ens33"

    struct rtentry rt = {0};
    struct sockaddr_in *gw = (struct sockaddr_in *)&rt.rt_gateway;
    gw->sin_family = AF_INET;
    gw->sin_addr.s_addr = inet_addr(GATEWAY);

    struct sockaddr_in *dst = (struct sockaddr_in *)&rt.rt_dst;
    dst->sin_family = AF_INET;
    dst->sin_addr.s_addr = inet_addr(DST);

    struct sockaddr_in *genmask = (struct sockaddr_in *)&rt.rt_genmask;
    genmask->sin_family = AF_INET;
    genmask->sin_addr.s_addr = inet_addr(GENMASK);

    rt.rt_dev = DEVNAME;
    rt.rt_flags = RTF_UP | RTF_GATEWAY;

    int ret = ioctl(sockfd, SIOCADDRT, &rt);
    if (ret) {
        perror("add route");
    }

    close(sockfd);
}

3.5 ioctl获取和设置ARP表项

void get_arp() {
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);

    struct arpreq req = {0};
    struct sockaddr_in *sin = (struct sockaddr_in *)&req.arp_pa;
#define DEV "ens33"
#define IP "192.168.0.107"
    sin->sin_family = AF_INET;
    sin->sin_addr.s_addr = inet_addr(IP);
    memcpy(req.arp_dev, DEV, sizeof(DEV));

    int ret = ioctl(sockfd, SIOCGARP, &req);
    if (ret) {
        perror("get arp");
    } else {
        printf("%s %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n", IP,
                req.arp_ha.sa_data[0],
                req.arp_ha.sa_data[1],
                req.arp_ha.sa_data[2],
                req.arp_ha.sa_data[3],
                req.arp_ha.sa_data[4],
                req.arp_ha.sa_data[5]);
    }

    close(sockfd);
}

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

物联网心球

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值