genl.c revision b77d3d724945f38b39f3116e3aead4edcbd08a36
15bc087c573c70c84c6a39946457590b42d392a33Andreas Huber/* 25bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * Copyright (C) 2011 The Android Open Source Project 35bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * 45bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License"); 55bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * you may not use this file except in compliance with the License. 65bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * You may obtain a copy of the License at 75bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * 85bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * http://www.apache.org/licenses/LICENSE-2.0 95bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * 105bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * Unless required by applicable law or agreed to in writing, software 115bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS, 125bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * See the License for the specific language governing permissions and 145bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * limitations under the License. 155bc087c573c70c84c6a39946457590b42d392a33Andreas Huber */ 165bc087c573c70c84c6a39946457590b42d392a33Andreas Huber 175bc087c573c70c84c6a39946457590b42d392a33Andreas Huber/* NOTICE: This is a clean room re-implementation of libnl */ 185bc087c573c70c84c6a39946457590b42d392a33Andreas Huber 195bc087c573c70c84c6a39946457590b42d392a33Andreas Huber#include <errno.h> 205bc087c573c70c84c6a39946457590b42d392a33Andreas Huber#include <unistd.h> 215bc087c573c70c84c6a39946457590b42d392a33Andreas Huber#include <stdio.h> 225bc087c573c70c84c6a39946457590b42d392a33Andreas Huber#include <sys/time.h> 235bc087c573c70c84c6a39946457590b42d392a33Andreas Huber#include <sys/socket.h> 245bc087c573c70c84c6a39946457590b42d392a33Andreas Huber#include <linux/netlink.h> 255bc087c573c70c84c6a39946457590b42d392a33Andreas Huber#include "netlink-types.h" 265bc087c573c70c84c6a39946457590b42d392a33Andreas Huber 275bc087c573c70c84c6a39946457590b42d392a33Andreas Huber/* Get head of attribute data. */ 285bc087c573c70c84c6a39946457590b42d392a33Andreas Huberstruct nlattr *genlmsg_attrdata(const struct genlmsghdr *gnlh, int hdrlen) 295bc087c573c70c84c6a39946457590b42d392a33Andreas Huber{ 307314fa17093d514199fedcb55ac41136a1b31cb3Andreas Huber return (struct nlattr *) \ 317314fa17093d514199fedcb55ac41136a1b31cb3Andreas Huber ((char *) gnlh + GENL_HDRLEN + NLMSG_ALIGN(hdrlen)); 327314fa17093d514199fedcb55ac41136a1b31cb3Andreas Huber 337314fa17093d514199fedcb55ac41136a1b31cb3Andreas Huber} 347314fa17093d514199fedcb55ac41136a1b31cb3Andreas Huber 355bc087c573c70c84c6a39946457590b42d392a33Andreas Huber/* Get length of attribute data. */ 3643c3e6ce02215ca99d506458f596cb1211639f29Andreas Huberint genlmsg_attrlen(const struct genlmsghdr *gnlh, int hdrlen) 375bc087c573c70c84c6a39946457590b42d392a33Andreas Huber{ 385bc087c573c70c84c6a39946457590b42d392a33Andreas Huber struct nlattr *nla; 3943c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber struct nlmsghdr *nlh; 405bc087c573c70c84c6a39946457590b42d392a33Andreas Huber 4143c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber nla = genlmsg_attrdata(gnlh, hdrlen); 4243c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber nlh = (struct nlmsghdr *) ((char *) gnlh - NLMSG_HDRLEN); 4343c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber return (char *) nlmsg_tail(nlh) - (char *) nla; 4443c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber} 4543c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber 4643c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber/* Add generic netlink header to netlink message. */ 475bc087c573c70c84c6a39946457590b42d392a33Andreas Hubervoid *genlmsg_put(struct nl_msg *msg, uint32_t pid, uint32_t seq, int family, 485bc087c573c70c84c6a39946457590b42d392a33Andreas Huber int hdrlen, int flags, uint8_t cmd, uint8_t version) 495bc087c573c70c84c6a39946457590b42d392a33Andreas Huber{ 505bc087c573c70c84c6a39946457590b42d392a33Andreas Huber int new_size; 515bc087c573c70c84c6a39946457590b42d392a33Andreas Huber struct nlmsghdr *nlh; 525bc087c573c70c84c6a39946457590b42d392a33Andreas Huber struct timeval tv; 537314fa17093d514199fedcb55ac41136a1b31cb3Andreas Huber struct genlmsghdr *gmh; 545bc087c573c70c84c6a39946457590b42d392a33Andreas Huber 555bc087c573c70c84c6a39946457590b42d392a33Andreas Huber /* Make sure nl_msg has enough space */ 565bc087c573c70c84c6a39946457590b42d392a33Andreas Huber new_size = NLMSG_HDRLEN + GENL_HDRLEN + hdrlen; 575bc087c573c70c84c6a39946457590b42d392a33Andreas Huber if ((sizeof(struct nl_msg) + new_size) > msg->nm_size) 585bc087c573c70c84c6a39946457590b42d392a33Andreas Huber goto fail; 595bc087c573c70c84c6a39946457590b42d392a33Andreas Huber 605bc087c573c70c84c6a39946457590b42d392a33Andreas Huber /* Fill in netlink header */ 615bc087c573c70c84c6a39946457590b42d392a33Andreas Huber nlh = msg->nm_nlh; 625bc087c573c70c84c6a39946457590b42d392a33Andreas Huber nlh->nlmsg_len = new_size; 635bc087c573c70c84c6a39946457590b42d392a33Andreas Huber nlh->nlmsg_type = family; 645bc087c573c70c84c6a39946457590b42d392a33Andreas Huber nlh->nlmsg_pid = getpid(); 655bc087c573c70c84c6a39946457590b42d392a33Andreas Huber nlh->nlmsg_flags = flags | NLM_F_REQUEST | NLM_F_ACK; 66 67 /* Get current time for sequence number */ 68 if (gettimeofday(&tv, NULL)) 69 nlh->nlmsg_seq = 1; 70 else 71 nlh->nlmsg_seq = (int) tv.tv_sec; 72 73 /* Setup genlmsghdr in new message */ 74 gmh = (struct genlmsghdr *) ((char *)nlh + NLMSG_HDRLEN); 75 gmh->cmd = (__u8) cmd; 76 gmh->version = version; 77 78 return gmh; 79fail: 80 return NULL; 81 82} 83 84/* Socket has already been alloced to connect it to kernel? */ 85int genl_connect(struct nl_sock *sk) 86{ 87 return nl_connect(sk, NETLINK_GENERIC); 88 89} 90 91int genl_ctrl_alloc_cache(struct nl_sock *sock, struct nl_cache **result) 92{ 93 int rc = -1; 94 int nl80211_genl_id = -1; 95 char sendbuf[sizeof(struct nlmsghdr)+sizeof(struct genlmsghdr)]; 96 struct nlmsghdr nlmhdr; 97 struct genlmsghdr gmhhdr; 98 struct iovec sendmsg_iov; 99 struct msghdr msg; 100 int num_char; 101 const int RECV_BUF_SIZE = getpagesize(); 102 char *recvbuf; 103 struct iovec recvmsg_iov; 104 int nl80211_flag = 0, nlm_f_multi = 0, nlmsg_done = 0; 105 struct nlmsghdr *nlh; 106 107 /* REQUEST GENERIC NETLINK FAMILY ID */ 108 /* Message buffer */ 109 nlmhdr.nlmsg_len = sizeof(sendbuf); 110 nlmhdr.nlmsg_type = NETLINK_GENERIC; 111 nlmhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP; 112 nlmhdr.nlmsg_seq = sock->s_seq_next; 113 nlmhdr.nlmsg_pid = sock->s_local.nl_pid; 114 115 /* Generic netlink header */ 116 memset(&gmhhdr, 0, sizeof(gmhhdr)); 117 gmhhdr.cmd = CTRL_CMD_GETFAMILY; 118 gmhhdr.version = CTRL_ATTR_FAMILY_ID; 119 120 /* Combine netlink and generic netlink headers */ 121 memcpy(&sendbuf[0], &nlmhdr, sizeof(nlmhdr)); 122 memcpy(&sendbuf[0]+sizeof(nlmhdr), &gmhhdr, sizeof(gmhhdr)); 123 124 /* Create IO vector with Netlink message */ 125 sendmsg_iov.iov_base = &sendbuf; 126 sendmsg_iov.iov_len = sizeof(sendbuf); 127 128 /* Socket message */ 129 msg.msg_name = (void *) &sock->s_peer; 130 msg.msg_namelen = sizeof(sock->s_peer); 131 msg.msg_iov = &sendmsg_iov; 132 msg.msg_iovlen = 1; /* Only sending one iov */ 133 msg.msg_control = NULL; 134 msg.msg_controllen = 0; 135 msg.msg_flags = 0; 136 137 /* Send message and verify sent */ 138 num_char = sendmsg(sock->s_fd, &msg, 0); 139 if (num_char == -1) 140 return -errno; 141 142 /* RECEIVE GENL CMD RESPONSE */ 143 144 /* Create receive iov buffer */ 145 recvbuf = (char *) malloc(RECV_BUF_SIZE); 146 147 /* Attach to iov */ 148 recvmsg_iov.iov_base = recvbuf; 149 recvmsg_iov.iov_len = RECV_BUF_SIZE; 150 151 msg.msg_iov = &recvmsg_iov; 152 msg.msg_iovlen = 1; 153 154 /***************************************************************/ 155 /* Receive message. If multipart message, keep receiving until */ 156 /* message type is NLMSG_DONE */ 157 /***************************************************************/ 158 159 do { 160 161 int recvmsg_len, nlmsg_rem; 162 163 /* Receive message */ 164 memset(recvbuf, 0, RECV_BUF_SIZE); 165 recvmsg_len = recvmsg(sock->s_fd, &msg, 0); 166 167 /* Make sure receive successful */ 168 if (recvmsg_len < 0) { 169 rc = -errno; 170 goto error_recvbuf; 171 } 172 173 /* Parse nlmsghdr */ 174 nlmsg_for_each_msg(nlh, (struct nlmsghdr *) recvbuf, \ 175 recvmsg_len, nlmsg_rem) { 176 struct nlattr *nla; 177 int nla_rem; 178 179 /* Check type */ 180 switch (nlh->nlmsg_type) { 181 case NLMSG_DONE: 182 goto return_genl_id; 183 break; 184 case NLMSG_ERROR: 185 186 /* Should check nlmsgerr struct received */ 187 fprintf(stderr, "Receive message error\n"); 188 goto error_recvbuf; 189 case NLMSG_OVERRUN: 190 fprintf(stderr, "Receive data partly lost\n"); 191 goto error_recvbuf; 192 case NLMSG_MIN_TYPE: 193 case NLMSG_NOOP: 194 break; 195 default: 196 break; 197 } 198 199 200 201 /* Check flags */ 202 if (nlh->nlmsg_flags & NLM_F_MULTI) 203 nlm_f_multi = 1; 204 else 205 nlm_f_multi = 0; 206 207 if (nlh->nlmsg_type & NLMSG_DONE) 208 nlmsg_done = 1; 209 else 210 nlmsg_done = 0; 211 212 /* Iteratve over attributes */ 213 nla_for_each_attr(nla, 214 nlmsg_attrdata(nlh, GENL_HDRLEN), 215 nlmsg_attrlen(nlh, GENL_HDRLEN), 216 nla_rem){ 217 218 /* If this family is nl80211 */ 219 if (nla->nla_type == CTRL_ATTR_FAMILY_NAME && 220 !strcmp((char *)nla_data(nla), 221 "nl80211")) 222 nl80211_flag = 1; 223 224 /* Save the family id */ 225 else if (nl80211_flag && 226 nla->nla_type == CTRL_ATTR_FAMILY_ID) { 227 nl80211_genl_id = 228 *((int *)nla_data(nla)); 229 nl80211_flag = 0; 230 } 231 232 } 233 234 } 235 236 } while (nlm_f_multi && !nlmsg_done); 237 238return_genl_id: 239 /* Return family id as cache pointer */ 240 *result = (struct nl_cache *) nl80211_genl_id; 241 rc = 0; 242error_recvbuf: 243 free(recvbuf); 244error: 245 return rc; 246} 247 248/* Checks the netlink cache to find family reference by name string */ 249/* NOTE: Caller needs to call genl_family_put() when done with * 250 * returned object */ 251struct genl_family *genl_ctrl_search_by_name(struct nl_cache *cache, \ 252 const char *name) 253{ 254 /* TODO: When will we release this memory ? */ 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 strcpy(gf->gf_name, "nl80211"); 267 268 return gf; 269fail: 270 return NULL; 271 272} 273 274int genl_ctrl_resolve(struct nl_sock *sk, const char *name) 275{ 276 /* Hack to support wpa_supplicant */ 277 if (strcmp(name, "nlctrl") == 0) 278 return NETLINK_GENERIC; 279 else { 280 int errsv = errno; 281 fprintf(stderr, \ 282 "Only nlctrl supported by genl_ctrl_resolve!\n"); 283 return -errsv; 284 } 285 286} 287 288