最近在做工程时,用到了内核间通信,需要把内核部分得到发送至用户空间。下面给出demo例子:
分为内核部分和用户空间部分:
首先在内核部分增加一个netlink消息类型
#define NETLINK_URL 23
创建内核的netlink socket
-
static struct sock *nlfd;
-
struct netlink_kernel_cfg cfg = {
-
.groups = 1, //组播标识,当前只有1个组
-
.input = netlink_receive,//接收回调函数
扫描二维码关注公众号,回复: 11149348 查看本文章 -
};
-
nlfd = netlink_kernel_create(net, NETLINK_URL, &cfg);
-
if (nlfd == NULL) {
-
printk(KERN_INFO "netlink kernel create failed\n");
-
return -ENOMEM;
-
}
向用户空间广播报文
-
int send_urlinfo_to_usrspace(struct sk_buff *skb, char *url)
-
{
-
struct sk_buff *info;
-
struct nlmsghdr *nlh;
-
struct packet_info *data;
-
int ret;
-
if(unlikely(nlfd== NULL))
-
return 0;
-
if (!netlink_has_listeners(nlfd, 1))
-
return 0;
-
info = alloc_skb(NLMSG_SPACE(PACKET_INFO_PAYLOAD),GFP_ATOMIC);
-
if(info == NULL)
-
return;
-
skb_put(info, NLMSG_SPACE(PACKET_INFO_PAYLOAD));
-
nlh = (struct nlmsghdr *)info->data;
-
nlh->nlmsg_len = NLMSG_SPACE(PACKET_INFO_PAYLOAD);
-
nlh->nlmsg_pid = 0;
-
nlh->nlmsg_flags = 0;
-
data = NLMSG_DATA(nlh);
-
memset(data, 0, sizeof(struct packet_info));
-
strncpy(data->url, url, sizeof(data->url));
-
fill_mac_and_ip(skb, info);
-
ret = netlink_broadcast(nlfd, info, 0, 1, GFP_ATOMIC);
-
debug("send_urlinfo_to_usrspace, ret = %d, %d, %s\n", ret, info->len, url);
-
return ret;
-
}
接收用户空间的报文
-
static void netlink_receive(struct sk_buff *skb)
-
{
-
int ret;
-
mutex_lock(&receive_mutex);
-
ret = netlink_rcv_skb(skb, &user_rcv_msg);
-
mutex_unlock(&receive_mutex);
-
}
-
static int user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
-
{
-
struct packet_info *data;
-
int err, len;
-
nlh = nlmsg_hdr(skb);
-
len = skb->len;
-
data = nlmsg_data(nlh);
-
switch (nlh->nlmsg_type)
-
{
-
case ADD_URL:
-
if (nlmsg_len(nlh) < sizeof(struct packet_info))
-
return -EINVAL;
-
err = process_usr_info(data->url, strlen(data->url), data->blacklist);
-
break;
-
default:
-
printk(KERN_INFO "recv type error = %d\n", nlh->nlmsg_type);
-
err = -EINVAL;
-
break;
-
}
-
return err;
-
}
用户空间代码:
创建netlink socket,并绑定
-
if((nlsock = socket(PF_NETLINK, SOCK_RAW, NETLINK_URL)) < 0) {
-
printf( "Unable to create apmon socket: %s\n", strerror(errno));
-
return -1;
-
}
-
memset(&addr, 0, sizeof(addr));
-
addr.nl_family = AF_NETLINK;
-
addr.nl_pid = 0;
-
addr.nl_groups = 1;
-
if (bind(nlsock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
-
perror("bind");
-
}
接收部分,报文缓存在pbf中
-
static int netlink_recv(void *pbf, int maxlen)
-
{
-
struct sockaddr_nl dest_addr;
-
struct iovec iov;
-
struct msghdr hdr;
-
memset(pbf, 0, sizeof(struct nlmsghdr) + sizeof(struct packet_info));
-
memset(&dest_addr, 0, sizeof(dest_addr));
-
memset(&iov, 0, sizeof(iov));
-
memset(&hdr, 0, sizeof(hdr));
-
iov.iov_base = pbf;
-
iov.iov_len = maxlen;
-
hdr.msg_name = (void *)&dest_addr;
-
hdr.msg_namelen = sizeof(dest_addr);
-
hdr.msg_iov = &iov;
-
hdr.msg_iovlen = 1;
-
return recvmsg(nlsock, &hdr, 0);
-
}
发送报文至内核
-
struct nlmsghdr nlh = {0};
-
struct sockaddr_nl snl;
-
memset (&snl, 0, sizeof snl);
-
snl.nl_family = AF_NETLINK;
-
struct req req_ = {0};
-
req_.nlh.nlmsg_len = sizeof(struct req);
-
req_.nlh.nlmsg_type = 0x11;
-
req_.nlh.nlmsg_flags = NLM_F_REQUEST;
-
req_.nlh.nlmsg_pid = 0;
-
req_.nlh.nlmsg_seq = 0;
-
req_.info.blacklist = 0;
-
strcpy(req_.info.url, r->info.url);
-
ret = sendto(nlsock, (void*)&req_, sizeof(struct req), 0 , (struct sockaddr *) &snl, sizeof snl);
-
if (ret < 0)
-
perror("sendto");
-
else printf("send len %d\n", ret);