1 /* 2 * Driver interaction with Linux nl80211/cfg80211 - Android specific 3 * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi> 4 * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net> 5 * Copyright (c) 2009-2010, Atheros Communications 6 * 7 * This software may be distributed under the terms of the BSD license. 8 * See README for more details. 9 */ 10 11 #include "includes.h" 12 #include <sys/ioctl.h> 13 #include <net/if.h> 14 #include <netlink/genl/genl.h> 15 #include <netlink/genl/family.h> 16 #include <netlink/genl/ctrl.h> 17 #include <fcntl.h> 18 19 #include "utils/common.h" 20 #include "driver_nl80211.h" 21 #include "android_drv.h" 22 23 24 typedef struct android_wifi_priv_cmd { 25 char *buf; 26 int used_len; 27 int total_len; 28 } android_wifi_priv_cmd; 29 30 static int drv_errors = 0; 31 32 static void wpa_driver_send_hang_msg(struct wpa_driver_nl80211_data *drv) 33 { 34 drv_errors++; 35 if (drv_errors > DRV_NUMBER_SEQUENTIAL_ERRORS) { 36 drv_errors = 0; 37 wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED"); 38 } 39 } 40 41 42 static int android_priv_cmd(struct i802_bss *bss, const char *cmd) 43 { 44 struct wpa_driver_nl80211_data *drv = bss->drv; 45 struct ifreq ifr; 46 android_wifi_priv_cmd priv_cmd; 47 char buf[MAX_DRV_CMD_SIZE]; 48 int ret; 49 50 os_memset(&ifr, 0, sizeof(ifr)); 51 os_memset(&priv_cmd, 0, sizeof(priv_cmd)); 52 os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ); 53 54 os_memset(buf, 0, sizeof(buf)); 55 os_strlcpy(buf, cmd, sizeof(buf)); 56 57 priv_cmd.buf = buf; 58 priv_cmd.used_len = sizeof(buf); 59 priv_cmd.total_len = sizeof(buf); 60 ifr.ifr_data = &priv_cmd; 61 62 ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr); 63 if (ret < 0) { 64 wpa_printf(MSG_ERROR, "%s: failed to issue private commands", 65 __func__); 66 wpa_driver_send_hang_msg(drv); 67 return ret; 68 } 69 70 drv_errors = 0; 71 return 0; 72 } 73 74 75 int android_pno_start(struct i802_bss *bss, 76 struct wpa_driver_scan_params *params) 77 { 78 struct wpa_driver_nl80211_data *drv = bss->drv; 79 struct ifreq ifr; 80 android_wifi_priv_cmd priv_cmd; 81 int ret = 0, i = 0, bp; 82 char buf[WEXT_PNO_MAX_COMMAND_SIZE]; 83 84 bp = WEXT_PNOSETUP_HEADER_SIZE; 85 os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp); 86 buf[bp++] = WEXT_PNO_TLV_PREFIX; 87 buf[bp++] = WEXT_PNO_TLV_VERSION; 88 buf[bp++] = WEXT_PNO_TLV_SUBVERSION; 89 buf[bp++] = WEXT_PNO_TLV_RESERVED; 90 91 while (i < WEXT_PNO_AMOUNT && (size_t) i < params->num_ssids) { 92 /* Check that there is enough space needed for 1 more SSID, the 93 * other sections and null termination */ 94 if ((bp + WEXT_PNO_SSID_HEADER_SIZE + MAX_SSID_LEN + 95 WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int) sizeof(buf)) 96 break; 97 wpa_hexdump_ascii(MSG_DEBUG, "For PNO Scan", 98 params->ssids[i].ssid, 99 params->ssids[i].ssid_len); 100 buf[bp++] = WEXT_PNO_SSID_SECTION; 101 buf[bp++] = params->ssids[i].ssid_len; 102 os_memcpy(&buf[bp], params->ssids[i].ssid, 103 params->ssids[i].ssid_len); 104 bp += params->ssids[i].ssid_len; 105 i++; 106 } 107 108 buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION; 109 os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x", 110 WEXT_PNO_SCAN_INTERVAL); 111 bp += WEXT_PNO_SCAN_INTERVAL_LENGTH; 112 113 buf[bp++] = WEXT_PNO_REPEAT_SECTION; 114 os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x", 115 WEXT_PNO_REPEAT); 116 bp += WEXT_PNO_REPEAT_LENGTH; 117 118 buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION; 119 os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x", 120 WEXT_PNO_MAX_REPEAT); 121 bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1; 122 123 memset(&ifr, 0, sizeof(ifr)); 124 memset(&priv_cmd, 0, sizeof(priv_cmd)); 125 os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ); 126 127 priv_cmd.buf = buf; 128 priv_cmd.used_len = bp; 129 priv_cmd.total_len = bp; 130 ifr.ifr_data = &priv_cmd; 131 132 ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr); 133 134 if (ret < 0) { 135 wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d", 136 ret); 137 wpa_driver_send_hang_msg(drv); 138 return ret; 139 } 140 141 drv_errors = 0; 142 143 return android_priv_cmd(bss, "PNOFORCE 1"); 144 } 145 146 147 int android_pno_stop(struct i802_bss *bss) 148 { 149 return android_priv_cmd(bss, "PNOFORCE 0"); 150 } 151 152 153 #ifdef ANDROID_P2P 154 #ifdef ANDROID_P2P_STUB 155 156 int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration) 157 { 158 return 0; 159 } 160 161 162 int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len) 163 { 164 return 0; 165 } 166 167 168 int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow) 169 { 170 return -1; 171 } 172 173 174 int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon, 175 const struct wpabuf *proberesp, 176 const struct wpabuf *assocresp) 177 { 178 return 0; 179 } 180 181 #endif /* ANDROID_P2P_STUB */ 182 #endif /* ANDROID_P2P */ 183 184 185 int android_nl_socket_set_nonblocking(struct nl_handle *handle) 186 { 187 return fcntl(nl_socket_get_fd(handle), F_SETFL, O_NONBLOCK); 188 } 189 190 191 int android_genl_ctrl_resolve(struct nl_handle *handle, const char *name) 192 { 193 /* 194 * Android ICS has very minimal genl_ctrl_resolve() implementation, so 195 * need to work around that. 196 */ 197 struct nl_cache *cache = NULL; 198 struct genl_family *nl80211 = NULL; 199 int id = -1; 200 201 if (genl_ctrl_alloc_cache(handle, &cache) < 0) { 202 wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic " 203 "netlink cache"); 204 goto fail; 205 } 206 207 nl80211 = genl_ctrl_search_by_name(cache, name); 208 if (nl80211 == NULL) 209 goto fail; 210 211 id = genl_family_get_id(nl80211); 212 213 fail: 214 if (nl80211) 215 genl_family_put(nl80211); 216 if (cache) 217 nl_cache_free(cache); 218 219 return id; 220 } 221