[other]-在linux kernel中netlink的使用示例

思考

userspace和kernel space通信的方式有哪些? 应用程序是如何调用到驱动的?

[答案]内核与用户空间通信有很多种通信方式,netlink是其中一种,其余的还有/proc、ioctl、sockopt、共享内存等等。netlink的特点是异步全双工

1、在socket.h中,INET协议族的定义

如果我们要实现一个新的netlink驱动,在后面添加一个PF协议号即可

/* Supported address families. */
#define AF_UNSPEC	0
#define AF_UNIX		1	/* Unix domain sockets 		*/
#define AF_LOCAL	1	/* POSIX name for AF_UNIX	*/
#define AF_INET		2	/* Internet IP Protocol 	*/
#define AF_AX25		3	/* Amateur Radio AX.25 		*/
#define AF_IPX		4	/* Novell IPX 			*/
#define AF_APPLETALK	5	/* AppleTalk DDP 		*/
#define AF_NETROM	6	/* Amateur Radio NET/ROM 	*/
#define AF_BRIDGE	7	/* Multiprotocol bridge 	*/
#define AF_ATMPVC	8	/* ATM PVCs			*/
#define AF_X25		9	/* Reserved for X.25 project 	*/
#define AF_INET6	10	/* IP version 6			*/
#define AF_ROSE		11	/* Amateur Radio X.25 PLP	*/
#define AF_DECnet	12	/* Reserved for DECnet project	*/
#define AF_NETBEUI	13	/* Reserved for 802.2LLC project*/
#define AF_SECURITY	14	/* Security callback pseudo AF */
#define AF_KEY		15      /* PF_KEY key management API */
#define AF_NETLINK	16
#define AF_ROUTE	AF_NETLINK /* Alias to emulate 4.4BSD */
#define AF_PACKET	17	/* Packet family		*/
#define AF_ASH		18	/* Ash				*/
#define AF_ECONET	19	/* Acorn Econet			*/
#define AF_ATMSVC	20	/* ATM SVCs			*/
#define AF_RDS		21	/* RDS sockets 			*/
#define AF_SNA		22	/* Linux SNA Project (nutters!) */
#define AF_IRDA		23	/* IRDA sockets			*/
#define AF_PPPOX	24	/* PPPoX sockets		*/
#define AF_WANPIPE	25	/* Wanpipe API Sockets */
#define AF_LLC		26	/* Linux LLC			*/
#define AF_IB		27	/* Native InfiniBand address	*/
#define AF_MPLS		28	/* MPLS */
#define AF_CAN		29	/* Controller Area Network      */
#define AF_TIPC		30	/* TIPC sockets			*/
#define AF_BLUETOOTH	31	/* Bluetooth sockets 		*/
#define AF_IUCV		32	/* IUCV sockets			*/
#define AF_RXRPC	33	/* RxRPC sockets 		*/
#define AF_ISDN		34	/* mISDN sockets 		*/
#define AF_PHONET	35	/* Phonet sockets		*/
#define AF_IEEE802154	36	/* IEEE802154 sockets		*/
#define AF_CAIF		37	/* CAIF sockets			*/
#define AF_ALG		38	/* Algorithm sockets		*/
#define AF_NFC		39	/* NFC sockets			*/
#define AF_VSOCK	40	/* vSockets			*/
#define AF_MAX		41	/* For now.. */

