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