genl.c revision 2d9a6281ca4fdacd88098f3b135b89b9d0c65226
1ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker/* 2ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * Copyright (C) 2011 The Android Open Source Project 3ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * 4ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * Licensed under the Apache License, Version 2.0 (the "License"); 5ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * you may not use this file except in compliance with the License. 6ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * You may obtain a copy of the License at 7ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * 8ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * http://www.apache.org/licenses/LICENSE-2.0 9ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * 10ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * Unless required by applicable law or agreed to in writing, software 11ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * distributed under the License is distributed on an "AS IS" BASIS, 12ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * See the License for the specific language governing permissions and 14ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * limitations under the License. 15ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker */ 16ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 17ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker/* NOTICE: This is a clean room re-implementation of libnl */ 18ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 19ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker#include <errno.h> 20ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker#include <unistd.h> 21ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker#include <stdio.h> 22ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker#include <sys/time.h> 23ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker#include <linux/netlink.h> 242d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt#include <netlink/genl/ctrl.h> 252d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt#include <netlink/genl/family.h> 26ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker#include "netlink-types.h" 27ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 28ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker/* Get head of attribute data. */ 29ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makerstruct nlattr *genlmsg_attrdata(const struct genlmsghdr *gnlh, int hdrlen) 30ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker{ 31ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker return (struct nlattr *) \ 32ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker ((char *) gnlh + GENL_HDRLEN + NLMSG_ALIGN(hdrlen)); 33ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 34ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker} 35ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 36ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker/* Get length of attribute data. */ 37ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makerint genlmsg_attrlen(const struct genlmsghdr *gnlh, int hdrlen) 38ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker{ 39ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker struct nlattr *nla; 40ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker struct nlmsghdr *nlh; 41ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 42ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker nla = genlmsg_attrdata(gnlh, hdrlen); 43ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker nlh = (struct nlmsghdr *) ((char *) gnlh - NLMSG_HDRLEN); 44ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker return (char *) nlmsg_tail(nlh) - (char *) nla; 45ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker} 46ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 47ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker/* Add generic netlink header to netlink message. */ 48ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makervoid *genlmsg_put(struct nl_msg *msg, uint32_t pid, uint32_t seq, int family, 49ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker int hdrlen, int flags, uint8_t cmd, uint8_t version) 50ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker{ 51ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker int new_size; 52ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker struct nlmsghdr *nlh; 53ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker struct timeval tv; 54ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker struct genlmsghdr *gmh; 55ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 56ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker /* Make sure nl_msg has enough space */ 57ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker new_size = NLMSG_HDRLEN + GENL_HDRLEN + hdrlen; 58ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker if ((sizeof(struct nl_msg) + new_size) > msg->nm_size) 59ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker goto fail; 60ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 61ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker /* Fill in netlink header */ 62ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker nlh = msg->nm_nlh; 63ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker nlh->nlmsg_len = new_size; 64ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker nlh->nlmsg_type = family; 65ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker nlh->nlmsg_pid = getpid(); 66ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker nlh->nlmsg_flags = flags | NLM_F_REQUEST | NLM_F_ACK; 67ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 68ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker /* Get current time for sequence number */ 69ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker if (gettimeofday(&tv, NULL)) 70ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker nlh->nlmsg_seq = 1; 71ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker else 72ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker nlh->nlmsg_seq = (int) tv.tv_sec; 73ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 74ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker /* Setup genlmsghdr in new message */ 75ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker gmh = (struct genlmsghdr *) ((char *)nlh + NLMSG_HDRLEN); 76ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker gmh->cmd = (__u8) cmd; 77ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker gmh->version = version; 78ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 79ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker return gmh; 80ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makerfail: 81ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker return NULL; 82ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 83ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker} 84ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 85ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker/* Socket has already been alloced to connect it to kernel? */ 86ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makerint genl_connect(struct nl_sock *sk) 87ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker{ 88ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker return nl_connect(sk, NETLINK_GENERIC); 89ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 90ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker} 91ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 92ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makerint genl_ctrl_alloc_cache(struct nl_sock *sock, struct nl_cache **result) 93ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker{ 94ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker int rc = -1; 95ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker int nl80211_genl_id = -1; 96ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker char sendbuf[sizeof(struct nlmsghdr)+sizeof(struct genlmsghdr)]; 97ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker struct nlmsghdr nlmhdr; 98ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker struct genlmsghdr gmhhdr; 99ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker struct iovec sendmsg_iov; 100ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker struct msghdr msg; 101ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker int num_char; 102ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker const int RECV_BUF_SIZE = getpagesize(); 103ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker char *recvbuf; 104ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker struct iovec recvmsg_iov; 105ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker int nl80211_flag = 0, nlm_f_multi = 0, nlmsg_done = 0; 106ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker struct nlmsghdr *nlh; 107ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 108ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker /* REQUEST GENERIC NETLINK FAMILY ID */ 109ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker /* Message buffer */ 110ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker nlmhdr.nlmsg_len = sizeof(sendbuf); 111ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker nlmhdr.nlmsg_type = NETLINK_GENERIC; 112ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker nlmhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP; 113ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker nlmhdr.nlmsg_seq = sock->s_seq_next; 114ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker nlmhdr.nlmsg_pid = sock->s_local.nl_pid; 115ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 116ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker /* Generic netlink header */ 117e5de9ee4915bafd7f31a96260613d8b93aba8351Dmitry Shmidt memset(&gmhhdr, 0, sizeof(gmhhdr)); 118ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker gmhhdr.cmd = CTRL_CMD_GETFAMILY; 119ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker gmhhdr.version = CTRL_ATTR_FAMILY_ID; 120ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 121ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker /* Combine netlink and generic netlink headers */ 122ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker memcpy(&sendbuf[0], &nlmhdr, sizeof(nlmhdr)); 123ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker memcpy(&sendbuf[0]+sizeof(nlmhdr), &gmhhdr, sizeof(gmhhdr)); 124ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 125ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker /* Create IO vector with Netlink message */ 126ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker sendmsg_iov.iov_base = &sendbuf; 127ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker sendmsg_iov.iov_len = sizeof(sendbuf); 128ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 129ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker /* Socket message */ 130ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker msg.msg_name = (void *) &sock->s_peer; 131ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker msg.msg_namelen = sizeof(sock->s_peer); 132ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker msg.msg_iov = &sendmsg_iov; 133ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker msg.msg_iovlen = 1; /* Only sending one iov */ 134ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker msg.msg_control = NULL; 135ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker msg.msg_controllen = 0; 136ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker msg.msg_flags = 0; 137ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 138ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker /* Send message and verify sent */ 139ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker num_char = sendmsg(sock->s_fd, &msg, 0); 140ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker if (num_char == -1) 141ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker return -errno; 142ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 143ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker /* RECEIVE GENL CMD RESPONSE */ 144ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 145ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker /* Create receive iov buffer */ 146ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker recvbuf = (char *) malloc(RECV_BUF_SIZE); 147ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 148ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker /* Attach to iov */ 149ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker recvmsg_iov.iov_base = recvbuf; 150ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker recvmsg_iov.iov_len = RECV_BUF_SIZE; 151ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 152ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker msg.msg_iov = &recvmsg_iov; 153ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker msg.msg_iovlen = 1; 154ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 155ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker /***************************************************************/ 156ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker /* Receive message. If multipart message, keep receiving until */ 157ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker /* message type is NLMSG_DONE */ 158ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker /***************************************************************/ 159ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 160ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker do { 161ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 162ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker int recvmsg_len, nlmsg_rem; 163ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 164ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker /* Receive message */ 165ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker memset(recvbuf, 0, RECV_BUF_SIZE); 166ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker recvmsg_len = recvmsg(sock->s_fd, &msg, 0); 167ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 168ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker /* Make sure receive successful */ 169ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker if (recvmsg_len < 0) { 170ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker rc = -errno; 171ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker goto error_recvbuf; 172ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker } 173ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 174ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker /* Parse nlmsghdr */ 175ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker nlmsg_for_each_msg(nlh, (struct nlmsghdr *) recvbuf, \ 176ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker recvmsg_len, nlmsg_rem) { 177ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker struct nlattr *nla; 178ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker int nla_rem; 179ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 180ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker /* Check type */ 181ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker switch (nlh->nlmsg_type) { 182ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker case NLMSG_DONE: 183ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker goto return_genl_id; 184ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker break; 185ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker case NLMSG_ERROR: 186ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 187ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker /* Should check nlmsgerr struct received */ 188ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker fprintf(stderr, "Receive message error\n"); 189ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker goto error_recvbuf; 190ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker case NLMSG_OVERRUN: 191ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker fprintf(stderr, "Receive data partly lost\n"); 192ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker goto error_recvbuf; 193ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker case NLMSG_MIN_TYPE: 194ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker case NLMSG_NOOP: 195ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker break; 196ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker default: 197ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker break; 198ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker } 199ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 200ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 201ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 202ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker /* Check flags */ 203ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker if (nlh->nlmsg_flags & NLM_F_MULTI) 204ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker nlm_f_multi = 1; 205ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker else 206ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker nlm_f_multi = 0; 207ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 208ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker if (nlh->nlmsg_type & NLMSG_DONE) 209ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker nlmsg_done = 1; 210ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker else 211ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker nlmsg_done = 0; 212ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 213ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker /* Iteratve over attributes */ 214ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker nla_for_each_attr(nla, 215ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker nlmsg_attrdata(nlh, GENL_HDRLEN), 216ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker nlmsg_attrlen(nlh, GENL_HDRLEN), 217ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker nla_rem){ 218ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 219ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker /* If this family is nl80211 */ 220ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker if (nla->nla_type == CTRL_ATTR_FAMILY_NAME && 221ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker !strcmp((char *)nla_data(nla), 222ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker "nl80211")) 223ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker nl80211_flag = 1; 224ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 225ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker /* Save the family id */ 226ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker else if (nl80211_flag && 227e5de9ee4915bafd7f31a96260613d8b93aba8351Dmitry Shmidt nla->nla_type == CTRL_ATTR_FAMILY_ID) { 228e5de9ee4915bafd7f31a96260613d8b93aba8351Dmitry Shmidt nl80211_genl_id = 229ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker *((int *)nla_data(nla)); 230e5de9ee4915bafd7f31a96260613d8b93aba8351Dmitry Shmidt nl80211_flag = 0; 231e5de9ee4915bafd7f31a96260613d8b93aba8351Dmitry Shmidt } 232ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 233ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker } 234ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 235ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker } 236ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 237ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker } while (nlm_f_multi && !nlmsg_done); 238ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 239ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makerreturn_genl_id: 240ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker /* Return family id as cache pointer */ 241ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker *result = (struct nl_cache *) nl80211_genl_id; 242ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker rc = 0; 243ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makererror_recvbuf: 244ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker free(recvbuf); 245ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makererror: 246ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker return rc; 247ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker} 248ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 249ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker/* Checks the netlink cache to find family reference by name string */ 250ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker/* NOTE: Caller needs to call genl_family_put() when done with * 251ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * returned object */ 252ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makerstruct genl_family *genl_ctrl_search_by_name(struct nl_cache *cache, \ 253ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker const char *name) 254ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker{ 255ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker struct genl_family *gf = (struct genl_family *) \ 256ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker malloc(sizeof(struct genl_family)); 257ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker if (!gf) 258ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker goto fail; 259ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker memset(gf, 0, sizeof(*gf)); 260ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 261ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker /* Add ref */ 262ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker gf->ce_refcnt++; 263ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 264ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker /* Overriding cache pointer as family id for now */ 265ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker gf->gf_id = (uint16_t) ((uint32_t) cache); 2662d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt strncpy(gf->gf_name, name, GENL_NAMSIZ); 267ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 268ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker return gf; 269ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makerfail: 270ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker return NULL; 271ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 272ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker} 273ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 274ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makerint genl_ctrl_resolve(struct nl_sock *sk, const char *name) 275ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker{ 2762d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt struct nl_cache *cache = NULL; 2772d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt struct genl_family *gf = NULL; 2782d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt int id = -1; 2792d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt 280ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker /* Hack to support wpa_supplicant */ 281ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker if (strcmp(name, "nlctrl") == 0) 282ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker return NETLINK_GENERIC; 2832d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt 2842d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt if (strcmp(name, "nl80211") != 0) { 2852d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt fprintf(stderr, "%s is not supported\n", name); 2862d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt return id; 287ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker } 288ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 2892d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt if (!genl_ctrl_alloc_cache(sk, &cache)) { 2902d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt gf = genl_ctrl_search_by_name(cache, name); 2912d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt if (gf) 2922d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt id = genl_family_get_id(gf); 2932d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt } 2942d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt 2952d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt if (gf) 2962d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt genl_family_put(gf); 2972d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt if (cache) 2982d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt nl_cache_free(cache); 299ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker 3002d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt return id; 3012d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt} 302