用戶態與內核態交互通信的方法不止一種,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 [cpp] static struct nf_sockopt_ops nso = { .pf = PF_INET, // 協議族 .set_optmin = 常數, // 定義最小set命令字 .set_optmax = 常數+N, // 定義最大set命令字 .set = recv_msg, // 定義set處理函數 .get_optmin = 常數, // 定義最小get命令字 .get_optmax = 常數+N, // 定義最大get命令字 .get = send_msg, // 定義set處理函數 }; 其中命令字不能和內核已有的重復,宜大不宜小。命令字很重要,是用來做標識符的。而且用戶態和內核態要定義的相同, [cpp] #define SOCKET_OPS_BASE 128 #define SOCKET_OPS_SET (SOCKET_OPS_BASE) #define SOCKET_OPS_GET (SOCKET_OPS_BASE) #define SOCKET_OPS_MAX (SOCKET_OPS_BASE + 1) set/get處理函數是直接由用戶空間的 set/getsockopt函數調用的。 setsockopt函數向內核寫數據,用getsockopt向內核讀數據。www.2cto.com 另外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 [cpp] #include <linux/module.h> #include <linux/kernel.h> #include <linux/types.h> #include <linux/string.h> #include <linux/netfilter_ipv4.h> #include <linux/init.h> #include <asm/uaccess.h> #define SOCKET_OPS_BASE 128 #define SOCKET_OPS_SET (SOCKET_OPS_BASE) #define SOCKET_OPS_GET (SOCKET_OPS_BASE) #define SOCKET_OPS_MAX (SOCKET_OPS_BASE + 1) #define KMSG "--------kernel---------" #define KMSG_LEN sizeof("--------kernel---------") MODULE_LICENSE("GPL"); MODULE_AUTHOR("SiasJack");/*作者*/ MODULE_DESCRIPTION("sockopt module,simple module");//描述 MODULE_VERSION("1.0");//版本號 static int recv_msg(struct sock *sk, int cmd, void __user *user, unsigned int len) { int ret = 0; printk(KERN_INFO "sockopt: recv_msg()\n"); if (cmd == SOCKET_OPS_SET) { char umsg[64]; int len = sizeof(char)*64; memset(umsg, 0, len); ret = copy_from_user(umsg, user, len); printk("recv_msg: umsg = %s. ret = %d\n", umsg, ret); } return 0; } static int send_msg(struct sock *sk, int cmd, void __user *user, int *len) { int ret = 0; printk(KERN_INFO "sockopt: send_msg()\n"); if (cmd == SOCKET_OPS_GET) { ret = copy_to_user(user, KMSG, KMSG_LEN); printk("send_msg: umsg = %s. ret = %d. success\n", KMSG, ret); } return 0; } static struct nf_sockopt_ops test_sockops = { .pf = PF_INET, .set_optmin = SOCKET_OPS_SET, .set_optmax = SOCKET_OPS_MAX, .set = recv_msg, .get_optmin = SOCKET_OPS_GET, .get_optmax = SOCKET_OPS_MAX, .get = send_msg, .owner = THIS_MODULE, }; static int __init init_sockopt(void) { printk(KERN_INFO "sockopt: init_sockopt()\n"); return nf_register_sockopt(&test_sockops); } static void __exit exit_sockopt(void) { printk(KERN_INFO "sockopt: fini_sockopt()\n"); nf_unregister_sockopt(&test_sockops); } module_init(init_sockopt); module_exit(exit_sockopt); 用戶態的user.c [cpp] #include <unistd.h> #include <stdio.h> #include <sys/socket.h> #include <linux/in.h> #include <string.h> #include <errno.h> #define SOCKET_OPS_BASE 128 #define SOCKET_OPS_SET (SOCKET_OPS_BASE) #define SOCKET_OPS_GET (SOCKET_OPS_BASE) #define SOCKET_OPS_MAX (SOCKET_OPS_BASE + 1) #define UMSG "----------user------------" #define UMSG_LEN sizeof("----------user------------") char kmsg[64]; int main(void) { int sockfd; int len; int ret; sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); if(sockfd < 0) { printf("can not create a socket\n"); return -1; } /*call function recv_msg()*/ ret = setsockopt(sockfd, IPPROTO_IP, SOCKET_OPS_SET, UMSG, UMSG_LEN); printf("setsockopt: ret = %d. msg = %s\n", ret, UMSG); len = sizeof(char)*64; /*call function send_msg()*/ ret = getsockopt(sockfd, IPPROTO_IP, SOCKET_OPS_GET, kmsg, &len); printf("getsockopt: ret = %d. msg = %s\n", ret, kmsg); if (ret != 0) { printf("getsockopt error: errno = %d, errstr = %s\n", errno, strerror(errno)); } close(sockfd); return 0; } Makefile----系統不同命令可能不同,我的fedora 12 [cpp] TARGET = socketopt OBJS = module.o MDIR = drivers/misc EXTRA_CFLAGS = -DEXPORT_SYMTAB CURRENT = $(shell uname -r) KDIR = /lib/modules/$(CURRENT)/build PWD = $(shell pwd) DEST = /lib/modules/$(CURRENT)/kernel/$(MDIR) obj-m := $(TARGET).o $(TARGET)-objs :=$(OBJS) default: make -C $(KDIR) SUBDIRS=$(PWD) modules gcc -o user user.c $(TARGET).o: $(OBJS) $(LD) $(LD_RFLAG) -r -o $@ $(OBJS) insmod: insmod $(TARGET).ko rmmod: rmmod $(TARGET).ko clean: -rm -rf *.o *.ko .$(TARGET).ko.cmd .*.flags *.mod.c modules.order Module.symvers .tmp_versions -rm -rf protocol/*.o protocol/.*.o.cmd *.markers -rm -rf user -include $(KDIR)/Rules.make 運行的結果 [cpp] [root@root socket]# make //編譯 make -C /lib/modules/2.6.31.5-127.fc12.i686.PAE/build SUBDIRS=/root/study/c_study/socket modules make[1]: Entering directory `/usr/src/kernels/2.6.31.5-127.fc12.i686.PAE' CC [M] /root/study/c_study/socket/module.o LD [M] /root/study/c_study/socket/socketopt.o Building modules, stage 2. MODPOST 1 modules CC /root/study/c_study/socket/socketopt.mod.o LD [M] /root/study/c_study/socket/socketopt.ko make[1]: Leaving directory `/usr/src/kernels/2.6.31.5-127.fc12.i686.PAE' gcc -o user user.c [root@root socket]# [root@root socket]# make insmod //加載 insmod socketopt.ko [root@root socket]# [root@root socket]# lsmod //查看加載成功 Module Size Used by socketopt 1968 0 sunrpc 158388 1 [root@root socket]# dmesg -c //清楚以前的系統信息 [root@root socket]# ./user //運行用戶態 setsockopt: ret = 0. msg = ----------user------------ getsockopt: ret = 0. msg = --------kernel--------- [root@root socket]# dmesg //查看最新生成的日志 sockopt: recv_msg() recv_msg: umsg = ----------user------------. ret = 0 sockopt: send_msg() send_msg: umsg = --------kernel---------. ret = 0. success