summaryrefslogtreecommitdiffstats
path: root/netlink_msg.c
diff options
context:
space:
mode:
Diffstat (limited to 'netlink_msg.c')
-rw-r--r--netlink_msg.c168
1 files changed, 168 insertions, 0 deletions
diff --git a/netlink_msg.c b/netlink_msg.c
new file mode 100644
index 0000000..7363028
--- /dev/null
+++ b/netlink_msg.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2012 Daniel Drown
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * netlink_msg.c - send an ifaddrmsg/ifinfomsg/rtmsg via netlink
+ */
+
+#include <netinet/in.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <string.h>
+#include <errno.h>
+
+#include <netlink-types.h>
+#include <netlink/socket.h>
+#include <netlink/netlink.h>
+#include <netlink/msg.h>
+
+#include "netlink_msg.h"
+#include "netlink_callbacks.h"
+
+/* function: family_size
+ * returns the size of the address structure for the given family, or 0 on error
+ * family - AF_INET or AF_INET6
+ */
+size_t inet_family_size(int family) {
+ if(family == AF_INET) {
+ return sizeof(struct in_addr);
+ } else if(family == AF_INET6) {
+ return sizeof(struct in6_addr);
+ } else {
+ return 0;
+ }
+}
+
+/* function: nlmsg_alloc_generic
+ * allocates a netlink message with the given struct inside of it. returns NULL on failure
+ * type - netlink message type
+ * flags - netlink message flags
+ * payload_struct - pointer to a struct to add to netlink message
+ * payload_len - bytelength of structure
+ */
+struct nl_msg *nlmsg_alloc_generic(uint16_t type, uint16_t flags, void *payload_struct, size_t payload_len) {
+ struct nl_msg *msg;
+
+ msg = nlmsg_alloc();
+ if(!msg) {
+ return NULL;
+ }
+
+ if ((sizeof(struct nl_msg) + payload_len) > msg->nm_size) {
+ nlmsg_free(msg);
+ return NULL;
+ }
+
+ msg->nm_nlh->nlmsg_len = NLMSG_LENGTH(payload_len);
+ msg->nm_nlh->nlmsg_flags = flags;
+ msg->nm_nlh->nlmsg_type = type;
+
+ memcpy(nlmsg_data(msg->nm_nlh), payload_struct, payload_len);
+
+ return msg;
+}
+
+/* function: nlmsg_alloc_ifaddr
+ * allocates a netlink message with a struct ifaddrmsg inside of it. returns NULL on failure
+ * type - netlink message type
+ * flags - netlink message flags
+ * ifa - ifaddrmsg to copy into the new netlink message
+ */
+struct nl_msg *nlmsg_alloc_ifaddr(uint16_t type, uint16_t flags, struct ifaddrmsg *ifa) {
+ return nlmsg_alloc_generic(type, flags, ifa, sizeof(*ifa));
+}
+
+/* function: nlmsg_alloc_ifinfo
+ * allocates a netlink message with a struct ifinfomsg inside of it. returns NULL on failure
+ * type - netlink message type
+ * flags - netlink message flags
+ * ifi - ifinfomsg to copy into the new netlink message
+ */
+struct nl_msg *nlmsg_alloc_ifinfo(uint16_t type, uint16_t flags, struct ifinfomsg *ifi) {
+ return nlmsg_alloc_generic(type, flags, ifi, sizeof(*ifi));
+}
+
+/* function: nlmsg_alloc_rtmsg
+ * allocates a netlink message with a struct rtmsg inside of it. returns NULL on failure
+ * type - netlink message type
+ * flags - netlink message flags
+ * rt - rtmsg to copy into the new netlink message
+ */
+struct nl_msg *nlmsg_alloc_rtmsg(uint16_t type, uint16_t flags, struct rtmsg *rt) {
+ return nlmsg_alloc_generic(type, flags, rt, sizeof(*rt));
+}
+
+/* function: send_netlink_msg
+ * sends a netlink message, reads a response, and hands the response(s) to the callbacks
+ * msg - netlink message to send
+ * callbacks - callbacks to use on responses
+ */
+void send_netlink_msg(struct nl_msg *msg, struct nl_cb *callbacks) {
+ struct nl_sock *nl_sk;
+
+ nl_sk = nl_socket_alloc();
+ if(!nl_sk)
+ goto cleanup;
+
+ if(nl_connect(nl_sk, NETLINK_ROUTE) != 0)
+ goto cleanup;
+
+ if(nl_send_auto_complete(nl_sk, msg) < 0)
+ goto cleanup;
+
+ nl_recvmsgs(nl_sk, callbacks);
+
+cleanup:
+ if(nl_sk)
+ nl_socket_free(nl_sk);
+}
+
+/* function: send_ifaddrmsg
+ * sends a netlink/ifaddrmsg message and hands the responses to the callbacks
+ * type - netlink message type
+ * flags - netlink message flags
+ * ifa - ifaddrmsg to send
+ * callbacks - callbacks to use with the responses
+ */
+void send_ifaddrmsg(uint16_t type, uint16_t flags, struct ifaddrmsg *ifa, struct nl_cb *callbacks) {
+ struct nl_msg *msg = NULL;
+
+ msg = nlmsg_alloc_ifaddr(type, flags, ifa);
+ if(!msg)
+ return;
+
+ send_netlink_msg(msg, callbacks);
+
+ nlmsg_free(msg);
+}
+
+/* function: netlink_sendrecv
+ * send a nl_msg and return an int status - only supports OK/ERROR responses
+ * msg - msg to send
+ */
+int netlink_sendrecv(struct nl_msg *msg) {
+ struct nl_cb *callbacks = NULL;
+ int retval = -EIO;
+
+ callbacks = alloc_ack_callbacks(&retval);
+ if(!callbacks) {
+ return -ENOMEM;
+ }
+
+ send_netlink_msg(msg, callbacks);
+
+ nl_cb_put(callbacks);
+
+ return retval;
+}