Linux Kernel 学习笔记17:内核与用户层通信之sockopt

来源:互联网 发布:太原新医医院网络平台 编辑:程序博客网 时间:2024/06/07 20:27

(本章基于:Linux-4.4.0-37)

sockopt是内核与用户层通信方法中非常简单的一种,其本质是通过copy_to_user/copy_from_user在内核与用户层传递数据,因此效率不高,常用于传递控制、状态等信息;


内核层:

数据结构:

linux/netfilter.h

static struct nf_sockopt_ops my_sockopt_ops ={        .pf                     = PF_INET,             //协议族        .set_optmin             = MY_SOCKOPT_SET_MIN,  //最小set命令        .set_optmax             = MY_SOCKOPT_SET_MAX,  //最大set命令        .set                    = my_sockopt_set,      //set处理函数        .get_optmin             = MY_SOCKOPT_GET_MIN,  //最小get命令        .get_optmax             = MY_SOCKOPT_GET_MAX,  //最大get命令        .get                    = my_sockopt_get,      //get处理函数};
在内核中由结构struct nf_sockopt_ops来描述sockopt,其中定义了set/get处理函数对应用户层的setsockopt/getsockopt。最小、最大命令字规定了命令字范围,命令字必须大于等于最小命令字,小于最大命令字。命令字的值自行在内核层与用户层定义,尽量定义较大的命令字,以避免与内核已存在的命令字重复。


操作函数:

int nf_register_sockopt(struct nf_sockopt_ops *reg);void nf_unregister_sockopt(struct nf_sockopt_ops *reg);

用户层:

用户层使用getsockopt/setsockopt调用底层接口,定义如下:

int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);

例:

在本例中,内核层定义了一个5个空间的大小的整型数组,通过set/get接口可修改/读取每个空间的数据;


头文件 my_sockopt.h

#ifndef __MY_SOCKOPT_H_#define __MY_SOCKOPT_H_#define MY_SOCKOPT_BASE                 (2413)#define MY_SOCKOPT_SET_MIN              ((MY_SOCKOPT_BASE) + 1)#define MY_SOCKOPT_SET_1                ((MY_SOCKOPT_BASE) + 1)#define MY_SOCKOPT_SET_2                ((MY_SOCKOPT_BASE) + 2)#define MY_SOCKOPT_SET_3                ((MY_SOCKOPT_BASE) + 3)#define MY_SOCKOPT_SET_4                ((MY_SOCKOPT_BASE) + 4)#define MY_SOCKOPT_SET_5                ((MY_SOCKOPT_BASE) + 5)#define MY_SOCKOPT_SET_MAX              ((MY_SOCKOPT_BASE) + 6)#define MY_SOCKOPT_GET_MIN              ((MY_SOCKOPT_BASE) + 6)#define MY_SOCKOPT_GET_1                ((MY_SOCKOPT_BASE) + 6)#define MY_SOCKOPT_GET_2                ((MY_SOCKOPT_BASE) + 7)#define MY_SOCKOPT_GET_3                ((MY_SOCKOPT_BASE) + 8)#define MY_SOCKOPT_GET_4                ((MY_SOCKOPT_BASE) + 9)#define MY_SOCKOPT_GET_5                ((MY_SOCKOPT_BASE) + 10)#define MY_SOCKOPT_GET_MAX              ((MY_SOCKOPT_BASE) + 11)#endif

内核层sockopt.c

