22#include <netlink-private/netlink.h>
23#include <netlink-private/socket.h>
24#include <netlink-private/utils.h>
25#include <netlink/netlink.h>
26#include <netlink/utils.h>
27#include <netlink/handlers.h>
28#include <netlink/msg.h>
29#include <netlink/attr.h>
30#include <linux/socket.h>
102 struct sockaddr_nl local = { 0 };
106 flags |= SOCK_CLOEXEC;
110 return -NLE_BAD_SOCK;
112 sk->s_fd = socket(AF_NETLINK, SOCK_RAW | flags, protocol);
115 NL_DBG(4,
"nl_connect(%p): socket() failed with %d (%s)\n", sk, errsv,
116 nl_strerror_l(errsv));
117 err = -nl_syserr2nlerr(errsv);
125 if (_nl_socket_is_local_port_unspecified (sk)) {
127 uint32_t used_ports[32] = { 0 };
134 _nl_socket_set_local_port_no_release (sk, 0);
138 port = _nl_socket_set_local_port_no_release(sk, 1);
142 err = bind(sk->s_fd, (
struct sockaddr*) &sk->s_local,
143 sizeof(sk->s_local));
150 if (errsv == EADDRINUSE) {
151 NL_DBG(4,
"nl_connect(%p): local port %u already in use. Retry.\n", sk, (
unsigned) port);
152 _nl_socket_used_ports_set(used_ports, port);
154 NL_DBG(4,
"nl_connect(%p): bind() for port %u failed with %d (%s)\n",
155 sk, (
unsigned) port, errsv, nl_strerror_l(errsv));
156 _nl_socket_used_ports_release_all(used_ports);
157 err = -nl_syserr2nlerr(errsv);
161 _nl_socket_used_ports_release_all(used_ports);
164 err = bind(sk->s_fd, (
struct sockaddr*) &sk->s_local,
165 sizeof(sk->s_local));
168 NL_DBG(4,
"nl_connect(%p): bind() failed with %d (%s)\n",
169 sk, errsv, nl_strerror_l(errsv));
170 err = -nl_syserr2nlerr(errsv);
175 addrlen =
sizeof(local);
176 err = getsockname(sk->s_fd, (
struct sockaddr *) &local,
179 NL_DBG(4,
"nl_connect(%p): getsockname() failed with %d (%s)\n",
180 sk, errno, nl_strerror_l(errno));
181 err = -nl_syserr2nlerr(errno);
185 if (addrlen !=
sizeof(local)) {
190 if (local.nl_family != AF_NETLINK) {
191 err = -NLE_AF_NOSUPPORT;
195 if (sk->s_local.nl_pid != local.nl_pid) {
201 sk->s_proto = protocol;
205 if (sk->s_fd != -1) {
264int nl_sendto(
struct nl_sock *sk,
void *buf,
size_t size)
272 return -NLE_BAD_SOCK;
274 ret = sendto(sk->s_fd, buf, size, 0, (
struct sockaddr *)
275 &sk->s_peer,
sizeof(sk->s_peer));
277 NL_DBG(4,
"nl_sendto(%p): sendto() failed with %d (%s)\n",
278 sk, errno, nl_strerror_l(errno));
279 return -nl_syserr2nlerr(errno);
321int nl_sendmsg(
struct nl_sock *sk,
struct nl_msg *msg,
struct msghdr *hdr)
327 return -NLE_BAD_SOCK;
329 nlmsg_set_src(msg, &sk->s_local);
336 ret = sendmsg(sk->s_fd, hdr, 0);
338 NL_DBG(4,
"nl_sendmsg(%p): sendmsg() failed with %d (%s)\n",
339 sk, errno, nl_strerror_l(errno));
340 return -nl_syserr2nlerr(errno);
343 NL_DBG(4,
"sent %d bytes\n", ret);
367int nl_send_iovec(
struct nl_sock *sk,
struct nl_msg *msg,
struct iovec *iov,
unsigned iovlen)
369 struct sockaddr_nl *dst;
371 struct msghdr hdr = {
372 .msg_name = (
void *) &sk->s_peer,
373 .msg_namelen =
sizeof(
struct sockaddr_nl),
375 .msg_iovlen = iovlen,
377 char buf[CMSG_SPACE(
sizeof(
struct ucred))];
382 dst = nlmsg_get_dst(msg);
383 if (dst->nl_family == AF_NETLINK)
387 creds = nlmsg_get_creds(msg);
389 struct cmsghdr *cmsg;
391 hdr.msg_control = buf;
392 hdr.msg_controllen =
sizeof(buf);
394 cmsg = CMSG_FIRSTHDR(&hdr);
395 cmsg->cmsg_level = SOL_SOCKET;
396 cmsg->cmsg_type = SCM_CREDENTIALS;
397 cmsg->cmsg_len = CMSG_LEN(
sizeof(
struct ucred));
398 memcpy(CMSG_DATA(cmsg), creds,
sizeof(
struct ucred));
441int nl_send(
struct nl_sock *sk,
struct nl_msg *msg)
443 struct nl_cb *cb = sk->s_cb;
446 return cb->cb_send_ow(sk, msg);
477 struct nlmsghdr *nlh;
481 nlh->nlmsg_pid = nl_socket_get_local_port(sk);
484 nlh->nlmsg_seq = sk->s_seq_next++;
486 if (msg->nm_protocol == -1)
487 msg->nm_protocol = sk->s_proto;
489 nlh->nlmsg_flags |= NLM_F_REQUEST;
491 if (!(sk->s_flags & NL_NO_AUTO_ACK))
492 nlh->nlmsg_flags |= NLM_F_ACK;
551 return wait_for_ack(sk);
652int nl_recv(
struct nl_sock *sk,
struct sockaddr_nl *nla,
653 unsigned char **buf,
struct ucred **creds)
657 static int page_size = 0;
659 struct msghdr msg = {
660 .msg_name = (
void *) nla,
661 .msg_namelen =
sizeof(
struct sockaddr_nl),
665 struct ucred* tmpcreds = NULL;
671 if ( (sk->s_flags & NL_MSG_PEEK)
672 || (!(sk->s_flags & NL_MSG_PEEK_EXPLICIT) && sk->s_bufsize == 0))
673 flags |= MSG_PEEK | MSG_TRUNC;
676 page_size = getpagesize() * 4;
678 iov.iov_len = sk->s_bufsize ? sk->s_bufsize : page_size;
679 iov.iov_base = malloc(iov.iov_len);
686 if (creds && (sk->s_flags & NL_SOCK_PASSCRED)) {
687 msg.msg_controllen = CMSG_SPACE(
sizeof(
struct ucred));
688 msg.msg_control = malloc(msg.msg_controllen);
689 if (!msg.msg_control) {
696 n = recvmsg(sk->s_fd, &msg, flags);
702 if (errno == EINTR) {
703 NL_DBG(3,
"recvmsg() returned EINTR, retrying\n");
707 NL_DBG(4,
"recvmsg(%p): nl_recv() failed with %d (%s)\n",
708 sk, errno, nl_strerror_l(errno));
709 retval = -nl_syserr2nlerr(errno);
713 if (msg.msg_flags & MSG_CTRUNC) {
716 if (msg.msg_controllen == 0) {
717 retval = -NLE_MSG_TRUNC;
718 NL_DBG(4,
"recvmsg(%p): Received unexpected control data", sk);
722 msg.msg_controllen *= 2;
723 tmp = realloc(msg.msg_control, msg.msg_controllen);
728 msg.msg_control = tmp;
732 if (iov.iov_len < n || (msg.msg_flags & MSG_TRUNC)) {
737 retval = -NLE_MSG_TRUNC;
745 tmp = realloc(iov.iov_base, iov.iov_len);
761 if (msg.msg_namelen !=
sizeof(
struct sockaddr_nl)) {
762 retval = -NLE_NOADDR;
766 if (creds && (sk->s_flags & NL_SOCK_PASSCRED)) {
767 struct cmsghdr *cmsg;
769 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
770 if (cmsg->cmsg_level != SOL_SOCKET)
772 if (cmsg->cmsg_type != SCM_CREDENTIALS)
774 tmpcreds = malloc(
sizeof(*tmpcreds));
779 memcpy(tmpcreds, CMSG_DATA(cmsg),
sizeof(*tmpcreds));
786 free(msg.msg_control);
803#define NL_CB_CALL(cb, type, msg) \
805 err = nl_cb_call(cb, type, msg); \
820static int recvmsgs(
struct nl_sock *sk,
struct nl_cb *cb)
822 int n, err = 0, multipart = 0, interrupted = 0, nrecv = 0;
823 unsigned char *buf = NULL;
824 struct nlmsghdr *hdr;
831 struct sockaddr_nl nla = {0};
832 struct nl_msg *msg = NULL;
833 struct ucred *creds = NULL;
836 NL_DBG(3,
"Attempting to read from %p\n", sk);
838 n = cb->cb_recv_ow(sk, &nla, &buf, &creds);
840 n =
nl_recv(sk, &nla, &buf, &creds);
845 NL_DBG(3,
"recvmsgs(%p): Read %d bytes\n", sk, n);
847 hdr = (
struct nlmsghdr *) buf;
849 NL_DBG(3,
"recvmsgs(%p): Processing valid message...\n", sk);
858 nlmsg_set_proto(msg, sk->s_proto);
859 nlmsg_set_src(msg, &nla);
861 nlmsg_set_creds(msg, creds);
877 }
else if (!(sk->s_flags & NL_NO_AUTO_ACK)) {
878 if (hdr->nlmsg_seq != sk->s_seq_expect) {
882 err = -NLE_SEQ_MISMATCH;
888 if (hdr->nlmsg_type == NLMSG_DONE ||
889 hdr->nlmsg_type == NLMSG_ERROR ||
890 hdr->nlmsg_type == NLMSG_NOOP ||
891 hdr->nlmsg_type == NLMSG_OVERRUN) {
895 NL_DBG(3,
"recvmsgs(%p): Increased expected " \
896 "sequence number to %d\n",
897 sk, sk->s_seq_expect);
900 if (hdr->nlmsg_flags & NLM_F_MULTI)
903 if (hdr->nlmsg_flags & NLM_F_DUMP_INTR) {
917 if (hdr->nlmsg_flags & NLM_F_ACK) {
929 if (hdr->nlmsg_type == NLMSG_DONE) {
939 else if (hdr->nlmsg_type == NLMSG_NOOP) {
949 else if (hdr->nlmsg_type == NLMSG_OVERRUN) {
953 err = -NLE_MSG_OVERFLOW;
959 else if (hdr->nlmsg_type == NLMSG_ERROR) {
962 if (hdr->nlmsg_len <
nlmsg_size(
sizeof(*e))) {
970 err = -NLE_MSG_TRUNC;
973 }
else if (e->error) {
974 NL_DBG(4,
"recvmsgs(%p): RTNETLINK responded with %d (%s)\n",
975 sk, -e->error, nl_strerror_l(-e->error));
979 err = cb->cb_err(&nla, e,
986 err = -nl_syserr2nlerr(e->error);
990 err = -nl_syserr2nlerr(e->error);
1016 goto continue_reading;
1026 err = -NLE_DUMP_INTR;
1048 if (cb->cb_recvmsgs_ow)
1049 return cb->cb_recvmsgs_ow(sk, cb);
1051 return recvmsgs(sk, cb);
1093static int ack_wait_handler(
struct nl_msg *msg,
void *arg)
1125 int (*parser)(
struct nl_cache_ops *,
struct sockaddr_nl *,
1126 struct nlmsghdr *,
struct nl_parser_param *);
1127 struct nl_object *result;
1131static int __store_answer(
struct nl_object *obj,
struct nl_parser_param *p)
1133 struct pickup_param *pp = p->pp_arg;
1144static int __pickup_answer(
struct nl_msg *msg,
void *arg)
1146 struct pickup_param *pp = arg;
1147 struct nl_parser_param parse_arg = {
1148 .pp_cb = __store_answer,
1152 return pp->parser(NULL, &msg->nm_src, msg->nm_nlh, &parse_arg);
1155static int __pickup_answer_syserr(
struct sockaddr_nl *nla,
struct nlmsgerr *nlerr,
void *arg)
1157 *(((
struct pickup_param *) arg)->syserror) = nlerr->error;
1159 return -nl_syserr2nlerr(nlerr->error);
1173 int (*parser)(
struct nl_cache_ops *,
struct sockaddr_nl *,
1174 struct nlmsghdr *,
struct nl_parser_param *),
1175 struct nl_object **result)
1190 int (*parser)(
struct nl_cache_ops *,
struct sockaddr_nl *,
1191 struct nlmsghdr *,
struct nl_parser_param *),
1192 struct nl_object **result,
1197 struct pickup_param pp = {
1208 pp.syserror = syserror;
1216 *result = pp.result;
int nl_cb_set(struct nl_cb *cb, enum nl_cb_type type, enum nl_cb_kind kind, nl_recvmsg_msg_cb_t func, void *arg)
Set up a callback.
struct nl_cb * nl_cb_clone(struct nl_cb *orig)
Clone an existing callback handle.
int nl_cb_err(struct nl_cb *cb, enum nl_cb_kind kind, nl_recvmsg_err_cb_t func, void *arg)
Set up an error callback.
@ NL_STOP
Stop parsing altogether and discard remaining messages.
@ NL_OK
Proceed with whatever would come next.
@ NL_SKIP
Skip this message.
@ NL_CB_SKIPPED
Message wants to be skipped.
@ NL_CB_FINISH
Last message in a series of multi part messages received.
@ NL_CB_MSG_OUT
Called for every message sent out except for nl_sendto()
@ NL_CB_DUMP_INTR
Flag NLM_F_DUMP_INTR is set in message.
@ NL_CB_MSG_IN
Called for every message received.
@ NL_CB_OVERRUN
Report received that data was lost.
@ NL_CB_VALID
Message is valid.
@ NL_CB_ACK
Message is an acknowledgement.
@ NL_CB_SEQ_CHECK
Called instead of internal sequence number checking.
@ NL_CB_SEND_ACK
Sending of an acknowledge message has been requested.
@ NL_CB_INVALID
Message is malformed and invalid.
@ NL_CB_CUSTOM
Customized handler specified by the user.
int nlmsg_ok(const struct nlmsghdr *nlh, int remaining)
check if the netlink message fits into the remaining bytes
#define NL_AUTO_PORT
Will cause the netlink port to be set to the port assigned to the netlink icoket ust before sending t...
struct nlmsghdr * nlmsg_hdr(struct nl_msg *n)
Return actual netlink message.
struct nl_msg * nlmsg_alloc_simple(int nlmsgtype, int flags)
Allocate a new netlink message.
void * nlmsg_data(const struct nlmsghdr *nlh)
Return pointer to message payload.
struct nlmsghdr * nlmsg_next(struct nlmsghdr *nlh, int *remaining)
next netlink message in message stream
struct nl_msg * nlmsg_convert(struct nlmsghdr *hdr)
Convert a netlink message received from a netlink socket to a nl_msg.
void nlmsg_free(struct nl_msg *msg)
Release a reference from an netlink message.
#define NL_AUTO_SEQ
May be used to refer to a sequence number which should be automatically set just before sending the m...
int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad)
Append data to tail of a netlink message.
int nlmsg_size(int payload)
Calculates size of netlink message based on payload length.
void nl_object_get(struct nl_object *obj)
Acquire a reference on a object.
int nl_send_iovec(struct nl_sock *sk, struct nl_msg *msg, struct iovec *iov, unsigned iovlen)
Transmit Netlink message (taking IO vector)
int nl_send(struct nl_sock *sk, struct nl_msg *msg)
Transmit Netlink message.
int nl_recv(struct nl_sock *sk, struct sockaddr_nl *nla, unsigned char **buf, struct ucred **creds)
Receive data from netlink socket.
int nl_recvmsgs_default(struct nl_sock *sk)
Receive a set of message from a netlink socket using handlers in nl_sock.
int nl_send_auto(struct nl_sock *sk, struct nl_msg *msg)
Finalize and transmit Netlink message.
void nl_complete_msg(struct nl_sock *sk, struct nl_msg *msg)
Finalize Netlink message.
int nl_send_sync(struct nl_sock *sk, struct nl_msg *msg)
Finalize and transmit Netlink message and wait for ACK or error message.
void nl_auto_complete(struct nl_sock *sk, struct nl_msg *msg)
int nl_connect(struct nl_sock *sk, int protocol)
Create file descriptor and bind socket.
int nl_recvmsgs_report(struct nl_sock *sk, struct nl_cb *cb)
Receive a set of messages from a netlink socket and report parsed messages.
int nl_pickup_keep_syserr(struct nl_sock *sk, int(*parser)(struct nl_cache_ops *, struct sockaddr_nl *, struct nlmsghdr *, struct nl_parser_param *), struct nl_object **result, int *syserror)
Pickup netlink answer, parse is and return object with preserving system error.
int nl_send_auto_complete(struct nl_sock *sk, struct nl_msg *msg)
int nl_recvmsgs(struct nl_sock *sk, struct nl_cb *cb)
Receive a set of messages from a netlink socket.
int nl_pickup(struct nl_sock *sk, int(*parser)(struct nl_cache_ops *, struct sockaddr_nl *, struct nlmsghdr *, struct nl_parser_param *), struct nl_object **result)
Pickup netlink answer, parse is and return object.
void nl_close(struct nl_sock *sk)
Close Netlink socket.
int nl_sendmsg(struct nl_sock *sk, struct nl_msg *msg, struct msghdr *hdr)
Transmit Netlink message using sendmsg()
int nl_sendto(struct nl_sock *sk, void *buf, size_t size)
Transmit raw data over Netlink socket.
int nl_wait_for_ack(struct nl_sock *sk)
Wait for ACK.
int nl_send_simple(struct nl_sock *sk, int type, int flags, void *buf, size_t size)
Construct and transmit a Netlink message.
void nl_socket_set_local_port(struct nl_sock *sk, uint32_t port)
Set local port of socket.
int nl_socket_set_buffer_size(struct nl_sock *sk, int rxbuf, int txbuf)
Set socket buffer size of netlink socket.