150276Speter/*
262449Speter * Driver interaction with Linux nl80211/cfg80211 - Android specific
350276Speter * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
450276Speter * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
550276Speter * Copyright (c) 2009-2010, Atheros Communications
650276Speter *
750276Speter * This software may be distributed under the terms of the BSD license.
850276Speter * See README for more details.
950276Speter */
1050276Speter
1150276Speter#include "includes.h"
1250276Speter#include <sys/ioctl.h>
1350276Speter#include <net/if.h>
1450276Speter#include <netlink/genl/genl.h>
1550276Speter#include <netlink/genl/family.h>
1650276Speter#include <netlink/genl/ctrl.h>
1750276Speter#include <fcntl.h>
1850276Speter
1950276Speter#include "utils/common.h"
2050276Speter#include "driver_nl80211.h"
2150276Speter#include "android_drv.h"
2250276Speter
2350276Speter
2450276Spetertypedef struct android_wifi_priv_cmd {
2550276Speter	char *buf;
2650276Speter	int used_len;
2750276Speter	int total_len;
2850276Speter} android_wifi_priv_cmd;
2950276Speter
3050276Speterstatic int drv_errors = 0;
3150276Speter
3250276Speterstatic void wpa_driver_send_hang_msg(struct wpa_driver_nl80211_data *drv)
3350276Speter{
3450276Speter	drv_errors++;
3550276Speter	if (drv_errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
3650276Speter		drv_errors = 0;
3750276Speter		wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
3850276Speter	}
3950276Speter}
4050276Speter
4150276Speter
4250276Speterstatic int android_priv_cmd(struct i802_bss *bss, const char *cmd)
4350276Speter{
4450276Speter	struct wpa_driver_nl80211_data *drv = bss->drv;
4562449Speter	struct ifreq ifr;
4650276Speter	android_wifi_priv_cmd priv_cmd;
4750276Speter	char buf[MAX_DRV_CMD_SIZE];
4850276Speter	int ret;
4962449Speter
5062449Speter	os_memset(&ifr, 0, sizeof(ifr));
5162449Speter	os_memset(&priv_cmd, 0, sizeof(priv_cmd));
5262449Speter	os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
5350276Speter
5462449Speter	os_memset(buf, 0, sizeof(buf));
5562449Speter	os_strlcpy(buf, cmd, sizeof(buf));
5650276Speter
5762449Speter	priv_cmd.buf = buf;
5850276Speter	priv_cmd.used_len = sizeof(buf);
5962449Speter	priv_cmd.total_len = sizeof(buf);
6062449Speter	ifr.ifr_data = &priv_cmd;
6150276Speter
6262449Speter	ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
6362449Speter	if (ret < 0) {
6462449Speter		wpa_printf(MSG_ERROR, "%s: failed to issue private commands",
6550276Speter			   __func__);
6662449Speter		wpa_driver_send_hang_msg(drv);
6750276Speter		return ret;
6862449Speter	}
6950276Speter
7062449Speter	drv_errors = 0;
7150276Speter	return 0;
7250276Speter}
7362449Speter
7462449Speter
7550276Speterint android_pno_start(struct i802_bss *bss,
7662449Speter		      struct wpa_driver_scan_params *params)
7762449Speter{
7862449Speter	struct wpa_driver_nl80211_data *drv = bss->drv;
7950276Speter	struct ifreq ifr;
8050276Speter	android_wifi_priv_cmd priv_cmd;
8162449Speter	int ret = 0, i = 0, bp;
8262449Speter	char buf[WEXT_PNO_MAX_COMMAND_SIZE];
8350276Speter
8462449Speter	bp = WEXT_PNOSETUP_HEADER_SIZE;
8562449Speter	os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp);
8650276Speter	buf[bp++] = WEXT_PNO_TLV_PREFIX;
8750276Speter	buf[bp++] = WEXT_PNO_TLV_VERSION;
8850276Speter	buf[bp++] = WEXT_PNO_TLV_SUBVERSION;
8950276Speter	buf[bp++] = WEXT_PNO_TLV_RESERVED;
9050276Speter
9150276Speter	while (i < WEXT_PNO_AMOUNT && (size_t) i < params->num_ssids) {
9250276Speter		/* Check that there is enough space needed for 1 more SSID, the
9350276Speter		 * other sections and null termination */
9462449Speter		if ((bp + WEXT_PNO_SSID_HEADER_SIZE + MAX_SSID_LEN +
9562449Speter		     WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int) sizeof(buf))
9662449Speter			break;
9750276Speter		wpa_hexdump_ascii(MSG_DEBUG, "For PNO Scan",
9850276Speter				  params->ssids[i].ssid,
9950276Speter				  params->ssids[i].ssid_len);
10050276Speter		buf[bp++] = WEXT_PNO_SSID_SECTION;
10150276Speter		buf[bp++] = params->ssids[i].ssid_len;
10250276Speter		os_memcpy(&buf[bp], params->ssids[i].ssid,
10350276Speter			  params->ssids[i].ssid_len);
10450276Speter		bp += params->ssids[i].ssid_len;
10550276Speter		i++;
10650276Speter	}
10750276Speter
10850276Speter	buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION;
10950276Speter	os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x",
11050276Speter		    WEXT_PNO_SCAN_INTERVAL);
11150276Speter	bp += WEXT_PNO_SCAN_INTERVAL_LENGTH;
11250276Speter
11362449Speter	buf[bp++] = WEXT_PNO_REPEAT_SECTION;
11462449Speter	os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x",
11550276Speter		    WEXT_PNO_REPEAT);
11662449Speter	bp += WEXT_PNO_REPEAT_LENGTH;
11762449Speter
11862449Speter	buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION;
11962449Speter	os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x",
12062449Speter		    WEXT_PNO_MAX_REPEAT);
12162449Speter	bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1;
12250276Speter
12350276Speter	memset(&ifr, 0, sizeof(ifr));
12450276Speter	memset(&priv_cmd, 0, sizeof(priv_cmd));
12550276Speter	os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
12650276Speter
12750276Speter	priv_cmd.buf = buf;
12862449Speter	priv_cmd.used_len = bp;
12962449Speter	priv_cmd.total_len = bp;
13050276Speter	ifr.ifr_data = &priv_cmd;
13162449Speter
13262449Speter	ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
13362449Speter
13462449Speter	if (ret < 0) {
13550276Speter		wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d",
13662449Speter			   ret);
13762449Speter		wpa_driver_send_hang_msg(drv);
13862449Speter		return ret;
13962449Speter	}
14062449Speter
14162449Speter	drv_errors = 0;
14262449Speter
14362449Speter	return android_priv_cmd(bss, "PNOFORCE 1");
14462449Speter}
14562449Speter
14662449Speter
14762449Speterint android_pno_stop(struct i802_bss *bss)
14862449Speter{
14962449Speter	return android_priv_cmd(bss, "PNOFORCE 0");
15062449Speter}
15162449Speter
15262449Speter
15362449Speter#ifdef ANDROID_P2P
15462449Speter#ifdef ANDROID_LIB_STUB
15562449Speter
15662449Speterint wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration)
15762449Speter{
15862449Speter	return 0;
15962449Speter}
16062449Speter
16162449Speter
16262449Speterint wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len)
16362449Speter{
16462449Speter	return 0;
16550276Speter}
16662449Speter
16762449Speter
16862449Speterint wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow)
16962449Speter{
17050276Speter	return -1;
17162449Speter}
17250276Speter
17362449Speter
17462449Speterint wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon,
17562449Speter				 const struct wpabuf *proberesp,
17650276Speter				 const struct wpabuf *assocresp)
17750276Speter{
17862449Speter	return 0;
17962449Speter}
18050276Speter
18150276Speter#endif /* ANDROID_LIB_STUB */
18250276Speter#endif /* ANDROID_P2P */
18350276Speter
18450276Speter
18550276Speterint android_nl_socket_set_nonblocking(struct nl_sock *handle)
18650276Speter{
18750276Speter	return fcntl(nl_socket_get_fd(handle), F_SETFL, O_NONBLOCK);
18850276Speter}
18950276Speter