1b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt/*
2b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt * Driver interaction with extended Linux CFG8021
3b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt *
4b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt * This program is free software; you can redistribute it and/or modify
5b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt * it under the terms of the GNU General Public License version 2 as
6b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt * published by the Free Software Foundation.
7b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt *
8b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt * Alternatively, this software may be distributed under the terms of BSD
9b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt * license.
10b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt *
11b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt */
12b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt
132748d5ff9a4f58551a99e72432252fee3bf1f369Dmitry Shmidt#include "hardware_legacy/driver_nl80211.h"
14991c6863090c21e49229be18a6859d0ec5eaac17Dmitry Shmidt#include "wpa_supplicant_i.h"
15991c6863090c21e49229be18a6859d0ec5eaac17Dmitry Shmidt#include "config.h"
16776e94c9c91c7cbbd0bf3ba12ad77ae1ad29f8f9Dmitry Shmidt#ifdef ANDROID
17776e94c9c91c7cbbd0bf3ba12ad77ae1ad29f8f9Dmitry Shmidt#include "android_drv.h"
18776e94c9c91c7cbbd0bf3ba12ad77ae1ad29f8f9Dmitry Shmidt#endif
19b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt
209002fdbdf86753148dafcf910ad47fa0a1b85471Dmitry Shmidt#define MAX_WPSP2PIE_CMD_SIZE		512
21776e94c9c91c7cbbd0bf3ba12ad77ae1ad29f8f9Dmitry Shmidt
22d261d2a4e8c8ba5d52a3f6d24a15404e5a3a49e6Dmitry Shmidttypedef struct android_wifi_priv_cmd {
23d261d2a4e8c8ba5d52a3f6d24a15404e5a3a49e6Dmitry Shmidt	char *buf;
24d261d2a4e8c8ba5d52a3f6d24a15404e5a3a49e6Dmitry Shmidt	int used_len;
25d261d2a4e8c8ba5d52a3f6d24a15404e5a3a49e6Dmitry Shmidt	int total_len;
26d261d2a4e8c8ba5d52a3f6d24a15404e5a3a49e6Dmitry Shmidt} android_wifi_priv_cmd;
27d261d2a4e8c8ba5d52a3f6d24a15404e5a3a49e6Dmitry Shmidt
28991c6863090c21e49229be18a6859d0ec5eaac17Dmitry Shmidtstatic int drv_errors = 0;
29991c6863090c21e49229be18a6859d0ec5eaac17Dmitry Shmidt
30991c6863090c21e49229be18a6859d0ec5eaac17Dmitry Shmidtstatic void wpa_driver_send_hang_msg(struct wpa_driver_nl80211_data *drv)
31991c6863090c21e49229be18a6859d0ec5eaac17Dmitry Shmidt{
32991c6863090c21e49229be18a6859d0ec5eaac17Dmitry Shmidt	drv_errors++;
33991c6863090c21e49229be18a6859d0ec5eaac17Dmitry Shmidt	if (drv_errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
34991c6863090c21e49229be18a6859d0ec5eaac17Dmitry Shmidt		drv_errors = 0;
35991c6863090c21e49229be18a6859d0ec5eaac17Dmitry Shmidt		wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
36991c6863090c21e49229be18a6859d0ec5eaac17Dmitry Shmidt	}
37991c6863090c21e49229be18a6859d0ec5eaac17Dmitry Shmidt}
38991c6863090c21e49229be18a6859d0ec5eaac17Dmitry Shmidt
39b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidtint wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf,
40b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt				  size_t buf_len )
41b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt{
42b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt	struct i802_bss *bss = priv;
43b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
44d261d2a4e8c8ba5d52a3f6d24a15404e5a3a49e6Dmitry Shmidt	struct ifreq ifr;
45d261d2a4e8c8ba5d52a3f6d24a15404e5a3a49e6Dmitry Shmidt	android_wifi_priv_cmd priv_cmd;
46b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt	int ret = 0;
47b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt
48b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt	if (os_strcasecmp(cmd, "STOP") == 0) {
49776e94c9c91c7cbbd0bf3ba12ad77ae1ad29f8f9Dmitry Shmidt		linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0);
50b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt		wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STOPPED");
51b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt	} else if (os_strcasecmp(cmd, "START") == 0) {
52776e94c9c91c7cbbd0bf3ba12ad77ae1ad29f8f9Dmitry Shmidt		linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1);
53b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt		wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STARTED");
54b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt	} else if (os_strcasecmp(cmd, "MACADDR") == 0) {
55b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt		u8 macaddr[ETH_ALEN] = {};
56b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt
57776e94c9c91c7cbbd0bf3ba12ad77ae1ad29f8f9Dmitry Shmidt		ret = linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, macaddr);
58b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt		if (!ret)
59b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt			ret = os_snprintf(buf, buf_len,
60b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt					  "Macaddr = " MACSTR "\n", MAC2STR(macaddr));
61d261d2a4e8c8ba5d52a3f6d24a15404e5a3a49e6Dmitry Shmidt	} else { /* Use private command */
62b7a3187fbbba0991b789298cb208d913334a6acbDmitry Shmidt		os_memcpy(buf, cmd, strlen(cmd) + 1);
63d261d2a4e8c8ba5d52a3f6d24a15404e5a3a49e6Dmitry Shmidt		memset(&ifr, 0, sizeof(ifr));
64d261d2a4e8c8ba5d52a3f6d24a15404e5a3a49e6Dmitry Shmidt		memset(&priv_cmd, 0, sizeof(priv_cmd));
6530277c38a4fb41c7f71c790cd637f0d0aea94cc3Dmitry Shmidt		os_strncpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
66d261d2a4e8c8ba5d52a3f6d24a15404e5a3a49e6Dmitry Shmidt
67d261d2a4e8c8ba5d52a3f6d24a15404e5a3a49e6Dmitry Shmidt		priv_cmd.buf = buf;
68d261d2a4e8c8ba5d52a3f6d24a15404e5a3a49e6Dmitry Shmidt		priv_cmd.used_len = buf_len;
69d261d2a4e8c8ba5d52a3f6d24a15404e5a3a49e6Dmitry Shmidt		priv_cmd.total_len = buf_len;
70d261d2a4e8c8ba5d52a3f6d24a15404e5a3a49e6Dmitry Shmidt		ifr.ifr_data = &priv_cmd;
71d261d2a4e8c8ba5d52a3f6d24a15404e5a3a49e6Dmitry Shmidt
72776e94c9c91c7cbbd0bf3ba12ad77ae1ad29f8f9Dmitry Shmidt		if ((ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr)) < 0) {
73d261d2a4e8c8ba5d52a3f6d24a15404e5a3a49e6Dmitry Shmidt			wpa_printf(MSG_ERROR, "%s: failed to issue private commands\n", __func__);
74991c6863090c21e49229be18a6859d0ec5eaac17Dmitry Shmidt			wpa_driver_send_hang_msg(drv);
75991c6863090c21e49229be18a6859d0ec5eaac17Dmitry Shmidt		} else {
76991c6863090c21e49229be18a6859d0ec5eaac17Dmitry Shmidt			drv_errors = 0;
77d261d2a4e8c8ba5d52a3f6d24a15404e5a3a49e6Dmitry Shmidt			ret = 0;
78d261d2a4e8c8ba5d52a3f6d24a15404e5a3a49e6Dmitry Shmidt			if ((os_strcasecmp(cmd, "LINKSPEED") == 0) ||
790428c19916e443cb002cba53263c3421ca6bd2d3Dmitry Shmidt			    (os_strcasecmp(cmd, "RSSI") == 0) ||
80ef8e2e571ffc2141a05c0087523e674b92ac2ea8Dmitry Shmidt			    (os_strcasecmp(cmd, "GETBAND") == 0) ||
81ef8e2e571ffc2141a05c0087523e674b92ac2ea8Dmitry Shmidt			    (os_strncasecmp(cmd, "WLS_BATCHING", 12) == 0))
82d261d2a4e8c8ba5d52a3f6d24a15404e5a3a49e6Dmitry Shmidt				ret = strlen(buf);
836d97ec46bbec3f31c652c0208e3393d7aa2bee71Dmitry Shmidt			else if ((os_strncasecmp(cmd, "COUNTRY", 7) == 0) ||
846d97ec46bbec3f31c652c0208e3393d7aa2bee71Dmitry Shmidt				 (os_strncasecmp(cmd, "SETBAND", 7) == 0))
85f65a4f72f06979609a89ad9a494a5aa9f0744980Dmitry Shmidt				wpa_supplicant_event(drv->ctx,
86f65a4f72f06979609a89ad9a494a5aa9f0744980Dmitry Shmidt					EVENT_CHANNEL_LIST_CHANGED, NULL);
87d261d2a4e8c8ba5d52a3f6d24a15404e5a3a49e6Dmitry Shmidt			wpa_printf(MSG_DEBUG, "%s %s len = %d, %d", __func__, buf, ret, strlen(buf));
88d261d2a4e8c8ba5d52a3f6d24a15404e5a3a49e6Dmitry Shmidt		}
89b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt	}
90b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt	return ret;
91b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt}
92b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt
93b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidtint wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration)
94b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt{
95b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt	char buf[MAX_DRV_CMD_SIZE];
96b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt
97b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt	memset(buf, 0, sizeof(buf));
98b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt	wpa_printf(MSG_DEBUG, "%s: Entry", __func__);
99b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt	snprintf(buf, sizeof(buf), "P2P_SET_NOA %d %d %d", count, start, duration);
100b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt	return wpa_driver_nl80211_driver_cmd(priv, buf, buf, strlen(buf)+1);
101b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt}
102b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt
103fd38f980c1e877dbc7da6204cc9208e3dbbf0546Dmitry Shmidtint wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len)
104fd38f980c1e877dbc7da6204cc9208e3dbbf0546Dmitry Shmidt{
105776e94c9c91c7cbbd0bf3ba12ad77ae1ad29f8f9Dmitry Shmidt	/* Return 0 till we handle p2p_presence request completely in the driver */
106776e94c9c91c7cbbd0bf3ba12ad77ae1ad29f8f9Dmitry Shmidt	return 0;
107fd38f980c1e877dbc7da6204cc9208e3dbbf0546Dmitry Shmidt}
108fd38f980c1e877dbc7da6204cc9208e3dbbf0546Dmitry Shmidt
109b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidtint wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow)
110b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt{
111b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt	char buf[MAX_DRV_CMD_SIZE];
112b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt
113b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt	memset(buf, 0, sizeof(buf));
114b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt	wpa_printf(MSG_DEBUG, "%s: Entry", __func__);
115b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt	snprintf(buf, sizeof(buf), "P2P_SET_PS %d %d %d", legacy_ps, opp_ps, ctwindow);
116b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt	return wpa_driver_nl80211_driver_cmd(priv, buf, buf, strlen(buf) + 1);
117b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt}
118b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt
119b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidtint wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon,
120b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt				 const struct wpabuf *proberesp,
121b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt				 const struct wpabuf *assocresp)
122b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt{
123b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt	char buf[MAX_WPSP2PIE_CMD_SIZE];
124b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt	struct wpabuf *ap_wps_p2p_ie = NULL;
125b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt	char *_cmd = "SET_AP_WPS_P2P_IE";
126b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt	char *pbuf;
127b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt	int ret = 0;
128b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt	int i;
129b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt	struct cmd_desc {
130b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt		int cmd;
131b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt		const struct wpabuf *src;
132b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt	} cmd_arr[] = {
133b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt		{0x1, beacon},
134b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt		{0x2, proberesp},
135b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt		{0x4, assocresp},
136b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt		{-1, NULL}
137b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt	};
138b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt
139b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt	wpa_printf(MSG_DEBUG, "%s: Entry", __func__);
140b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt	for (i = 0; cmd_arr[i].cmd != -1; i++) {
141b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt		os_memset(buf, 0, sizeof(buf));
142b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt		pbuf = buf;
143b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt		pbuf += sprintf(pbuf, "%s %d", _cmd, cmd_arr[i].cmd);
144b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt		*pbuf++ = '\0';
145b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt		ap_wps_p2p_ie = cmd_arr[i].src ?
146b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt			wpabuf_dup(cmd_arr[i].src) : NULL;
147b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt		if (ap_wps_p2p_ie) {
148b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt			os_memcpy(pbuf, wpabuf_head(ap_wps_p2p_ie), wpabuf_len(ap_wps_p2p_ie));
149b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt			ret = wpa_driver_nl80211_driver_cmd(priv, buf, buf,
150b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt				strlen(_cmd) + 3 + wpabuf_len(ap_wps_p2p_ie));
151b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt			wpabuf_free(ap_wps_p2p_ie);
152b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt			if (ret < 0)
153b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt				break;
154b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt		}
155b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt	}
156b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt
157b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt	return ret;
158b05da5a8c808715098cae93ef1db1f2684f71c9fDmitry Shmidt}
159