基于内核模块的测试代码编写(3)

发表于:2014-08-03来源:uml.org.cn作者:fvceww点击数: 标签:测试代码
向内核中注册/proc下文件的调用是 create_proc_entry,创建中需要指定文件名,访问权限和父节点名,返回为指向 proc_dir_entry结构的指针。通过该返回指针,可

  向内核中注册/proc下文件的调用是 create_proc_entry,创建中需要指定文件名,访问权限和父节点名,返回为指向 proc_dir_entry结构的指针。通过该返回指针,可以进一步修改文件的用户id,组id,绑定的内核数据等;但最为关键的是可以指定用户读或写该文件时,在内核中被执行的回调函数。下面是一个向proc文件系统中注册新文件的示例:

static int __init proc_module_init(void){
entry = create_proc_entry("astring", 0644, myprocroot);
if (entry) {
entry->data = &string_var;
entry->read_proc = &string_read_proc;
entry->write_proc = &string_write_proc;
}
return 0
}
static void __exit procfs_exam_exit(void){
remove_proc_entry("astring", myprocroot);
remove_proc_entry("myproctest", NULL);
}
//read proc
int string_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data){
count = sprintf(page, "%s", (char *)data);
return count;
}
//write proc
int string_write_proc(struct file *file, const char __user *buffer,
unsigned long count, void *data){
if (count > STR_MAX_SIZE) {
count = 255;
}
copy_from_user(data, buffer, count);
return count;
} 

  4.5 af_netlink

  netlink是一种特殊的socket,用于用户态与内核态的双向通讯。在实现用户和内核交互的各种方式中,netlink的主要特点得意于它继承了 socket的一些基本特性,包括异步通讯,多播,双向性,不需要额外的文件。在用户态中,netlink的使用与标准的socket API相同,在内核态,则需要使用专门的API。下面介绍具体的使用方法:

  在用户态中,首先通过要创建socket,其中指定domain必须为AF_NETLINK,协议为通常SOCK_RAW,协议类型为NETLINK_GENERIC或其它自定义类型

  sd = socket(AF_NETLINK, SOCK_RAW,NETLINK_GENERIC);

  然后通过bind绑定源端的地址,地址结构定义如下,其中nl_family为AF_NETLINK,nl_pad 目前无用填充0,nl_pid为进程id,若为0代表内核;nl_groups用于组播时的组号。

struct sockaddr_nl {    
sa_family_t    nl_family;    
unsigned short nl_pad;  
  __u32         nl_pid;    
__u32          nl_groups;    
} saddr;  

bind(sd, (struct sockaddr*)&saddr, sizeof(saddr));

  通过sendmsg可以发送消息msg到指定的地址。

  ret = sendmsg(sd, &msg, 0);

  在msg的所有元素中,msg_name需要指向一个 sockaddr_nl 结构的首地址,用来表示发送的目的端的地址,如果是发送到内核,其中的nl_pid字段置为0;msg_iov是要发送消息集合的向量,向量中的每一项代表一条消息。每一项指向数据的首部为一个nlmsghdr结构,其字段定义了该条消息长度,消息类型,序号,发送者进程id等;随后跟随的是消息的主体数据部分。 当要接收消息时,通过recvmsg可以获得类似的消息向量,从而获得数据及发送者等有关信息。

  在内核态,通过netlink_kernel_create可以在内核中新建socket结构并注册接收到消息的回调函数input,其原型为:

  struct sock * netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len));

  当接收到消息时,回调函数input中的sk指针就指向了刚刚创建的socket在内核中的结构,通过对该结构的访问,可以获得要接收的数据。一种基本的input实现如下:

void input (struct sock *sk, int len) {
struct sk_buff *skb;    
struct nlmsghdr *nlh = NULL;    
u8 *data = NULL;    
while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {    
nlh = (struct nlmsghdr *)skb->data;    
data = NLMSG_DATA(nlh);    
}       
}

  此外,sock_release是在内核中释放socket的方法;而通过netlink_unicast和netlink_broadcast可以在内核中令netlink socket发送数据,具体的方法可以参考 http://blog.chinaunix.net/u/19940/showart_144827.html

  4.6 其它方法

  以上所介绍的方法具有一个共同特点,它们不需要较高版本的内核支持,添加新的功能不需要重新编译内核或替代内核中的原有功能。当然,还有一些其它方法,可能会需要内核版本或重新编译内核等条件的支持,但同样能达到用户态和内核态交互这一目标,比如修改或添加新的系统调用,或利用sysfs,relayfs 等特殊的虚拟文件系统。这里不再一一介绍。

原文转自:http://www.uml.org.cn/Test/201210242.asp