DO NOT MERGE: Revert "delete libnl_2"
This reverts commit 7097f052d9
.
libnl_2 needs to stay in AOSP for now for compatibility with
GPL test builds.
This commit is contained in:
parent
7ab32aca56
commit
6e3fffeca6
|
@ -0,0 +1,2 @@
|
|||
include/netlink/version.h.in
|
||||
cscope.*
|
|
@ -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)
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue