最近在做工程时,用到了内核间通信,需要把内核部分得到发送至用户空间。下面给出demo例子:
分为内核部分和用户空间部分:
首先在内核部分增加一个netlink消息类型
#define NETLINK_URL 23创建内核的netlink socket
static struct sock *nlfd;
struct netlink_kernel_cfg cfg = {
.groups = 1, //组播标识,当前只有1个组
.input = netlink_receive,//接收回调函数
};
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);


538

被折叠的 条评论
为什么被折叠?



