Home | History | Annotate | Download | only in wpa_supplicant_8_lib
      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