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
- Linux Kernel 学习笔记17:内核与用户层通信之sockopt
- Linux Kernel 学习笔记9:内核与用户层通信之netlink
- Linux Kernel 学习笔记9:内核与用户层通信之netlink
- netfilter内核态与用户态 通信 之 sockopt
- netfilter内核态与用户态 通信 之 sockopt
- netfilter内核态与用户态 通信 之 sockopt
- linux 内核进程与用户进程的通信 方法一 使用sockopt与内核交换数据
- linux 内核进程与用户进程的通信 方法一 使用sockopt与内核交换数据
- linux 内核进程与用户进程的通信 方法一 使用sockopt与内核交换数据
- 使用sockopt实现内核与用户之间通信
- linux kernel 内核空间与用户空间通信 netlink套接字 与 系统调用的 异同
- linux 内核与用户空间通信之netlink使用方法[转]
- linux 内核与用户空间通信之netlink使用方法
- linux 内核与用户空间通信之netlink使用方法
- Linux内核空间与用户空间通信之netlink
- linux 内核与用户空间通信之netlink使用方法
- linux 内核与用户空间通信之netlink使用方法
- linux 内核与用户空间通信之netlink使用方法
- 这一刻让我明白大师为什么如此令人尊敬
- 【读书笔记】构造、析构、赋值(Effective C++)
- mysql字符大小写转换
- 微信小程序中换行,空格写法
- React Error: Minified React error #119
- Linux Kernel 学习笔记17:内核与用户层通信之sockopt
- Oracle连接总结
- java 集合 LinkedHashSet
- 文章标题 CSU 1963: Feed the rabbit (斜率DP优化)
- poj1195(二维树状数组,点修改,区间求和)
- Leetcode练习<十八> 罗马数字转换为整数
- LA 4015 树形DP 在路程不超过k的情况下,求最多可到达多少节点
- 1127: 矩阵乘积
- LeetCode | 66. Plus One