144d362409d5469aed47d19e7908d19bd194493aThomas Graf/* 244d362409d5469aed47d19e7908d19bd194493aThomas Graf * lib/nl.c Core Netlink Interface 344d362409d5469aed47d19e7908d19bd194493aThomas Graf * 444d362409d5469aed47d19e7908d19bd194493aThomas Graf * This library is free software; you can redistribute it and/or 544d362409d5469aed47d19e7908d19bd194493aThomas Graf * modify it under the terms of the GNU Lesser General Public 644d362409d5469aed47d19e7908d19bd194493aThomas Graf * License as published by the Free Software Foundation version 2.1 744d362409d5469aed47d19e7908d19bd194493aThomas Graf * of the License. 844d362409d5469aed47d19e7908d19bd194493aThomas Graf * 98a3efffa5b3fde252675239914118664d36a2c24Thomas Graf * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> 1044d362409d5469aed47d19e7908d19bd194493aThomas Graf */ 1144d362409d5469aed47d19e7908d19bd194493aThomas Graf 1244d362409d5469aed47d19e7908d19bd194493aThomas Graf/** 136782b6f709d03877a5661a4c8d8f8bd1b461f43fThomas Graf * @defgroup core Core 1444d362409d5469aed47d19e7908d19bd194493aThomas Graf * 154fd5f7cb6627a22bd9f228b4259d5106ae39d535Thomas Graf * @details 1644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @par 1) Connecting the socket 1744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @code 1844d362409d5469aed47d19e7908d19bd194493aThomas Graf * // Bind and connect the socket to a protocol, NETLINK_ROUTE in this example. 191155370f520cb64657e25153255cf7dc1424317fThomas Graf * nl_connect(sk, NETLINK_ROUTE); 2044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @endcode 2144d362409d5469aed47d19e7908d19bd194493aThomas Graf * 2244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @par 2) Sending data 2344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @code 2444d362409d5469aed47d19e7908d19bd194493aThomas Graf * // The most rudimentary method is to use nl_sendto() simply pushing 2544d362409d5469aed47d19e7908d19bd194493aThomas Graf * // a piece of data to the other netlink peer. This method is not 2644d362409d5469aed47d19e7908d19bd194493aThomas Graf * // recommended. 2744d362409d5469aed47d19e7908d19bd194493aThomas Graf * const char buf[] = { 0x01, 0x02, 0x03, 0x04 }; 281155370f520cb64657e25153255cf7dc1424317fThomas Graf * nl_sendto(sk, buf, sizeof(buf)); 2944d362409d5469aed47d19e7908d19bd194493aThomas Graf * 3044d362409d5469aed47d19e7908d19bd194493aThomas Graf * // A more comfortable interface is nl_send() taking a pointer to 3144d362409d5469aed47d19e7908d19bd194493aThomas Graf * // a netlink message. 3244d362409d5469aed47d19e7908d19bd194493aThomas Graf * struct nl_msg *msg = my_msg_builder(); 331155370f520cb64657e25153255cf7dc1424317fThomas Graf * nl_send(sk, nlmsg_hdr(msg)); 3444d362409d5469aed47d19e7908d19bd194493aThomas Graf * 3544d362409d5469aed47d19e7908d19bd194493aThomas Graf * // nl_sendmsg() provides additional control over the sendmsg() message 3644d362409d5469aed47d19e7908d19bd194493aThomas Graf * // header in order to allow more specific addressing of multiple peers etc. 3744d362409d5469aed47d19e7908d19bd194493aThomas Graf * struct msghdr hdr = { ... }; 381155370f520cb64657e25153255cf7dc1424317fThomas Graf * nl_sendmsg(sk, nlmsg_hdr(msg), &hdr); 3944d362409d5469aed47d19e7908d19bd194493aThomas Graf * 4044d362409d5469aed47d19e7908d19bd194493aThomas Graf * // You're probably too lazy to fill out the netlink pid, sequence number 4144d362409d5469aed47d19e7908d19bd194493aThomas Graf * // and message flags all the time. nl_send_auto_complete() automatically 4244d362409d5469aed47d19e7908d19bd194493aThomas Graf * // extends your message header as needed with an appropriate sequence 431155370f520cb64657e25153255cf7dc1424317fThomas Graf * // number, the netlink pid stored in the netlink socket and the message 442bdee95a765457fe4206b89d51974ae56e75c588Thomas Graf * // flags NLM_F_REQUEST and NLM_F_ACK (if not disabled in the socket) 451155370f520cb64657e25153255cf7dc1424317fThomas Graf * nl_send_auto_complete(sk, nlmsg_hdr(msg)); 4644d362409d5469aed47d19e7908d19bd194493aThomas Graf * 4744d362409d5469aed47d19e7908d19bd194493aThomas Graf * // Simple protocols don't require the complex message construction interface 4844d362409d5469aed47d19e7908d19bd194493aThomas Graf * // and may favour nl_send_simple() to easly send a bunch of payload 4944d362409d5469aed47d19e7908d19bd194493aThomas Graf * // encapsulated in a netlink message header. 501155370f520cb64657e25153255cf7dc1424317fThomas Graf * nl_send_simple(sk, MY_MSG_TYPE, 0, buf, sizeof(buf)); 5144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @endcode 5244d362409d5469aed47d19e7908d19bd194493aThomas Graf * 5344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @par 3) Receiving data 5444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @code 5544d362409d5469aed47d19e7908d19bd194493aThomas Graf * // nl_recv() receives a single message allocating a buffer for the message 5644d362409d5469aed47d19e7908d19bd194493aThomas Graf * // content and gives back the pointer to you. 5744d362409d5469aed47d19e7908d19bd194493aThomas Graf * struct sockaddr_nl peer; 5844d362409d5469aed47d19e7908d19bd194493aThomas Graf * unsigned char *msg; 591155370f520cb64657e25153255cf7dc1424317fThomas Graf * nl_recv(sk, &peer, &msg); 6044d362409d5469aed47d19e7908d19bd194493aThomas Graf * 6144d362409d5469aed47d19e7908d19bd194493aThomas Graf * // nl_recvmsgs() receives a bunch of messages until the callback system 6244d362409d5469aed47d19e7908d19bd194493aThomas Graf * // orders it to state, usually after receving a compolete multi part 6344d362409d5469aed47d19e7908d19bd194493aThomas Graf * // message series. 641155370f520cb64657e25153255cf7dc1424317fThomas Graf * nl_recvmsgs(sk, my_callback_configuration); 6544d362409d5469aed47d19e7908d19bd194493aThomas Graf * 6644d362409d5469aed47d19e7908d19bd194493aThomas Graf * // nl_recvmsgs_default() acts just like nl_recvmsg() but uses the callback 671155370f520cb64657e25153255cf7dc1424317fThomas Graf * // configuration stored in the socket. 681155370f520cb64657e25153255cf7dc1424317fThomas Graf * nl_recvmsgs_default(sk); 6944d362409d5469aed47d19e7908d19bd194493aThomas Graf * 7044d362409d5469aed47d19e7908d19bd194493aThomas Graf * // In case you want to wait for the ACK to be recieved that you requested 7144d362409d5469aed47d19e7908d19bd194493aThomas Graf * // with your latest message, you can call nl_wait_for_ack() 721155370f520cb64657e25153255cf7dc1424317fThomas Graf * nl_wait_for_ack(sk); 7344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @endcode 7444d362409d5469aed47d19e7908d19bd194493aThomas Graf * 7544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @par 4) Closing 7644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @code 7744d362409d5469aed47d19e7908d19bd194493aThomas Graf * // Close the socket first to release kernel memory 781155370f520cb64657e25153255cf7dc1424317fThomas Graf * nl_close(sk); 7944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @endcode 8044d362409d5469aed47d19e7908d19bd194493aThomas Graf * 8144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{ 8244d362409d5469aed47d19e7908d19bd194493aThomas Graf */ 8344d362409d5469aed47d19e7908d19bd194493aThomas Graf 8444d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink-local.h> 8544d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/netlink.h> 8644d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/utils.h> 8744d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/handlers.h> 8844d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/msg.h> 8944d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/attr.h> 9044d362409d5469aed47d19e7908d19bd194493aThomas Graf 9144d362409d5469aed47d19e7908d19bd194493aThomas Graf/** 9244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Connection Management 9344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{ 9444d362409d5469aed47d19e7908d19bd194493aThomas Graf */ 9544d362409d5469aed47d19e7908d19bd194493aThomas Graf 9644d362409d5469aed47d19e7908d19bd194493aThomas Graf/** 9744d362409d5469aed47d19e7908d19bd194493aThomas Graf * Create and connect netlink socket. 981155370f520cb64657e25153255cf7dc1424317fThomas Graf * @arg sk Netlink socket. 9944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg protocol Netlink protocol to use. 10044d362409d5469aed47d19e7908d19bd194493aThomas Graf * 10144d362409d5469aed47d19e7908d19bd194493aThomas Graf * Creates a netlink socket using the specified protocol, binds the socket 10244d362409d5469aed47d19e7908d19bd194493aThomas Graf * and issues a connection attempt. 10344d362409d5469aed47d19e7908d19bd194493aThomas Graf * 10444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return 0 on success or a negative error code. 10544d362409d5469aed47d19e7908d19bd194493aThomas Graf */ 1061155370f520cb64657e25153255cf7dc1424317fThomas Grafint nl_connect(struct nl_sock *sk, int protocol) 10744d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 10844d362409d5469aed47d19e7908d19bd194493aThomas Graf int err; 10944d362409d5469aed47d19e7908d19bd194493aThomas Graf socklen_t addrlen; 11044d362409d5469aed47d19e7908d19bd194493aThomas Graf 1111155370f520cb64657e25153255cf7dc1424317fThomas Graf sk->s_fd = socket(AF_NETLINK, SOCK_RAW, protocol); 1121155370f520cb64657e25153255cf7dc1424317fThomas Graf if (sk->s_fd < 0) { 1138a3efffa5b3fde252675239914118664d36a2c24Thomas Graf err = -nl_syserr2nlerr(errno); 11491c330aae51cd6cd44ad730e10dc82724998c810Thomas Graf goto errout; 11591c330aae51cd6cd44ad730e10dc82724998c810Thomas Graf } 11644d362409d5469aed47d19e7908d19bd194493aThomas Graf 1171155370f520cb64657e25153255cf7dc1424317fThomas Graf if (!(sk->s_flags & NL_SOCK_BUFSIZE_SET)) { 118664e1deaeb59ad9db0b2eeec613cf8a93551f567Thomas Graf err = nl_socket_set_buffer_size(sk, 0, 0); 11944d362409d5469aed47d19e7908d19bd194493aThomas Graf if (err < 0) 12091c330aae51cd6cd44ad730e10dc82724998c810Thomas Graf goto errout; 12144d362409d5469aed47d19e7908d19bd194493aThomas Graf } 12244d362409d5469aed47d19e7908d19bd194493aThomas Graf 1231155370f520cb64657e25153255cf7dc1424317fThomas Graf err = bind(sk->s_fd, (struct sockaddr*) &sk->s_local, 1241155370f520cb64657e25153255cf7dc1424317fThomas Graf sizeof(sk->s_local)); 12591c330aae51cd6cd44ad730e10dc82724998c810Thomas Graf if (err < 0) { 1268a3efffa5b3fde252675239914118664d36a2c24Thomas Graf err = -nl_syserr2nlerr(errno); 12791c330aae51cd6cd44ad730e10dc82724998c810Thomas Graf goto errout; 12891c330aae51cd6cd44ad730e10dc82724998c810Thomas Graf } 12944d362409d5469aed47d19e7908d19bd194493aThomas Graf 1301155370f520cb64657e25153255cf7dc1424317fThomas Graf addrlen = sizeof(sk->s_local); 1311155370f520cb64657e25153255cf7dc1424317fThomas Graf err = getsockname(sk->s_fd, (struct sockaddr *) &sk->s_local, 13244d362409d5469aed47d19e7908d19bd194493aThomas Graf &addrlen); 13391c330aae51cd6cd44ad730e10dc82724998c810Thomas Graf if (err < 0) { 1348a3efffa5b3fde252675239914118664d36a2c24Thomas Graf err = -nl_syserr2nlerr(errno); 13591c330aae51cd6cd44ad730e10dc82724998c810Thomas Graf goto errout; 13691c330aae51cd6cd44ad730e10dc82724998c810Thomas Graf } 13744d362409d5469aed47d19e7908d19bd194493aThomas Graf 1381155370f520cb64657e25153255cf7dc1424317fThomas Graf if (addrlen != sizeof(sk->s_local)) { 1398a3efffa5b3fde252675239914118664d36a2c24Thomas Graf err = -NLE_NOADDR; 14091c330aae51cd6cd44ad730e10dc82724998c810Thomas Graf goto errout; 14191c330aae51cd6cd44ad730e10dc82724998c810Thomas Graf } 14244d362409d5469aed47d19e7908d19bd194493aThomas Graf 1431155370f520cb64657e25153255cf7dc1424317fThomas Graf if (sk->s_local.nl_family != AF_NETLINK) { 1448a3efffa5b3fde252675239914118664d36a2c24Thomas Graf err = -NLE_AF_NOSUPPORT; 14591c330aae51cd6cd44ad730e10dc82724998c810Thomas Graf goto errout; 14691c330aae51cd6cd44ad730e10dc82724998c810Thomas Graf } 14744d362409d5469aed47d19e7908d19bd194493aThomas Graf 1481155370f520cb64657e25153255cf7dc1424317fThomas Graf sk->s_proto = protocol; 14944d362409d5469aed47d19e7908d19bd194493aThomas Graf 15044d362409d5469aed47d19e7908d19bd194493aThomas Graf return 0; 15191c330aae51cd6cd44ad730e10dc82724998c810Thomas Graferrout: 1521155370f520cb64657e25153255cf7dc1424317fThomas Graf close(sk->s_fd); 1531155370f520cb64657e25153255cf7dc1424317fThomas Graf sk->s_fd = -1; 15491c330aae51cd6cd44ad730e10dc82724998c810Thomas Graf 15591c330aae51cd6cd44ad730e10dc82724998c810Thomas Graf return err; 15644d362409d5469aed47d19e7908d19bd194493aThomas Graf} 15744d362409d5469aed47d19e7908d19bd194493aThomas Graf 15844d362409d5469aed47d19e7908d19bd194493aThomas Graf/** 15944d362409d5469aed47d19e7908d19bd194493aThomas Graf * Close/Disconnect netlink socket. 1601155370f520cb64657e25153255cf7dc1424317fThomas Graf * @arg sk Netlink socket. 16144d362409d5469aed47d19e7908d19bd194493aThomas Graf */ 1621155370f520cb64657e25153255cf7dc1424317fThomas Grafvoid nl_close(struct nl_sock *sk) 16344d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 1641155370f520cb64657e25153255cf7dc1424317fThomas Graf if (sk->s_fd >= 0) { 1651155370f520cb64657e25153255cf7dc1424317fThomas Graf close(sk->s_fd); 1661155370f520cb64657e25153255cf7dc1424317fThomas Graf sk->s_fd = -1; 16744d362409d5469aed47d19e7908d19bd194493aThomas Graf } 16844d362409d5469aed47d19e7908d19bd194493aThomas Graf 1691155370f520cb64657e25153255cf7dc1424317fThomas Graf sk->s_proto = 0; 17044d362409d5469aed47d19e7908d19bd194493aThomas Graf} 17144d362409d5469aed47d19e7908d19bd194493aThomas Graf 17244d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */ 17344d362409d5469aed47d19e7908d19bd194493aThomas Graf 17444d362409d5469aed47d19e7908d19bd194493aThomas Graf/** 17544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Send 17644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{ 17744d362409d5469aed47d19e7908d19bd194493aThomas Graf */ 17844d362409d5469aed47d19e7908d19bd194493aThomas Graf 17944d362409d5469aed47d19e7908d19bd194493aThomas Graf/** 18044d362409d5469aed47d19e7908d19bd194493aThomas Graf * Send raw data over netlink socket. 1811155370f520cb64657e25153255cf7dc1424317fThomas Graf * @arg sk Netlink socket. 18244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg buf Data buffer. 18344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg size Size of data buffer. 18444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return Number of characters written on success or a negative error code. 18544d362409d5469aed47d19e7908d19bd194493aThomas Graf */ 1861155370f520cb64657e25153255cf7dc1424317fThomas Grafint nl_sendto(struct nl_sock *sk, void *buf, size_t size) 18744d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 18844d362409d5469aed47d19e7908d19bd194493aThomas Graf int ret; 18944d362409d5469aed47d19e7908d19bd194493aThomas Graf 1901155370f520cb64657e25153255cf7dc1424317fThomas Graf ret = sendto(sk->s_fd, buf, size, 0, (struct sockaddr *) 1911155370f520cb64657e25153255cf7dc1424317fThomas Graf &sk->s_peer, sizeof(sk->s_peer)); 19244d362409d5469aed47d19e7908d19bd194493aThomas Graf if (ret < 0) 1938a3efffa5b3fde252675239914118664d36a2c24Thomas Graf return -nl_syserr2nlerr(errno); 19444d362409d5469aed47d19e7908d19bd194493aThomas Graf 19544d362409d5469aed47d19e7908d19bd194493aThomas Graf return ret; 19644d362409d5469aed47d19e7908d19bd194493aThomas Graf} 19744d362409d5469aed47d19e7908d19bd194493aThomas Graf 19844d362409d5469aed47d19e7908d19bd194493aThomas Graf/** 19944d362409d5469aed47d19e7908d19bd194493aThomas Graf * Send netlink message with control over sendmsg() message header. 2001155370f520cb64657e25153255cf7dc1424317fThomas Graf * @arg sk Netlink socket. 20144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg msg Netlink message to be sent. 20244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg hdr Sendmsg() message header. 20344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return Number of characters sent on sucess or a negative error code. 20444d362409d5469aed47d19e7908d19bd194493aThomas Graf */ 2051155370f520cb64657e25153255cf7dc1424317fThomas Grafint nl_sendmsg(struct nl_sock *sk, struct nl_msg *msg, struct msghdr *hdr) 20644d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 20744d362409d5469aed47d19e7908d19bd194493aThomas Graf struct nl_cb *cb; 20844d362409d5469aed47d19e7908d19bd194493aThomas Graf int ret; 20944d362409d5469aed47d19e7908d19bd194493aThomas Graf 2101155370f520cb64657e25153255cf7dc1424317fThomas Graf nlmsg_set_src(msg, &sk->s_local); 21144d362409d5469aed47d19e7908d19bd194493aThomas Graf 2121155370f520cb64657e25153255cf7dc1424317fThomas Graf cb = sk->s_cb; 21344d362409d5469aed47d19e7908d19bd194493aThomas Graf if (cb->cb_set[NL_CB_MSG_OUT]) 21444d362409d5469aed47d19e7908d19bd194493aThomas Graf if (nl_cb_call(cb, NL_CB_MSG_OUT, msg) != NL_OK) 21544d362409d5469aed47d19e7908d19bd194493aThomas Graf return 0; 21644d362409d5469aed47d19e7908d19bd194493aThomas Graf 2171155370f520cb64657e25153255cf7dc1424317fThomas Graf ret = sendmsg(sk->s_fd, hdr, 0); 21844d362409d5469aed47d19e7908d19bd194493aThomas Graf if (ret < 0) 2198a3efffa5b3fde252675239914118664d36a2c24Thomas Graf return -nl_syserr2nlerr(errno); 22044d362409d5469aed47d19e7908d19bd194493aThomas Graf 22127c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto NL_DBG(4, "sent %d bytes\n", ret); 22244d362409d5469aed47d19e7908d19bd194493aThomas Graf return ret; 22344d362409d5469aed47d19e7908d19bd194493aThomas Graf} 22444d362409d5469aed47d19e7908d19bd194493aThomas Graf 22544d362409d5469aed47d19e7908d19bd194493aThomas Graf 22644d362409d5469aed47d19e7908d19bd194493aThomas Graf/** 22744d362409d5469aed47d19e7908d19bd194493aThomas Graf * Send netlink message. 2281155370f520cb64657e25153255cf7dc1424317fThomas Graf * @arg sk Netlink socket. 22944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg msg Netlink message to be sent. 23027c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto * @arg iov iovec to be sent. 23127c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto * @arg iovlen number of struct iovec to be sent. 23244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @see nl_sendmsg() 23344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return Number of characters sent on success or a negative error code. 23444d362409d5469aed47d19e7908d19bd194493aThomas Graf */ 235256d7e723c0ff402422d3501866e9301b3f64c0fThomas Grafint nl_send_iovec(struct nl_sock *sk, struct nl_msg *msg, struct iovec *iov, unsigned iovlen) 23644d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 23744d362409d5469aed47d19e7908d19bd194493aThomas Graf struct sockaddr_nl *dst; 23844d362409d5469aed47d19e7908d19bd194493aThomas Graf struct ucred *creds; 23944d362409d5469aed47d19e7908d19bd194493aThomas Graf struct msghdr hdr = { 2401155370f520cb64657e25153255cf7dc1424317fThomas Graf .msg_name = (void *) &sk->s_peer, 24144d362409d5469aed47d19e7908d19bd194493aThomas Graf .msg_namelen = sizeof(struct sockaddr_nl), 24227c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto .msg_iov = iov, 24327c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto .msg_iovlen = iovlen, 24444d362409d5469aed47d19e7908d19bd194493aThomas Graf }; 24544d362409d5469aed47d19e7908d19bd194493aThomas Graf 24644d362409d5469aed47d19e7908d19bd194493aThomas Graf /* Overwrite destination if specified in the message itself, defaults 2471155370f520cb64657e25153255cf7dc1424317fThomas Graf * to the peer address of the socket. 24844d362409d5469aed47d19e7908d19bd194493aThomas Graf */ 24944d362409d5469aed47d19e7908d19bd194493aThomas Graf dst = nlmsg_get_dst(msg); 25044d362409d5469aed47d19e7908d19bd194493aThomas Graf if (dst->nl_family == AF_NETLINK) 25144d362409d5469aed47d19e7908d19bd194493aThomas Graf hdr.msg_name = dst; 25244d362409d5469aed47d19e7908d19bd194493aThomas Graf 25344d362409d5469aed47d19e7908d19bd194493aThomas Graf /* Add credentials if present. */ 25444d362409d5469aed47d19e7908d19bd194493aThomas Graf creds = nlmsg_get_creds(msg); 25544d362409d5469aed47d19e7908d19bd194493aThomas Graf if (creds != NULL) { 25644d362409d5469aed47d19e7908d19bd194493aThomas Graf char buf[CMSG_SPACE(sizeof(struct ucred))]; 25744d362409d5469aed47d19e7908d19bd194493aThomas Graf struct cmsghdr *cmsg; 25844d362409d5469aed47d19e7908d19bd194493aThomas Graf 25944d362409d5469aed47d19e7908d19bd194493aThomas Graf hdr.msg_control = buf; 26044d362409d5469aed47d19e7908d19bd194493aThomas Graf hdr.msg_controllen = sizeof(buf); 26144d362409d5469aed47d19e7908d19bd194493aThomas Graf 26244d362409d5469aed47d19e7908d19bd194493aThomas Graf cmsg = CMSG_FIRSTHDR(&hdr); 26344d362409d5469aed47d19e7908d19bd194493aThomas Graf cmsg->cmsg_level = SOL_SOCKET; 26444d362409d5469aed47d19e7908d19bd194493aThomas Graf cmsg->cmsg_type = SCM_CREDENTIALS; 26544d362409d5469aed47d19e7908d19bd194493aThomas Graf cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred)); 26644d362409d5469aed47d19e7908d19bd194493aThomas Graf memcpy(CMSG_DATA(cmsg), creds, sizeof(struct ucred)); 26744d362409d5469aed47d19e7908d19bd194493aThomas Graf } 26844d362409d5469aed47d19e7908d19bd194493aThomas Graf 2691155370f520cb64657e25153255cf7dc1424317fThomas Graf return nl_sendmsg(sk, msg, &hdr); 27044d362409d5469aed47d19e7908d19bd194493aThomas Graf} 27144d362409d5469aed47d19e7908d19bd194493aThomas Graf 27227c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto 27327c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto 27444d362409d5469aed47d19e7908d19bd194493aThomas Graf/** 27527c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto* Send netlink message. 27627c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto* @arg sk Netlink socket. 27727c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto* @arg msg Netlink message to be sent. 27827c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto* @see nl_sendmsg() 27927c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto* @return Number of characters sent on success or a negative error code. 28027c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto*/ 28127c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramotoint nl_send(struct nl_sock *sk, struct nl_msg *msg) 28227c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto{ 28327c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto struct iovec iov = { 28427c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto .iov_base = (void *) nlmsg_hdr(msg), 28527c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto .iov_len = nlmsg_hdr(msg)->nlmsg_len, 28627c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto }; 28727c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto 28827c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto return nl_send_iovec(sk, msg, &iov, 1); 28927c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto} 29027c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto 29127c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramotovoid nl_auto_complete(struct nl_sock *sk, struct nl_msg *msg) 29244d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 29344d362409d5469aed47d19e7908d19bd194493aThomas Graf struct nlmsghdr *nlh; 29444d362409d5469aed47d19e7908d19bd194493aThomas Graf 29544d362409d5469aed47d19e7908d19bd194493aThomas Graf nlh = nlmsg_hdr(msg); 29644d362409d5469aed47d19e7908d19bd194493aThomas Graf if (nlh->nlmsg_pid == 0) 2971155370f520cb64657e25153255cf7dc1424317fThomas Graf nlh->nlmsg_pid = sk->s_local.nl_pid; 29844d362409d5469aed47d19e7908d19bd194493aThomas Graf 29944d362409d5469aed47d19e7908d19bd194493aThomas Graf if (nlh->nlmsg_seq == 0) 3001155370f520cb64657e25153255cf7dc1424317fThomas Graf nlh->nlmsg_seq = sk->s_seq_next++; 30144d362409d5469aed47d19e7908d19bd194493aThomas Graf 30244d362409d5469aed47d19e7908d19bd194493aThomas Graf if (msg->nm_protocol == -1) 3031155370f520cb64657e25153255cf7dc1424317fThomas Graf msg->nm_protocol = sk->s_proto; 30427c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto 3052bdee95a765457fe4206b89d51974ae56e75c588Thomas Graf nlh->nlmsg_flags |= NLM_F_REQUEST; 3062bdee95a765457fe4206b89d51974ae56e75c588Thomas Graf 3072bdee95a765457fe4206b89d51974ae56e75c588Thomas Graf if (!(sk->s_flags & NL_NO_AUTO_ACK)) 3082bdee95a765457fe4206b89d51974ae56e75c588Thomas Graf nlh->nlmsg_flags |= NLM_F_ACK; 30927c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto} 31027c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto 31127c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto/** 31227c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto * Send netlink message and check & extend header values as needed. 31327c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto * @arg sk Netlink socket. 31427c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto * @arg msg Netlink message to be sent. 31527c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto * 31627c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto * Checks the netlink message \c nlh for completness and extends it 31727c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto * as required before sending it out. Checked fields include pid, 31827c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto * sequence nr, and flags. 31927c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto * 32027c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto * @see nl_send() 32127c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto * @return Number of characters sent or a negative error code. 32227c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto */ 32327c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramotoint nl_send_auto_complete(struct nl_sock *sk, struct nl_msg *msg) 32427c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto{ 32527c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto struct nl_cb *cb = sk->s_cb; 32627c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto 32727c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto nl_auto_complete(sk, msg); 32844d362409d5469aed47d19e7908d19bd194493aThomas Graf 32944d362409d5469aed47d19e7908d19bd194493aThomas Graf if (cb->cb_send_ow) 3301155370f520cb64657e25153255cf7dc1424317fThomas Graf return cb->cb_send_ow(sk, msg); 33144d362409d5469aed47d19e7908d19bd194493aThomas Graf else 3321155370f520cb64657e25153255cf7dc1424317fThomas Graf return nl_send(sk, msg); 33344d362409d5469aed47d19e7908d19bd194493aThomas Graf} 33444d362409d5469aed47d19e7908d19bd194493aThomas Graf 33544d362409d5469aed47d19e7908d19bd194493aThomas Graf/** 33644d362409d5469aed47d19e7908d19bd194493aThomas Graf * Send simple netlink message using nl_send_auto_complete() 3371155370f520cb64657e25153255cf7dc1424317fThomas Graf * @arg sk Netlink socket. 33844d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg type Netlink message type. 33944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg flags Netlink message flags. 34044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg buf Data buffer. 34144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg size Size of data buffer. 34244d362409d5469aed47d19e7908d19bd194493aThomas Graf * 34344d362409d5469aed47d19e7908d19bd194493aThomas Graf * Builds a netlink message with the specified type and flags and 34444d362409d5469aed47d19e7908d19bd194493aThomas Graf * appends the specified data as payload to the message. 34544d362409d5469aed47d19e7908d19bd194493aThomas Graf * 34644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @see nl_send_auto_complete() 34744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return Number of characters sent on success or a negative error code. 34844d362409d5469aed47d19e7908d19bd194493aThomas Graf */ 3491155370f520cb64657e25153255cf7dc1424317fThomas Grafint nl_send_simple(struct nl_sock *sk, int type, int flags, void *buf, 35044d362409d5469aed47d19e7908d19bd194493aThomas Graf size_t size) 35144d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 35244d362409d5469aed47d19e7908d19bd194493aThomas Graf int err; 35344d362409d5469aed47d19e7908d19bd194493aThomas Graf struct nl_msg *msg; 35444d362409d5469aed47d19e7908d19bd194493aThomas Graf 35544d362409d5469aed47d19e7908d19bd194493aThomas Graf msg = nlmsg_alloc_simple(type, flags); 35644d362409d5469aed47d19e7908d19bd194493aThomas Graf if (!msg) 3578a3efffa5b3fde252675239914118664d36a2c24Thomas Graf return -NLE_NOMEM; 35844d362409d5469aed47d19e7908d19bd194493aThomas Graf 3596de17f3308cfd53ad922d144a1b28ddd962d6678Thomas Graf if (buf && size) { 3606de17f3308cfd53ad922d144a1b28ddd962d6678Thomas Graf err = nlmsg_append(msg, buf, size, NLMSG_ALIGNTO); 3616de17f3308cfd53ad922d144a1b28ddd962d6678Thomas Graf if (err < 0) 3626de17f3308cfd53ad922d144a1b28ddd962d6678Thomas Graf goto errout; 3636de17f3308cfd53ad922d144a1b28ddd962d6678Thomas Graf } 3646de17f3308cfd53ad922d144a1b28ddd962d6678Thomas Graf 36544d362409d5469aed47d19e7908d19bd194493aThomas Graf 3661155370f520cb64657e25153255cf7dc1424317fThomas Graf err = nl_send_auto_complete(sk, msg); 3676de17f3308cfd53ad922d144a1b28ddd962d6678Thomas Graferrout: 36844d362409d5469aed47d19e7908d19bd194493aThomas Graf nlmsg_free(msg); 36944d362409d5469aed47d19e7908d19bd194493aThomas Graf 37044d362409d5469aed47d19e7908d19bd194493aThomas Graf return err; 37144d362409d5469aed47d19e7908d19bd194493aThomas Graf} 37244d362409d5469aed47d19e7908d19bd194493aThomas Graf 37344d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */ 37444d362409d5469aed47d19e7908d19bd194493aThomas Graf 37544d362409d5469aed47d19e7908d19bd194493aThomas Graf/** 37644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Receive 37744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{ 37844d362409d5469aed47d19e7908d19bd194493aThomas Graf */ 37944d362409d5469aed47d19e7908d19bd194493aThomas Graf 38044d362409d5469aed47d19e7908d19bd194493aThomas Graf/** 38144d362409d5469aed47d19e7908d19bd194493aThomas Graf * Receive data from netlink socket 3821155370f520cb64657e25153255cf7dc1424317fThomas Graf * @arg sk Netlink socket. 38344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg nla Destination pointer for peer's netlink address. 38444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg buf Destination pointer for message content. 38544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg creds Destination pointer for credentials. 38644d362409d5469aed47d19e7908d19bd194493aThomas Graf * 38744d362409d5469aed47d19e7908d19bd194493aThomas Graf * Receives a netlink message, allocates a buffer in \c *buf and 38844d362409d5469aed47d19e7908d19bd194493aThomas Graf * stores the message content. The peer's netlink address is stored 38944d362409d5469aed47d19e7908d19bd194493aThomas Graf * in \c *nla. The caller is responsible for freeing the buffer allocated 39044d362409d5469aed47d19e7908d19bd194493aThomas Graf * in \c *buf if a positive value is returned. Interruped system calls 39144d362409d5469aed47d19e7908d19bd194493aThomas Graf * are handled by repeating the read. The input buffer size is determined 39244d362409d5469aed47d19e7908d19bd194493aThomas Graf * by peeking before the actual read is done. 39344d362409d5469aed47d19e7908d19bd194493aThomas Graf * 39444d362409d5469aed47d19e7908d19bd194493aThomas Graf * A non-blocking sockets causes the function to return immediately with 39544d362409d5469aed47d19e7908d19bd194493aThomas Graf * a return value of 0 if no data is available. 39644d362409d5469aed47d19e7908d19bd194493aThomas Graf * 39744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return Number of octets read, 0 on EOF or a negative error code. 39844d362409d5469aed47d19e7908d19bd194493aThomas Graf */ 3991155370f520cb64657e25153255cf7dc1424317fThomas Grafint nl_recv(struct nl_sock *sk, struct sockaddr_nl *nla, 40044d362409d5469aed47d19e7908d19bd194493aThomas Graf unsigned char **buf, struct ucred **creds) 40144d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 40244d362409d5469aed47d19e7908d19bd194493aThomas Graf int n; 40344d362409d5469aed47d19e7908d19bd194493aThomas Graf int flags = 0; 40444d362409d5469aed47d19e7908d19bd194493aThomas Graf static int page_size = 0; 40544d362409d5469aed47d19e7908d19bd194493aThomas Graf struct iovec iov; 40644d362409d5469aed47d19e7908d19bd194493aThomas Graf struct msghdr msg = { 40744d362409d5469aed47d19e7908d19bd194493aThomas Graf .msg_name = (void *) nla, 40844d362409d5469aed47d19e7908d19bd194493aThomas Graf .msg_namelen = sizeof(struct sockaddr_nl), 40944d362409d5469aed47d19e7908d19bd194493aThomas Graf .msg_iov = &iov, 41044d362409d5469aed47d19e7908d19bd194493aThomas Graf .msg_iovlen = 1, 41144d362409d5469aed47d19e7908d19bd194493aThomas Graf .msg_control = NULL, 41244d362409d5469aed47d19e7908d19bd194493aThomas Graf .msg_controllen = 0, 41344d362409d5469aed47d19e7908d19bd194493aThomas Graf .msg_flags = 0, 41444d362409d5469aed47d19e7908d19bd194493aThomas Graf }; 41544d362409d5469aed47d19e7908d19bd194493aThomas Graf struct cmsghdr *cmsg; 41644d362409d5469aed47d19e7908d19bd194493aThomas Graf 4171155370f520cb64657e25153255cf7dc1424317fThomas Graf if (sk->s_flags & NL_MSG_PEEK) 41844d362409d5469aed47d19e7908d19bd194493aThomas Graf flags |= MSG_PEEK; 41944d362409d5469aed47d19e7908d19bd194493aThomas Graf 42044d362409d5469aed47d19e7908d19bd194493aThomas Graf if (page_size == 0) 42144d362409d5469aed47d19e7908d19bd194493aThomas Graf page_size = getpagesize(); 42244d362409d5469aed47d19e7908d19bd194493aThomas Graf 42344d362409d5469aed47d19e7908d19bd194493aThomas Graf iov.iov_len = page_size; 424b7c5bf98c4079304f78242d8b3c65451efc12b77Thomas Graf iov.iov_base = *buf = malloc(iov.iov_len); 42544d362409d5469aed47d19e7908d19bd194493aThomas Graf 4261155370f520cb64657e25153255cf7dc1424317fThomas Graf if (sk->s_flags & NL_SOCK_PASSCRED) { 42744d362409d5469aed47d19e7908d19bd194493aThomas Graf msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred)); 42844d362409d5469aed47d19e7908d19bd194493aThomas Graf msg.msg_control = calloc(1, msg.msg_controllen); 42944d362409d5469aed47d19e7908d19bd194493aThomas Graf } 43044d362409d5469aed47d19e7908d19bd194493aThomas Grafretry: 43144d362409d5469aed47d19e7908d19bd194493aThomas Graf 4321155370f520cb64657e25153255cf7dc1424317fThomas Graf n = recvmsg(sk->s_fd, &msg, flags); 43344d362409d5469aed47d19e7908d19bd194493aThomas Graf if (!n) 43444d362409d5469aed47d19e7908d19bd194493aThomas Graf goto abort; 43544d362409d5469aed47d19e7908d19bd194493aThomas Graf else if (n < 0) { 43644d362409d5469aed47d19e7908d19bd194493aThomas Graf if (errno == EINTR) { 43744d362409d5469aed47d19e7908d19bd194493aThomas Graf NL_DBG(3, "recvmsg() returned EINTR, retrying\n"); 43844d362409d5469aed47d19e7908d19bd194493aThomas Graf goto retry; 43944d362409d5469aed47d19e7908d19bd194493aThomas Graf } else if (errno == EAGAIN) { 44044d362409d5469aed47d19e7908d19bd194493aThomas Graf NL_DBG(3, "recvmsg() returned EAGAIN, aborting\n"); 44144d362409d5469aed47d19e7908d19bd194493aThomas Graf goto abort; 44244d362409d5469aed47d19e7908d19bd194493aThomas Graf } else { 44344d362409d5469aed47d19e7908d19bd194493aThomas Graf free(msg.msg_control); 44444d362409d5469aed47d19e7908d19bd194493aThomas Graf free(*buf); 4458a3efffa5b3fde252675239914118664d36a2c24Thomas Graf return -nl_syserr2nlerr(errno); 44644d362409d5469aed47d19e7908d19bd194493aThomas Graf } 44744d362409d5469aed47d19e7908d19bd194493aThomas Graf } 44844d362409d5469aed47d19e7908d19bd194493aThomas Graf 44944d362409d5469aed47d19e7908d19bd194493aThomas Graf if (iov.iov_len < n || 45044d362409d5469aed47d19e7908d19bd194493aThomas Graf msg.msg_flags & MSG_TRUNC) { 45144d362409d5469aed47d19e7908d19bd194493aThomas Graf /* Provided buffer is not long enough, enlarge it 45244d362409d5469aed47d19e7908d19bd194493aThomas Graf * and try again. */ 45344d362409d5469aed47d19e7908d19bd194493aThomas Graf iov.iov_len *= 2; 45444d362409d5469aed47d19e7908d19bd194493aThomas Graf iov.iov_base = *buf = realloc(*buf, iov.iov_len); 45544d362409d5469aed47d19e7908d19bd194493aThomas Graf goto retry; 45644d362409d5469aed47d19e7908d19bd194493aThomas Graf } else if (msg.msg_flags & MSG_CTRUNC) { 45744d362409d5469aed47d19e7908d19bd194493aThomas Graf msg.msg_controllen *= 2; 45844d362409d5469aed47d19e7908d19bd194493aThomas Graf msg.msg_control = realloc(msg.msg_control, msg.msg_controllen); 45944d362409d5469aed47d19e7908d19bd194493aThomas Graf goto retry; 46044d362409d5469aed47d19e7908d19bd194493aThomas Graf } else if (flags != 0) { 46144d362409d5469aed47d19e7908d19bd194493aThomas Graf /* Buffer is big enough, do the actual reading */ 46244d362409d5469aed47d19e7908d19bd194493aThomas Graf flags = 0; 46344d362409d5469aed47d19e7908d19bd194493aThomas Graf goto retry; 46444d362409d5469aed47d19e7908d19bd194493aThomas Graf } 46544d362409d5469aed47d19e7908d19bd194493aThomas Graf 46644d362409d5469aed47d19e7908d19bd194493aThomas Graf if (msg.msg_namelen != sizeof(struct sockaddr_nl)) { 46744d362409d5469aed47d19e7908d19bd194493aThomas Graf free(msg.msg_control); 46844d362409d5469aed47d19e7908d19bd194493aThomas Graf free(*buf); 4698a3efffa5b3fde252675239914118664d36a2c24Thomas Graf return -NLE_NOADDR; 47044d362409d5469aed47d19e7908d19bd194493aThomas Graf } 47144d362409d5469aed47d19e7908d19bd194493aThomas Graf 47244d362409d5469aed47d19e7908d19bd194493aThomas Graf for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { 47344d362409d5469aed47d19e7908d19bd194493aThomas Graf if (cmsg->cmsg_level == SOL_SOCKET && 47444d362409d5469aed47d19e7908d19bd194493aThomas Graf cmsg->cmsg_type == SCM_CREDENTIALS) { 47544d362409d5469aed47d19e7908d19bd194493aThomas Graf *creds = calloc(1, sizeof(struct ucred)); 47644d362409d5469aed47d19e7908d19bd194493aThomas Graf memcpy(*creds, CMSG_DATA(cmsg), sizeof(struct ucred)); 47744d362409d5469aed47d19e7908d19bd194493aThomas Graf break; 47844d362409d5469aed47d19e7908d19bd194493aThomas Graf } 47944d362409d5469aed47d19e7908d19bd194493aThomas Graf } 48044d362409d5469aed47d19e7908d19bd194493aThomas Graf 48144d362409d5469aed47d19e7908d19bd194493aThomas Graf free(msg.msg_control); 48244d362409d5469aed47d19e7908d19bd194493aThomas Graf return n; 48344d362409d5469aed47d19e7908d19bd194493aThomas Graf 48444d362409d5469aed47d19e7908d19bd194493aThomas Grafabort: 48544d362409d5469aed47d19e7908d19bd194493aThomas Graf free(msg.msg_control); 48644d362409d5469aed47d19e7908d19bd194493aThomas Graf free(*buf); 48744d362409d5469aed47d19e7908d19bd194493aThomas Graf return 0; 48844d362409d5469aed47d19e7908d19bd194493aThomas Graf} 48944d362409d5469aed47d19e7908d19bd194493aThomas Graf 49044d362409d5469aed47d19e7908d19bd194493aThomas Graf#define NL_CB_CALL(cb, type, msg) \ 49144d362409d5469aed47d19e7908d19bd194493aThomas Grafdo { \ 49244d362409d5469aed47d19e7908d19bd194493aThomas Graf err = nl_cb_call(cb, type, msg); \ 49344d362409d5469aed47d19e7908d19bd194493aThomas Graf switch (err) { \ 49444d362409d5469aed47d19e7908d19bd194493aThomas Graf case NL_OK: \ 49544d362409d5469aed47d19e7908d19bd194493aThomas Graf err = 0; \ 49644d362409d5469aed47d19e7908d19bd194493aThomas Graf break; \ 49744d362409d5469aed47d19e7908d19bd194493aThomas Graf case NL_SKIP: \ 49844d362409d5469aed47d19e7908d19bd194493aThomas Graf goto skip; \ 49944d362409d5469aed47d19e7908d19bd194493aThomas Graf case NL_STOP: \ 50044d362409d5469aed47d19e7908d19bd194493aThomas Graf goto stop; \ 50144d362409d5469aed47d19e7908d19bd194493aThomas Graf default: \ 50244d362409d5469aed47d19e7908d19bd194493aThomas Graf goto out; \ 50344d362409d5469aed47d19e7908d19bd194493aThomas Graf } \ 50444d362409d5469aed47d19e7908d19bd194493aThomas Graf} while (0) 50544d362409d5469aed47d19e7908d19bd194493aThomas Graf 5061155370f520cb64657e25153255cf7dc1424317fThomas Grafstatic int recvmsgs(struct nl_sock *sk, struct nl_cb *cb) 50744d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 50844d362409d5469aed47d19e7908d19bd194493aThomas Graf int n, err = 0, multipart = 0; 50923ee46ef7115c2e311c36e43a833e6c3deada18aThomas Graf unsigned char *buf = NULL; 51044d362409d5469aed47d19e7908d19bd194493aThomas Graf struct nlmsghdr *hdr; 51144d362409d5469aed47d19e7908d19bd194493aThomas Graf struct sockaddr_nl nla = {0}; 51244d362409d5469aed47d19e7908d19bd194493aThomas Graf struct nl_msg *msg = NULL; 51344d362409d5469aed47d19e7908d19bd194493aThomas Graf struct ucred *creds = NULL; 51444d362409d5469aed47d19e7908d19bd194493aThomas Graf 51544d362409d5469aed47d19e7908d19bd194493aThomas Grafcontinue_reading: 5161155370f520cb64657e25153255cf7dc1424317fThomas Graf NL_DBG(3, "Attempting to read from %p\n", sk); 51744d362409d5469aed47d19e7908d19bd194493aThomas Graf if (cb->cb_recv_ow) 5181155370f520cb64657e25153255cf7dc1424317fThomas Graf n = cb->cb_recv_ow(sk, &nla, &buf, &creds); 51944d362409d5469aed47d19e7908d19bd194493aThomas Graf else 5201155370f520cb64657e25153255cf7dc1424317fThomas Graf n = nl_recv(sk, &nla, &buf, &creds); 52144d362409d5469aed47d19e7908d19bd194493aThomas Graf 52244d362409d5469aed47d19e7908d19bd194493aThomas Graf if (n <= 0) 52344d362409d5469aed47d19e7908d19bd194493aThomas Graf return n; 52444d362409d5469aed47d19e7908d19bd194493aThomas Graf 5251155370f520cb64657e25153255cf7dc1424317fThomas Graf NL_DBG(3, "recvmsgs(%p): Read %d bytes\n", sk, n); 52644d362409d5469aed47d19e7908d19bd194493aThomas Graf 52744d362409d5469aed47d19e7908d19bd194493aThomas Graf hdr = (struct nlmsghdr *) buf; 52844d362409d5469aed47d19e7908d19bd194493aThomas Graf while (nlmsg_ok(hdr, n)) { 5291155370f520cb64657e25153255cf7dc1424317fThomas Graf NL_DBG(3, "recgmsgs(%p): Processing valid message...\n", sk); 53044d362409d5469aed47d19e7908d19bd194493aThomas Graf 53123ee46ef7115c2e311c36e43a833e6c3deada18aThomas Graf nlmsg_free(msg); 53244d362409d5469aed47d19e7908d19bd194493aThomas Graf msg = nlmsg_convert(hdr); 53344d362409d5469aed47d19e7908d19bd194493aThomas Graf if (!msg) { 5348a3efffa5b3fde252675239914118664d36a2c24Thomas Graf err = -NLE_NOMEM; 53544d362409d5469aed47d19e7908d19bd194493aThomas Graf goto out; 53644d362409d5469aed47d19e7908d19bd194493aThomas Graf } 53744d362409d5469aed47d19e7908d19bd194493aThomas Graf 5381155370f520cb64657e25153255cf7dc1424317fThomas Graf nlmsg_set_proto(msg, sk->s_proto); 53944d362409d5469aed47d19e7908d19bd194493aThomas Graf nlmsg_set_src(msg, &nla); 54044d362409d5469aed47d19e7908d19bd194493aThomas Graf if (creds) 54144d362409d5469aed47d19e7908d19bd194493aThomas Graf nlmsg_set_creds(msg, creds); 54244d362409d5469aed47d19e7908d19bd194493aThomas Graf 54344d362409d5469aed47d19e7908d19bd194493aThomas Graf /* Raw callback is the first, it gives the most control 54444d362409d5469aed47d19e7908d19bd194493aThomas Graf * to the user and he can do his very own parsing. */ 54544d362409d5469aed47d19e7908d19bd194493aThomas Graf if (cb->cb_set[NL_CB_MSG_IN]) 54644d362409d5469aed47d19e7908d19bd194493aThomas Graf NL_CB_CALL(cb, NL_CB_MSG_IN, msg); 54744d362409d5469aed47d19e7908d19bd194493aThomas Graf 54844d362409d5469aed47d19e7908d19bd194493aThomas Graf /* Sequence number checking. The check may be done by 54944d362409d5469aed47d19e7908d19bd194493aThomas Graf * the user, otherwise a very simple check is applied 55044d362409d5469aed47d19e7908d19bd194493aThomas Graf * enforcing strict ordering */ 55144d362409d5469aed47d19e7908d19bd194493aThomas Graf if (cb->cb_set[NL_CB_SEQ_CHECK]) 55244d362409d5469aed47d19e7908d19bd194493aThomas Graf NL_CB_CALL(cb, NL_CB_SEQ_CHECK, msg); 5531155370f520cb64657e25153255cf7dc1424317fThomas Graf else if (hdr->nlmsg_seq != sk->s_seq_expect) { 55444d362409d5469aed47d19e7908d19bd194493aThomas Graf if (cb->cb_set[NL_CB_INVALID]) 55544d362409d5469aed47d19e7908d19bd194493aThomas Graf NL_CB_CALL(cb, NL_CB_INVALID, msg); 55644d362409d5469aed47d19e7908d19bd194493aThomas Graf else { 5578a3efffa5b3fde252675239914118664d36a2c24Thomas Graf err = -NLE_SEQ_MISMATCH; 55844d362409d5469aed47d19e7908d19bd194493aThomas Graf goto out; 55944d362409d5469aed47d19e7908d19bd194493aThomas Graf } 56044d362409d5469aed47d19e7908d19bd194493aThomas Graf } 56144d362409d5469aed47d19e7908d19bd194493aThomas Graf 56244d362409d5469aed47d19e7908d19bd194493aThomas Graf if (hdr->nlmsg_type == NLMSG_DONE || 56344d362409d5469aed47d19e7908d19bd194493aThomas Graf hdr->nlmsg_type == NLMSG_ERROR || 56444d362409d5469aed47d19e7908d19bd194493aThomas Graf hdr->nlmsg_type == NLMSG_NOOP || 56544d362409d5469aed47d19e7908d19bd194493aThomas Graf hdr->nlmsg_type == NLMSG_OVERRUN) { 56644d362409d5469aed47d19e7908d19bd194493aThomas Graf /* We can't check for !NLM_F_MULTI since some netlink 56744d362409d5469aed47d19e7908d19bd194493aThomas Graf * users in the kernel are broken. */ 5681155370f520cb64657e25153255cf7dc1424317fThomas Graf sk->s_seq_expect++; 56944d362409d5469aed47d19e7908d19bd194493aThomas Graf NL_DBG(3, "recvmsgs(%p): Increased expected " \ 57044d362409d5469aed47d19e7908d19bd194493aThomas Graf "sequence number to %d\n", 5711155370f520cb64657e25153255cf7dc1424317fThomas Graf sk, sk->s_seq_expect); 57244d362409d5469aed47d19e7908d19bd194493aThomas Graf } 57344d362409d5469aed47d19e7908d19bd194493aThomas Graf 57444d362409d5469aed47d19e7908d19bd194493aThomas Graf if (hdr->nlmsg_flags & NLM_F_MULTI) 57544d362409d5469aed47d19e7908d19bd194493aThomas Graf multipart = 1; 57644d362409d5469aed47d19e7908d19bd194493aThomas Graf 57744d362409d5469aed47d19e7908d19bd194493aThomas Graf /* Other side wishes to see an ack for this message */ 57844d362409d5469aed47d19e7908d19bd194493aThomas Graf if (hdr->nlmsg_flags & NLM_F_ACK) { 57944d362409d5469aed47d19e7908d19bd194493aThomas Graf if (cb->cb_set[NL_CB_SEND_ACK]) 58044d362409d5469aed47d19e7908d19bd194493aThomas Graf NL_CB_CALL(cb, NL_CB_SEND_ACK, msg); 58144d362409d5469aed47d19e7908d19bd194493aThomas Graf else { 58244d362409d5469aed47d19e7908d19bd194493aThomas Graf /* FIXME: implement */ 58344d362409d5469aed47d19e7908d19bd194493aThomas Graf } 58444d362409d5469aed47d19e7908d19bd194493aThomas Graf } 58544d362409d5469aed47d19e7908d19bd194493aThomas Graf 58644d362409d5469aed47d19e7908d19bd194493aThomas Graf /* messages terminates a multpart message, this is 58744d362409d5469aed47d19e7908d19bd194493aThomas Graf * usually the end of a message and therefore we slip 58844d362409d5469aed47d19e7908d19bd194493aThomas Graf * out of the loop by default. the user may overrule 58944d362409d5469aed47d19e7908d19bd194493aThomas Graf * this action by skipping this packet. */ 59044d362409d5469aed47d19e7908d19bd194493aThomas Graf if (hdr->nlmsg_type == NLMSG_DONE) { 59144d362409d5469aed47d19e7908d19bd194493aThomas Graf multipart = 0; 59244d362409d5469aed47d19e7908d19bd194493aThomas Graf if (cb->cb_set[NL_CB_FINISH]) 59344d362409d5469aed47d19e7908d19bd194493aThomas Graf NL_CB_CALL(cb, NL_CB_FINISH, msg); 59444d362409d5469aed47d19e7908d19bd194493aThomas Graf } 59544d362409d5469aed47d19e7908d19bd194493aThomas Graf 59644d362409d5469aed47d19e7908d19bd194493aThomas Graf /* Message to be ignored, the default action is to 59744d362409d5469aed47d19e7908d19bd194493aThomas Graf * skip this message if no callback is specified. The 59844d362409d5469aed47d19e7908d19bd194493aThomas Graf * user may overrule this action by returning 59944d362409d5469aed47d19e7908d19bd194493aThomas Graf * NL_PROCEED. */ 60044d362409d5469aed47d19e7908d19bd194493aThomas Graf else if (hdr->nlmsg_type == NLMSG_NOOP) { 60144d362409d5469aed47d19e7908d19bd194493aThomas Graf if (cb->cb_set[NL_CB_SKIPPED]) 60244d362409d5469aed47d19e7908d19bd194493aThomas Graf NL_CB_CALL(cb, NL_CB_SKIPPED, msg); 60344d362409d5469aed47d19e7908d19bd194493aThomas Graf else 60444d362409d5469aed47d19e7908d19bd194493aThomas Graf goto skip; 60544d362409d5469aed47d19e7908d19bd194493aThomas Graf } 60644d362409d5469aed47d19e7908d19bd194493aThomas Graf 60744d362409d5469aed47d19e7908d19bd194493aThomas Graf /* Data got lost, report back to user. The default action is to 60844d362409d5469aed47d19e7908d19bd194493aThomas Graf * quit parsing. The user may overrule this action by retuning 60944d362409d5469aed47d19e7908d19bd194493aThomas Graf * NL_SKIP or NL_PROCEED (dangerous) */ 61044d362409d5469aed47d19e7908d19bd194493aThomas Graf else if (hdr->nlmsg_type == NLMSG_OVERRUN) { 61144d362409d5469aed47d19e7908d19bd194493aThomas Graf if (cb->cb_set[NL_CB_OVERRUN]) 61244d362409d5469aed47d19e7908d19bd194493aThomas Graf NL_CB_CALL(cb, NL_CB_OVERRUN, msg); 61344d362409d5469aed47d19e7908d19bd194493aThomas Graf else { 6148a3efffa5b3fde252675239914118664d36a2c24Thomas Graf err = -NLE_MSG_OVERFLOW; 61544d362409d5469aed47d19e7908d19bd194493aThomas Graf goto out; 61644d362409d5469aed47d19e7908d19bd194493aThomas Graf } 61744d362409d5469aed47d19e7908d19bd194493aThomas Graf } 61844d362409d5469aed47d19e7908d19bd194493aThomas Graf 61944d362409d5469aed47d19e7908d19bd194493aThomas Graf /* Message carries a nlmsgerr */ 62044d362409d5469aed47d19e7908d19bd194493aThomas Graf else if (hdr->nlmsg_type == NLMSG_ERROR) { 62144d362409d5469aed47d19e7908d19bd194493aThomas Graf struct nlmsgerr *e = nlmsg_data(hdr); 62244d362409d5469aed47d19e7908d19bd194493aThomas Graf 62344d362409d5469aed47d19e7908d19bd194493aThomas Graf if (hdr->nlmsg_len < nlmsg_msg_size(sizeof(*e))) { 62444d362409d5469aed47d19e7908d19bd194493aThomas Graf /* Truncated error message, the default action 62544d362409d5469aed47d19e7908d19bd194493aThomas Graf * is to stop parsing. The user may overrule 62644d362409d5469aed47d19e7908d19bd194493aThomas Graf * this action by returning NL_SKIP or 62744d362409d5469aed47d19e7908d19bd194493aThomas Graf * NL_PROCEED (dangerous) */ 62844d362409d5469aed47d19e7908d19bd194493aThomas Graf if (cb->cb_set[NL_CB_INVALID]) 62944d362409d5469aed47d19e7908d19bd194493aThomas Graf NL_CB_CALL(cb, NL_CB_INVALID, msg); 63044d362409d5469aed47d19e7908d19bd194493aThomas Graf else { 6318a3efffa5b3fde252675239914118664d36a2c24Thomas Graf err = -NLE_MSG_TRUNC; 63244d362409d5469aed47d19e7908d19bd194493aThomas Graf goto out; 63344d362409d5469aed47d19e7908d19bd194493aThomas Graf } 63444d362409d5469aed47d19e7908d19bd194493aThomas Graf } else if (e->error) { 63544d362409d5469aed47d19e7908d19bd194493aThomas Graf /* Error message reported back from kernel. */ 63644d362409d5469aed47d19e7908d19bd194493aThomas Graf if (cb->cb_err) { 63744d362409d5469aed47d19e7908d19bd194493aThomas Graf err = cb->cb_err(&nla, e, 63844d362409d5469aed47d19e7908d19bd194493aThomas Graf cb->cb_err_arg); 63944d362409d5469aed47d19e7908d19bd194493aThomas Graf if (err < 0) 64044d362409d5469aed47d19e7908d19bd194493aThomas Graf goto out; 64144d362409d5469aed47d19e7908d19bd194493aThomas Graf else if (err == NL_SKIP) 64244d362409d5469aed47d19e7908d19bd194493aThomas Graf goto skip; 64344d362409d5469aed47d19e7908d19bd194493aThomas Graf else if (err == NL_STOP) { 6448a3efffa5b3fde252675239914118664d36a2c24Thomas Graf err = -nl_syserr2nlerr(e->error); 64544d362409d5469aed47d19e7908d19bd194493aThomas Graf goto out; 64644d362409d5469aed47d19e7908d19bd194493aThomas Graf } 64744d362409d5469aed47d19e7908d19bd194493aThomas Graf } else { 6488a3efffa5b3fde252675239914118664d36a2c24Thomas Graf err = -nl_syserr2nlerr(e->error); 64944d362409d5469aed47d19e7908d19bd194493aThomas Graf goto out; 65044d362409d5469aed47d19e7908d19bd194493aThomas Graf } 65144d362409d5469aed47d19e7908d19bd194493aThomas Graf } else if (cb->cb_set[NL_CB_ACK]) 65244d362409d5469aed47d19e7908d19bd194493aThomas Graf NL_CB_CALL(cb, NL_CB_ACK, msg); 65344d362409d5469aed47d19e7908d19bd194493aThomas Graf } else { 65444d362409d5469aed47d19e7908d19bd194493aThomas Graf /* Valid message (not checking for MULTIPART bit to 65544d362409d5469aed47d19e7908d19bd194493aThomas Graf * get along with broken kernels. NL_SKIP has no 65644d362409d5469aed47d19e7908d19bd194493aThomas Graf * effect on this. */ 65744d362409d5469aed47d19e7908d19bd194493aThomas Graf if (cb->cb_set[NL_CB_VALID]) 65844d362409d5469aed47d19e7908d19bd194493aThomas Graf NL_CB_CALL(cb, NL_CB_VALID, msg); 65944d362409d5469aed47d19e7908d19bd194493aThomas Graf } 66044d362409d5469aed47d19e7908d19bd194493aThomas Grafskip: 66144d362409d5469aed47d19e7908d19bd194493aThomas Graf err = 0; 66244d362409d5469aed47d19e7908d19bd194493aThomas Graf hdr = nlmsg_next(hdr, &n); 66344d362409d5469aed47d19e7908d19bd194493aThomas Graf } 66444d362409d5469aed47d19e7908d19bd194493aThomas Graf 66523ee46ef7115c2e311c36e43a833e6c3deada18aThomas Graf nlmsg_free(msg); 66644d362409d5469aed47d19e7908d19bd194493aThomas Graf free(buf); 66744d362409d5469aed47d19e7908d19bd194493aThomas Graf free(creds); 66844d362409d5469aed47d19e7908d19bd194493aThomas Graf buf = NULL; 66944d362409d5469aed47d19e7908d19bd194493aThomas Graf msg = NULL; 67044d362409d5469aed47d19e7908d19bd194493aThomas Graf creds = NULL; 67144d362409d5469aed47d19e7908d19bd194493aThomas Graf 67244d362409d5469aed47d19e7908d19bd194493aThomas Graf if (multipart) { 67344d362409d5469aed47d19e7908d19bd194493aThomas Graf /* Multipart message not yet complete, continue reading */ 67444d362409d5469aed47d19e7908d19bd194493aThomas Graf goto continue_reading; 67544d362409d5469aed47d19e7908d19bd194493aThomas Graf } 67644d362409d5469aed47d19e7908d19bd194493aThomas Grafstop: 67744d362409d5469aed47d19e7908d19bd194493aThomas Graf err = 0; 67844d362409d5469aed47d19e7908d19bd194493aThomas Grafout: 67944d362409d5469aed47d19e7908d19bd194493aThomas Graf nlmsg_free(msg); 68044d362409d5469aed47d19e7908d19bd194493aThomas Graf free(buf); 68144d362409d5469aed47d19e7908d19bd194493aThomas Graf free(creds); 68244d362409d5469aed47d19e7908d19bd194493aThomas Graf 68344d362409d5469aed47d19e7908d19bd194493aThomas Graf return err; 68444d362409d5469aed47d19e7908d19bd194493aThomas Graf} 68544d362409d5469aed47d19e7908d19bd194493aThomas Graf 68644d362409d5469aed47d19e7908d19bd194493aThomas Graf/** 68744d362409d5469aed47d19e7908d19bd194493aThomas Graf * Receive a set of messages from a netlink socket. 6881155370f520cb64657e25153255cf7dc1424317fThomas Graf * @arg sk Netlink socket. 68944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg cb set of callbacks to control behaviour. 69044d362409d5469aed47d19e7908d19bd194493aThomas Graf * 69144d362409d5469aed47d19e7908d19bd194493aThomas Graf * Repeatedly calls nl_recv() or the respective replacement if provided 69244d362409d5469aed47d19e7908d19bd194493aThomas Graf * by the application (see nl_cb_overwrite_recv()) and parses the 69344d362409d5469aed47d19e7908d19bd194493aThomas Graf * received data as netlink messages. Stops reading if one of the 69444d362409d5469aed47d19e7908d19bd194493aThomas Graf * callbacks returns NL_STOP or nl_recv returns either 0 or a negative error code. 69544d362409d5469aed47d19e7908d19bd194493aThomas Graf * 69644d362409d5469aed47d19e7908d19bd194493aThomas Graf * A non-blocking sockets causes the function to return immediately if 69744d362409d5469aed47d19e7908d19bd194493aThomas Graf * no data is available. 69844d362409d5469aed47d19e7908d19bd194493aThomas Graf * 69944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return 0 on success or a negative error code from nl_recv(). 70044d362409d5469aed47d19e7908d19bd194493aThomas Graf */ 7011155370f520cb64657e25153255cf7dc1424317fThomas Grafint nl_recvmsgs(struct nl_sock *sk, struct nl_cb *cb) 70244d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 70344d362409d5469aed47d19e7908d19bd194493aThomas Graf if (cb->cb_recvmsgs_ow) 7041155370f520cb64657e25153255cf7dc1424317fThomas Graf return cb->cb_recvmsgs_ow(sk, cb); 70544d362409d5469aed47d19e7908d19bd194493aThomas Graf else 7061155370f520cb64657e25153255cf7dc1424317fThomas Graf return recvmsgs(sk, cb); 70744d362409d5469aed47d19e7908d19bd194493aThomas Graf} 70844d362409d5469aed47d19e7908d19bd194493aThomas Graf 70944d362409d5469aed47d19e7908d19bd194493aThomas Graf/** 7101155370f520cb64657e25153255cf7dc1424317fThomas Graf * Receive a set of message from a netlink socket using handlers in nl_sock. 7111155370f520cb64657e25153255cf7dc1424317fThomas Graf * @arg sk Netlink socket. 71244d362409d5469aed47d19e7908d19bd194493aThomas Graf * 7131155370f520cb64657e25153255cf7dc1424317fThomas Graf * Calls nl_recvmsgs() with the handlers configured in the netlink socket. 71444d362409d5469aed47d19e7908d19bd194493aThomas Graf */ 7151155370f520cb64657e25153255cf7dc1424317fThomas Grafint nl_recvmsgs_default(struct nl_sock *sk) 71644d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 7171155370f520cb64657e25153255cf7dc1424317fThomas Graf return nl_recvmsgs(sk, sk->s_cb); 71844d362409d5469aed47d19e7908d19bd194493aThomas Graf 71944d362409d5469aed47d19e7908d19bd194493aThomas Graf} 72044d362409d5469aed47d19e7908d19bd194493aThomas Graf 72144d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int ack_wait_handler(struct nl_msg *msg, void *arg) 72244d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 72344d362409d5469aed47d19e7908d19bd194493aThomas Graf return NL_STOP; 72444d362409d5469aed47d19e7908d19bd194493aThomas Graf} 72544d362409d5469aed47d19e7908d19bd194493aThomas Graf 72644d362409d5469aed47d19e7908d19bd194493aThomas Graf/** 72744d362409d5469aed47d19e7908d19bd194493aThomas Graf * Wait for ACK. 7281155370f520cb64657e25153255cf7dc1424317fThomas Graf * @arg sk Netlink socket. 72944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @pre The netlink socket must be in blocking state. 73044d362409d5469aed47d19e7908d19bd194493aThomas Graf * 73144d362409d5469aed47d19e7908d19bd194493aThomas Graf * Waits until an ACK is received for the latest not yet acknowledged 73244d362409d5469aed47d19e7908d19bd194493aThomas Graf * netlink message. 73344d362409d5469aed47d19e7908d19bd194493aThomas Graf */ 7341155370f520cb64657e25153255cf7dc1424317fThomas Grafint nl_wait_for_ack(struct nl_sock *sk) 73544d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 73644d362409d5469aed47d19e7908d19bd194493aThomas Graf int err; 73744d362409d5469aed47d19e7908d19bd194493aThomas Graf struct nl_cb *cb; 73844d362409d5469aed47d19e7908d19bd194493aThomas Graf 7391155370f520cb64657e25153255cf7dc1424317fThomas Graf cb = nl_cb_clone(sk->s_cb); 74044d362409d5469aed47d19e7908d19bd194493aThomas Graf if (cb == NULL) 7418a3efffa5b3fde252675239914118664d36a2c24Thomas Graf return -NLE_NOMEM; 74244d362409d5469aed47d19e7908d19bd194493aThomas Graf 74344d362409d5469aed47d19e7908d19bd194493aThomas Graf nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_wait_handler, NULL); 7441155370f520cb64657e25153255cf7dc1424317fThomas Graf err = nl_recvmsgs(sk, cb); 74544d362409d5469aed47d19e7908d19bd194493aThomas Graf nl_cb_put(cb); 74644d362409d5469aed47d19e7908d19bd194493aThomas Graf 74744d362409d5469aed47d19e7908d19bd194493aThomas Graf return err; 74844d362409d5469aed47d19e7908d19bd194493aThomas Graf} 74944d362409d5469aed47d19e7908d19bd194493aThomas Graf 75044d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */ 75144d362409d5469aed47d19e7908d19bd194493aThomas Graf 75244d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */ 753