#include <linux/init.h>#include <linux/module.h>#include <linux/netfilter.h>#include "my_sockopt.h"static int buf[5];int my_sockopt_set(struct sock *sk, int optval, void __user *user, unsigned int len){        int value;        int cmd;        switch(optval)        {        case MY_SOCKOPT_SET_1:                cmd = 0;                break;        case MY_SOCKOPT_SET_2:                cmd = 1;                break;        case MY_SOCKOPT_SET_3:                cmd = 2;                break;        case MY_SOCKOPT_SET_4:                cmd = 3;                break;        case MY_SOCKOPT_SET_5:                cmd = 4;                break;        default:                printk(KERN_INFO "my sockopt set fault\n");                return -EFAULT;        }        if ( copy_from_user((void*)&value, user, len) != 0 ) {                return -EFAULT;        }        buf[cmd] = value;        printk(KERN_INFO "my sockopt set%d:%d\n", cmd, value);        return 0;}int my_sockopt_get(struct sock *sk, int optval, void __user *user, int *len){        int value;        printk(KERN_INFO "my sockopt get\n");        switch(optval)        {        case MY_SOCKOPT_GET_1:                value = buf[0];                break;        case MY_SOCKOPT_GET_2:                value = buf[1];                break;        case MY_SOCKOPT_GET_3:                value = buf[2];                break;        case MY_SOCKOPT_GET_4:                value = buf[3];                break;        case MY_SOCKOPT_GET_5:                value = buf[4];                break;        default:                printk(KERN_INFO "my sockopt get default\n");                return -EFAULT;        }        *len = 4;        if(copy_to_user(user, (void*)&value, *len) != 0) {                printk(KERN_INFO "my sockopt get fault\n");                return -EFAULT;        }        return 0;}static struct nf_sockopt_ops my_sockopt_ops ={        .pf                     = PF_INET,        .set_optmin             = MY_SOCKOPT_SET_MIN,        .set_optmax             = MY_SOCKOPT_SET_MAX,        .set                    = my_sockopt_set,        .get_optmin             = MY_SOCKOPT_GET_MIN,        .get_optmax             = MY_SOCKOPT_GET_MAX,        .get                    = my_sockopt_get,};static __init int hello_init(void){        int result;        memset(buf, 0, sizeof(buf));        result = nf_register_sockopt(&my_sockopt_ops);        if(result != 0) {                printk(KERN_ALERT "register sockopt error!\n");        }        printk(KERN_ALERT "hello init success!\n");        return 0;}static __exit void hello_exit(void){        nf_unregister_sockopt(&my_sockopt_ops);        printk(KERN_WARNING "helloworld exit!\n");}module_init(hello_init);module_exit(hello_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("Stone");

用户层 test.c

#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include "my_sockopt.h"static intmy_sockopt(int direction, int index, int *value){        int fd;        int size;        if(!value) {                return -1;        }        fd = socket(PF_INET, SOCK_RAW, IPPROTO_RAW);        if(!fd) {                perror("socket");                return -2;        }        if(direction == 0) {                size = sizeof(int);                getsockopt(fd, IPPROTO_IP, MY_SOCKOPT_GET_1 + index - 1, value, &size);        } else if(direction == 1) {                setsockopt(fd, IPPROTO_IP, MY_SOCKOPT_SET_1 + index - 1, value, sizeof(int));        } else {                close(fd);                return -3;        }        close(fd);        return 0;}intmain(int argc, char **argv){        int direction;        int index;        int value;        if(argc <= 2) {                printf("parameter error 1!\n");                exit(EXIT_FAILURE);        }        if(strcmp(argv[1], "get") == 0) {                direction = 0;        } else if(strcmp(argv[1], "set") == 0) {                direction = 1;        } else {                printf("parameter error! 2\n");                exit(EXIT_FAILURE);        }        if(direction == 0 && argc != 3) {                printf("parameter error! 3\n");                exit(EXIT_FAILURE);        }        if(direction == 1 && argc != 4) {                printf("parameter error! 4\n");                exit(EXIT_FAILURE);        }        index = atoi(argv[2]);        if(index < 1 || index >5) {                printf("parameter error! 5\n");                exit(EXIT_FAILURE);        }        if(direction == 1) {                value = atoi(argv[3]);        }        if(my_sockopt(direction, index, &value) == 0) {                if(direction == 0) {                        printf("get index%d:%d\n", index, value);                }        } else {                printf("sockopt error!\n");                exit(EXIT_FAILURE);        }        return 0;}
























阅读全文
0 0
原创粉丝点击