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