在linux kernel中netlink的使用示例
文章目录1、在socket.h中,INET协议族的定义2、以PF_ALG为例,注册一个netlink驱动,在af_alg.c中:3、以PF_ALG为例,写一个userspace调用程序1、在socket.h中,INET协议族的定义/* Supported address families. */#define AF_UNSPEC0#define AF_UNIX1/* Unix domain soc
·
思考
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;
}
更多推荐
已为社区贡献5条内容
所有评论(0)