mirror of
https://github.com/strongswan/strongswan.git
synced 2025-10-03 00:00:24 -04:00
kernel-netlink: Add simple wrapper for Netlink event sockets
This commit is contained in:
parent
e323539428
commit
cb0bdb847d
@ -79,9 +79,6 @@
|
||||
#define ROUTING_TABLE_PRIO 0
|
||||
#endif
|
||||
|
||||
/** multicast groups (for groups > 31 setsockopt has to be used) */
|
||||
#define nl_group(group) (1 << (group - 1))
|
||||
|
||||
ENUM(rt_msg_names, RTM_NEWLINK, RTM_GETRULE,
|
||||
"RTM_NEWLINK",
|
||||
"RTM_DELLINK",
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2022 Tobias Brunner
|
||||
* Copyright (C) 2008-2023 Tobias Brunner
|
||||
* Copyright (C) 2014 Martin Willi
|
||||
*
|
||||
* Copyright (C) secunet Security Networks AG
|
||||
@ -58,6 +58,7 @@
|
||||
#endif
|
||||
|
||||
typedef struct private_netlink_socket_t private_netlink_socket_t;
|
||||
typedef struct private_netlink_event_socket_t private_netlink_event_socket_t;
|
||||
|
||||
/**
|
||||
* Private variables and functions of netlink_socket_t class.
|
||||
@ -125,6 +126,37 @@ struct private_netlink_socket_t {
|
||||
bool ignore_retransmit_errors;
|
||||
};
|
||||
|
||||
/**
|
||||
* Private data of netlink_event_socket_t class
|
||||
*/
|
||||
struct private_netlink_event_socket_t {
|
||||
|
||||
/**
|
||||
* Public interface
|
||||
*/
|
||||
netlink_event_socket_t public;
|
||||
|
||||
/**
|
||||
* Registered callback
|
||||
*/
|
||||
netlink_event_cb_t cb;
|
||||
|
||||
/**
|
||||
* User data to pass to callback
|
||||
*/
|
||||
void *user;
|
||||
|
||||
/**
|
||||
* Netlink socket
|
||||
*/
|
||||
int socket;
|
||||
|
||||
/**
|
||||
* Buffer size for received Netlink messages
|
||||
*/
|
||||
u_int buflen;
|
||||
};
|
||||
|
||||
/**
|
||||
* #definable hook to simulate request message loss
|
||||
*/
|
||||
@ -700,6 +732,92 @@ netlink_socket_t *netlink_socket_create(int protocol, enum_name_t *names,
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
CALLBACK(watch_event, bool,
|
||||
private_netlink_event_socket_t *this, int fd, watcher_event_t event)
|
||||
{
|
||||
char buf[this->buflen];
|
||||
struct nlmsghdr *hdr = (struct nlmsghdr*)buf;
|
||||
struct sockaddr_nl addr;
|
||||
socklen_t addr_len = sizeof(addr);
|
||||
int len;
|
||||
|
||||
len = recvfrom(this->socket, buf, sizeof(buf), MSG_DONTWAIT,
|
||||
(struct sockaddr*)&addr, &addr_len);
|
||||
if (len < 0)
|
||||
{
|
||||
if (errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR)
|
||||
{
|
||||
DBG1(DBG_KNL, "netlink event read error: %s", strerror(errno));
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
else if (addr.nl_pid != 0)
|
||||
{ /* ignore non-kernel messages */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
while (NLMSG_OK(hdr, len))
|
||||
{
|
||||
this->cb(this->user, hdr);
|
||||
hdr = NLMSG_NEXT(hdr, len);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
METHOD(netlink_event_socket_t, destroy_event, void,
|
||||
private_netlink_event_socket_t *this)
|
||||
{
|
||||
if (this->socket != -1)
|
||||
{
|
||||
lib->watcher->remove(lib->watcher, this->socket);
|
||||
close(this->socket);
|
||||
}
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header
|
||||
*/
|
||||
netlink_event_socket_t *netlink_event_socket_create(int protocol, uint32_t groups,
|
||||
netlink_event_cb_t cb, void *user)
|
||||
{
|
||||
private_netlink_event_socket_t *this;
|
||||
struct sockaddr_nl addr = {
|
||||
.nl_family = AF_NETLINK,
|
||||
.nl_groups = groups,
|
||||
};
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.destroy = _destroy_event,
|
||||
},
|
||||
.cb = cb,
|
||||
.user = user,
|
||||
.buflen = netlink_get_buflen(),
|
||||
);
|
||||
|
||||
this->socket = socket(AF_NETLINK, SOCK_RAW, protocol);
|
||||
if (this->socket == -1)
|
||||
{
|
||||
DBG1(DBG_KNL, "unable to create netlink event socket: %s (%d)",
|
||||
strerror(errno), errno);
|
||||
destroy_event(this);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (bind(this->socket, (struct sockaddr*)&addr, sizeof(addr)))
|
||||
{
|
||||
DBG1(DBG_KNL, "unable to bind netlink event socket: %s (%d)",
|
||||
strerror(errno), errno);
|
||||
destroy_event(this);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lib->watcher->add(lib->watcher, this->socket, WATCHER_READ, watch_event, this);
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header
|
||||
*/
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2022 Tobias Brunner
|
||||
* Copyright (C) 2008-2023 Tobias Brunner
|
||||
*
|
||||
* Copyright (C) secunet Security Networks AG
|
||||
*
|
||||
@ -40,7 +40,16 @@ typedef union {
|
||||
u_char bytes[KERNEL_NETLINK_BUFSIZE];
|
||||
} netlink_buf_t __attribute__((aligned(RTA_ALIGNTO)));
|
||||
|
||||
/**
|
||||
* Callback function for netlink events.
|
||||
*
|
||||
* @param user user data, as passed to constructor
|
||||
* @param hdr received netlink message
|
||||
*/
|
||||
typedef void (*netlink_event_cb_t)(void *user, struct nlmsghdr *hdr);
|
||||
|
||||
typedef struct netlink_socket_t netlink_socket_t;
|
||||
typedef struct netlink_event_socket_t netlink_event_socket_t;
|
||||
|
||||
/**
|
||||
* Wrapper around a netlink socket.
|
||||
@ -80,6 +89,45 @@ struct netlink_socket_t {
|
||||
netlink_socket_t *netlink_socket_create(int protocol, enum_name_t *names,
|
||||
bool parallel);
|
||||
|
||||
/**
|
||||
* Wrapper around a bound netlink event socket.
|
||||
*/
|
||||
struct netlink_event_socket_t {
|
||||
|
||||
/**
|
||||
* Destroy the event socket.
|
||||
*/
|
||||
void (*destroy)(netlink_event_socket_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a netlink_event_socket_t object.
|
||||
*
|
||||
* @param protocol protocol type (e.g. NETLINK_XFRM or NETLINK_ROUTE)
|
||||
* @param groups event groups to bind (use nl_group())
|
||||
* @param cb callback to invoke for each event
|
||||
* @param user user data passed to callback
|
||||
*/
|
||||
netlink_event_socket_t *netlink_event_socket_create(int protocol, uint32_t groups,
|
||||
netlink_event_cb_t cb, void *user);
|
||||
|
||||
/**
|
||||
* Helper to create bitmask for Netlink multicast groups.
|
||||
*
|
||||
* For groups > 31, setsockopt() with NETLINK_ADD_MEMBERSHIP has to be used,
|
||||
* which is currently not supported by the event socket.
|
||||
*/
|
||||
static inline uint32_t nl_group(uint32_t group)
|
||||
{
|
||||
if (group > 31)
|
||||
{
|
||||
DBG1(DBG_KNL, "netlink multicast group %d currently not supported",
|
||||
group);
|
||||
return 0;
|
||||
}
|
||||
return group ? (1 << (group - 1)) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an rtattr and adds it to the given netlink message.
|
||||
*
|
||||
|
Loading…
x
Reference in New Issue
Block a user