Home | History | Annotate | Download | only in drivers
      1 /*
      2  * Driver interaction with Linux nl80211/cfg80211 - Android specific
      3  * Copyright (c) 2002-2014, Jouni Malinen <j (at) w1.fi>
      4  * Copyright (c) 2007, Johannes Berg <johannes (at) 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 
     24 typedef struct android_wifi_priv_cmd {
     25 	char *buf;
     26 	int used_len;
     27 	int total_len;
     28 } android_wifi_priv_cmd;
     29 
     30 static int drv_errors = 0;
     31 
     32 static 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 
     42 static 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 
     75 int 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 
    147 int 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 
    156 int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration)
    157 {
    158 	return 0;
    159 }
    160 
    161 
    162 int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len)
    163 {
    164 	return 0;
    165 }
    166 
    167 
    168 int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow)
    169 {
    170 	return -1;
    171 }
    172 
    173 
    174 int 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 
    185 int 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