2 * Driver interaction with extended Linux CFG8021
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.
8 * Alternatively, this software may be distributed under the terms of BSD
13 #include "driver_nl80211.h"
14 #include "driver_cmd_common.h"
16 #include "wpa_supplicant_i.h"
19 #define WPA_PS_ENABLED 0
20 #define WPA_PS_DISABLED 1
22 typedef struct android_wifi_priv_cmd {
26 } android_wifi_priv_cmd;
28 int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv, struct nl_msg *msg,
29 int (*valid_handler)(struct nl_msg *, void *),
32 static int drv_errors = 0;
34 static void wpa_driver_send_hang_msg(struct wpa_driver_nl80211_data *drv)
37 if (drv_errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
39 wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
43 static int wpa_driver_set_power_save(void *priv, int state)
45 struct i802_bss *bss = priv;
46 struct wpa_driver_nl80211_data *drv = bss->drv;
49 enum nl80211_ps_state ps_state;
55 genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
56 NL80211_CMD_SET_POWER_SAVE, 0);
58 if (state == WPA_PS_ENABLED)
59 ps_state = NL80211_PS_ENABLED;
61 ps_state = NL80211_PS_DISABLED;
63 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
64 NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE, ps_state);
66 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
69 wpa_printf(MSG_ERROR, "nl80211: Set power mode fail: %d", ret);
75 static int get_power_mode_handler(struct nl_msg *msg, void *arg)
77 struct nlattr *tb[NL80211_ATTR_MAX + 1];
78 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
79 int *state = (int *)arg;
81 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
82 genlmsg_attrlen(gnlh, 0), NULL);
84 if (!tb[NL80211_ATTR_PS_STATE])
88 *state = (int)nla_get_u32(tb[NL80211_ATTR_PS_STATE]);
89 wpa_printf(MSG_DEBUG, "nl80211: Get power mode = %d", *state);
90 *state = (*state == NL80211_PS_ENABLED) ?
91 WPA_PS_ENABLED : WPA_PS_DISABLED;
97 static int wpa_driver_get_power_save(void *priv, int *state)
99 struct i802_bss *bss = priv;
100 struct wpa_driver_nl80211_data *drv = bss->drv;
103 enum nl80211_ps_state ps_state;
109 genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
110 NL80211_CMD_GET_POWER_SAVE, 0);
112 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
114 ret = send_and_recv_msgs(drv, msg, get_power_mode_handler, state);
117 wpa_printf(MSG_ERROR, "nl80211: Get power mode fail: %d", ret);
123 static int wpa_driver_set_backgroundscan_params(void *priv)
125 struct i802_bss *bss = priv;
126 struct wpa_driver_nl80211_data *drv = bss->drv;
127 struct wpa_supplicant *wpa_s;
129 android_wifi_priv_cmd priv_cmd;
130 int ret = 0, i = 0, bp;
131 char buf[WEXT_PNO_MAX_COMMAND_SIZE];
132 struct wpa_ssid *ssid_conf;
135 wpa_printf(MSG_ERROR, "%s: drv is NULL. Exiting", __func__);
138 if (drv->ctx == NULL) {
139 wpa_printf(MSG_ERROR, "%s: drv->ctx is NULL. Exiting", __func__);
142 wpa_s = (struct wpa_supplicant *)(drv->ctx);
143 if (wpa_s->conf == NULL) {
144 wpa_printf(MSG_ERROR, "%s: wpa_s->conf is NULL. Exiting", __func__);
147 ssid_conf = wpa_s->conf->ssid;
149 bp = WEXT_PNOSETUP_HEADER_SIZE;
150 os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp);
151 buf[bp++] = WEXT_PNO_TLV_PREFIX;
152 buf[bp++] = WEXT_PNO_TLV_VERSION;
153 buf[bp++] = WEXT_PNO_TLV_SUBVERSION;
154 buf[bp++] = WEXT_PNO_TLV_RESERVED;
156 while ((i < WEXT_PNO_AMOUNT) && (ssid_conf != NULL)) {
157 /* Check that there is enough space needed for 1 more SSID, the other sections and null termination */
158 if ((bp + WEXT_PNO_SSID_HEADER_SIZE + MAX_SSID_LEN + WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int)sizeof(buf))
160 if ((!ssid_conf->disabled) && (ssid_conf->ssid_len <= MAX_SSID_LEN)){
161 wpa_printf(MSG_DEBUG, "For PNO Scan: %s", ssid_conf->ssid);
162 buf[bp++] = WEXT_PNO_SSID_SECTION;
163 buf[bp++] = ssid_conf->ssid_len;
164 os_memcpy(&buf[bp], ssid_conf->ssid, ssid_conf->ssid_len);
165 bp += ssid_conf->ssid_len;
168 ssid_conf = ssid_conf->next;
171 buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION;
172 os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x", WEXT_PNO_SCAN_INTERVAL);
173 bp += WEXT_PNO_SCAN_INTERVAL_LENGTH;
175 buf[bp++] = WEXT_PNO_REPEAT_SECTION;
176 os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x", WEXT_PNO_REPEAT);
177 bp += WEXT_PNO_REPEAT_LENGTH;
179 buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION;
180 os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x", WEXT_PNO_MAX_REPEAT);
181 bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1;
183 memset(&ifr, 0, sizeof(ifr));
184 memset(&priv_cmd, 0, sizeof(priv_cmd));
185 os_strncpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
188 priv_cmd.used_len = bp;
189 priv_cmd.total_len = bp;
190 ifr.ifr_data = &priv_cmd;
192 ret = ioctl(drv->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
195 wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d", ret);
196 wpa_driver_send_hang_msg(drv);
203 int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf,
206 struct i802_bss *bss = priv;
207 struct wpa_driver_nl80211_data *drv = bss->drv;
209 android_wifi_priv_cmd priv_cmd;
212 if (os_strcasecmp(cmd, "STOP") == 0) {
213 linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0);
214 wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STOPPED");
215 } else if (os_strcasecmp(cmd, "START") == 0) {
216 linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1);
217 wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STARTED");
218 } else if (os_strcasecmp(cmd, "MACADDR") == 0) {
219 u8 macaddr[ETH_ALEN] = {};
221 ret = linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, macaddr);
223 ret = os_snprintf(buf, buf_len,
224 "Macaddr = " MACSTR "\n", MAC2STR(macaddr));
225 } else if (os_strcasecmp(cmd, "RELOAD") == 0) {
226 wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
227 } else if (os_strncasecmp(cmd, "POWERMODE ", 10) == 0) {
230 state = atoi(cmd + 10);
231 ret = wpa_driver_set_power_save(priv, state);
233 wpa_driver_send_hang_msg(drv);
236 } else if (os_strncasecmp(cmd, "GETPOWER", 8) == 0) {
239 ret = wpa_driver_get_power_save(priv, &state);
240 if (!ret && (state != -1)) {
241 ret = os_snprintf(buf, buf_len, "POWERMODE = %d\n", state);
244 wpa_driver_send_hang_msg(drv);
246 } else { /* Use private command */
247 if (os_strcasecmp(cmd, "BGSCAN-START") == 0) {
248 ret = wpa_driver_set_backgroundscan_params(priv);
252 os_memcpy(buf, "PNOFORCE 1", 11);
253 } else if (os_strcasecmp(cmd, "BGSCAN-STOP") == 0) {
254 os_memcpy(buf, "PNOFORCE 0", 11);
256 os_memcpy(buf, cmd, strlen(cmd) + 1);
258 memset(&ifr, 0, sizeof(ifr));
259 memset(&priv_cmd, 0, sizeof(priv_cmd));
260 os_strncpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
263 priv_cmd.used_len = buf_len;
264 priv_cmd.total_len = buf_len;
265 ifr.ifr_data = &priv_cmd;
267 #ifndef __i386__ /* we don't support SIOCDEVPRIVATE */
268 if ((ret = ioctl(drv->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr)) < 0) {
269 wpa_printf(MSG_ERROR, "%s: failed to issue private commands\n", __func__);
270 wpa_driver_send_hang_msg(drv);
274 if ((os_strcasecmp(cmd, "LINKSPEED") == 0) ||
275 (os_strcasecmp(cmd, "RSSI") == 0) ||
276 (os_strcasecmp(cmd, "GETBAND") == 0) ||
277 (os_strcasecmp(cmd, "P2P_GET_NOA") == 0))
280 wpa_printf(MSG_DEBUG, "%s %s len = %d, %d", __func__, buf, ret, strlen(buf));
287 int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration)
289 char buf[MAX_DRV_CMD_SIZE];
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);
297 int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len)
299 char rbuf[MAX_DRV_CMD_SIZE];
300 char *cmd = "P2P_GET_NOA";
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));
311 hexstr2bin(rbuf, buf, ret);
315 int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow)
317 char buf[MAX_DRV_CMD_SIZE];
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);
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)
329 char buf[MAX_WPSP2PIE_CMD_SIZE];
330 struct wpabuf *ap_wps_p2p_ie = NULL;
331 char *_cmd = "SET_AP_WPS_P2P_IE";
337 const struct wpabuf *src;
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));
349 pbuf += sprintf(pbuf, "%s %d", _cmd, cmd_arr[i].cmd);
351 ap_wps_p2p_ie = cmd_arr[i].src ?
352 wpabuf_dup(cmd_arr[i].src) : NULL;
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);