/* Protocol families, same as address families. */
#define PF_UNSPEC	AF_UNSPEC
#define PF_UNIX		AF_UNIX
#define PF_LOCAL	AF_LOCAL
#define PF_INET		AF_INET
#define PF_AX25		AF_AX25
#define PF_IPX		AF_IPX
#define PF_APPLETALK	AF_APPLETALK
#define	PF_NETROM	AF_NETROM
#define PF_BRIDGE	AF_BRIDGE
#define PF_ATMPVC	AF_ATMPVC
#define PF_X25		AF_X25
#define PF_INET6	AF_INET6
#define PF_ROSE		AF_ROSE
#define PF_DECnet	AF_DECnet
#define PF_NETBEUI	AF_NETBEUI
#define PF_SECURITY	AF_SECURITY
#define PF_KEY		AF_KEY
#define PF_NETLINK	AF_NETLINK
#define PF_ROUTE	AF_ROUTE
#define PF_PACKET	AF_PACKET
#define PF_ASH		AF_ASH
#define PF_ECONET	AF_ECONET
#define PF_ATMSVC	AF_ATMSVC
#define PF_RDS		AF_RDS
#define PF_SNA		AF_SNA
#define PF_IRDA		AF_IRDA
#define PF_PPPOX	AF_PPPOX
#define PF_WANPIPE	AF_WANPIPE
#define PF_LLC		AF_LLC
#define PF_IB		AF_IB
#define PF_MPLS		AF_MPLS
#define PF_CAN		AF_CAN
#define PF_TIPC		AF_TIPC
#define PF_BLUETOOTH	AF_BLUETOOTH
#define PF_IUCV		AF_IUCV
#define PF_RXRPC	AF_RXRPC
#define PF_ISDN		AF_ISDN
#define PF_PHONET	AF_PHONET
#define PF_IEEE802154	AF_IEEE802154
#define PF_CAIF		AF_CAIF
#define PF_ALG		AF_ALG
#define PF_NFC		AF_NFC
#define PF_VSOCK	AF_VSOCK
#define PF_MAX		AF_MAX

/* Maximum queue length specifiable by listen.  */
#define SOMAXCONN	128

2、以PF_ALG为例,注册一个netlink驱动,在af_alg.c中:

static const struct net_proto_family alg_family = {
	.family	=	PF_ALG,
	.create	=	alg_create,
	.owner	=	THIS_MODULE,
};

static int __init af_alg_init(void)
{
......
	err = sock_register(&alg_family);
......
}

在alg_create中,将alg_proto_ops和alg_proto绑定在一起,然后实现各个ops子函数
static const struct proto_ops alg_proto_ops = {
	.family		=	PF_ALG,
	.owner		=	THIS_MODULE,

	.connect	=	sock_no_connect,
	.socketpair	=	sock_no_socketpair,
	.getname	=	sock_no_getname,
	.ioctl		=	sock_no_ioctl,
	.listen		=	sock_no_listen,
	.shutdown	=	sock_no_shutdown,
	.getsockopt	=	sock_no_getsockopt,
	.mmap		=	sock_no_mmap,
	.sendpage	=	sock_no_sendpage,
	.sendmsg	=	sock_no_sendmsg,
	.recvmsg	=	sock_no_recvmsg,
	.poll		=	sock_no_poll,

	.bind		=	alg_bind,
	.release	=	af_alg_release,
	.setsockopt	=	alg_setsockopt,
	.accept		=	alg_accept,
};

static struct proto alg_proto = {
	.name			= "ALG",
	.owner			= THIS_MODULE,
	.memory_allocated	= &alg_memory_allocated,
	.obj_size		= sizeof(struct alg_sock),
};

3、以PF_ALG为例,写一个userspace调用程序

aes_128_cbc_oper —>linux_af_alg_skcipher—>linux_af_alg_socket

建立一个socket会话的大概流程:

socket(AF_ALG,...)
bind()
setsockopt
accept
sendmsg
recvmsg

相关代码

