summaryrefslogtreecommitdiffstats
path: root/libnl_2
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2014-03-21 16:59:20 -0700
committerQiwen Zhao <zhao@google.com>2014-06-04 08:15:48 -0700
commit6e3fffeca6ac00379b0a22888d04a58ee0f51057 (patch)
tree83c5fd1c67e992c1d6ca53094a8dab59921e3e97 /libnl_2
parent7ab32aca56fe8df4575fc2e2e40ff7e1d38fca60 (diff)
downloadsystem_core-6e3fffeca6ac00379b0a22888d04a58ee0f51057.zip
system_core-6e3fffeca6ac00379b0a22888d04a58ee0f51057.tar.gz
system_core-6e3fffeca6ac00379b0a22888d04a58ee0f51057.tar.bz2
DO NOT MERGE: Revert "delete libnl_2"
This reverts commit 7097f052d946bc9fbe298c7a88e1d943f54f684e. libnl_2 needs to stay in AOSP for now for compatibility with GPL test builds.
Diffstat (limited to 'libnl_2')
-rw-r--r--libnl_2/.gitignore2
-rw-r--r--libnl_2/Android.mk39
-rw-r--r--libnl_2/README88
-rw-r--r--libnl_2/attr.c239
-rw-r--r--libnl_2/cache.c37
-rw-r--r--libnl_2/dbg.c12
-rw-r--r--libnl_2/genl/family.c44
-rw-r--r--libnl_2/genl/genl.c302
-rw-r--r--libnl_2/handlers.c90
-rw-r--r--libnl_2/msg.c150
-rw-r--r--libnl_2/netlink.c273
-rw-r--r--libnl_2/object.c33
-rw-r--r--libnl_2/socket.c141
13 files changed, 1450 insertions, 0 deletions
diff --git a/libnl_2/.gitignore b/libnl_2/.gitignore
new file mode 100644
index 0000000..d4ca744
--- /dev/null
+++ b/libnl_2/.gitignore
@@ -0,0 +1,2 @@
+include/netlink/version.h.in
+cscope.*
diff --git a/libnl_2/Android.mk b/libnl_2/Android.mk
new file mode 100644
index 0000000..3721fc6
--- /dev/null
+++ b/libnl_2/Android.mk
@@ -0,0 +1,39 @@
+#######################################
+# * Netlink cache not implemented
+# * Library is not thread safe
+#######################################
+
+LOCAL_PATH := $(call my-dir)
+
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ attr.c \
+ cache.c \
+ genl/genl.c \
+ genl/family.c \
+ handlers.c \
+ msg.c \
+ netlink.c \
+ object.c \
+ socket.c \
+ dbg.c
+
+LOCAL_C_INCLUDES += \
+ external/libnl-headers
+
+# Static Library
+LOCAL_MODULE := libnl_2
+LOCAL_MODULE_TAGS := optional
+LOCAL_32_BIT_ONLY := true
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES :=
+LOCAL_WHOLE_STATIC_LIBRARIES:= libnl_2
+LOCAL_SHARED_LIBRARIES:= liblog
+LOCAL_MODULE := libnl_2
+LOCAL_MODULE_TAGS := optional
+LOCAL_32_BIT_ONLY := true
+include $(BUILD_SHARED_LIBRARY)
diff --git a/libnl_2/README b/libnl_2/README
new file mode 100644
index 0000000..14db6db
--- /dev/null
+++ b/libnl_2/README
@@ -0,0 +1,88 @@
+Netlink Protocol Library
+
+This library is a clean room re-implementation of libnl 2.0 and
+re-licensed under Apache 2.0. It was developed primarily to support
+wpa_supplicant. However, with additional development can be extended
+to support other netlink applications.
+
+Netlink Protocol Format (RFC3549)
+
++-----------------+-+-------------------+-+
+|Netlink Message |P| Generic Netlink |P|
+| Header |A| Message Header |A|
+|(struct nlmsghdr)|D|(struct genlmsghdr)|D|
++-----------------+-+-------------------+-+-------------+
+|len:4|type:2|flags:2|seq:4 pid:4|cmd:1|ver:1|reserved:2|
++--------------------------------+----------------------+
++-----------------+-+-----------------+-+-----------------+-+-----------------+-+---+
+|Netlink Attribute|P|Netlink Attribute|P|Netlink Attribute|P|Netlink Attribute|P|...|
+| #0 Header |A| #0 Payload |A| #1 Header |A| #1 Payload |A| |
+| (struct nlattr) |D| (void) |D| (struct nlattr) |D| (void) |D| |
++-----------------+-+-----------------+-+-----------------+-+-----------------+-+---+
+|len:2(==4+payload)|type:2|payload|pad|
++-------------------------+-------+---+
+
+NETLINK OVERVIEW
+
+* Each netlink message consists of a bitstream with a netlink header.
+* After this header a second header *can* be used specific to the netlink
+ family in use. This library was tested using the generic netlink
+ protocol defined by struct genlmsghdr to support nl80211.
+* After the header(s) netlink attributes can be appended to the message
+ which hold can hold basic types such as unsigned integers and strings.
+* Attributes can also be nested. This is accomplished by calling "nla_nest_start"
+ which creates an empty attribute with nest attributes as its payload. Then to
+ close the nest, "nla_nest_end" is called.
+* All data structures in this implementation are byte-aligned (Currently 4 bytes).
+* Acknowledgements (ACKs) are sent as NLMSG_ERROR netlink message types (0x2) and
+ have an error value of 0.
+
+KNOWN ISSUES
+
+ GENERAL
+ * Not tested for thread safety
+
+ Android.mk
+ * No dynamic library because of netlink cache not implemented and
+ not tested for thread safety
+
+ attr.c
+ * nla_parse - does not use nla_policy argument
+
+ cache.c
+ * netlink cache not implemented and only supports one netlink family id
+ which is stored in the nl_cache pointer instead of an actual cache
+
+ netlink.c
+ * nl_recvmsgs - does not support nl_cb_overwrite_recv()
+ * nl_recv - sets/unsets asynchronous socket flag
+
+SOURCE FILES
+
+* Android.mk - Android makefile
+* README - This file
+* attr.c - Netlink attributes
+* cache.c - Netlink cache
+* genl/family.c - Generic netlink family id
+* genl/genl.c - Generic netlink
+* handlers.c - Netlink callbacks
+* msg.c - Netlink messages construction
+* netlink.c - Netlink socket communication
+* object.c - libnl object wrapper
+* socket.c - Netlink kernel socket utils
+
+IMPORTANT HEADER FILES - NOTE: These are based on the the origin GPL libnl headers
+
+* netlink-types.h - Contains many important structs for libnl
+ to represent netlink objects
+* netlink/netlink-kernel.h - Netlink kernel headers and field constants.
+* netlink/msg.h - macros for iterating over netlink messages
+* netlink/attr.h - netlink attribute constants, iteration macros and setters
+
+REFERENCES
+
+* nl80211.h
+* netlink_types.h
+* $LINUX_KERNEL/net/wireless/nl80211.c
+* http://www.infradead.org/~tgr/libnl/doc-3.0/index.html
+* http://www.netfilter.org/projects/libmnl/doxygen/index.html
diff --git a/libnl_2/attr.c b/libnl_2/attr.c
new file mode 100644
index 0000000..2ef7590
--- /dev/null
+++ b/libnl_2/attr.c
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * 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.
+ */
+
+/* NOTICE: This is a clean room re-implementation of libnl */
+
+#include <errno.h>
+#include "netlink/netlink.h"
+#include "netlink/msg.h"
+#include "netlink/attr.h"
+#include "netlink-types.h"
+
+/* Return payload of string attribute. */
+char *nla_get_string(struct nlattr *nla)
+{
+ return (char *) nla_data(nla);
+}
+
+/* Return payload of 16 bit integer attribute. */
+uint16_t nla_get_u16(struct nlattr *nla)
+{
+ return *((uint16_t *) nla_data(nla));
+}
+
+/* Return payload of 32 bit integer attribute. */
+uint32_t nla_get_u32(struct nlattr *nla)
+{
+ return *((uint32_t *) nla_data(nla));
+}
+
+/* Return value of 8 bit integer attribute. */
+uint8_t nla_get_u8(struct nlattr *nla)
+{
+ return *((uint8_t *) nla_data(nla));
+}
+
+/* Return payload of uint64_t attribute. */
+uint64_t nla_get_u64(struct nlattr *nla)
+{
+ uint64_t tmp;
+ nla_memcpy(&tmp, nla, sizeof(tmp));
+ return tmp;
+}
+
+/* Head of payload */
+void *nla_data(const struct nlattr *nla)
+{
+ return (void *) ((char *) nla + NLA_HDRLEN);
+}
+
+/* Return length of the payload . */
+int nla_len(const struct nlattr *nla)
+{
+ return nla->nla_len - NLA_HDRLEN;
+}
+
+int nla_padlen(int payload)
+{
+ return NLA_ALIGN(payload) - payload;
+}
+
+/* Start a new level of nested attributes. */
+struct nlattr *nla_nest_start(struct nl_msg *msg, int attrtype)
+{
+ struct nlattr *start = (struct nlattr *)nlmsg_tail(msg->nm_nlh);
+ int rc;
+
+ rc = nla_put(msg, attrtype, 0, NULL);
+ if (rc < 0)
+ return NULL;
+
+ return start;
+}
+
+/* Finalize nesting of attributes. */
+int nla_nest_end(struct nl_msg *msg, struct nlattr *start)
+{
+ /* Set attribute size */
+ start->nla_len = (unsigned char *)nlmsg_tail(nlmsg_hdr(msg)) -
+ (unsigned char *)start;
+ return 0;
+}
+
+/* Return next attribute in a stream of attributes. */
+struct nlattr *nla_next(const struct nlattr *nla, int *remaining)
+{
+ struct nlattr *next_nla = NULL;
+ if (nla->nla_len >= sizeof(struct nlattr) &&
+ nla->nla_len <= *remaining){
+ next_nla = (struct nlattr *) \
+ ((char *) nla + NLA_ALIGN(nla->nla_len));
+ *remaining = *remaining - NLA_ALIGN(nla->nla_len);
+ }
+
+ return next_nla;
+
+}
+
+/* Check if the attribute header and payload can be accessed safely. */
+int nla_ok(const struct nlattr *nla, int remaining)
+{
+ return remaining > 0 &&
+ nla->nla_len >= sizeof(struct nlattr) &&
+ sizeof(struct nlattr) <= (unsigned int) remaining &&
+ nla->nla_len <= remaining;
+}
+
+/* Create attribute index based on a stream of attributes. */
+/* NOTE: Policy not used ! */
+int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head,
+ int len, struct nla_policy *policy)
+{
+ struct nlattr *pos;
+ int rem;
+
+ /* First clear table */
+ memset(tb, 0, (maxtype + 1) * sizeof(struct nlattr *));
+
+ nla_for_each_attr(pos, head, len, rem) {
+ int type = nla_type(pos);
+
+ if ((type <= maxtype) && (type != 0))
+ tb[type] = pos;
+ }
+
+ return 0;
+}
+
+
+/* Create attribute index based on nested attribute. */
+int nla_parse_nested(struct nlattr *tb[], int maxtype,
+ struct nlattr *nla, struct nla_policy *policy)
+{
+ return nla_parse(tb, maxtype, nla_data(nla), nla_len(nla), policy);
+}
+
+
+/* Add a unspecific attribute to netlink message. */
+int nla_put(struct nl_msg *msg, int attrtype, int datalen, const void *data)
+{
+ struct nlattr *nla;
+
+ /* Reserve space and init nla header */
+ nla = nla_reserve(msg, attrtype, datalen);
+ if (nla) {
+ memcpy(nla_data(nla), data, datalen);
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+/* Add 8 bit integer attribute to netlink message. */
+int nla_put_u8(struct nl_msg *msg, int attrtype, uint8_t value)
+{
+ return nla_put(msg, attrtype, sizeof(uint8_t), &value);
+}
+
+/* Add 16 bit integer attribute to netlink message. */
+int nla_put_u16(struct nl_msg *msg, int attrtype, uint16_t value)
+{
+ return nla_put(msg, attrtype, sizeof(uint16_t), &value);
+}
+
+/* Add 32 bit integer attribute to netlink message. */
+int nla_put_u32(struct nl_msg *msg, int attrtype, uint32_t value)
+{
+ return nla_put(msg, attrtype, sizeof(uint32_t), &value);
+}
+
+/* Add 64 bit integer attribute to netlink message. */
+int nla_put_u64(struct nl_msg *msg, int attrtype, uint64_t value)
+{
+ return nla_put(msg, attrtype, sizeof(uint64_t), &value);
+}
+
+/* Add nested attributes to netlink message. */
+/* Takes the attributes found in the nested message and appends them
+ * to the message msg nested in a container of the type attrtype. The
+ * nested message may not have a family specific header */
+int nla_put_nested(struct nl_msg *msg, int attrtype, struct nl_msg *nested)
+{
+ int rc;
+
+ rc = nla_put(msg, attrtype, nlmsg_attrlen(nlmsg_hdr(nested), 0),
+ nlmsg_attrdata(nlmsg_hdr(nested), 0));
+ return rc;
+
+}
+
+/* Return type of the attribute. */
+int nla_type(const struct nlattr *nla)
+{
+ return (int)nla->nla_type & NLA_TYPE_MASK;
+}
+
+/* Reserves room for an attribute in specified netlink message and fills
+ * in the attribute header (type,length). Return NULL if insufficient space */
+struct nlattr *nla_reserve(struct nl_msg *msg, int attrtype, int data_len)
+{
+
+ struct nlattr *nla;
+ const unsigned int NEW_SIZE = NLMSG_ALIGN(msg->nm_nlh->nlmsg_len) +
+ NLA_ALIGN(NLA_HDRLEN + data_len);
+
+ /* Check enough space for attribute */
+ if (NEW_SIZE > msg->nm_size)
+ return NULL;
+
+ nla = (struct nlattr *)nlmsg_tail(msg->nm_nlh);
+ nla->nla_type = attrtype;
+ nla->nla_len = NLA_HDRLEN + data_len;
+ memset((unsigned char *)nla + nla->nla_len, 0, nla_padlen(data_len));
+ msg->nm_nlh->nlmsg_len = NEW_SIZE;
+ return nla;
+}
+
+/* Copy attribute payload to another memory area. */
+int nla_memcpy(void *dest, struct nlattr *src, int count)
+{
+ if (!src || !dest)
+ return 0;
+ if (count > nla_len(src))
+ count = nla_len(src);
+ memcpy(dest, nla_data(src), count);
+ return count;
+}
diff --git a/libnl_2/cache.c b/libnl_2/cache.c
new file mode 100644
index 0000000..c21974d
--- /dev/null
+++ b/libnl_2/cache.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * 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.
+ */
+
+/* NOTICE: This is a clean room re-implementation of libnl */
+
+#include "netlink/cache.h"
+#include "netlink/object.h"
+
+void nl_cache_free(struct nl_cache *cache)
+{
+
+}
+
+void nl_cache_clear(struct nl_cache *cache)
+{
+
+}
+
+void nl_cache_remove(struct nl_object *obj)
+{
+
+}
+
+
diff --git a/libnl_2/dbg.c b/libnl_2/dbg.c
new file mode 100644
index 0000000..9764de6
--- /dev/null
+++ b/libnl_2/dbg.c
@@ -0,0 +1,12 @@
+#include "netlink/netlink.h"
+#include <android/log.h>
+
+void libnl_printf(int level, char *format, ...)
+{
+ va_list ap;
+
+ level = ANDROID_LOG_ERROR;
+ va_start(ap, format);
+ __android_log_vprint(level, "libnl_2", format, ap);
+ va_end(ap);
+}
diff --git a/libnl_2/genl/family.c b/libnl_2/genl/family.c
new file mode 100644
index 0000000..1beee6e
--- /dev/null
+++ b/libnl_2/genl/family.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * 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.
+ */
+
+/* NOTICE: This is a clean room re-implementation of libnl */
+
+#include "netlink-types.h"
+
+static struct genl_family *genl_family_find_byname(const char *name)
+{
+ return NULL;
+}
+
+/* Release reference and none outstanding */
+void genl_family_put(struct genl_family *family)
+{
+ family->ce_refcnt--;
+ if (family->ce_refcnt <= 0)
+ free(family);
+}
+
+unsigned int genl_family_get_id(struct genl_family *family)
+{
+ const int NO_FAMILY_ID = 0;
+
+ if (!family)
+ return NO_FAMILY_ID;
+ else
+ return family->gf_id;
+
+}
+
diff --git a/libnl_2/genl/genl.c b/libnl_2/genl/genl.c
new file mode 100644
index 0000000..1a39c6a
--- /dev/null
+++ b/libnl_2/genl/genl.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * 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.
+ */
+
+/* NOTICE: This is a clean room re-implementation of libnl */
+
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <linux/netlink.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/genl/family.h>
+#include "netlink-types.h"
+
+/* Get head of attribute data. */
+struct nlattr *genlmsg_attrdata(const struct genlmsghdr *gnlh, int hdrlen)
+{
+ return (struct nlattr *) \
+ ((char *) gnlh + GENL_HDRLEN + NLMSG_ALIGN(hdrlen));
+
+}
+
+/* Get length of attribute data. */
+int genlmsg_attrlen(const struct genlmsghdr *gnlh, int hdrlen)
+{
+ struct nlattr *nla;
+ struct nlmsghdr *nlh;
+
+ nla = genlmsg_attrdata(gnlh, hdrlen);
+ nlh = (struct nlmsghdr *) ((char *) gnlh - NLMSG_HDRLEN);
+ return (char *) nlmsg_tail(nlh) - (char *) nla;
+}
+
+/* Add generic netlink header to netlink message. */
+void *genlmsg_put(struct nl_msg *msg, uint32_t pid, uint32_t seq, int family,
+ int hdrlen, int flags, uint8_t cmd, uint8_t version)
+{
+ int new_size;
+ struct nlmsghdr *nlh;
+ struct timeval tv;
+ struct genlmsghdr *gmh;
+
+ /* Make sure nl_msg has enough space */
+ new_size = NLMSG_HDRLEN + GENL_HDRLEN + hdrlen;
+ if ((sizeof(struct nl_msg) + new_size) > msg->nm_size)
+ goto fail;
+
+ /* Fill in netlink header */
+ nlh = msg->nm_nlh;
+ nlh->nlmsg_len = new_size;
+ nlh->nlmsg_type = family;
+ nlh->nlmsg_pid = getpid();
+ nlh->nlmsg_flags = flags | NLM_F_REQUEST | NLM_F_ACK;
+
+ /* Get current time for sequence number */
+ if (gettimeofday(&tv, NULL))
+ nlh->nlmsg_seq = 1;
+ else
+ nlh->nlmsg_seq = (int) tv.tv_sec;
+
+ /* Setup genlmsghdr in new message */
+ gmh = (struct genlmsghdr *) ((char *)nlh + NLMSG_HDRLEN);
+ gmh->cmd = (__u8) cmd;
+ gmh->version = version;
+
+ return gmh;
+fail:
+ return NULL;
+
+}
+
+/* Socket has already been alloced to connect it to kernel? */
+int genl_connect(struct nl_sock *sk)
+{
+ return nl_connect(sk, NETLINK_GENERIC);
+
+}
+
+int genl_ctrl_alloc_cache(struct nl_sock *sock, struct nl_cache **result)
+{
+ int rc = -1;
+ int nl80211_genl_id = -1;
+ char sendbuf[sizeof(struct nlmsghdr)+sizeof(struct genlmsghdr)];
+ struct nlmsghdr nlmhdr;
+ struct genlmsghdr gmhhdr;
+ struct iovec sendmsg_iov;
+ struct msghdr msg;
+ int num_char;
+ const int RECV_BUF_SIZE = getpagesize();
+ char *recvbuf;
+ struct iovec recvmsg_iov;
+ int nl80211_flag = 0, nlm_f_multi = 0, nlmsg_done = 0;
+ struct nlmsghdr *nlh;
+
+ /* REQUEST GENERIC NETLINK FAMILY ID */
+ /* Message buffer */
+ nlmhdr.nlmsg_len = sizeof(sendbuf);
+ nlmhdr.nlmsg_type = NETLINK_GENERIC;
+ nlmhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP;
+ nlmhdr.nlmsg_seq = sock->s_seq_next;
+ nlmhdr.nlmsg_pid = sock->s_local.nl_pid;
+
+ /* Generic netlink header */
+ memset(&gmhhdr, 0, sizeof(gmhhdr));
+ gmhhdr.cmd = CTRL_CMD_GETFAMILY;
+ gmhhdr.version = CTRL_ATTR_FAMILY_ID;
+
+ /* Combine netlink and generic netlink headers */
+ memcpy(&sendbuf[0], &nlmhdr, sizeof(nlmhdr));
+ memcpy(&sendbuf[0]+sizeof(nlmhdr), &gmhhdr, sizeof(gmhhdr));
+
+ /* Create IO vector with Netlink message */
+ sendmsg_iov.iov_base = &sendbuf;
+ sendmsg_iov.iov_len = sizeof(sendbuf);
+
+ /* Socket message */
+ msg.msg_name = (void *) &sock->s_peer;
+ msg.msg_namelen = sizeof(sock->s_peer);
+ msg.msg_iov = &sendmsg_iov;
+ msg.msg_iovlen = 1; /* Only sending one iov */
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ msg.msg_flags = 0;
+
+ /* Send message and verify sent */
+ num_char = sendmsg(sock->s_fd, &msg, 0);
+ if (num_char == -1)
+ return -errno;
+
+ /* RECEIVE GENL CMD RESPONSE */
+
+ /* Create receive iov buffer */
+ recvbuf = (char *) malloc(RECV_BUF_SIZE);
+
+ /* Attach to iov */
+ recvmsg_iov.iov_base = recvbuf;
+ recvmsg_iov.iov_len = RECV_BUF_SIZE;
+
+ msg.msg_iov = &recvmsg_iov;
+ msg.msg_iovlen = 1;
+
+ /***************************************************************/
+ /* Receive message. If multipart message, keep receiving until */
+ /* message type is NLMSG_DONE */
+ /***************************************************************/
+
+ do {
+
+ int recvmsg_len, nlmsg_rem;
+
+ /* Receive message */
+ memset(recvbuf, 0, RECV_BUF_SIZE);
+ recvmsg_len = recvmsg(sock->s_fd, &msg, 0);
+
+ /* Make sure receive successful */
+ if (recvmsg_len < 0) {
+ rc = -errno;
+ goto error_recvbuf;
+ }
+
+ /* Parse nlmsghdr */
+ nlmsg_for_each_msg(nlh, (struct nlmsghdr *) recvbuf, \
+ recvmsg_len, nlmsg_rem) {
+ struct nlattr *nla;
+ int nla_rem;
+
+ /* Check type */
+ switch (nlh->nlmsg_type) {
+ case NLMSG_DONE:
+ goto return_genl_id;
+ break;
+ case NLMSG_ERROR:
+
+ /* Should check nlmsgerr struct received */
+ fprintf(stderr, "Receive message error\n");
+ goto error_recvbuf;
+ case NLMSG_OVERRUN:
+ fprintf(stderr, "Receive data partly lost\n");
+ goto error_recvbuf;
+ case NLMSG_MIN_TYPE:
+ case NLMSG_NOOP:
+ break;
+ default:
+ break;
+ }
+
+
+
+ /* Check flags */
+ if (nlh->nlmsg_flags & NLM_F_MULTI)
+ nlm_f_multi = 1;
+ else
+ nlm_f_multi = 0;
+
+ if (nlh->nlmsg_type & NLMSG_DONE)
+ nlmsg_done = 1;
+ else
+ nlmsg_done = 0;
+
+ /* Iteratve over attributes */
+ nla_for_each_attr(nla,
+ nlmsg_attrdata(nlh, GENL_HDRLEN),
+ nlmsg_attrlen(nlh, GENL_HDRLEN),
+ nla_rem){
+
+ /* If this family is nl80211 */
+ if (nla->nla_type == CTRL_ATTR_FAMILY_NAME &&
+ !strcmp((char *)nla_data(nla),
+ "nl80211"))
+ nl80211_flag = 1;
+
+ /* Save the family id */
+ else if (nl80211_flag &&
+ nla->nla_type == CTRL_ATTR_FAMILY_ID) {
+ nl80211_genl_id =
+ *((int *)nla_data(nla));
+ nl80211_flag = 0;
+ }
+
+ }
+
+ }
+
+ } while (nlm_f_multi && !nlmsg_done);
+
+return_genl_id:
+ /* Return family id as cache pointer */
+ *result = (struct nl_cache *) nl80211_genl_id;
+ rc = 0;
+error_recvbuf:
+ free(recvbuf);
+error:
+ return rc;
+}
+
+/* Checks the netlink cache to find family reference by name string */
+/* NOTE: Caller needs to call genl_family_put() when done with *
+ * returned object */
+struct genl_family *genl_ctrl_search_by_name(struct nl_cache *cache, \
+ const char *name)
+{
+ struct genl_family *gf = (struct genl_family *) \
+ malloc(sizeof(struct genl_family));
+ if (!gf)
+ goto fail;
+ memset(gf, 0, sizeof(*gf));
+
+ /* Add ref */
+ gf->ce_refcnt++;
+
+ /* Overriding cache pointer as family id for now */
+ gf->gf_id = (uint16_t) ((uint32_t) cache);
+ strncpy(gf->gf_name, name, GENL_NAMSIZ);
+
+ return gf;
+fail:
+ return NULL;
+
+}
+
+int genl_ctrl_resolve(struct nl_sock *sk, const char *name)
+{
+ struct nl_cache *cache = NULL;
+ struct genl_family *gf = NULL;
+ int id = -1;
+
+ /* Hack to support wpa_supplicant */
+ if (strcmp(name, "nlctrl") == 0)
+ return NETLINK_GENERIC;
+
+ if (strcmp(name, "nl80211") != 0) {
+ fprintf(stderr, "%s is not supported\n", name);
+ return id;
+ }
+
+ if (!genl_ctrl_alloc_cache(sk, &cache)) {
+ gf = genl_ctrl_search_by_name(cache, name);
+ if (gf)
+ id = genl_family_get_id(gf);
+ }
+
+ if (gf)
+ genl_family_put(gf);
+ if (cache)
+ nl_cache_free(cache);
+
+ return id;
+}
diff --git a/libnl_2/handlers.c b/libnl_2/handlers.c
new file mode 100644
index 0000000..48dcab4
--- /dev/null
+++ b/libnl_2/handlers.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * 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.
+ */
+
+/* NOTICE: This is a clean room re-implementation of libnl */
+
+#include <malloc.h>
+#include "netlink-types.h"
+#include "netlink/handlers.h"
+
+/* Allocate a new callback handle. */
+struct nl_cb *nl_cb_alloc(enum nl_cb_kind kind)
+{
+ struct nl_cb *cb;
+
+ cb = (struct nl_cb *) malloc(sizeof(struct nl_cb));
+ if (cb == NULL)
+ goto fail;
+ memset(cb, 0, sizeof(*cb));
+
+ return nl_cb_get(cb);
+fail:
+ return NULL;
+}
+
+/* Clone an existing callback handle */
+struct nl_cb *nl_cb_clone(struct nl_cb *orig)
+{
+ struct nl_cb *new_cb;
+
+ new_cb = nl_cb_alloc(NL_CB_DEFAULT);
+ if (new_cb == NULL)
+ goto fail;
+
+ /* Copy original and set refcount to 1 */
+ memcpy(new_cb, orig, sizeof(*orig));
+ new_cb->cb_refcnt = 1;
+
+ return new_cb;
+fail:
+ return NULL;
+}
+
+/* Set up a callback. */
+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)
+{
+ cb->cb_set[type] = func;
+ cb->cb_args[type] = arg;
+ return 0;
+}
+
+
+
+/* Set up an error callback. */
+int nl_cb_err(struct nl_cb *cb, enum nl_cb_kind kind, \
+ nl_recvmsg_err_cb_t func, void *arg)
+{
+ cb->cb_err = func;
+ cb->cb_err_arg = arg;
+ return 0;
+
+}
+
+struct nl_cb *nl_cb_get(struct nl_cb *cb)
+{
+ cb->cb_refcnt++;
+ return cb;
+}
+
+void nl_cb_put(struct nl_cb *cb)
+{
+ if (!cb)
+ return;
+ cb->cb_refcnt--;
+ if (cb->cb_refcnt <= 0)
+ free(cb);
+}
diff --git a/libnl_2/msg.c b/libnl_2/msg.c
new file mode 100644
index 0000000..1303e8a
--- /dev/null
+++ b/libnl_2/msg.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * 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.
+ */
+
+/* NOTICE: This is a clean room re-implementation of libnl */
+
+#include <malloc.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <linux/netlink.h>
+#include "netlink-types.h"
+
+/* Allocate a new netlink message with the default maximum payload size. */
+struct nl_msg *nlmsg_alloc(void)
+{
+ /* Whole page will store nl_msg + nlmsghdr + genlmsghdr + payload */
+ const int page_sz = getpagesize();
+ struct nl_msg *nm;
+ struct nlmsghdr *nlh;
+
+ /* Netlink message */
+ nm = (struct nl_msg *) malloc(page_sz);
+ if (!nm)
+ goto fail;
+
+ /* Netlink message header pointer */
+ nlh = (struct nlmsghdr *) ((char *) nm + sizeof(struct nl_msg));
+
+ /* Initialize */
+ memset(nm, 0, page_sz);
+ nm->nm_size = page_sz;
+
+ nm->nm_src.nl_family = AF_NETLINK;
+ nm->nm_src.nl_pid = getpid();
+
+ nm->nm_dst.nl_family = AF_NETLINK;
+ nm->nm_dst.nl_pid = 0; /* Kernel */
+
+ /* Initialize and add to netlink message */
+ nlh->nlmsg_len = NLMSG_HDRLEN;
+ nm->nm_nlh = nlh;
+
+ /* Add to reference count and return nl_msg */
+ nlmsg_get(nm);
+ return nm;
+fail:
+ return NULL;
+}
+
+/* Return pointer to message payload. */
+void *nlmsg_data(const struct nlmsghdr *nlh)
+{
+ return (char *) nlh + NLMSG_HDRLEN;
+}
+
+/* Add reference count to nl_msg */
+void nlmsg_get(struct nl_msg *nm)
+{
+ nm->nm_refcnt++;
+}
+
+/* Release a reference from an netlink message. */
+void nlmsg_free(struct nl_msg *nm)
+{
+ if (nm) {
+ nm->nm_refcnt--;
+ if (nm->nm_refcnt <= 0)
+ free(nm);
+ }
+
+}
+
+/* Return actual netlink message. */
+struct nlmsghdr *nlmsg_hdr(struct nl_msg *n)
+{
+ return n->nm_nlh;
+}
+
+/* Return head of attributes data / payload section */
+struct nlattr *nlmsg_attrdata(const struct nlmsghdr *nlh, int hdrlen)
+{
+ unsigned char *data = nlmsg_data(nlh);
+ return (struct nlattr *)(data + NLMSG_ALIGN(hdrlen));
+}
+
+/* Returns pointer to end of netlink message */
+void *nlmsg_tail(const struct nlmsghdr *nlh)
+{
+ return (void *)((char *)nlh + NLMSG_ALIGN(nlh->nlmsg_len));
+}
+
+/* Next netlink message in message stream */
+struct nlmsghdr *nlmsg_next(struct nlmsghdr *nlh, int *remaining)
+{
+ struct nlmsghdr *next_nlh = NULL;
+ int len = nlmsg_len(nlh);
+
+ len = NLMSG_ALIGN(len);
+ if (*remaining > 0 &&
+ len <= *remaining &&
+ len >= (int) sizeof(struct nlmsghdr)) {
+ next_nlh = (struct nlmsghdr *)((char *)nlh + len);
+ *remaining -= len;
+ }
+
+ return next_nlh;
+}
+
+int nlmsg_datalen(const struct nlmsghdr *nlh)
+{
+ return nlh->nlmsg_len - NLMSG_HDRLEN;
+}
+
+/* Length of attributes data */
+int nlmsg_attrlen(const struct nlmsghdr *nlh, int hdrlen)
+{
+ return nlmsg_datalen(nlh) - NLMSG_ALIGN(hdrlen);
+}
+
+/* Length of netlink message */
+int nlmsg_len(const struct nlmsghdr *nlh)
+{
+ return nlh->nlmsg_len;
+}
+
+/* Check if the netlink message fits into the remaining bytes */
+int nlmsg_ok(const struct nlmsghdr *nlh, int rem)
+{
+ return rem >= (int)sizeof(struct nlmsghdr) &&
+ rem >= nlmsg_len(nlh) &&
+ nlmsg_len(nlh) >= (int) sizeof(struct nlmsghdr) &&
+ nlmsg_len(nlh) <= (rem);
+}
+
+int nlmsg_padlen(int payload)
+{
+ return NLMSG_ALIGN(payload) - payload;
+}
diff --git a/libnl_2/netlink.c b/libnl_2/netlink.c
new file mode 100644
index 0000000..ee3d600
--- /dev/null
+++ b/libnl_2/netlink.c
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * 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.
+ */
+
+/* NOTICE: This is a clean room re-implementation of libnl */
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include "netlink-types.h"
+
+#define NL_BUFFER_SZ (32768U)
+
+/* Checks message for completeness and sends it out */
+int nl_send_auto_complete(struct nl_sock *sk, struct nl_msg *msg)
+{
+ struct nlmsghdr *nlh = msg->nm_nlh;
+ struct timeval tv;
+
+ if (!nlh) {
+ int errsv = errno;
+ fprintf(stderr, "Netlink message header is NULL!\n");
+ return -errsv;
+ }
+
+ /* Complete the nl_msg header */
+ if (gettimeofday(&tv, NULL))
+ nlh->nlmsg_seq = 1;
+ else
+ nlh->nlmsg_seq = (int) tv.tv_sec;
+ nlh->nlmsg_pid = sk->s_local.nl_pid;
+ nlh->nlmsg_flags |= NLM_F_REQUEST | NLM_F_ACK;
+
+ return nl_send(sk, msg);
+}
+
+/* Receives a netlink message, allocates a buffer in *buf and stores
+ * the message content. The peer's netlink address is stored in
+ * *nla. The caller is responsible for freeing the buffer allocated in
+ * *buf if a positive value is returned. Interrupted system calls are
+ * handled by repeating the read. The input buffer size is determined
+ * by peeking before the actual read is done */
+int nl_recv(struct nl_sock *sk, struct sockaddr_nl *nla, \
+ unsigned char **buf, struct ucred **creds)
+{
+ int rc = -1;
+ int sk_flags;
+ int RECV_BUF_SIZE = getpagesize();
+ int errsv;
+ struct iovec recvmsg_iov;
+ struct msghdr msg;
+
+ /* Allocate buffer */
+ *buf = (unsigned char *) malloc(RECV_BUF_SIZE);
+ if (!(*buf)) {
+ rc = -ENOMEM;
+ goto fail;
+ }
+
+ /* Prepare to receive message */
+ recvmsg_iov.iov_base = *buf;
+ recvmsg_iov.iov_len = RECV_BUF_SIZE;
+
+ msg.msg_name = (void *) &sk->s_peer;
+ msg.msg_namelen = sizeof(sk->s_peer);
+ msg.msg_iov = &recvmsg_iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ msg.msg_flags = 0;
+
+ /* Make non blocking and then restore previous setting */
+ sk_flags = fcntl(sk->s_fd, F_GETFL, 0);
+ fcntl(sk->s_fd, F_SETFL, O_NONBLOCK);
+ rc = recvmsg(sk->s_fd, &msg, 0);
+ errsv = errno;
+ fcntl(sk->s_fd, F_SETFL, sk_flags);
+
+ if (rc < 0) {
+ rc = -errsv;
+ free(*buf);
+ *buf = NULL;
+ }
+
+fail:
+ return rc;
+}
+
+/* Receive a set of messages from a netlink socket */
+/* NOTE: Does not currently support callback replacements!!! */
+int nl_recvmsgs(struct nl_sock *sk, struct nl_cb *cb)
+{
+ struct sockaddr_nl nla;
+ struct ucred *creds;
+
+ int rc, cb_rc = NL_OK, done = 0;
+
+ do {
+ unsigned char *buf;
+ int i, rem, flags;
+ struct nlmsghdr *nlh;
+ struct nlmsgerr *nlme;
+ struct nl_msg *msg;
+
+ done = 0;
+ rc = nl_recv(sk, &nla, &buf, &creds);
+ if (rc < 0)
+ break;
+
+ nlmsg_for_each_msg(nlh, (struct nlmsghdr *) buf, rc, rem) {
+
+ if (rc <= 0 || cb_rc == NL_STOP)
+ break;
+
+ /* Check for callbacks */
+
+ msg = (struct nl_msg *) malloc(sizeof(struct nl_msg));
+ memset(msg, 0, sizeof(*msg));
+ msg->nm_nlh = nlh;
+
+ /* Check netlink message type */
+
+ switch (msg->nm_nlh->nlmsg_type) {
+ case NLMSG_ERROR: /* Used for ACK too */
+ /* Certainly we should be doing some
+ * checking here to make sure this
+ * message is intended for us */
+ nlme = nlmsg_data(msg->nm_nlh);
+ if (nlme->error == 0)
+ msg->nm_nlh->nlmsg_flags |= NLM_F_ACK;
+
+ rc = nlme->error;
+ cb_rc = cb->cb_err(&nla, nlme, cb->cb_err_arg);
+ nlme = NULL;
+ break;
+
+ case NLMSG_DONE:
+ done = 1;
+
+ case NLMSG_OVERRUN:
+ case NLMSG_NOOP:
+ default:
+ break;
+ };
+
+ for (i = 0; i <= NL_CB_TYPE_MAX; i++) {
+
+ if (cb->cb_set[i]) {
+ switch (i) {
+ case NL_CB_VALID:
+ if (rc > 0)
+ cb_rc = cb->cb_set[i](msg, cb->cb_args[i]);
+ break;
+
+ case NL_CB_FINISH:
+ if ((msg->nm_nlh->nlmsg_flags & NLM_F_MULTI) &&
+ (msg->nm_nlh->nlmsg_type & NLMSG_DONE))
+ cb_rc = cb->cb_set[i](msg, cb->cb_args[i]);
+
+ break;
+
+ case NL_CB_ACK:
+ if (msg->nm_nlh->nlmsg_flags & NLM_F_ACK)
+ cb_rc = cb->cb_set[i](msg, cb->cb_args[i]);
+
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ free(msg);
+ if (done)
+ break;
+ }
+ free(buf);
+ buf = NULL;
+
+ if (done)
+ break;
+ } while (rc > 0 && cb_rc != NL_STOP);
+
+success:
+fail:
+ return rc;
+}
+
+/* Send raw data over netlink socket */
+int nl_send(struct nl_sock *sk, struct nl_msg *msg)
+{
+ struct nlmsghdr *nlh = nlmsg_hdr(msg);
+ struct iovec msg_iov;
+
+ /* Create IO vector with Netlink message */
+ msg_iov.iov_base = nlh;
+ msg_iov.iov_len = nlh->nlmsg_len;
+
+ return nl_send_iovec(sk, msg, &msg_iov, 1);
+}
+
+/* Send netlink message */
+int nl_send_iovec(struct nl_sock *sk, struct nl_msg *msg,
+ struct iovec *iov, unsigned iovlen)
+{
+ int rc;
+
+ /* Socket message */
+ struct msghdr mh = {
+ .msg_name = (void *) &sk->s_peer,
+ .msg_namelen = sizeof(sk->s_peer),
+ .msg_iov = iov,
+ .msg_iovlen = iovlen,
+ .msg_control = NULL,
+ .msg_controllen = 0,
+ .msg_flags = 0
+ };
+
+ /* Send message and verify sent */
+ rc = nl_sendmsg(sk, (struct nl_msg *) &mh, 0);
+ if (rc < 0)
+ fprintf(stderr, "Error sending netlink message: %d\n", errno);
+ return rc;
+
+}
+
+/* Send netlink message with control over sendmsg() message header */
+int nl_sendmsg(struct nl_sock *sk, struct nl_msg *msg, struct msghdr *hdr)
+{
+ return sendmsg(sk->s_fd, (struct msghdr *) msg, (int) hdr);
+}
+
+/* Create and connect netlink socket */
+int nl_connect(struct nl_sock *sk, int protocol)
+{
+ struct sockaddr addr;
+ socklen_t addrlen;
+ int rc;
+
+ /* Create RX socket */
+ sk->s_fd = socket(PF_NETLINK, SOCK_RAW, protocol);
+ if (sk->s_fd < 0)
+ return -errno;
+
+ /* Set size of RX and TX buffers */
+ if (nl_socket_set_buffer_size(sk, NL_BUFFER_SZ, NL_BUFFER_SZ) < 0)
+ return -errno;
+
+ /* Bind RX socket */
+ rc = bind(sk->s_fd, (struct sockaddr *)&sk->s_local, \
+ sizeof(sk->s_local));
+ if (rc < 0)
+ return -errno;
+ addrlen = sizeof(addr);
+ getsockname(sk->s_fd, &addr, &addrlen);
+
+ return 0;
+
+}
diff --git a/libnl_2/object.c b/libnl_2/object.c
new file mode 100644
index 0000000..c53accf
--- /dev/null
+++ b/libnl_2/object.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * 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.
+ */
+
+/* NOTICE: This is a clean room re-implementation of libnl */
+
+#include "netlink-types.h"
+
+void nl_object_put(struct nl_object *obj)
+{
+ obj->ce_refcnt--;
+ if (!obj->ce_refcnt)
+ nl_object_free(obj);
+}
+
+void nl_object_free(struct nl_object *obj)
+{
+ nl_cache_remove(obj);
+}
+
+
diff --git a/libnl_2/socket.c b/libnl_2/socket.c
new file mode 100644
index 0000000..e94eb9e
--- /dev/null
+++ b/libnl_2/socket.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * 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.
+ */
+
+/* NOTICE: This is a clean room re-implementation of libnl */
+
+#include <errno.h>
+#include <unistd.h>
+#include <malloc.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include "netlink-types.h"
+
+/* Join group */
+int nl_socket_add_membership(struct nl_sock *sk, int group)
+{
+ return setsockopt(sk->s_fd, SOL_NETLINK,
+ NETLINK_ADD_MEMBERSHIP, &group, sizeof(group));
+}
+
+/* Allocate new netlink socket. */
+static struct nl_sock *_nl_socket_alloc(void)
+{
+ struct nl_sock *sk;
+ struct timeval tv;
+ struct nl_cb *cb;
+
+ sk = (struct nl_sock *) malloc(sizeof(struct nl_sock));
+ if (!sk)
+ return NULL;
+ memset(sk, 0, sizeof(*sk));
+
+ /* Get current time */
+
+ if (gettimeofday(&tv, NULL))
+ goto fail;
+ else
+ sk->s_seq_next = (int) tv.tv_sec;
+
+ /* Create local socket */
+ sk->s_local.nl_family = AF_NETLINK;
+ sk->s_local.nl_pid = 0; /* Kernel fills in pid */
+ sk->s_local.nl_groups = 0; /* No groups */
+
+ /* Create peer socket */
+ sk->s_peer.nl_family = AF_NETLINK;
+ sk->s_peer.nl_pid = 0; /* Kernel */
+ sk->s_peer.nl_groups = 0; /* No groups */
+
+ return sk;
+fail:
+ free(sk);
+ return NULL;
+}
+
+/* Allocate new netlink socket. */
+struct nl_sock *nl_socket_alloc(void)
+{
+ struct nl_sock *sk = _nl_socket_alloc();
+ struct nl_cb *cb;
+
+ if (!sk)
+ return NULL;
+
+ cb = nl_cb_alloc(NL_CB_DEFAULT);
+ if (!cb)
+ goto cb_fail;
+ sk->s_cb = cb;
+ return sk;
+cb_fail:
+ free(sk);
+ return NULL;
+}
+
+/* Allocate new socket with custom callbacks. */
+struct nl_sock *nl_socket_alloc_cb(struct nl_cb *cb)
+{
+ struct nl_sock *sk = _nl_socket_alloc();
+
+ if (!sk)
+ return NULL;
+
+ sk->s_cb = cb;
+ nl_cb_get(cb);
+
+ return sk;
+}
+
+/* Free a netlink socket. */
+void nl_socket_free(struct nl_sock *sk)
+{
+ nl_cb_put(sk->s_cb);
+ close(sk->s_fd);
+ free(sk);
+}
+
+/* Sets socket buffer size of netlink socket */
+int nl_socket_set_buffer_size(struct nl_sock *sk, int rxbuf, int txbuf)
+{
+ if (setsockopt(sk->s_fd, SOL_SOCKET, SO_SNDBUF, \
+ &rxbuf, (socklen_t) sizeof(rxbuf)))
+ goto error;
+
+ if (setsockopt(sk->s_fd, SOL_SOCKET, SO_RCVBUF, \
+ &txbuf, (socklen_t) sizeof(txbuf)))
+ goto error;
+
+ return 0;
+error:
+ return -errno;
+
+}
+
+int nl_socket_get_fd(struct nl_sock *sk)
+{
+ return sk->s_fd;
+}
+
+void nl_socket_set_cb(struct nl_sock *sk, struct nl_cb *cb)
+{
+ nl_cb_put(sk->s_cb);
+ sk->s_cb = cb;
+ nl_cb_get(cb);
+}
+
+struct nl_cb *nl_socket_get_cb(struct nl_sock *sk)
+{
+ return nl_cb_get(sk->s_cb);
+}