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