1/* 2 * Driver interaction with extended Linux CFG8021 3 * 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. 7 * 8 * Alternatively, this software may be distributed under the terms of BSD 9 * license. 10 * 11 */ 12 13#include "includes.h" 14#include <sys/types.h> 15#include <fcntl.h> 16#include <net/if.h> 17 18#include "common.h" 19#include "linux_ioctl.h" 20#include "driver_nl80211.h" 21#include "wpa_supplicant_i.h" 22#include "config.h" 23#ifdef ANDROID 24#include "android_drv.h" 25#endif 26 27#define WPA_PS_ENABLED 0 28#define WPA_PS_DISABLED 1 29 30 31/* Return type for setBand*/ 32enum { 33 SEND_CHANNEL_CHANGE_EVENT = 0, 34 DO_NOT_SEND_CHANNEL_CHANGE_EVENT, 35}; 36 37typedef struct android_wifi_priv_cmd { 38 char *buf; 39 int used_len; 40 int total_len; 41} android_wifi_priv_cmd; 42 43static int drv_errors = 0; 44 45static void wpa_driver_send_hang_msg(struct wpa_driver_nl80211_data *drv) 46{ 47 drv_errors++; 48 if (drv_errors > DRV_NUMBER_SEQUENTIAL_ERRORS) { 49 drv_errors = 0; 50 wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED"); 51 } 52} 53 54static void wpa_driver_notify_country_change(void *ctx, char *cmd) 55{ 56 if ((os_strncasecmp(cmd, "COUNTRY", 7) == 0) || 57 (os_strncasecmp(cmd, "SETBAND", 7) == 0)) { 58 union wpa_event_data event; 59 60 os_memset(&event, 0, sizeof(event)); 61 event.channel_list_changed.initiator = REGDOM_SET_BY_USER; 62 if (os_strncasecmp(cmd, "COUNTRY", 7) == 0) { 63 event.channel_list_changed.type = REGDOM_TYPE_COUNTRY; 64 if (os_strlen(cmd) > 9) { 65 event.channel_list_changed.alpha2[0] = cmd[8]; 66 event.channel_list_changed.alpha2[1] = cmd[9]; 67 } 68 } else { 69 event.channel_list_changed.type = REGDOM_TYPE_UNKNOWN; 70 } 71 wpa_supplicant_event(ctx, EVENT_CHANNEL_LIST_CHANGED, &event); 72 } 73} 74 75int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf, 76 size_t buf_len ) 77{ 78 struct i802_bss *bss = priv; 79 struct wpa_driver_nl80211_data *drv = bss->drv; 80 struct wpa_driver_nl80211_data *driver; 81 struct ifreq ifr; 82 android_wifi_priv_cmd priv_cmd; 83 int ret = 0; 84 85 if (os_strcasecmp(cmd, "START") == 0) { 86 dl_list_for_each(driver, &drv->global->interfaces, struct wpa_driver_nl80211_data, list) { 87 linux_set_iface_flags(drv->global->ioctl_sock, driver->first_bss->ifname, 1); 88 wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STARTED"); 89 } 90 } else if (os_strcasecmp(cmd, "MACADDR") == 0) { 91 u8 macaddr[ETH_ALEN] = {}; 92 93 ret = linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, macaddr); 94 if (!ret) 95 ret = os_snprintf(buf, buf_len, 96 "Macaddr = " MACSTR "\n", MAC2STR(macaddr)); 97 } else { /* Use private command */ 98 memset(&ifr, 0, sizeof(ifr)); 99 memset(&priv_cmd, 0, sizeof(priv_cmd)); 100 os_memcpy(buf, cmd, strlen(cmd) + 1); 101 os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ); 102 103 priv_cmd.buf = buf; 104 priv_cmd.used_len = buf_len; 105 priv_cmd.total_len = buf_len; 106 ifr.ifr_data = &priv_cmd; 107 108 if ((ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr)) < 0) { 109 wpa_printf(MSG_ERROR, "%s: failed to issue private commands\n", __func__); 110 } else { 111 drv_errors = 0; 112 if((os_strncasecmp(cmd, "SETBAND", 7) == 0) && 113 ret == DO_NOT_SEND_CHANNEL_CHANGE_EVENT) { 114 return 0; 115 } 116 117 ret = 0; 118 if ((os_strcasecmp(cmd, "LINKSPEED") == 0) || 119 (os_strcasecmp(cmd, "RSSI") == 0) || 120 (os_strcasecmp(cmd, "GETBAND") == 0) ) 121 ret = strlen(buf); 122 else if (os_strcasecmp(cmd, "P2P_DEV_ADDR") == 0) 123 wpa_printf(MSG_DEBUG, "%s: P2P: Device address ("MACSTR")", 124 __func__, MAC2STR(buf)); 125 else if (os_strcasecmp(cmd, "P2P_SET_PS") == 0) 126 wpa_printf(MSG_DEBUG, "%s: P2P: %s ", __func__, buf); 127 else if (os_strcasecmp(cmd, "P2P_SET_NOA") == 0) 128 wpa_printf(MSG_DEBUG, "%s: P2P: %s ", __func__, buf); 129 else if (os_strcasecmp(cmd, "STOP") == 0) { 130 wpa_printf(MSG_DEBUG, "%s: %s ", __func__, buf); 131 dl_list_for_each(driver, &drv->global->interfaces, struct wpa_driver_nl80211_data, list) { 132 linux_set_iface_flags(drv->global->ioctl_sock, driver->first_bss->ifname, 0); 133 wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STOPPED"); 134 } 135 } 136 else 137 wpa_printf(MSG_DEBUG, "%s %s len = %d, %lu", __func__, buf, ret, buf_len); 138 wpa_driver_notify_country_change(drv->ctx, cmd); 139 } 140 } 141 return ret; 142} 143 144int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration) 145{ 146 char buf[MAX_DRV_CMD_SIZE]; 147 148 memset(buf, 0, sizeof(buf)); 149 wpa_printf(MSG_DEBUG, "%s: Entry", __func__); 150 snprintf(buf, sizeof(buf), "P2P_SET_NOA %d %d %d", count, start, duration); 151 return wpa_driver_nl80211_driver_cmd(priv, buf, buf, strlen(buf)+1); 152} 153 154int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len) 155{ 156 /* Return 0 till we handle p2p_presence request completely in the driver */ 157 return 0; 158} 159 160int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow) 161{ 162 char buf[MAX_DRV_CMD_SIZE]; 163 164 memset(buf, 0, sizeof(buf)); 165 wpa_printf(MSG_DEBUG, "%s: Entry", __func__); 166 snprintf(buf, sizeof(buf), "P2P_SET_PS %d %d %d", legacy_ps, opp_ps, ctwindow); 167 return wpa_driver_nl80211_driver_cmd(priv, buf, buf, strlen(buf) + 1); 168} 169 170int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon, 171 const struct wpabuf *proberesp, 172 const struct wpabuf *assocresp) 173{ 174 175 return 0; 176} 177