netlink 通信广播demo

最近在做工程时,用到了内核间通信,需要把内核部分得到发送至用户空间。下面给出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);



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值