diff options
author | Colin Cross <ccross@android.com> | 2014-03-21 16:59:20 -0700 |
---|---|---|
committer | Colin Cross <ccross@android.com> | 2014-03-21 17:05:29 -0700 |
commit | a63a9ec8085f43a9eb49ada8d50cac1431944b18 (patch) | |
tree | 13582ece0bc8542614f9a10e0ef8b1f0fadeda35 /libnl_2/genl | |
parent | f8f0531bb69a90e87f1bafa875e665e3935610b1 (diff) | |
download | system_core-a63a9ec8085f43a9eb49ada8d50cac1431944b18.zip system_core-a63a9ec8085f43a9eb49ada8d50cac1431944b18.tar.gz system_core-a63a9ec8085f43a9eb49ada8d50cac1431944b18.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/genl')
-rw-r--r-- | libnl_2/genl/family.c | 44 | ||||
-rw-r--r-- | libnl_2/genl/genl.c | 302 |
2 files changed, 346 insertions, 0 deletions
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; +} |