1281681Srpaulo/*
2281681Srpaulo * Driver interaction with Linux nl80211/cfg80211 - Android specific
3281681Srpaulo * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
4281681Srpaulo * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
5281681Srpaulo * Copyright (c) 2009-2010, Atheros Communications
6281681Srpaulo *
7281681Srpaulo * This software may be distributed under the terms of the BSD license.
8281681Srpaulo * See README for more details.
9281681Srpaulo */
10281681Srpaulo
11281681Srpaulo#include "includes.h"
12281681Srpaulo#include <sys/ioctl.h>
13281681Srpaulo#include <net/if.h>
14281681Srpaulo#include <netlink/genl/genl.h>
15281681Srpaulo#include <netlink/genl/family.h>
16281681Srpaulo#include <netlink/genl/ctrl.h>
17281681Srpaulo#include <fcntl.h>
18281681Srpaulo
19281681Srpaulo#include "utils/common.h"
20281681Srpaulo#include "driver_nl80211.h"
21281681Srpaulo#include "android_drv.h"
22281681Srpaulo
23281681Srpaulo
24281681Srpaulotypedef struct android_wifi_priv_cmd {
25281681Srpaulo	char *buf;
26281681Srpaulo	int used_len;
27281681Srpaulo	int total_len;
28281681Srpaulo} android_wifi_priv_cmd;
29281681Srpaulo
30281681Srpaulostatic int drv_errors = 0;
31281681Srpaulo
32281681Srpaulostatic void wpa_driver_send_hang_msg(struct wpa_driver_nl80211_data *drv)
33281681Srpaulo{
34281681Srpaulo	drv_errors++;
35281681Srpaulo	if (drv_errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
36281681Srpaulo		drv_errors = 0;
37281681Srpaulo		wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
38281681Srpaulo	}
39281681Srpaulo}
40281681Srpaulo
41281681Srpaulo
42281681Srpaulostatic int android_priv_cmd(struct i802_bss *bss, const char *cmd)
43281681Srpaulo{
44281681Srpaulo	struct wpa_driver_nl80211_data *drv = bss->drv;
45281681Srpaulo	struct ifreq ifr;
46281681Srpaulo	android_wifi_priv_cmd priv_cmd;
47281681Srpaulo	char buf[MAX_DRV_CMD_SIZE];
48281681Srpaulo	int ret;
49281681Srpaulo
50281681Srpaulo	os_memset(&ifr, 0, sizeof(ifr));
51281681Srpaulo	os_memset(&priv_cmd, 0, sizeof(priv_cmd));
52281681Srpaulo	os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
53281681Srpaulo
54281681Srpaulo	os_memset(buf, 0, sizeof(buf));
55281681Srpaulo	os_strlcpy(buf, cmd, sizeof(buf));
56281681Srpaulo
57281681Srpaulo	priv_cmd.buf = buf;
58281681Srpaulo	priv_cmd.used_len = sizeof(buf);
59281681Srpaulo	priv_cmd.total_len = sizeof(buf);
60281681Srpaulo	ifr.ifr_data = &priv_cmd;
61281681Srpaulo
62281681Srpaulo	ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
63281681Srpaulo	if (ret < 0) {
64281681Srpaulo		wpa_printf(MSG_ERROR, "%s: failed to issue private commands",
65281681Srpaulo			   __func__);
66281681Srpaulo		wpa_driver_send_hang_msg(drv);
67281681Srpaulo		return ret;
68281681Srpaulo	}
69281681Srpaulo
70281681Srpaulo	drv_errors = 0;
71281681Srpaulo	return 0;
72281681Srpaulo}
73281681Srpaulo
74281681Srpaulo
75281681Srpauloint android_pno_start(struct i802_bss *bss,
76281681Srpaulo		      struct wpa_driver_scan_params *params)
77281681Srpaulo{
78281681Srpaulo	struct wpa_driver_nl80211_data *drv = bss->drv;
79281681Srpaulo	struct ifreq ifr;
80281681Srpaulo	android_wifi_priv_cmd priv_cmd;
81281681Srpaulo	int ret = 0, i = 0, bp;
82281681Srpaulo	char buf[WEXT_PNO_MAX_COMMAND_SIZE];
83281681Srpaulo
84281681Srpaulo	bp = WEXT_PNOSETUP_HEADER_SIZE;
85281681Srpaulo	os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp);
86281681Srpaulo	buf[bp++] = WEXT_PNO_TLV_PREFIX;
87281681Srpaulo	buf[bp++] = WEXT_PNO_TLV_VERSION;
88281681Srpaulo	buf[bp++] = WEXT_PNO_TLV_SUBVERSION;
89281681Srpaulo	buf[bp++] = WEXT_PNO_TLV_RESERVED;
90281681Srpaulo
91281681Srpaulo	while (i < WEXT_PNO_AMOUNT && (size_t) i < params->num_ssids) {
92281681Srpaulo		/* Check that there is enough space needed for 1 more SSID, the
93281681Srpaulo		 * other sections and null termination */
94281681Srpaulo		if ((bp + WEXT_PNO_SSID_HEADER_SIZE + MAX_SSID_LEN +
95281681Srpaulo		     WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int) sizeof(buf))
96281681Srpaulo			break;
97281681Srpaulo		wpa_hexdump_ascii(MSG_DEBUG, "For PNO Scan",
98281681Srpaulo				  params->ssids[i].ssid,
99281681Srpaulo				  params->ssids[i].ssid_len);
100281681Srpaulo		buf[bp++] = WEXT_PNO_SSID_SECTION;
101281681Srpaulo		buf[bp++] = params->ssids[i].ssid_len;
102281681Srpaulo		os_memcpy(&buf[bp], params->ssids[i].ssid,
103281681Srpaulo			  params->ssids[i].ssid_len);
104281681Srpaulo		bp += params->ssids[i].ssid_len;
105281681Srpaulo		i++;
106281681Srpaulo	}
107281681Srpaulo
108281681Srpaulo	buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION;
109281681Srpaulo	os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x",
110281681Srpaulo		    WEXT_PNO_SCAN_INTERVAL);
111281681Srpaulo	bp += WEXT_PNO_SCAN_INTERVAL_LENGTH;
112281681Srpaulo
113281681Srpaulo	buf[bp++] = WEXT_PNO_REPEAT_SECTION;
114281681Srpaulo	os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x",
115281681Srpaulo		    WEXT_PNO_REPEAT);
116281681Srpaulo	bp += WEXT_PNO_REPEAT_LENGTH;
117281681Srpaulo
118281681Srpaulo	buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION;
119281681Srpaulo	os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x",
120281681Srpaulo		    WEXT_PNO_MAX_REPEAT);
121281681Srpaulo	bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1;
122281681Srpaulo
123281681Srpaulo	memset(&ifr, 0, sizeof(ifr));
124281681Srpaulo	memset(&priv_cmd, 0, sizeof(priv_cmd));
125281681Srpaulo	os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
126281681Srpaulo
127281681Srpaulo	priv_cmd.buf = buf;
128281681Srpaulo	priv_cmd.used_len = bp;
129281681Srpaulo	priv_cmd.total_len = bp;
130281681Srpaulo	ifr.ifr_data = &priv_cmd;
131281681Srpaulo
132281681Srpaulo	ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
133281681Srpaulo
134281681Srpaulo	if (ret < 0) {
135281681Srpaulo		wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d",
136281681Srpaulo			   ret);
137281681Srpaulo		wpa_driver_send_hang_msg(drv);
138281681Srpaulo		return ret;
139281681Srpaulo	}
140281681Srpaulo
141281681Srpaulo	drv_errors = 0;
142281681Srpaulo
143281681Srpaulo	return android_priv_cmd(bss, "PNOFORCE 1");
144281681Srpaulo}
145281681Srpaulo
146281681Srpaulo
147281681Srpauloint android_pno_stop(struct i802_bss *bss)
148281681Srpaulo{
149281681Srpaulo	return android_priv_cmd(bss, "PNOFORCE 0");
150281681Srpaulo}
151281681Srpaulo
152281681Srpaulo
153281681Srpaulo#ifdef ANDROID_P2P
154289549Srpaulo#ifdef ANDROID_LIB_STUB
155281681Srpaulo
156281681Srpauloint wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration)
157281681Srpaulo{
158281681Srpaulo	return 0;
159281681Srpaulo}
160281681Srpaulo
161281681Srpaulo
162281681Srpauloint wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len)
163281681Srpaulo{
164281681Srpaulo	return 0;
165281681Srpaulo}
166281681Srpaulo
167281681Srpaulo
168281681Srpauloint wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow)
169281681Srpaulo{
170281681Srpaulo	return -1;
171281681Srpaulo}
172281681Srpaulo
173281681Srpaulo
174281681Srpauloint wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon,
175281681Srpaulo				 const struct wpabuf *proberesp,
176281681Srpaulo				 const struct wpabuf *assocresp)
177281681Srpaulo{
178281681Srpaulo	return 0;
179281681Srpaulo}
180281681Srpaulo
181289549Srpaulo#endif /* ANDROID_LIB_STUB */
182281681Srpaulo#endif /* ANDROID_P2P */
183281681Srpaulo
184281681Srpaulo
185281681Srpauloint android_nl_socket_set_nonblocking(struct nl_handle *handle)
186281681Srpaulo{
187281681Srpaulo	return fcntl(nl_socket_get_fd(handle), F_SETFL, O_NONBLOCK);
188281681Srpaulo}
189281681Srpaulo
190281681Srpaulo
191