static int linux_af_alg_socket(const char *type, const char *name)
{
	struct sockaddr_alg sa;
	int s;

	s = socket(AF_ALG, SOCK_SEQPACKET, 0);
	if (s < 0) {
		LogErr("%s: Failed to open AF_ALG socket: %s\n",
			   __func__, strerror(errno));
		return -1;
	}

	os_memset(&sa, 0, sizeof(sa));
	sa.salg_family = AF_ALG;
	os_strlcpy((char *) sa.salg_type, type, sizeof(sa.salg_type));
	os_strlcpy((char *) sa.salg_name, name, sizeof(sa.salg_name));
	if (bind(s, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
		LogErr("%s: Failed to bind AF_ALG socket(%s,%s): %s\n",__func__, (char *) sa.salg_type, (char *) sa.salg_name, strerror(errno));
		close(s);
		return -1;
	}

	return s;
}

static struct linux_af_alg_skcipher *linux_af_alg_skcipher(const char *alg, const u8 *key, size_t key_len)
{
	struct linux_af_alg_skcipher *skcipher;

	skcipher = os_zalloc(sizeof(*skcipher));
	if (!skcipher)
		goto fail;
	skcipher->t = -1;

	skcipher->s = linux_af_alg_socket(TYPE_NAME, alg);
	if (skcipher->s < 0)
		goto fail;

	if (setsockopt(skcipher->s, SOL_ALG, ALG_SET_KEY, key, key_len) < 0) {
		LogErr("%s: setsockopt(ALG_SET_KEY) failed: %s\n",
			   __func__, strerror(errno));
		goto fail;
	}

	skcipher->t = accept(skcipher->s, NULL, NULL);
	if (skcipher->t < 0) {
		LogErr("%s: accept on AF_ALG socket failed: %s\n",
			   __func__, strerror(errno));
		goto fail;
	}

	return skcipher;
fail:
	linux_af_alg_skcipher_deinit(skcipher);
	return NULL;
}

static int aes_128_cbc_oper(char *alg_name, const u8 *key,size_t key_len, int enc, const u8 *iv, u8 *data, size_t data_len)
{
	struct linux_af_alg_skcipher *skcipher;
	char buf[100];
	struct iovec io[1];
	struct msghdr msg;
	struct cmsghdr *hdr;
	ssize_t ret;
	u32 *op;
	struct af_alg_iv *alg_iv;
	size_t iv_len = AES_BLOCK_SIZE;

	skcipher = linux_af_alg_skcipher(alg_name, key, key_len);//alg_name = "__cbc-aes-asr-ce"
	if (!skcipher)
		return -1;

	io[0].iov_base = (void *) data;
	io[0].iov_len = data_len;
	os_memset(&msg, 0, sizeof(msg));
	os_memset(buf, 0, sizeof(buf));
	msg.msg_control = buf;
	msg.msg_controllen = CMSG_SPACE(sizeof(u32)) +
		CMSG_SPACE(sizeof(*alg_iv) + iv_len);
	msg.msg_iov = io;
	msg.msg_iovlen = 1;

	hdr = CMSG_FIRSTHDR(&msg);
	hdr->cmsg_level = SOL_ALG;
	hdr->cmsg_type = ALG_SET_OP;
	hdr->cmsg_len = CMSG_LEN(sizeof(u32));
	op = (u32 *) CMSG_DATA(hdr);
	*op = enc ? ALG_OP_ENCRYPT : ALG_OP_DECRYPT;

	hdr = CMSG_NXTHDR(&msg, hdr);
	hdr->cmsg_level = SOL_ALG;
	hdr->cmsg_type = ALG_SET_IV;
	hdr->cmsg_len = CMSG_SPACE(sizeof(*alg_iv) + iv_len);
	alg_iv = (struct af_alg_iv *) CMSG_DATA(hdr);
	if(NULL != iv){
		alg_iv->ivlen = iv_len;
		os_memcpy(alg_iv->iv, iv, iv_len);
	}else
	{
		alg_iv->ivlen = 0;
	}

	ret = sendmsg(skcipher->t, &msg, 0);
	if (ret < 0) {
		LogErr("%s: sendmsg failed: %s\n",
			   __func__, strerror(errno));
		linux_af_alg_skcipher_deinit(skcipher);
		return -1;
	}

	ret = recvmsg(skcipher->t, &msg, 0);
	if (ret < 0) {
		LogErr("%s: recvmsg failed: %s\n",
			   __func__, strerror(errno));
		linux_af_alg_skcipher_deinit(skcipher);
		return -1;
	}
	if ((size_t) ret < data_len) {
		LogErr(
			   "%s: recvmsg not return full data (%d/%d)\n",
			   __func__, (int) ret, (int) data_len);
		linux_af_alg_skcipher_deinit(skcipher);
		return -1;
	}

	//s_to_binary(data,data_len);
	linux_af_alg_skcipher_deinit(skcipher);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_42135087/article/details/107313886