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