1/*
2 * Driver interaction with Linux nl80211/cfg80211 - Android specific
3 * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
4 * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
5 * Copyright (c) 2009-2010, Atheros Communications
6 *
7 * This software may be distributed under the terms of the BSD license.
8 * See README for more details.
9 */
10
11#include "includes.h"
12#include <sys/ioctl.h>
13#include <net/if.h>
14#include <netlink/genl/genl.h>
15#include <netlink/genl/family.h>
16#include <netlink/genl/ctrl.h>
17#include <fcntl.h>
18
19#include "utils/common.h"
20#include "driver_nl80211.h"
21#include "android_drv.h"
22
23
24typedef struct android_wifi_priv_cmd {
25	char *buf;
26	int used_len;
27	int total_len;
28} android_wifi_priv_cmd;
29
30static int drv_errors = 0;
31
32static void wpa_driver_send_hang_msg(struct wpa_driver_nl80211_data *drv)
33{
34	drv_errors++;
35	if (drv_errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
36		drv_errors = 0;
37		wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
38	}
39}
40
41
42static int android_priv_cmd(struct i802_bss *bss, const char *cmd)
43{
44	struct wpa_driver_nl80211_data *drv = bss->drv;
45	struct ifreq ifr;
46	android_wifi_priv_cmd priv_cmd;
47	char buf[MAX_DRV_CMD_SIZE];
48	int ret;
49
50	os_memset(&ifr, 0, sizeof(ifr));
51	os_memset(&priv_cmd, 0, sizeof(priv_cmd));
52	os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
53
54	os_memset(buf, 0, sizeof(buf));
55	os_strlcpy(buf, cmd, sizeof(buf));
56
57	priv_cmd.buf = buf;
58	priv_cmd.used_len = sizeof(buf);
59	priv_cmd.total_len = sizeof(buf);
60	ifr.ifr_data = &priv_cmd;
61
62	ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
63	if (ret < 0) {
64		wpa_printf(MSG_ERROR, "%s: failed to issue private commands",
65			   __func__);
66		wpa_driver_send_hang_msg(drv);
67		return ret;
68	}
69
70	drv_errors = 0;
71	return 0;
72}
73
74
75int android_pno_start(struct i802_bss *bss,
76		      struct wpa_driver_scan_params *params)
77{
78	struct wpa_driver_nl80211_data *drv = bss->drv;
79	struct ifreq ifr;
80	android_wifi_priv_cmd priv_cmd;
81	int ret = 0, i = 0, bp;
82	char buf[WEXT_PNO_MAX_COMMAND_SIZE];
83
84	bp = WEXT_PNOSETUP_HEADER_SIZE;
85	os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp);
86	buf[bp++] = WEXT_PNO_TLV_PREFIX;
87	buf[bp++] = WEXT_PNO_TLV_VERSION;
88	buf[bp++] = WEXT_PNO_TLV_SUBVERSION;
89	buf[bp++] = WEXT_PNO_TLV_RESERVED;
90
91	while (i < WEXT_PNO_AMOUNT && (size_t) i < params->num_ssids) {
92		/* Check that there is enough space needed for 1 more SSID, the
93		 * other sections and null termination */
94		if ((bp + WEXT_PNO_SSID_HEADER_SIZE + MAX_SSID_LEN +
95		     WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int) sizeof(buf))
96			break;
97		wpa_hexdump_ascii(MSG_DEBUG, "For PNO Scan",
98				  params->ssids[i].ssid,
99				  params->ssids[i].ssid_len);
100		buf[bp++] = WEXT_PNO_SSID_SECTION;
101		buf[bp++] = params->ssids[i].ssid_len;
102		os_memcpy(&buf[bp], params->ssids[i].ssid,
103			  params->ssids[i].ssid_len);
104		bp += params->ssids[i].ssid_len;
105		i++;
106	}
107
108	buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION;
109	os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x",
110		    WEXT_PNO_SCAN_INTERVAL);
111	bp += WEXT_PNO_SCAN_INTERVAL_LENGTH;
112
113	buf[bp++] = WEXT_PNO_REPEAT_SECTION;
114	os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x",
115		    WEXT_PNO_REPEAT);
116	bp += WEXT_PNO_REPEAT_LENGTH;
117
118	buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION;
119	os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x",
120		    WEXT_PNO_MAX_REPEAT);
121	bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1;
122
123	memset(&ifr, 0, sizeof(ifr));
124	memset(&priv_cmd, 0, sizeof(priv_cmd));
125	os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
126
127	priv_cmd.buf = buf;
128	priv_cmd.used_len = bp;
129	priv_cmd.total_len = bp;
130	ifr.ifr_data = &priv_cmd;
131
132	ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
133
134	if (ret < 0) {
135		wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d",
136			   ret);
137		wpa_driver_send_hang_msg(drv);
138		return ret;
139	}
140
141	drv_errors = 0;
142
143	return android_priv_cmd(bss, "PNOFORCE 1");
144}
145
146
147int android_pno_stop(struct i802_bss *bss)
148{
149	return android_priv_cmd(bss, "PNOFORCE 0");
150}
151
152
153#ifdef ANDROID_P2P
154#ifdef ANDROID_LIB_STUB
155
156int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration)
157{
158	return 0;
159}
160
161
162int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len)
163{
164	return 0;
165}
166
167
168int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow)
169{
170	return -1;
171}
172
173
174int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon,
175				 const struct wpabuf *proberesp,
176				 const struct wpabuf *assocresp)
177{
178	return 0;
179}
180
181#endif /* ANDROID_LIB_STUB */
182#endif /* ANDROID_P2P */
183
184
185int android_nl_socket_set_nonblocking(struct nl_handle *handle)
186{
187	return fcntl(nl_socket_get_fd(handle), F_SETFL, O_NONBLOCK);
188}
189
190
191