记不清从哪个kernel版本开始,内核态就不能直接使用系统调用了。当然,socket的系统调用也不能用了。不过好在kernel提供了一组内核态的socket API。在net/socket.c文件中,可以看到这么几个导出符号:
[cpp] view plaincopyprint?
- EXPORT_SYMBOL(kernel_sendmsg);
- EXPORT_SYMBOL(kernel_recvmsg);
- EXPORT_SYMBOL(sock_create_kern);
- EXPORT_SYMBOL(sock_release);
- EXPORT_SYMBOL(kernel_bind);
- EXPORT_SYMBOL(kernel_listen);
- EXPORT_SYMBOL(kernel_accept);
- EXPORT_SYMBOL(kernel_connect);
- EXPORT_SYMBOL(kernel_getsockname);
- EXPORT_SYMBOL(kernel_getpeername);
- EXPORT_SYMBOL(kernel_getsockopt);
- EXPORT_SYMBOL(kernel_setsockopt);
- EXPORT_SYMBOL(kernel_sendpage);
- EXPORT_SYMBOL(kernel_sock_ioctl);
- EXPORT_SYMBOL(kernel_sock_shutdown);
基本上,在用户态的socket的API,在内核态都有对应的API。
下面是一个项目中的代码,socket操作我加了注视。不用去关心代码功能,只要看一下socket部分的操作即可,非常简单。
[cpp] view plaincopyprint?
- #include <linux/socket.h>
- #include <linux/net.h>
- #include <linux/in.h>
- struct fsg_common{
- ....
- struct socket *encrypt_sock;
- struct msghdr encrypt_msg;
- struct sockaddr_in encrypt_servaddr;
- struct data_pkt *encrypt_pkt;
- }
- static int encrypt_socket_init(struct fsg_common *common)
- {
- struct socket *sock;
- int ret;
- char *dst_addr = "111.111.111.111";
- /* init servaddr */
- memset(&common->encrypt_servaddr, 0, sizeof(common->encrypt_servaddr));
- common->encrypt_servaddr.sin_family = AF_INET;
- common->encrypt_servaddr.sin_port = htons(9999);
- //kernel态的IP地址转换函数,有两个函数in4_pton和in6_pton,分别用于IPv4和IPv6
- in4_pton(dst_addr, strlen(dst_addr), (u8*)&common->encrypt_servaddr.sin_addr, '\0', NULL);
- //内核态udp通信地址使用struct msghdr封装
- common->encrypt_msg.msg_name = &common->encrypt_servaddr;
- common->encrypt_msg.msg_namelen = sizeof(common->encrypt_servaddr);
- //创建套接字,类似socket()函数,返回的sock指针就是后面数据传递用的套接字了
- ret = sock_create_kern(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock);
- if (ret < 0 || NULL == sock) {
- ERROR(common, "init encrypt board socket fail\n");
- return ret;
- }
- common->encrypt_sock = sock;
- common->encrypt_pkt = kmalloc(sizeof(struct data_pkt), GFP_KERNEL);
- if (NULL == common->encrypt_pkt)
- return -1;
- return 0;
- }
- static void encrypt_socket_close(struct fsg_common *common)
- {
- //关闭套接字,类似用户态的close()函数
- sock_release(common->encrypt_sock);
- common->encrypt_sock = NULL;
- }
- static int encrypt_data(struct fsg_common *common, u8* data, unsigned int size, loff_t offset)
- {
- struct socket *sock = common->encrypt_sock;
- struct data_pkt *pkt = common->encrypt_pkt;
- struct sockaddr *pservaddr = (struct sockaddr *)&common->encrypt_servaddr;
- int servlen = sizeof(common->encrypt_servaddr);
- if (unlikely(NULL == sock || NULL == pkt || NULL == pservaddr))
- return -1;
- memset(pkt, 0, sizeof(struct data_pkt));
- unsigned int copied_size = 0;
- struct kvec vec;
- struct msghdr msg;
- memset(&msg, 0, sizeof(msg));
- while (copied_size < size) {
- pkt->res=0xffffffff;
- pkt->file_offset = offset;
- memcpy(pkt->data, data + copied_size, SECTOR_SIZE);
- //配置udp发送数据地址及长度
- vec.iov_base = (void *)pkt;
- vec.iov_len = sizeof(struct data_pkt);
- ret = kernel_sendmsg(sock, &common->encrypt_msg, &vec, 1, sizeof(struct data_pkt));
- printk("send data(return :%d):\n", ret);
- //接收udp报文
- ret = kernel_recvmsg(sock, &msg, &vec, 1, sizeof(struct data_pkt), 0);
- printk("recv data(return :%d):\n", ret);
- memcpy(data+copied_size, pkt->data, 512);
- copied_size += 512;
- }
- return 0;