/*
- * Copyright (C) 2008-2022 Tobias Brunner
+ * Copyright (C) 2008-2023 Tobias Brunner
* Copyright (C) 2014 Martin Willi
*
* Copyright (C) secunet Security Networks AG
#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.
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
*/
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
*/
/*
- * Copyright (C) 2008-2022 Tobias Brunner
+ * Copyright (C) 2008-2023 Tobias Brunner
*
* Copyright (C) secunet Security Networks AG
*
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.
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.
*