Chinaunix首页 | 论坛 | 博客
  • 博客访问: 73466
  • 博文数量: 26
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 35
  • 用 户 组: 普通用户
  • 注册时间: 2015-09-27 23:09
文章分类

全部博文(26)

文章存档

2016年(14)

2015年(12)

我的朋友

分类: LINUX

2015-12-18 11:28:19

用户态与内核态交互通信的方法不止一种,sockopt是比较方便的一个,写法也简单.
缺点就是使用 copy_from_user()/copy_to_user()完成内核和用户的通信, 效率其实不高, 多用在传递控制 选项 信息,不适合做大量的数据传输

用户态函数:
发送:int setsockopt ( int sockfd, int proto, int cmd, void *data, int datelen);
接收:int getsockopt(int sockfd, int proto, int cmd, void *data, int datalen)
第一个参数是socket描述符;
第二个参数proto是sock协议,IP RAW的就用SOL_SOCKET/SOL_IP等,TCP/UDP socket的可用SOL_SOCKET/SOL_IP/SOL_TCP/SOL_UDP等,即高层的socket是都可以使用低层socket的命令字 的,IPPROTO_IP
第三个参数cmd是操作命令字,由自己定义;
第四个参数是数据缓冲区起始位置指针,set操作时是将缓冲区数据写入内核,get的时候是将内核中的数 据读入该缓冲区;
第五个参数数据长度

内核态函数
注册:nf_register_sockopt(struct nf_sockopt_ops *sockops)
解除:nf_unregister_sockopt(struct nf_sockopt_ops *sockops)

结构体 nf_sockopt_ops test_sockops 
  1. static struct nf_sockopt_ops nso = {  
  2.  .pf  = PF_INET,       // 协议族  
  3.  .set_optmin = 常数,    // 定义最小set命令字  
  4.  .set_optmax = 常数+N,  // 定义最大set命令字  
  5.  .set  = recv_msg,   // 定义set处理函数  
  6.  .get_optmin = 常数,    // 定义最小get命令字  
  7.  .get_optmax = 常数+N,  // 定义最大get命令字  
  8.  .get  = send_msg,   // 定义set处理函数  
  9. };  


其中命令字不能和内核已有的重复,宜大不宜小。命令字很重要,是用来做标识符的。而且用户态和内核态要定义的相同,
  1. #define SOCKET_OPS_BASE          128  
  2. #define SOCKET_OPS_SET       (SOCKET_OPS_BASE)  
  3. #define SOCKET_OPS_GET      (SOCKET_OPS_BASE)  
  4. #define SOCKET_OPS_MAX       (SOCKET_OPS_BASE + 1)  

set/get处理函数是直接由用户空间的 set/getsockopt函数调用的。 setsockopt函数向内核写数据,用getsockopt向内核读数据。
另外set和get的处理函数的参数应该是这样的
int recv_msg(struct sock *sk, int cmd, void __user *user, unsigned int len)
int send_msg(struct sock *sk, int cmd, void __user *user, unsigned int *len)

附上我修改网友的程序
内核态的module.c
  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5. #include   
  6. #include   
  7. #include    
  8.   
  9. #define SOCKET_OPS_BASE          128  
  10. #define SOCKET_OPS_SET       (SOCKET_OPS_BASE)  
  11. #define SOCKET_OPS_GET      (SOCKET_OPS_BASE)  
  12. #define SOCKET_OPS_MAX       (SOCKET_OPS_BASE + 1)  
  13.   
  14. #define KMSG          "--------kernel---------"  
  15. #define KMSG_LEN      sizeof("--------kernel---------")  
  16.   
  17. MODULE_LICENSE("GPL");  
  18. MODULE_AUTHOR("SiasJack");/*作者*/  
  19. MODULE_DESCRIPTION("sockopt module,simple module");//描述  
  20. MODULE_VERSION("1.0");//版本号  
  21.   
  22. static int recv_msg(struct sock *sk, int cmd, void __user *user, unsigned int len)  
  23. {  
  24.     int ret = 0;  
  25.     printk(KERN_INFO "sockopt: recv_msg()\n");   
  26.   
  27.     if (cmd == SOCKET_OPS_SET)  
  28.     {     
  29.         char umsg[64];  
  30.         int len = sizeof(char)*64;  
  31.         memset(umsg, 0, len);  
  32.         ret = copy_from_user(umsg, user, len);  
  33.         printk("recv_msg: umsg = %s. ret = %d\n", umsg, ret);      
  34.     }     
  35.     return 0;  
  36. }   
  37.   
  38. static int send_msg(struct sock *sk, int cmd, void __user *user, int *len)  
  39. {  
  40.     int ret = 0;  
  41.     printk(KERN_INFO "sockopt: send_msg()\n");   
  42.     if (cmd == SOCKET_OPS_GET)  
  43.     {     
  44.         ret = copy_to_user(user, KMSG, KMSG_LEN);  
  45.         printk("send_msg: umsg = %s. ret = %d. success\n", KMSG, ret);  
  46.     }     
  47.     return 0;  
  48.   
  49. }  
  50.   
  51. static struct nf_sockopt_ops test_sockops =  
  52. {  
  53.     .pf = PF_INET,  
  54.     .set_optmin = SOCKET_OPS_SET,  
  55.     .set_optmax = SOCKET_OPS_MAX,  
  56.     .set = recv_msg,  
  57.     .get_optmin = SOCKET_OPS_GET,  
  58.     .get_optmax = SOCKET_OPS_MAX,  
  59.     .get = send_msg,  
  60.     .owner = THIS_MODULE,  
  61. };  
  62.   
  63. static int __init init_sockopt(void)  
  64. {  
  65.     printk(KERN_INFO "sockopt: init_sockopt()\n");  
  66.     return nf_register_sockopt(&test_sockops);  
  67. }  
  68.   
  69. static void __exit exit_sockopt(void)  
  70. {  
  71.     printk(KERN_INFO "sockopt: fini_sockopt()\n");  
  72.     nf_unregister_sockopt(&test_sockops);  
  73. }  
  74.   
  75. module_init(init_sockopt);  
  76. module_exit(exit_sockopt);  

