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