1 /* 2 * Driver interaction with extended Linux CFG8021 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 as 6 * published by the Free Software Foundation. 7 * 8 * Alternatively, this software may be distributed under the terms of BSD 9 * license. 10 * 11 */ 12 13 #include "driver_nl80211.h" 14 #include "wpa_supplicant_i.h" 15 #include "config.h" 16 #ifdef ANDROID 17 #include "android_drv.h" 18 #endif 19 20 #define WPA_PS_ENABLED 0 21 #define WPA_PS_DISABLED 1 22 23 #define MAX_WPSP2PIE_CMD_SIZE 512 24 25 typedef struct android_wifi_priv_cmd { 26 char *buf; 27 int used_len; 28 int total_len; 29 } android_wifi_priv_cmd; 30 31 int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv, struct nl_msg *msg, 32 int (*valid_handler)(struct nl_msg *, void *), 33 void *valid_data); 34 35 static int drv_errors = 0; 36 37 static void wpa_driver_send_hang_msg(struct wpa_driver_nl80211_data *drv) 38 { 39 drv_errors++; 40 if (drv_errors > DRV_NUMBER_SEQUENTIAL_ERRORS) { 41 drv_errors = 0; 42 wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED"); 43 } 44 } 45 46 static int wpa_driver_set_power_save(void *priv, int state) 47 { 48 struct i802_bss *bss = priv; 49 struct wpa_driver_nl80211_data *drv = bss->drv; 50 struct nl_msg *msg; 51 int ret = -1; 52 enum nl80211_ps_state ps_state; 53 54 msg = nlmsg_alloc(); 55 if (!msg) 56 return -1; 57 58 genlmsg_put(msg, 0, 0, drv->global->nl80211_id, 0, 0, 59 NL80211_CMD_SET_POWER_SAVE, 0); 60 61 if (state == WPA_PS_ENABLED) 62 ps_state = NL80211_PS_ENABLED; 63 else 64 ps_state = NL80211_PS_DISABLED; 65 66 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); 67 NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE, ps_state); 68 69 ret = send_and_recv_msgs(drv, msg, NULL, NULL); 70 msg = NULL; 71 if (ret < 0) 72 wpa_printf(MSG_ERROR, "nl80211: Set power mode fail: %d", ret); 73 nla_put_failure: 74 nlmsg_free(msg); 75 return ret; 76 } 77 78 static int get_power_mode_handler(struct nl_msg *msg, void *arg) 79 { 80 struct nlattr *tb[NL80211_ATTR_MAX + 1]; 81 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); 82 int *state = (int *)arg; 83 84 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), 85 genlmsg_attrlen(gnlh, 0), NULL); 86 87 if (!tb[NL80211_ATTR_PS_STATE]) 88 return NL_SKIP; 89 90 if (state) { 91 *state = (int)nla_get_u32(tb[NL80211_ATTR_PS_STATE]); 92 wpa_printf(MSG_DEBUG, "nl80211: Get power mode = %d", *state); 93 *state = (*state == NL80211_PS_ENABLED) ? 94 WPA_PS_ENABLED : WPA_PS_DISABLED; 95 } 96 97 return NL_SKIP; 98 } 99 100 static int wpa_driver_get_power_save(void *priv, int *state) 101 { 102 struct i802_bss *bss = priv; 103 struct wpa_driver_nl80211_data *drv = bss->drv; 104 struct nl_msg *msg; 105 int ret = -1; 106 enum nl80211_ps_state ps_state; 107 108 msg = nlmsg_alloc(); 109 if (!msg) 110 return -1; 111 112 genlmsg_put(msg, 0, 0, drv->global->nl80211_id, 0, 0, 113 NL80211_CMD_GET_POWER_SAVE, 0); 114 115 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); 116 117 ret = send_and_recv_msgs(drv, msg, get_power_mode_handler, state); 118 msg = NULL; 119 if (ret < 0) 120 wpa_printf(MSG_ERROR, "nl80211: Get power mode fail: %d", ret); 121 nla_put_failure: 122 nlmsg_free(msg); 123 return ret; 124 } 125 126 static int wpa_driver_set_backgroundscan_params(void *priv) 127 { 128 struct i802_bss *bss = priv; 129 struct wpa_driver_nl80211_data *drv = bss->drv; 130 struct wpa_supplicant *wpa_s; 131 struct ifreq ifr; 132 android_wifi_priv_cmd priv_cmd; 133 int ret = 0, i = 0, bp; 134 char buf[WEXT_PNO_MAX_COMMAND_SIZE]; 135 struct wpa_ssid *ssid_conf; 136 137 if (drv == NULL) { 138 wpa_printf(MSG_ERROR, "%s: drv is NULL. Exiting", __func__); 139 return -1; 140 } 141 if (drv->ctx == NULL) { 142 wpa_printf(MSG_ERROR, "%s: drv->ctx is NULL. Exiting", __func__); 143 return -1; 144 } 145 wpa_s = (struct wpa_supplicant *)(drv->ctx); 146 if (wpa_s->conf == NULL) { 147 wpa_printf(MSG_ERROR, "%s: wpa_s->conf is NULL. Exiting", __func__); 148 return -1; 149 } 150 ssid_conf = wpa_s->conf->ssid; 151 152 bp = WEXT_PNOSETUP_HEADER_SIZE; 153 os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp); 154 buf[bp++] = WEXT_PNO_TLV_PREFIX; 155 buf[bp++] = WEXT_PNO_TLV_VERSION; 156 buf[bp++] = WEXT_PNO_TLV_SUBVERSION; 157 buf[bp++] = WEXT_PNO_TLV_RESERVED; 158 159 while ((i < WEXT_PNO_AMOUNT) && (ssid_conf != NULL)) { 160 /* Check that there is enough space needed for 1 more SSID, the other sections and null termination */ 161 if ((bp + WEXT_PNO_SSID_HEADER_SIZE + MAX_SSID_LEN + WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int)sizeof(buf)) 162 break; 163 if ((!ssid_conf->disabled) && (ssid_conf->ssid_len <= MAX_SSID_LEN)){ 164 wpa_printf(MSG_DEBUG, "For PNO Scan: %s", ssid_conf->ssid); 165 buf[bp++] = WEXT_PNO_SSID_SECTION; 166 buf[bp++] = ssid_conf->ssid_len; 167 os_memcpy(&buf[bp], ssid_conf->ssid, ssid_conf->ssid_len); 168 bp += ssid_conf->ssid_len; 169 i++; 170 } 171 ssid_conf = ssid_conf->next; 172 } 173 174 buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION; 175 os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x", WEXT_PNO_SCAN_INTERVAL); 176 bp += WEXT_PNO_SCAN_INTERVAL_LENGTH; 177 178 buf[bp++] = WEXT_PNO_REPEAT_SECTION; 179 os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x", WEXT_PNO_REPEAT); 180 bp += WEXT_PNO_REPEAT_LENGTH; 181 182 buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION; 183 os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x", WEXT_PNO_MAX_REPEAT); 184 bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1; 185 186 memset(&ifr, 0, sizeof(ifr)); 187 memset(&priv_cmd, 0, sizeof(priv_cmd)); 188 os_strncpy(ifr.ifr_name, bss->ifname, IFNAMSIZ); 189 190 priv_cmd.buf = buf; 191 priv_cmd.used_len = bp; 192 priv_cmd.total_len = bp; 193 ifr.ifr_data = &priv_cmd; 194 195 ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr); 196 197 if (ret < 0) { 198 wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d", ret); 199 wpa_driver_send_hang_msg(drv); 200 } else { 201 drv_errors = 0; 202 } 203 return ret; 204 } 205 206 int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf, 207 size_t buf_len ) 208 { 209 struct i802_bss *bss = priv; 210 struct wpa_driver_nl80211_data *drv = bss->drv; 211 struct ifreq ifr; 212 android_wifi_priv_cmd priv_cmd; 213 int ret = 0; 214 215 if (os_strcasecmp(cmd, "STOP") == 0) { 216 linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0); 217 wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STOPPED"); 218 } else if (os_strcasecmp(cmd, "START") == 0) { 219 linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1); 220 wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STARTED"); 221 } else if (os_strcasecmp(cmd, "MACADDR") == 0) { 222 u8 macaddr[ETH_ALEN] = {}; 223 224 ret = linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, macaddr); 225 if (!ret) 226 ret = os_snprintf(buf, buf_len, 227 "Macaddr = " MACSTR "\n", MAC2STR(macaddr)); 228 } else if (os_strcasecmp(cmd, "RELOAD") == 0) { 229 wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED"); 230 } else if (os_strncasecmp(cmd, "POWERMODE ", 10) == 0) { 231 int state; 232 233 state = atoi(cmd + 10); 234 ret = wpa_driver_set_power_save(priv, state); 235 if (ret < 0) 236 wpa_driver_send_hang_msg(drv); 237 else 238 drv_errors = 0; 239 } else if (os_strncasecmp(cmd, "GETPOWER", 8) == 0) { 240 int state = -1; 241 242 ret = wpa_driver_get_power_save(priv, &state); 243 if (!ret && (state != -1)) { 244 ret = os_snprintf(buf, buf_len, "POWERMODE = %d\n", state); 245 drv_errors = 0; 246 } else { 247 wpa_driver_send_hang_msg(drv); 248 } 249 } else { /* Use private command */ 250 if (os_strcasecmp(cmd, "BGSCAN-START") == 0) { 251 ret = wpa_driver_set_backgroundscan_params(priv); 252 if (ret < 0) { 253 return ret; 254 } 255 os_memcpy(buf, "PNOFORCE 1", 11); 256 } else if (os_strcasecmp(cmd, "BGSCAN-STOP") == 0) { 257 os_memcpy(buf, "PNOFORCE 0", 11); 258 } else { 259 os_memcpy(buf, cmd, strlen(cmd) + 1); 260 } 261 memset(&ifr, 0, sizeof(ifr)); 262 memset(&priv_cmd, 0, sizeof(priv_cmd)); 263 os_strncpy(ifr.ifr_name, bss->ifname, IFNAMSIZ); 264 265 priv_cmd.buf = buf; 266 priv_cmd.used_len = buf_len; 267 priv_cmd.total_len = buf_len; 268 ifr.ifr_data = &priv_cmd; 269 270 if ((ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr)) < 0) { 271 wpa_printf(MSG_ERROR, "%s: failed to issue private commands\n", __func__); 272 wpa_driver_send_hang_msg(drv); 273 } else { 274 drv_errors = 0; 275 ret = 0; 276 if ((os_strcasecmp(cmd, "LINKSPEED") == 0) || 277 (os_strcasecmp(cmd, "RSSI") == 0) || 278 (os_strcasecmp(cmd, "GETBAND") == 0) ) 279 ret = strlen(buf); 280 else if (os_strcasecmp(cmd, "COUNTRY") == 0) 281 wpa_supplicant_event(drv->ctx, 282 EVENT_CHANNEL_LIST_CHANGED, NULL); 283 wpa_printf(MSG_DEBUG, "%s %s len = %d, %d", __func__, buf, ret, strlen(buf)); 284 } 285 } 286 return ret; 287 } 288 289 int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration) 290 { 291 char buf[MAX_DRV_CMD_SIZE]; 292 293 memset(buf, 0, sizeof(buf)); 294 wpa_printf(MSG_DEBUG, "%s: Entry", __func__); 295 snprintf(buf, sizeof(buf), "P2P_SET_NOA %d %d %d", count, start, duration); 296 return wpa_driver_nl80211_driver_cmd(priv, buf, buf, strlen(buf)+1); 297 } 298 299 int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len) 300 { 301 /* Return 0 till we handle p2p_presence request completely in the driver */ 302 return 0; 303 } 304 305 int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow) 306 { 307 char buf[MAX_DRV_CMD_SIZE]; 308 309 memset(buf, 0, sizeof(buf)); 310 wpa_printf(MSG_DEBUG, "%s: Entry", __func__); 311 snprintf(buf, sizeof(buf), "P2P_SET_PS %d %d %d", legacy_ps, opp_ps, ctwindow); 312 return wpa_driver_nl80211_driver_cmd(priv, buf, buf, strlen(buf) + 1); 313 } 314 315 int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon, 316 const struct wpabuf *proberesp, 317 const struct wpabuf *assocresp) 318 { 319 char buf[MAX_WPSP2PIE_CMD_SIZE]; 320 struct wpabuf *ap_wps_p2p_ie = NULL; 321 char *_cmd = "SET_AP_WPS_P2P_IE"; 322 char *pbuf; 323 int ret = 0; 324 int i; 325 struct cmd_desc { 326 int cmd; 327 const struct wpabuf *src; 328 } cmd_arr[] = { 329 {0x1, beacon}, 330 {0x2, proberesp}, 331 {0x4, assocresp}, 332 {-1, NULL} 333 }; 334 335 wpa_printf(MSG_DEBUG, "%s: Entry", __func__); 336 for (i = 0; cmd_arr[i].cmd != -1; i++) { 337 os_memset(buf, 0, sizeof(buf)); 338 pbuf = buf; 339 pbuf += sprintf(pbuf, "%s %d", _cmd, cmd_arr[i].cmd); 340 *pbuf++ = '\0'; 341 ap_wps_p2p_ie = cmd_arr[i].src ? 342 wpabuf_dup(cmd_arr[i].src) : NULL; 343 if (ap_wps_p2p_ie) { 344 os_memcpy(pbuf, wpabuf_head(ap_wps_p2p_ie), wpabuf_len(ap_wps_p2p_ie)); 345 ret = wpa_driver_nl80211_driver_cmd(priv, buf, buf, 346 strlen(_cmd) + 3 + wpabuf_len(ap_wps_p2p_ie)); 347 wpabuf_free(ap_wps_p2p_ie); 348 if (ret < 0) 349 break; 350 } 351 } 352 353 return ret; 354 } 355