用户态的user.c

  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5. #include   
  6. #include    
  7.   
  8. #define SOCKET_OPS_BASE      128  
  9. #define SOCKET_OPS_SET       (SOCKET_OPS_BASE)  
  10. #define SOCKET_OPS_GET      (SOCKET_OPS_BASE)  
  11. #define SOCKET_OPS_MAX       (SOCKET_OPS_BASE + 1)   
  12.   
  13. #define UMSG      "----------user------------"  
  14. #define UMSG_LEN  sizeof("----------user------------")   
  15.   
  16. char kmsg[64];   
  17.   
  18. int main(void)  
  19. {  
  20.     int sockfd;  
  21.     int len;  
  22.     int ret;   
  23.   
  24.     sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);  
  25.     if(sockfd < 0)  
  26.     {     
  27.         printf("can not create a socket\n");  
  28.         return -1;   
  29.     }     
  30.   
  31.     /*call function recv_msg()*/  
  32.     ret = setsockopt(sockfd, IPPROTO_IP, SOCKET_OPS_SET, UMSG, UMSG_LEN);  
  33.     printf("setsockopt: ret = %d. msg = %s\n", ret, UMSG);  
  34.     len = sizeof(char)*64;   
  35.   
  36.     /*call function send_msg()*/  
  37.     ret = getsockopt(sockfd, IPPROTO_IP, SOCKET_OPS_GET, kmsg, &len);  
  38.     printf("getsockopt: ret = %d. msg = %s\n", ret, kmsg);  
  39.     if (ret != 0)  
  40.     {     
  41.         printf("getsockopt error: errno = %d, errstr = %s\n", errno, strerror(errno));  
  42.     }     
  43.   
  44.     close(sockfd);  
  45.     return 0;  
  46. }  

Makefile----系统不同命令可能不同,我的fedora 12
  1. TARGET = socketopt  
  2. OBJS = module.o  
  3. MDIR = drivers/misc  
  4.   
  5. EXTRA_CFLAGS = -DEXPORT_SYMTAB  
  6. CURRENT = $(shell uname -r)  
  7. KDIR = /lib/modules/$(CURRENT)/build  
  8. PWD = $(shell pwd)  
  9. DEST = /lib/modules/$(CURRENT)/kernel/$(MDIR)  
  10.   
  11. obj-m := $(TARGET).o  
  12.   
  13. $(TARGET)-objs :=$(OBJS)  
  14.   
  15. default:  
  16.     make -C  $(KDIR) SUBDIRS=$(PWD) modules   
  17.     gcc -o user user.c  
  18. $(TARGET).o: $(OBJS)  
  19.     $(LD) $(LD_RFLAG) -r -o $@ $(OBJS)  
  20.   
  21. insmod:  
  22.     insmod $(TARGET).ko  
  23. rmmod:  
  24.     rmmod $(TARGET).ko  
  25.   
  26. clean:  
  27.     -rm -rf *.o *.ko .$(TARGET).ko.cmd .*.flags *.mod.c modules.order  Module.symvers .tmp_versions  
  28.     -rm -rf protocol/*.o protocol/.*.o.cmd *.markers   
  29.     -rm -rf user  
  30. -include $(KDIR)/Rules.make  

运行的结果
  1. [root@root socket]# make   //编译  
  2. make -C  /lib/modules/2.6.31.5-127.fc12.i686.PAE/build SUBDIRS=/root/study/c_study/socket modules   
  3. make[1]: Entering directory `/usr/src/kernels/2.6.31.5-127.fc12.i686.PAE'  
  4.   CC [M]  /root/study/c_study/socket/module.o  
  5.   LD [M]  /root/study/c_study/socket/socketopt.o  
  6.   Building modules, stage 2.  
  7.   MODPOST 1 modules  
  8.   CC      /root/study/c_study/socket/socketopt.mod.o  
  9.   LD [M]  /root/study/c_study/socket/socketopt.ko  
  10. make[1]: Leaving directory `/usr/src/kernels/2.6.31.5-127.fc12.i686.PAE'  
  11. gcc -o user user.c  
  12. [root@root socket]#   
  13. [root@root socket]# make insmod   //加载  
  14. insmod socketopt.ko  
  15. [root@root socket]#   
  16. [root@root socket]# lsmod    //查看加载成功  
  17. Module                  Size  Used by  
  18. socketopt               1968  0   
  19. sunrpc                158388  1   
  20. [root@root socket]# dmesg -c  //清楚以前的系统信息  
  21. [root@root socket]# ./user  //运行用户态  
  22. setsockopt: ret = 0. msg = ----------user------------  
  23. getsockopt: ret = 0. msg = --------kernel---------  
  24. [root@root socket]# dmesg  //查看最新生成的日志  
  25. sockopt: recv_msg()  
  26. recv_msg: umsg = ----------user------------. ret = 0  
  27. sockopt: send_msg()  
  28. send_msg: umsg = --------kernel---------. ret = 0. success  
阅读(1265) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~