wifi_hal.cpp revision 7f9a15d554f69311a0db43347d6473a7c4c46e2e
1 2#include <stdint.h> 3#include <fcntl.h> 4#include <sys/socket.h> 5#include <netlink/genl/genl.h> 6#include <netlink/genl/family.h> 7#include <netlink/genl/ctrl.h> 8#include <linux/rtnetlink.h> 9#include <netpacket/packet.h> 10#include <linux/filter.h> 11#include <linux/errqueue.h> 12 13#include <linux/pkt_sched.h> 14#include <netlink/object-api.h> 15#include <netlink/netlink.h> 16#include <netlink/socket.h> 17#include <netlink/attr.h> 18#include <netlink/handlers.h> 19#include <netlink/msg.h> 20 21#include <linux/nl80211.h> 22 23#include <dirent.h> 24#include <net/if.h> 25 26#include "sync.h" 27 28#define LOG_TAG "WifiHAL" 29 30#include <utils/Log.h> 31 32#include "wifi_hal.h" 33#include "common.h" 34#include "cpp_bindings.h" 35 36/* 37 BUGBUG: normally, libnl allocates ports for all connections it makes; but 38 being a static library, it doesn't really know how many other netlink connections 39 are made by the same process, if connections come from different shared libraries. 40 These port assignments exist to solve that problem - temporarily. We need to fix 41 libnl to try and allocate ports across the entire process. 42 */ 43 44#define WIFI_HAL_CMD_SOCK_PORT 644 45#define WIFI_HAL_EVENT_SOCK_PORT 645 46 47static void internal_event_handler(wifi_handle handle, int events); 48static int internal_valid_message_handler(nl_msg *msg, void *arg); 49static int wifi_get_multicast_id(wifi_handle handle, const char *name, const char *group); 50static int wifi_add_membership(wifi_handle handle, const char *group); 51static wifi_error wifi_init_interfaces(wifi_handle handle); 52 53/* Initialize/Cleanup */ 54 55void wifi_socket_set_local_port(struct nl_sock *sock, uint32_t port) 56{ 57 uint32_t pid = getpid() & 0x3FFFFF; 58 nl_socket_set_local_port(sock, pid + (port << 22)); 59} 60 61static nl_sock * wifi_create_nl_socket(int port) 62{ 63 // ALOGI("Creating socket"); 64 struct nl_sock *sock = nl_socket_alloc(); 65 if (sock == NULL) { 66 ALOGE("Could not create handle"); 67 return NULL; 68 } 69 70 wifi_socket_set_local_port(sock, port); 71 72 struct sockaddr_nl *addr_nl = NULL; 73 struct sockaddr *addr = NULL; 74 ALOGI("sizeof(sockaddr) = %zu, sizeof(sockaddr_nl) = %zu", sizeof(*addr), sizeof(*addr_nl)); 75 76 // ALOGI("Connecting socket"); 77 if (nl_connect(sock, NETLINK_GENERIC)) { 78 ALOGE("Could not connect handle"); 79 nl_socket_free(sock); 80 return NULL; 81 } 82 83 // ALOGI("Making socket nonblocking"); 84 if (nl_socket_set_nonblocking(sock)) { 85 ALOGE("Could make socket non-blocking"); 86 nl_socket_free(sock); 87 return NULL; 88 } 89 90 return sock; 91} 92 93wifi_error wifi_initialize(wifi_handle *handle) 94{ 95 srand(getpid()); 96 97 ALOGI("Initializing wifi"); 98 hal_info *info = (hal_info *)malloc(sizeof(hal_info)); 99 if (info == NULL) { 100 ALOGE("Could not allocate hal_info"); 101 return WIFI_ERROR_UNKNOWN; 102 } 103 104 memset(info, 0, sizeof(*info)); 105 106 ALOGI("Creating socket"); 107 struct nl_sock *cmd_sock = wifi_create_nl_socket(WIFI_HAL_CMD_SOCK_PORT); 108 if (cmd_sock == NULL) { 109 ALOGE("Could not create handle"); 110 return WIFI_ERROR_UNKNOWN; 111 } 112 113 struct nl_sock *event_sock = wifi_create_nl_socket(WIFI_HAL_EVENT_SOCK_PORT); 114 if (event_sock == NULL) { 115 ALOGE("Could not create handle"); 116 nl_socket_free(cmd_sock); 117 return WIFI_ERROR_UNKNOWN; 118 } 119 120 struct nl_cb *cb = nl_socket_get_cb(event_sock); 121 if (cb == NULL) { 122 ALOGE("Could not create handle"); 123 return WIFI_ERROR_UNKNOWN; 124 } 125 126 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, internal_valid_message_handler, info); 127 nl_cb_put(cb); 128 129 info->cmd_sock = cmd_sock; 130 info->event_sock = event_sock; 131 info->clean_up = false; 132 info->in_event_loop = false; 133 134 info->event_cb = (cb_info *)malloc(sizeof(cb_info) * DEFAULT_EVENT_CB_SIZE); 135 info->alloc_event_cb = DEFAULT_EVENT_CB_SIZE; 136 info->num_event_cb = 0; 137 138 info->cmd = (cmd_info *)malloc(sizeof(cmd_info) * DEFAULT_CMD_SIZE); 139 info->alloc_cmd = DEFAULT_CMD_SIZE; 140 info->num_cmd = 0; 141 142 info->nl80211_family_id = genl_ctrl_resolve(cmd_sock, "nl80211"); 143 if (info->nl80211_family_id < 0) { 144 ALOGE("Could not resolve nl80211 familty id"); 145 nl_socket_free(cmd_sock); 146 nl_socket_free(event_sock); 147 free(info); 148 return WIFI_ERROR_UNKNOWN; 149 } 150 151 *handle = info; 152 153 wifi_add_membership(*handle, "scan"); 154 wifi_add_membership(*handle, "mlme"); 155 wifi_add_membership(*handle, "regulatory"); 156 wifi_add_membership(*handle, "vendor"); 157 158 wifi_init_interfaces(*handle); 159 // ALOGI("Found %d interfaces", info->num_interfaces); 160 161 ALOGI("Initialized Wifi HAL Successfully"); 162 return WIFI_SUCCESS; 163} 164 165static int wifi_add_membership(wifi_handle handle, const char *group) 166{ 167 hal_info *info = (hal_info *)handle; 168 169 int id = wifi_get_multicast_id(handle, "nl80211", group); 170 if (id < 0) { 171 ALOGE("Could not find group %s", group); 172 return id; 173 } 174 175 int ret = nl_socket_add_membership(info->event_sock, id); 176 if (ret < 0) { 177 ALOGE("Could not add membership to group %s", group); 178 } 179 180 // ALOGI("Successfully added membership for group %s", group); 181 return ret; 182} 183 184static void internal_cleaned_up_handler(wifi_handle handle) 185{ 186 hal_info *info = (hal_info *)handle; 187 wifi_cleaned_up_handler cleaned_up_handler = info->cleaned_up_handler; 188 189 if (info->cmd_sock != 0) { 190 nl_socket_free(info->cmd_sock); 191 nl_socket_free(info->event_sock); 192 info->cmd_sock = NULL; 193 info->event_sock = NULL; 194 } 195 196 (*cleaned_up_handler)(handle); 197 free(info); 198 199 ALOGI("Internal cleanup completed"); 200} 201 202void wifi_cleanup(wifi_handle handle, wifi_cleaned_up_handler handler) 203{ 204 hal_info *info = (hal_info *)handle; 205 info->cleaned_up_handler = handler; 206 info->clean_up = true; 207 208 ALOGI("Wifi cleanup completed"); 209} 210 211static int internal_pollin_handler(wifi_handle handle) 212{ 213 hal_info *info = (hal_info *)handle; 214 struct nl_cb *cb = nl_socket_get_cb(info->event_sock); 215 int res = nl_recvmsgs(info->event_sock, cb); 216 nl_cb_put(cb); 217 return res; 218} 219 220static void internal_event_handler(wifi_handle handle, int events) 221{ 222 if (events & POLLERR) { 223 ALOGE("Error reading from socket"); 224 } else if (events & POLLHUP) { 225 ALOGE("Remote side hung up"); 226 } else if (events & POLLIN) { 227 ALOGI("Found some events!!!"); 228 internal_pollin_handler(handle); 229 } else { 230 ALOGE("Unknown event - %0x", events); 231 } 232} 233 234/* Run event handler */ 235void wifi_event_loop(wifi_handle handle) 236{ 237 hal_info *info = (hal_info *)handle; 238 if (info->in_event_loop) { 239 return; 240 } else { 241 info->in_event_loop = true; 242 } 243 244 pollfd pfd; 245 memset(&pfd, 0, sizeof(pfd)); 246 247 pfd.fd = nl_socket_get_fd(info->event_sock); 248 pfd.events = POLLIN; 249 250 /* TODO: Add support for timeouts */ 251 252 do { 253 int timeout = -1; /* Infinite timeout */ 254 pfd.revents = 0; 255 //ALOGI("Polling socket"); 256 int result = poll(&pfd, 1, -1); 257 if (result < 0) { 258 ALOGE("Error polling socket"); 259 } else if (pfd.revents & (POLLIN | POLLHUP | POLLERR)) { 260 internal_event_handler(handle, pfd.revents); 261 } 262 } while (!info->clean_up); 263 264 265 ALOGI("Cleaning up"); 266 internal_cleaned_up_handler(handle); 267} 268 269/////////////////////////////////////////////////////////////////////////////////////// 270 271static int internal_valid_message_handler(nl_msg *msg, void *arg) 272{ 273 wifi_handle handle = (wifi_handle)arg; 274 hal_info *info = (hal_info *)handle; 275 276 WifiEvent event(msg); 277 int res = event.parse(); 278 if (res < 0) { 279 ALOGE("Failed to parse event: %d", res); 280 return NL_SKIP; 281 } 282 283 int cmd = event.get_cmd(); 284 uint32_t vendor_id = 0; 285 uint32_t subcmd = 0; 286 287 if (cmd == NL80211_CMD_VENDOR) { 288 vendor_id = event.get_u32(NL80211_ATTR_VENDOR_ID); 289 subcmd = event.get_u32(NL80211_ATTR_VENDOR_SUBCMD); 290 ALOGI("event received %s, vendor_id = 0x%0x, subcmd = 0x%0x", 291 event.get_cmdString(), vendor_id, subcmd); 292 } else { 293 ALOGI("event received %s", event.get_cmdString()); 294 } 295 296 ALOGI("event received %s, vendor_id = 0x%0x", event.get_cmdString(), vendor_id); 297 event.log(); 298 299 for (int i = 0; i < info->num_event_cb; i++) { 300 if (cmd == info->event_cb[i].nl_cmd) { 301 if (cmd == NL80211_CMD_VENDOR && vendor_id != info->event_cb[i].vendor_id) { 302 /* event for a different vendor, ignore it */ 303 continue; 304 } 305 306 cb_info *cbi = &(info->event_cb[i]); 307 return (*(cbi->cb_func))(msg, cbi->cb_arg); 308 } 309 } 310 311 return NL_OK; 312} 313 314/////////////////////////////////////////////////////////////////////////////////////// 315 316class GetMulticastIdCommand : public WifiCommand 317{ 318private: 319 const char *mName; 320 const char *mGroup; 321 int mId; 322public: 323 GetMulticastIdCommand(wifi_handle handle, const char *name, const char *group) 324 : WifiCommand(handle, 0) 325 { 326 mName = name; 327 mGroup = group; 328 mId = -1; 329 } 330 331 int getId() { 332 return mId; 333 } 334 335 virtual int create() { 336 int nlctrlFamily = genl_ctrl_resolve(mInfo->cmd_sock, "nlctrl"); 337 // ALOGI("ctrl family = %d", nlctrlFamily); 338 int ret = mMsg.create(nlctrlFamily, CTRL_CMD_GETFAMILY, 0, 0); 339 if (ret < 0) { 340 return ret; 341 } 342 ret = mMsg.put_string(CTRL_ATTR_FAMILY_NAME, mName); 343 return ret; 344 } 345 346 virtual int handleResponse(WifiEvent reply) { 347 348 // ALOGI("handling reponse in %s", __func__); 349 350 struct nlattr **tb = reply.attributes(); 351 struct genlmsghdr *gnlh = reply.header(); 352 struct nlattr *mcgrp = NULL; 353 int i; 354 355 if (!tb[CTRL_ATTR_MCAST_GROUPS]) { 356 ALOGI("No multicast groups found"); 357 return NL_SKIP; 358 } else { 359 // ALOGI("Multicast groups attr size = %d", nla_len(tb[CTRL_ATTR_MCAST_GROUPS])); 360 } 361 362 for_each_attr(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) { 363 364 // ALOGI("Processing group"); 365 struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1]; 366 nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, (nlattr *)nla_data(mcgrp), 367 nla_len(mcgrp), NULL); 368 if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] || !tb2[CTRL_ATTR_MCAST_GRP_ID]) { 369 continue; 370 } 371 372 char *grpName = (char *)nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]); 373 int grpNameLen = nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME]); 374 // ALOGI("Found group name %s", grpName); 375 376 if (strncmp(grpName, mGroup, grpNameLen) != 0) 377 continue; 378 379 mId = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]); 380 break; 381 } 382 383 return NL_SKIP; 384 } 385 386}; 387 388static int wifi_get_multicast_id(wifi_handle handle, const char *name, const char *group) 389{ 390 GetMulticastIdCommand cmd(handle, name, group); 391 int res = cmd.requestResponse(); 392 if (res < 0) 393 return res; 394 else 395 return cmd.getId(); 396} 397 398///////////////////////////////////////////////////////////////////////// 399 400static bool is_wifi_interface(const char *name) 401{ 402 if (strncmp(name, "wlan", 4) != 0 && strncmp(name, "p2p", 3) != 0) { 403 /* not a wifi interface; ignore it */ 404 return false; 405 } else { 406 return true; 407 } 408} 409 410static int get_interface(const char *name, interface_info *info) 411{ 412 strcpy(info->name, name); 413 info->id = if_nametoindex(name); 414 // ALOGI("found an interface : %s, id = %d", name, info->id); 415 return WIFI_SUCCESS; 416} 417 418wifi_error wifi_init_interfaces(wifi_handle handle) 419{ 420 hal_info *info = (hal_info *)handle; 421 422 struct dirent *de; 423 424 DIR *d = opendir("/sys/class/net"); 425 if (d == 0) 426 return WIFI_ERROR_UNKNOWN; 427 428 int n = 0; 429 while ((de = readdir(d))) { 430 if (de->d_name[0] == '.') 431 continue; 432 if (is_wifi_interface(de->d_name) ) { 433 n++; 434 } 435 } 436 437 closedir(d); 438 439 d = opendir("/sys/class/net"); 440 if (d == 0) 441 return WIFI_ERROR_UNKNOWN; 442 443 info->interfaces = (interface_info **)malloc(sizeof(interface_info *) * n); 444 445 int i = 0; 446 while ((de = readdir(d))) { 447 if (de->d_name[0] == '.') 448 continue; 449 if (is_wifi_interface(de->d_name)) { 450 interface_info *ifinfo = (interface_info *)malloc(sizeof(interface_info)); 451 if (get_interface(de->d_name, ifinfo) != WIFI_SUCCESS) { 452 free(ifinfo); 453 continue; 454 } 455 ifinfo->handle = handle; 456 info->interfaces[i] = ifinfo; 457 i++; 458 } 459 } 460 461 closedir(d); 462 463 info->num_interfaces = n; 464 return WIFI_SUCCESS; 465} 466 467wifi_error wifi_get_ifaces(wifi_handle handle, int *num, wifi_interface_handle **interfaces) 468{ 469 hal_info *info = (hal_info *)handle; 470 471 *interfaces = (wifi_interface_handle *)info->interfaces; 472 *num = info->num_interfaces; 473 474 return WIFI_SUCCESS; 475} 476 477wifi_error wifi_get_iface_name(wifi_interface_handle handle, char *name, size_t size) 478{ 479 interface_info *info = (interface_info *)handle; 480 strcpy(name, info->name); 481 return WIFI_SUCCESS; 482} 483 484///////////////////////////////////////////////////////////////////////////// 485 486