PageRenderTime 132ms CodeModel.GetById 3ms app.highlight 112ms RepoModel.GetById 1ms app.codeStats 1ms

/drivers/net/wireless/bcmdhd/wl_android.c

https://bitbucket.org/arter97/arter97-cm-i9300
C | 2560 lines | 2100 code | 364 blank | 96 comment | 480 complexity | e79d2cfe161750fb625461f3a16e927b MD5 | raw file
   1/*
   2 * Linux cfg80211 driver - Android related functions
   3 *
   4 * Copyright (C) 1999-2012, Broadcom Corporation
   5 * 
   6 *      Unless you and Broadcom execute a separate written software license
   7 * agreement governing use of this software, this software is licensed to you
   8 * under the terms of the GNU General Public License version 2 (the "GPL"),
   9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
  10 * following added to such license:
  11 * 
  12 *      As a special exception, the copyright holders of this software give you
  13 * permission to link this software with independent modules, and to copy and
  14 * distribute the resulting executable under terms of your choice, provided that
  15 * you also meet, for each linked independent module, the terms and conditions of
  16 * the license of that module.  An independent module is a module which is not
  17 * derived from this software.  The special exception does not apply to any
  18 * modifications of the software.
  19 * 
  20 *      Notwithstanding the above, under no circumstances may you combine this
  21 * software in any way with any other Broadcom software provided under a license
  22 * other than the GPL, without Broadcom's express prior written consent.
  23 *
  24 * $Id: wl_android.c 393894 2013-03-29 07:14:35Z $
  25 */
  26
  27#include <linux/module.h>
  28#include <linux/netdevice.h>
  29
  30#include <wl_android.h>
  31#include <wldev_common.h>
  32#include <wlioctl.h>
  33#include <bcmutils.h>
  34#include <linux_osl.h>
  35#include <dhd_dbg.h>
  36#include <dngl_stats.h>
  37#include <dhd.h>
  38#include <bcmsdbus.h>
  39#ifdef WL_CFG80211
  40#include <wl_cfg80211.h>
  41#endif
  42#if defined(CONFIG_WIFI_CONTROL_FUNC)
  43#include <linux/platform_device.h>
  44#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
  45#include <linux/wlan_plat.h>
  46#else
  47#include <linux/wifi_tiwlan.h>
  48#endif
  49#endif /* CONFIG_WIFI_CONTROL_FUNC */
  50
  51/*
  52 * Android private command strings, PLEASE define new private commands here
  53 * so they can be updated easily in the future (if needed)
  54 */
  55
  56#define CMD_START		"START"
  57#define CMD_STOP		"STOP"
  58#define	CMD_SCAN_ACTIVE		"SCAN-ACTIVE"
  59#define	CMD_SCAN_PASSIVE	"SCAN-PASSIVE"
  60#define CMD_RSSI		"RSSI"
  61#define CMD_LINKSPEED		"LINKSPEED"
  62#define CMD_RXFILTER_START	"RXFILTER-START"
  63#define CMD_RXFILTER_STOP	"RXFILTER-STOP"
  64#define CMD_RXFILTER_ADD	"RXFILTER-ADD"
  65#define CMD_RXFILTER_REMOVE	"RXFILTER-REMOVE"
  66#define CMD_BTCOEXSCAN_START	"BTCOEXSCAN-START"
  67#define CMD_BTCOEXSCAN_STOP	"BTCOEXSCAN-STOP"
  68#define CMD_BTCOEXMODE		"BTCOEXMODE"
  69#define CMD_SETSUSPENDOPT	"SETSUSPENDOPT"
  70#define CMD_SETSUSPENDMODE      "SETSUSPENDMODE"
  71#define CMD_P2P_DEV_ADDR	"P2P_DEV_ADDR"
  72#define CMD_SETFWPATH		"SETFWPATH"
  73#define CMD_SETBAND		"SETBAND"
  74#define CMD_GETBAND		"GETBAND"
  75#define CMD_COUNTRY		"COUNTRY"
  76#define CMD_P2P_SET_NOA		"P2P_SET_NOA"
  77#if !defined WL_ENABLE_P2P_IF
  78#define CMD_P2P_GET_NOA			"P2P_GET_NOA"
  79#endif
  80#define CMD_P2P_SD_OFFLOAD		"P2P_SD_"
  81#define CMD_P2P_SET_PS		"P2P_SET_PS"
  82#define CMD_SET_AP_WPS_P2P_IE 		"SET_AP_WPS_P2P_IE"
  83#define CMD_SETROAMMODE		"SETROAMMODE"
  84
  85#ifdef CUSTOMER_HW4
  86#ifdef SUPPORT_AUTO_CHANNEL
  87#define CMD_SET_HAPD_AUTO_CHANNEL	"HAPD_AUTO_CHANNEL"
  88#endif /* SUPPORT_AUTO_CHANNEL */
  89#ifdef SUPPORT_HIDDEN_AP
  90/* Hostapd private command */
  91#define CMD_SET_HAPD_MAX_NUM_STA	"HAPD_MAX_NUM_STA"
  92#define CMD_SET_HAPD_SSID		"HAPD_SSID"
  93#define CMD_SET_HAPD_HIDE_SSID		"HAPD_HIDE_SSID"
  94#endif /* SUPPORT_HIDDEN_AP */
  95#ifdef SUPPORT_SOFTAP_SINGL_DISASSOC
  96#define CMD_HAPD_STA_DISASSOC		"HAPD_STA_DISASSOC"
  97#endif /* SUPPORT_SOFTAP_SINGL_DISASSOC */
  98#ifdef SUPPORT_SET_LPC
  99#define CMD_HAPD_LPC_ENABLED            "HAPD_LPC_ENABLED"
 100#endif /* SUPPORT_SET_LPC */
 101#ifdef SUPPORT_TRIGGER_HANG_EVENT
 102#define CMD_TEST_FORCE_HANG		"TEST_FORCE_HANG"
 103#endif /* SUPPORT_TRIGGER_HANG_EVENT */
 104#endif /* CUSTOMER_HW4 */
 105
 106/* CCX Private Commands */
 107#ifdef BCMCCX
 108#define CMD_GETCCKM_RN		"get cckm_rn"
 109#define CMD_SETCCKM_KRK		"set cckm_krk"
 110#define CMD_GET_ASSOC_RES_IES	"get assoc_res_ies"
 111#endif
 112
 113#ifdef PNO_SUPPORT
 114#define CMD_PNOSSIDCLR_SET	"PNOSSIDCLR"
 115#define CMD_PNOSETUP_SET	"PNOSETUP "
 116#define CMD_PNOENABLE_SET	"PNOFORCE"
 117#define CMD_PNODEBUG_SET	"PNODEBUG"
 118
 119#define PNO_TLV_PREFIX			'S'
 120#define PNO_TLV_VERSION			'1'
 121#define PNO_TLV_SUBVERSION 		'2'
 122#define PNO_TLV_RESERVED		'0'
 123#define PNO_TLV_TYPE_SSID_IE		'S'
 124#define PNO_TLV_TYPE_TIME		'T'
 125#define PNO_TLV_FREQ_REPEAT		'R'
 126#define PNO_TLV_FREQ_EXPO_MAX		'M'
 127
 128typedef struct cmd_tlv {
 129	char prefix;
 130	char version;
 131	char subver;
 132	char reserved;
 133} cmd_tlv_t;
 134#endif /* PNO_SUPPORT */
 135
 136#define CMD_OKC_SET_PMK		"SET_PMK"
 137#define CMD_OKC_ENABLE		"OKC_ENABLE"
 138
 139
 140#ifdef CUSTOMER_HW4
 141
 142#ifdef ROAM_API
 143#define CMD_ROAMTRIGGER_SET "SETROAMTRIGGER"
 144#define CMD_ROAMTRIGGER_GET "GETROAMTRIGGER"
 145#define CMD_ROAMDELTA_SET "SETROAMDELTA"
 146#define CMD_ROAMDELTA_GET "GETROAMDELTA"
 147#define CMD_ROAMSCANPERIOD_SET "SETROAMSCANPERIOD"
 148#define CMD_ROAMSCANPERIOD_GET "GETROAMSCANPERIOD"
 149#define CMD_FULLROAMSCANPERIOD_SET "SETFULLROAMSCANPERIOD"
 150#define CMD_FULLROAMSCANPERIOD_GET "GETFULLROAMSCANPERIOD"
 151#define CMD_COUNTRYREV_SET "SETCOUNTRYREV"
 152#define CMD_COUNTRYREV_GET "GETCOUNTRYREV"
 153#endif /* ROAM_API */
 154
 155#ifdef WES_SUPPORT
 156#define CMD_GETROAMSCANCONTROL "GETROAMSCANCONTROL"
 157#define CMD_SETROAMSCANCONTROL "SETROAMSCANCONTROL"
 158#define CMD_GETROAMSCANCHANNELS "GETROAMSCANCHANNELS"
 159#define CMD_SETROAMSCANCHANNELS "SETROAMSCANCHANNELS"
 160
 161#define CMD_GETSCANCHANNELTIME "GETSCANCHANNELTIME"
 162#define CMD_SETSCANCHANNELTIME "SETSCANCHANNELTIME"
 163#define CMD_GETSCANHOMETIME "GETSCANHOMETIME"
 164#define CMD_SETSCANHOMETIME "SETSCANHOMETIME"
 165#define CMD_GETSCANHOMEAWAYTIME "GETSCANHOMEAWAYTIME"
 166#define CMD_SETSCANHOMEAWAYTIME "SETSCANHOMEAWAYTIME"
 167#define CMD_GETSCANNPROBES "GETSCANNPROBES"
 168#define CMD_SETSCANNPROBES "SETSCANNPROBES"
 169
 170#define CMD_SENDACTIONFRAME "SENDACTIONFRAME"
 171#define CMD_REASSOC "REASSOC"
 172
 173#define CMD_GETWESMODE "GETWESMODE"
 174#define CMD_SETWESMODE "SETWESMODE"
 175
 176#define CMD_GETOKCMODE "GETOKCMODE"
 177#define CMD_SETOKCMODE "SETOKCMODE"
 178
 179#define ANDROID_WIFI_MAX_ROAM_SCAN_CHANNELS 100
 180
 181typedef struct android_wifi_reassoc_params {
 182	unsigned char bssid[18];
 183	int channel;
 184} android_wifi_reassoc_params_t;
 185
 186#define ANDROID_WIFI_REASSOC_PARAMS_SIZE sizeof(struct android_wifi_reassoc_params)
 187
 188#define ANDROID_WIFI_ACTION_FRAME_SIZE 1040
 189
 190typedef struct android_wifi_af_params {
 191	unsigned char bssid[18];
 192	int channel;
 193	int dwell_time;
 194	int len;
 195	unsigned char data[ANDROID_WIFI_ACTION_FRAME_SIZE];
 196} android_wifi_af_params_t;
 197
 198#define ANDROID_WIFI_AF_PARAMS_SIZE sizeof(struct android_wifi_af_params)
 199#endif /* WES_SUPPORT */
 200#ifdef SUPPORT_AMPDU_MPDU_CMD
 201#define CMD_AMPDU_MPDU		"AMPDU_MPDU"
 202#endif /* SUPPORT_AMPDU_MPDU_CMD */
 203
 204#define CMD_CHANGE_RL	"CHANGE_RL"
 205#define CMD_RESTORE_RL  "RESTORE_RL"
 206#endif /* CUSTOMER_HW4 */
 207typedef struct android_wifi_priv_cmd {
 208	char *buf;
 209	int used_len;
 210	int total_len;
 211} android_wifi_priv_cmd;
 212
 213#ifdef WL_GENL
 214static s32 wl_genl_handle_msg(struct sk_buff *skb, struct genl_info *info);
 215static int wl_genl_init(void);
 216static int wl_genl_deinit(void);
 217
 218extern struct net init_net;
 219/* attribute policy: defines which attribute has which type (e.g int, char * etc)
 220 * possible values defined in net/netlink.h
 221 */
 222static struct nla_policy wl_genl_policy[BCM_GENL_ATTR_MAX + 1] = {
 223	[BCM_GENL_ATTR_STRING] = { .type = NLA_NUL_STRING },
 224	[BCM_GENL_ATTR_MSG] = { .type = NLA_BINARY },
 225};
 226
 227#define WL_GENL_VER 1
 228/* family definition */
 229static struct genl_family wl_genl_family = {
 230	.id = GENL_ID_GENERATE,    /* Genetlink would generate the ID */
 231	.hdrsize = 0,
 232	.name = "bcm-genl",        /* Netlink I/F for Android */
 233	.version = WL_GENL_VER,     /* Version Number */
 234	.maxattr = BCM_GENL_ATTR_MAX,
 235};
 236
 237/* commands: mapping between the command enumeration and the actual function */
 238struct genl_ops wl_genl_ops = {
 239	.cmd = BCM_GENL_CMD_MSG,
 240	.flags = 0,
 241	.policy = wl_genl_policy,
 242	.doit = wl_genl_handle_msg,
 243	.dumpit = NULL,
 244};
 245
 246static struct genl_multicast_group wl_genl_mcast = {
 247	.id = GENL_ID_GENERATE,    /* Genetlink would generate the ID */
 248	.name = "bcm-genl-mcast",
 249};
 250
 251#endif /* WL_GENL */
 252
 253/**
 254 * Extern function declarations (TODO: move them to dhd_linux.h)
 255 */
 256void dhd_customer_gpio_wlan_ctrl(int onoff);
 257int dhd_dev_reset(struct net_device *dev, uint8 flag);
 258int dhd_dev_init_ioctl(struct net_device *dev);
 259#ifdef WL_CFG80211
 260int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr);
 261int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command);
 262#if defined(CUSTOMER_HW4) && defined(WES_SUPPORT)
 263int wl_cfg80211_set_wes_mode(int mode);
 264int wl_cfg80211_get_wes_mode(void);
 265int wl_cfg80211_get_ioctl_version(void);
 266#endif
 267#else
 268int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr)
 269{ return 0; }
 270int wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len)
 271{ return 0; }
 272int wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len)
 273{ return 0; }
 274int wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len)
 275{ return 0; }
 276#endif /* WK_CFG80211 */
 277extern int dhd_os_check_if_up(void *dhdp);
 278extern void *bcmsdh_get_drvdata(void);
 279#if defined(PROP_TXSTATUS) && !defined(PROP_TXSTATUS_VSDB)
 280extern int dhd_wlfc_init(dhd_pub_t *dhd);
 281extern void dhd_wlfc_deinit(dhd_pub_t *dhd);
 282#endif
 283
 284#if defined(CUSTOMER_HW4) && defined(WES_SUPPORT)
 285/* wl_roam.c */
 286extern int get_roamscan_mode(struct net_device *dev, int *mode);
 287extern int set_roamscan_mode(struct net_device *dev, int mode);
 288extern int get_roamscan_channel_list(struct net_device *dev, unsigned char channels[]);
 289extern int set_roamscan_channel_list(struct net_device *dev, unsigned char n,
 290	unsigned char channels[], int ioctl_ver);
 291#endif
 292
 293#ifdef ENABLE_4335BT_WAR
 294extern int bcm_bt_lock(int cookie);
 295extern void bcm_bt_unlock(int cookie);
 296static int lock_cookie_wifi = 'W' | 'i'<<8 | 'F'<<16 | 'i'<<24;	/* cookie is "WiFi" */
 297#endif /* ENABLE_4335BT_WAR */
 298
 299extern bool ap_fw_loaded;
 300#if defined(CUSTOMER_HW2) || defined(CUSTOMER_HW4)
 301extern char iface_name[IFNAMSIZ];
 302#endif /* CUSTOMER_HW2 || CUSTOMER_HW4 */
 303
 304#ifndef WIFI_TURNOFF_DELAY
 305#define WIFI_TURNOFF_DELAY	0
 306#endif
 307/**
 308 * Local (static) functions and variables
 309 */
 310
 311/* Initialize g_wifi_on to 1 so dhd_bus_start will be called for the first
 312 * time (only) in dhd_open, subsequential wifi on will be handled by
 313 * wl_android_wifi_on
 314 */
 315static int g_wifi_on = TRUE;
 316
 317/**
 318 * Local (static) function definitions
 319 */
 320static int wl_android_get_link_speed(struct net_device *net, char *command, int total_len)
 321{
 322	int link_speed;
 323	int bytes_written;
 324	int error;
 325
 326	error = wldev_get_link_speed(net, &link_speed);
 327	if (error)
 328		return -1;
 329
 330	/* Convert Kbps to Android Mbps */
 331	link_speed = link_speed / 1000;
 332	bytes_written = snprintf(command, total_len, "LinkSpeed %d", link_speed);
 333	DHD_INFO(("%s: command result is %s\n", __FUNCTION__, command));
 334	return bytes_written;
 335}
 336
 337static int wl_android_get_rssi(struct net_device *net, char *command, int total_len)
 338{
 339	wlc_ssid_t ssid = {0};
 340	int rssi;
 341	int bytes_written = 0;
 342	int error;
 343
 344	error = wldev_get_rssi(net, &rssi);
 345	if (error)
 346		return -1;
 347
 348	error = wldev_get_ssid(net, &ssid);
 349	if (error)
 350		return -1;
 351	if ((ssid.SSID_len == 0) || (ssid.SSID_len > DOT11_MAX_SSID_LEN)) {
 352		DHD_ERROR(("%s: wldev_get_ssid failed\n", __FUNCTION__));
 353	} else {
 354		memcpy(command, ssid.SSID, ssid.SSID_len);
 355		bytes_written = ssid.SSID_len;
 356	}
 357	bytes_written += snprintf(&command[bytes_written], total_len, " rssi %d", rssi);
 358	DHD_INFO(("%s: command result is %s (%d)\n", __FUNCTION__, command, bytes_written));
 359	return bytes_written;
 360}
 361
 362static int wl_android_set_suspendopt(struct net_device *dev, char *command, int total_len)
 363{
 364	int suspend_flag;
 365	int ret_now;
 366	int ret = 0;
 367
 368#ifdef CUSTOMER_HW4
 369	if (!dhd_download_fw_on_driverload) {
 370#endif /* CUSTOMER_HW4 */
 371		suspend_flag = *(command + strlen(CMD_SETSUSPENDOPT) + 1) - '0';
 372
 373		if (suspend_flag != 0)
 374			suspend_flag = 1;
 375		ret_now = net_os_set_suspend_disable(dev, suspend_flag);
 376
 377		if (ret_now != suspend_flag) {
 378			if (!(ret = net_os_set_suspend(dev, ret_now, 1)))
 379				DHD_INFO(("%s: Suspend Flag %d -> %d\n",
 380					__FUNCTION__, ret_now, suspend_flag));
 381			else
 382				DHD_ERROR(("%s: failed %d\n", __FUNCTION__, ret));
 383		}
 384#ifdef CUSTOMER_HW4
 385	}
 386#endif /* CUSTOMER_HW4 */
 387	return ret;
 388}
 389
 390static int wl_android_set_suspendmode(struct net_device *dev, char *command, int total_len)
 391{
 392	int ret = 0;
 393
 394#if !defined(CONFIG_HAS_EARLYSUSPEND) || !defined(DHD_USE_EARLYSUSPEND)
 395	int suspend_flag;
 396
 397	suspend_flag = *(command + strlen(CMD_SETSUSPENDMODE) + 1) - '0';
 398	if (suspend_flag != 0)
 399		suspend_flag = 1;
 400
 401	if (!(ret = net_os_set_suspend(dev, suspend_flag, 0)))
 402		DHD_INFO(("%s: Suspend Mode %d\n", __FUNCTION__, suspend_flag));
 403	else
 404		DHD_ERROR(("%s: failed %d\n", __FUNCTION__, ret));
 405#endif
 406
 407	return ret;
 408}
 409
 410static int wl_android_get_band(struct net_device *dev, char *command, int total_len)
 411{
 412	uint band;
 413	int bytes_written;
 414	int error;
 415
 416	error = wldev_get_band(dev, &band);
 417	if (error)
 418		return -1;
 419	bytes_written = snprintf(command, total_len, "Band %d", band);
 420	return bytes_written;
 421}
 422
 423#ifdef CUSTOMER_HW4
 424#ifdef ROAM_API
 425int wl_android_set_roam_trigger(
 426	struct net_device *dev, char* command, int total_len)
 427{
 428	int roam_trigger[2];
 429
 430	sscanf(command, "%*s %10d", &roam_trigger[0]);
 431	roam_trigger[1] = WLC_BAND_ALL;
 432
 433	return wldev_ioctl(dev, WLC_SET_ROAM_TRIGGER, roam_trigger,
 434		sizeof(roam_trigger), 1);
 435}
 436
 437static int wl_android_get_roam_trigger(
 438	struct net_device *dev, char *command, int total_len)
 439{
 440	int bytes_written;
 441	int roam_trigger[2] = {0, 0};
 442
 443	roam_trigger[1] = WLC_BAND_2G;
 444	if (wldev_ioctl(dev, WLC_GET_ROAM_TRIGGER, roam_trigger,
 445		sizeof(roam_trigger), 0)) {
 446		roam_trigger[1] = WLC_BAND_5G;
 447		if (wldev_ioctl(dev, WLC_GET_ROAM_TRIGGER, roam_trigger,
 448			sizeof(roam_trigger), 0))
 449			return -1;
 450	}
 451
 452	bytes_written = snprintf(command, total_len, "%s %d",
 453		CMD_ROAMTRIGGER_GET, roam_trigger[0]);
 454
 455	return bytes_written;
 456}
 457
 458int wl_android_set_roam_delta(
 459	struct net_device *dev, char* command, int total_len)
 460{
 461	int roam_delta[2];
 462
 463	sscanf(command, "%*s %10d", &roam_delta[0]);
 464	roam_delta[1] = WLC_BAND_ALL;
 465
 466	return wldev_ioctl(dev, WLC_SET_ROAM_DELTA, roam_delta,
 467		sizeof(roam_delta), 1);
 468}
 469
 470static int wl_android_get_roam_delta(
 471	struct net_device *dev, char *command, int total_len)
 472{
 473	int bytes_written;
 474	int roam_delta[2] = {0, 0};
 475
 476	roam_delta[1] = WLC_BAND_2G;
 477	if (wldev_ioctl(dev, WLC_GET_ROAM_DELTA, roam_delta,
 478		sizeof(roam_delta), 0)) {
 479		roam_delta[1] = WLC_BAND_5G;
 480		if (wldev_ioctl(dev, WLC_GET_ROAM_DELTA, roam_delta,
 481			sizeof(roam_delta), 0))
 482			return -1;
 483	}
 484
 485	bytes_written = snprintf(command, total_len, "%s %d",
 486		CMD_ROAMDELTA_GET, roam_delta[0]);
 487
 488	return bytes_written;
 489}
 490
 491int wl_android_set_roam_scan_period(
 492	struct net_device *dev, char* command, int total_len)
 493{
 494	int roam_scan_period = 0;
 495
 496	sscanf(command, "%*s %10d", &roam_scan_period);
 497	return wldev_ioctl(dev, WLC_SET_ROAM_SCAN_PERIOD, &roam_scan_period,
 498		sizeof(roam_scan_period), 1);
 499}
 500
 501static int wl_android_get_roam_scan_period(
 502	struct net_device *dev, char *command, int total_len)
 503{
 504	int bytes_written;
 505	int roam_scan_period = 0;
 506
 507	if (wldev_ioctl(dev, WLC_GET_ROAM_SCAN_PERIOD, &roam_scan_period,
 508		sizeof(roam_scan_period), 0))
 509		return -1;
 510
 511	bytes_written = snprintf(command, total_len, "%s %d",
 512		CMD_ROAMSCANPERIOD_GET, roam_scan_period);
 513
 514	return bytes_written;
 515}
 516
 517int wl_android_set_full_roam_scan_period(
 518	struct net_device *dev, char* command, int total_len)
 519{
 520	int error = 0;
 521	int full_roam_scan_period = 0;
 522	char smbuf[WLC_IOCTL_SMLEN];
 523
 524	sscanf(command+sizeof("SETFULLROAMSCANPERIOD"), "%d", &full_roam_scan_period);
 525	WL_TRACE(("fullroamperiod = %d\n", full_roam_scan_period));
 526
 527	error = wldev_iovar_setbuf(dev, "fullroamperiod", &full_roam_scan_period,
 528		sizeof(full_roam_scan_period), smbuf, sizeof(smbuf), NULL);
 529	if (error) {
 530		DHD_ERROR(("Failed to set full roam scan period, error = %d\n", error));
 531	}
 532
 533	return error;
 534}
 535
 536static int wl_android_get_full_roam_scan_period(
 537	struct net_device *dev, char *command, int total_len)
 538{
 539	int error;
 540	int bytes_written;
 541	int full_roam_scan_period = 0;
 542
 543	error = wldev_iovar_getint(dev, "fullroamperiod", &full_roam_scan_period);
 544
 545	if (error) {
 546		DHD_ERROR(("%s: get full roam scan period failed code %d\n",
 547			__func__, error));
 548		return -1;
 549	} else {
 550		DHD_INFO(("%s: get full roam scan period %d\n", __func__, full_roam_scan_period));
 551	}
 552
 553	bytes_written = snprintf(command, total_len, "%s %d",
 554		CMD_FULLROAMSCANPERIOD_GET, full_roam_scan_period);
 555
 556	return bytes_written;
 557}
 558
 559int wl_android_set_country_rev(
 560	struct net_device *dev, char* command, int total_len)
 561{
 562	int error = 0;
 563	wl_country_t cspec = {{0}, 0, {0} };
 564	char country_code[WLC_CNTRY_BUF_SZ];
 565	char smbuf[WLC_IOCTL_SMLEN];
 566	int rev = 0;
 567
 568	memset(country_code, 0, sizeof(country_code));
 569	sscanf(command+sizeof("SETCOUNTRYREV"), "%10s %10d", country_code, &rev);
 570	WL_TRACE(("country_code = %s, rev = %d\n", country_code, rev));
 571
 572	memcpy(cspec.country_abbrev, country_code, sizeof(country_code));
 573	memcpy(cspec.ccode, country_code, sizeof(country_code));
 574	cspec.rev = rev;
 575
 576	error = wldev_iovar_setbuf(dev, "country", (char *)&cspec,
 577		sizeof(cspec), smbuf, sizeof(smbuf), NULL);
 578
 579	if (error) {
 580		DHD_ERROR(("%s: set country '%s/%d' failed code %d\n",
 581			__FUNCTION__, cspec.ccode, cspec.rev, error));
 582	} else {
 583		dhd_bus_country_set(dev, &cspec);
 584		DHD_INFO(("%s: set country '%s/%d'\n",
 585			__FUNCTION__, cspec.ccode, cspec.rev));
 586	}
 587
 588	return error;
 589}
 590
 591static int wl_android_get_country_rev(
 592	struct net_device *dev, char *command, int total_len)
 593{
 594	int error;
 595	int bytes_written;
 596	char smbuf[WLC_IOCTL_SMLEN];
 597	wl_country_t cspec;
 598
 599	error = wldev_iovar_getbuf(dev, "country", NULL, 0, smbuf,
 600		sizeof(smbuf), NULL);
 601
 602	if (error) {
 603		DHD_ERROR(("%s: get country failed code %d\n",
 604			__FUNCTION__, error));
 605		return -1;
 606	} else {
 607		memcpy(&cspec, smbuf, sizeof(cspec));
 608		DHD_INFO(("%s: get country '%c%c %d'\n",
 609			__FUNCTION__, cspec.ccode[0], cspec.ccode[1], cspec.rev));
 610	}
 611
 612	bytes_written = snprintf(command, total_len, "%s %c%c %d",
 613		CMD_COUNTRYREV_GET, cspec.ccode[0], cspec.ccode[1], cspec.rev);
 614
 615	return bytes_written;
 616}
 617#endif /* ROAM_API */
 618
 619#ifdef WES_SUPPORT
 620int wl_android_get_roam_scan_control(struct net_device *dev, char *command, int total_len)
 621{
 622	int error = 0;
 623	int bytes_written = 0;
 624	int mode = 0;
 625
 626	error = get_roamscan_mode(dev, &mode);
 627	if (error) {
 628		DHD_ERROR(("%s: Failed to get Scan Control, error = %d\n", __FUNCTION__, error));
 629		return -1;
 630	}
 631
 632	bytes_written = snprintf(command, total_len, "%s %d", CMD_GETROAMSCANCONTROL, mode);
 633
 634	return bytes_written;
 635}
 636
 637int wl_android_set_roam_scan_control(struct net_device *dev, char *command, int total_len)
 638{
 639	int error = 0;
 640	int mode = 0;
 641
 642	if (sscanf(command, "%*s %d", &mode) != 1) {
 643		DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
 644		return -1;
 645	}
 646
 647	error = set_roamscan_mode(dev, mode);
 648	if (error) {
 649		DHD_ERROR(("%s: Failed to set Scan Control %d, error = %d\n",
 650		 __FUNCTION__, mode, error));
 651		return -1;
 652	}
 653
 654	return 0;
 655}
 656
 657int wl_android_get_roam_scan_channels(struct net_device *dev, char *command, int total_len)
 658{
 659	int bytes_written = 0;
 660	unsigned char channels[ANDROID_WIFI_MAX_ROAM_SCAN_CHANNELS] = {0};
 661	int channel_cnt = 0;
 662	char channel_info[10 + (ANDROID_WIFI_MAX_ROAM_SCAN_CHANNELS * 3)] = {0};
 663	int channel_info_len = 0;
 664	int i = 0;
 665
 666	channel_cnt = get_roamscan_channel_list(dev, channels);
 667
 668	channel_info_len += sprintf(&channel_info[channel_info_len], "%d ", channel_cnt);
 669	for (i = 0; i < channel_cnt; i++) {
 670		channel_info_len += sprintf(&channel_info[channel_info_len], "%d ", channels[i]);
 671
 672		if (channel_info_len > (sizeof(channel_info) - 10))
 673			break;
 674	}
 675	channel_info_len += sprintf(&channel_info[channel_info_len], "%s", "\0");
 676
 677	bytes_written = snprintf(command, total_len, "%s %s",
 678		CMD_GETROAMSCANCHANNELS, channel_info);
 679	return bytes_written;
 680}
 681
 682int wl_android_set_roam_scan_channels(struct net_device *dev, char *command, int total_len)
 683{
 684	int error = 0;
 685	unsigned char *p = (unsigned char *)(command + strlen(CMD_SETROAMSCANCHANNELS) + 1);
 686	int ioctl_version = wl_cfg80211_get_ioctl_version();
 687	error = set_roamscan_channel_list(dev, p[0], &p[1], ioctl_version);
 688	if (error) {
 689		DHD_ERROR(("%s: Failed to set Scan Channels %d, error = %d\n",
 690		 __FUNCTION__, p[0], error));
 691		return -1;
 692	}
 693
 694	return 0;
 695}
 696
 697int wl_android_get_scan_channel_time(struct net_device *dev, char *command, int total_len)
 698{
 699	int error = 0;
 700	int bytes_written = 0;
 701	int time = 0;
 702
 703	error = wldev_ioctl(dev, WLC_GET_SCAN_CHANNEL_TIME, &time, sizeof(time), 0);
 704	if (error) {
 705		DHD_ERROR(("%s: Failed to get Scan Channel Time, error = %d\n",
 706		__FUNCTION__, error));
 707		return -1;
 708	}
 709
 710	bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANCHANNELTIME, time);
 711
 712	return bytes_written;
 713}
 714
 715int wl_android_set_scan_channel_time(struct net_device *dev, char *command, int total_len)
 716{
 717	int error = 0;
 718	int time = 0;
 719
 720	if (sscanf(command, "%*s %d", &time) != 1) {
 721		DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
 722		return -1;
 723	}
 724
 725	error = wldev_ioctl(dev, WLC_SET_SCAN_CHANNEL_TIME, &time, sizeof(time), 1);
 726	if (error) {
 727		DHD_ERROR(("%s: Failed to set Scan Channel Time %d, error = %d\n",
 728		__FUNCTION__, time, error));
 729		return -1;
 730	}
 731
 732	return 0;
 733}
 734
 735int wl_android_get_scan_home_time(struct net_device *dev, char *command, int total_len)
 736{
 737	int error = 0;
 738	int bytes_written = 0;
 739	int time = 0;
 740
 741	error = wldev_ioctl(dev, WLC_GET_SCAN_HOME_TIME, &time, sizeof(time), 0);
 742	if (error) {
 743		DHD_ERROR(("Failed to get Scan Home Time, error = %d\n", error));
 744		return -1;
 745	}
 746
 747	bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANHOMETIME, time);
 748
 749	return bytes_written;
 750}
 751
 752int wl_android_set_scan_home_time(struct net_device *dev, char *command, int total_len)
 753{
 754	int error = 0;
 755	int time = 0;
 756
 757	if (sscanf(command, "%*s %d", &time) != 1) {
 758		DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
 759		return -1;
 760	}
 761
 762	error = wldev_ioctl(dev, WLC_SET_SCAN_HOME_TIME, &time, sizeof(time), 1);
 763	if (error) {
 764		DHD_ERROR(("%s: Failed to set Scan Home Time %d, error = %d\n",
 765		__FUNCTION__, time, error));
 766		return -1;
 767	}
 768
 769	return 0;
 770}
 771
 772int wl_android_get_scan_home_away_time(struct net_device *dev, char *command, int total_len)
 773{
 774	int error = 0;
 775	int bytes_written = 0;
 776	int time = 0;
 777
 778	error = wldev_iovar_getint(dev, "scan_home_away_time", &time);
 779	if (error) {
 780		DHD_ERROR(("%s: Failed to get Scan Home Away Time, error = %d\n",
 781		__FUNCTION__, error));
 782		return -1;
 783	}
 784
 785	bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANHOMEAWAYTIME, time);
 786
 787	return bytes_written;
 788}
 789
 790int wl_android_set_scan_home_away_time(struct net_device *dev, char *command, int total_len)
 791{
 792	int error = 0;
 793	int time = 0;
 794
 795	if (sscanf(command, "%*s %d", &time) != 1) {
 796		DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
 797		return -1;
 798	}
 799
 800	error = wldev_iovar_setint(dev, "scan_home_away_time", time);
 801	if (error) {
 802		DHD_ERROR(("%s: Failed to set Scan Home Away Time %d, error = %d\n",
 803		 __FUNCTION__, time, error));
 804		return -1;
 805	}
 806
 807	return 0;
 808}
 809
 810int wl_android_get_scan_nprobes(struct net_device *dev, char *command, int total_len)
 811{
 812	int error = 0;
 813	int bytes_written = 0;
 814	int num = 0;
 815
 816	error = wldev_ioctl(dev, WLC_GET_SCAN_NPROBES, &num, sizeof(num), 0);
 817	if (error) {
 818		DHD_ERROR(("%s: Failed to get Scan NProbes, error = %d\n", __FUNCTION__, error));
 819		return -1;
 820	}
 821
 822	bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANNPROBES, num);
 823
 824	return bytes_written;
 825}
 826
 827int wl_android_set_scan_nprobes(struct net_device *dev, char *command, int total_len)
 828{
 829	int error = 0;
 830	int num = 0;
 831
 832	if (sscanf(command, "%*s %d", &num) != 1) {
 833		DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
 834		return -1;
 835	}
 836
 837	error = wldev_ioctl(dev, WLC_SET_SCAN_NPROBES, &num, sizeof(num), 1);
 838	if (error) {
 839		DHD_ERROR(("%s: Failed to set Scan NProbes %d, error = %d\n",
 840		__FUNCTION__, num, error));
 841		return -1;
 842	}
 843
 844	return 0;
 845}
 846
 847int wl_android_send_action_frame(struct net_device *dev, char *command, int total_len)
 848{
 849	int error = -1;
 850	android_wifi_af_params_t *params = NULL;
 851	wl_action_frame_t *action_frame = NULL;
 852	wl_af_params_t *af_params = NULL;
 853	char *smbuf = NULL;
 854	struct ether_addr tmp_bssid;
 855	int tmp_channel = 0;
 856
 857	params = (android_wifi_af_params_t *)(command + strlen(CMD_SENDACTIONFRAME) + 1);
 858	if (params == NULL) {
 859		DHD_ERROR(("%s: Invalid params \n", __FUNCTION__));
 860		goto send_action_frame_out;
 861	}
 862
 863	smbuf = kmalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL);
 864	if (smbuf == NULL) {
 865		DHD_ERROR(("%s: failed to allocated memory %d bytes\n",
 866		__FUNCTION__, WLC_IOCTL_MAXLEN));
 867		goto send_action_frame_out;
 868	}
 869
 870	af_params = (wl_af_params_t *) kzalloc(WL_WIFI_AF_PARAMS_SIZE, GFP_KERNEL);
 871	if (af_params == NULL)
 872	{
 873		DHD_ERROR(("%s: unable to allocate frame\n", __FUNCTION__));
 874		goto send_action_frame_out;
 875	}
 876
 877	memset(&tmp_bssid, 0, ETHER_ADDR_LEN);
 878	if (bcm_ether_atoe((const char *)params->bssid, (struct ether_addr *)&tmp_bssid) == 0) {
 879		memset(&tmp_bssid, 0, ETHER_ADDR_LEN);
 880
 881		error = wldev_ioctl(dev, WLC_GET_BSSID, &tmp_bssid, ETHER_ADDR_LEN, false);
 882		if (error) {
 883			memset(&tmp_bssid, 0, ETHER_ADDR_LEN);
 884			DHD_ERROR(("%s: failed to get bssid, error=%d\n", __FUNCTION__, error));
 885			goto send_action_frame_out;
 886		}
 887	}
 888
 889	if (params->channel < 0) {
 890		struct channel_info ci;
 891		error = wldev_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci), false);
 892		if (error) {
 893			DHD_ERROR(("%s: failed to get channel, error=%d\n", __FUNCTION__, error));
 894			goto send_action_frame_out;
 895		}
 896
 897		tmp_channel = ci.hw_channel;
 898	}
 899	else {
 900		tmp_channel = params->channel;
 901	}
 902
 903	af_params->channel = tmp_channel;
 904	af_params->dwell_time = params->dwell_time;
 905	memcpy(&af_params->BSSID, &tmp_bssid, ETHER_ADDR_LEN);
 906	action_frame = &af_params->action_frame;
 907
 908	action_frame->packetId = 0;
 909	memcpy(&action_frame->da, &tmp_bssid, ETHER_ADDR_LEN);
 910	action_frame->len = params->len;
 911	memcpy(action_frame->data, params->data, action_frame->len);
 912
 913	error = wldev_iovar_setbuf(dev, "actframe", af_params,
 914		sizeof(wl_af_params_t), smbuf, WLC_IOCTL_MAXLEN, NULL);
 915	if (error) {
 916		DHD_ERROR(("%s: failed to set action frame, error=%d\n", __FUNCTION__, error));
 917	}
 918
 919send_action_frame_out:
 920	if (af_params)
 921		kfree(af_params);
 922
 923	if (smbuf)
 924		kfree(smbuf);
 925
 926	if (error)
 927		return -1;
 928	else
 929		return 0;
 930}
 931
 932int wl_android_reassoc(struct net_device *dev, char *command, int total_len)
 933{
 934	int error = 0;
 935	android_wifi_reassoc_params_t *params = NULL;
 936	uint band;
 937	chanspec_t channel;
 938	u32 params_size;
 939	wl_reassoc_params_t reassoc_params;
 940
 941	params = (android_wifi_reassoc_params_t *)(command + strlen(CMD_REASSOC) + 1);
 942	if (params == NULL) {
 943		DHD_ERROR(("%s: Invalid params \n", __FUNCTION__));
 944		return -1;
 945	}
 946
 947	memset(&reassoc_params, 0, WL_REASSOC_PARAMS_FIXED_SIZE);
 948
 949	if (bcm_ether_atoe((const char *)params->bssid,
 950	(struct ether_addr *)&reassoc_params.bssid) == 0) {
 951		DHD_ERROR(("%s: Invalid bssid \n", __FUNCTION__));
 952		return -1;
 953	}
 954
 955	if (params->channel < 0) {
 956		DHD_ERROR(("%s: Invalid Channel \n", __FUNCTION__));
 957		return -1;
 958	}
 959
 960	reassoc_params.chanspec_num = 1;
 961
 962	channel = params->channel;
 963#ifdef D11AC_IOTYPES
 964	if (wl_cfg80211_get_ioctl_version() == 1) {
 965		band = ((channel <= CH_MAX_2G_CHANNEL) ?
 966		WL_LCHANSPEC_BAND_2G : WL_LCHANSPEC_BAND_5G);
 967		reassoc_params.chanspec_list[0] = channel |
 968		band | WL_LCHANSPEC_BW_20 | WL_LCHANSPEC_CTL_SB_NONE;
 969	}
 970	else {
 971		band = ((channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G);
 972		reassoc_params.chanspec_list[0] = channel | band | WL_CHANSPEC_BW_20;
 973	}
 974#else
 975	band = ((channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G);
 976	reassoc_params.chanspec_list[0] = channel |
 977	band | WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE;
 978#endif /* D11AC_IOTYPES */
 979	params_size = WL_REASSOC_PARAMS_FIXED_SIZE + sizeof(chanspec_t);
 980
 981	error = wldev_ioctl(dev, WLC_REASSOC, &reassoc_params, params_size, true);
 982	if (error) {
 983		DHD_ERROR(("%s: failed to reassoc, error=%d\n", __FUNCTION__, error));
 984	}
 985
 986	if (error)
 987		return -1;
 988	else
 989		return 0;
 990}
 991
 992int wl_android_get_wes_mode(struct net_device *dev, char *command, int total_len)
 993{
 994	int bytes_written = 0;
 995	int mode = 0;
 996
 997	mode = wl_cfg80211_get_wes_mode();
 998
 999	bytes_written = snprintf(command, total_len, "%s %d", CMD_GETWESMODE, mode);
1000
1001	return bytes_written;
1002}
1003
1004int wl_android_set_wes_mode(struct net_device *dev, char *command, int total_len)
1005{
1006	int error = 0;
1007	int mode = 0;
1008
1009	if (sscanf(command, "%*s %d", &mode) != 1) {
1010		DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
1011		return -1;
1012	}
1013
1014	error = wl_cfg80211_set_wes_mode(mode);
1015	if (error) {
1016		DHD_ERROR(("%s: Failed to set WES Mode %d, error = %d\n",
1017		__FUNCTION__, mode, error));
1018		return -1;
1019	}
1020
1021	return 0;
1022}
1023
1024int wl_android_get_okc_mode(struct net_device *dev, char *command, int total_len)
1025{
1026	int error = 0;
1027	int bytes_written = 0;
1028	int mode = 0;
1029
1030	error = wldev_iovar_getint(dev, "okc_enable", &mode);
1031	if (error) {
1032		DHD_ERROR(("%s: Failed to get OKC Mode, error = %d\n", __FUNCTION__, error));
1033		return -1;
1034	}
1035
1036	bytes_written = snprintf(command, total_len, "%s %d", CMD_GETOKCMODE, mode);
1037
1038	return bytes_written;
1039}
1040
1041int wl_android_set_okc_mode(struct net_device *dev, char *command, int total_len)
1042{
1043	int error = 0;
1044	int mode = 0;
1045
1046	if (sscanf(command, "%*s %d", &mode) != 1) {
1047		DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
1048		return -1;
1049	}
1050
1051	error = wldev_iovar_setint(dev, "okc_enable", mode);
1052	if (error) {
1053		DHD_ERROR(("%s: Failed to set OKC Mode %d, error = %d\n",
1054		__FUNCTION__, mode, error));
1055		return -1;
1056	}
1057
1058	if (mode)
1059		 wldev_iovar_setint(dev, "ccx_enable", 0);
1060
1061	return error;
1062}
1063#endif /* WES_SUPPORT */
1064#endif /* CUSTOMER_HW4 */
1065
1066#if defined(PNO_SUPPORT) && !defined(WL_SCHED_SCAN)
1067static int wl_android_set_pno_setup(struct net_device *dev, char *command, int total_len)
1068{
1069	wlc_ssid_t ssids_local[MAX_PFN_LIST_COUNT];
1070	int res = -1;
1071	int nssid = 0;
1072	cmd_tlv_t *cmd_tlv_temp;
1073	char *str_ptr;
1074	int tlv_size_left;
1075	int pno_time = 0;
1076	int pno_repeat = 0;
1077	int pno_freq_expo_max = 0;
1078
1079#ifdef PNO_SET_DEBUG
1080	int i;
1081	char pno_in_example[] = {
1082		'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ',
1083		'S', '1', '2', '0',
1084		'S',
1085		0x05,
1086		'd', 'l', 'i', 'n', 'k',
1087		'S',
1088		0x04,
1089		'G', 'O', 'O', 'G',
1090		'T',
1091		'0', 'B',
1092		'R',
1093		'2',
1094		'M',
1095		'2',
1096		0x00
1097		};
1098#endif /* PNO_SET_DEBUG */
1099
1100	DHD_INFO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
1101
1102	if (total_len < (strlen(CMD_PNOSETUP_SET) + sizeof(cmd_tlv_t))) {
1103		DHD_ERROR(("%s argument=%d less min size\n", __FUNCTION__, total_len));
1104		goto exit_proc;
1105	}
1106
1107
1108#ifdef PNO_SET_DEBUG
1109	memcpy(command, pno_in_example, sizeof(pno_in_example));
1110	for (i = 0; i < sizeof(pno_in_example); i++)
1111		printf("%02X ", command[i]);
1112	printf("\n");
1113	total_len = sizeof(pno_in_example);
1114#endif
1115
1116	str_ptr = command + strlen(CMD_PNOSETUP_SET);
1117	tlv_size_left = total_len - strlen(CMD_PNOSETUP_SET);
1118
1119	cmd_tlv_temp = (cmd_tlv_t *)str_ptr;
1120	memset(ssids_local, 0, sizeof(ssids_local));
1121
1122	if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) &&
1123		(cmd_tlv_temp->version == PNO_TLV_VERSION) &&
1124		(cmd_tlv_temp->subver == PNO_TLV_SUBVERSION)) {
1125
1126		str_ptr += sizeof(cmd_tlv_t);
1127		tlv_size_left -= sizeof(cmd_tlv_t);
1128
1129		if ((nssid = wl_iw_parse_ssid_list_tlv(&str_ptr, ssids_local,
1130			MAX_PFN_LIST_COUNT, &tlv_size_left)) <= 0) {
1131			DHD_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid));
1132			goto exit_proc;
1133		} else {
1134			if ((str_ptr[0] != PNO_TLV_TYPE_TIME) || (tlv_size_left <= 1)) {
1135				DHD_ERROR(("%s scan duration corrupted field size %d\n",
1136					__FUNCTION__, tlv_size_left));
1137				goto exit_proc;
1138			}
1139			str_ptr++;
1140			pno_time = simple_strtoul(str_ptr, &str_ptr, 16);
1141			DHD_INFO(("%s: pno_time=%d\n", __FUNCTION__, pno_time));
1142
1143			if (str_ptr[0] != 0) {
1144				if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) {
1145					DHD_ERROR(("%s pno repeat : corrupted field\n",
1146						__FUNCTION__));
1147					goto exit_proc;
1148				}
1149				str_ptr++;
1150				pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16);
1151				DHD_INFO(("%s :got pno_repeat=%d\n", __FUNCTION__, pno_repeat));
1152				if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) {
1153					DHD_ERROR(("%s FREQ_EXPO_MAX corrupted field size\n",
1154						__FUNCTION__));
1155					goto exit_proc;
1156				}
1157				str_ptr++;
1158				pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 16);
1159				DHD_INFO(("%s: pno_freq_expo_max=%d\n",
1160					__FUNCTION__, pno_freq_expo_max));
1161			}
1162		}
1163	} else {
1164		DHD_ERROR(("%s get wrong TLV command\n", __FUNCTION__));
1165		goto exit_proc;
1166	}
1167
1168	res = dhd_dev_pno_set(dev, ssids_local, nssid, pno_time, pno_repeat, pno_freq_expo_max);
1169
1170exit_proc:
1171	return res;
1172}
1173#endif /* PNO_SUPPORT && !WL_SCHED_SCAN */
1174
1175static int wl_android_get_p2p_dev_addr(struct net_device *ndev, char *command, int total_len)
1176{
1177	int ret;
1178	int bytes_written = 0;
1179
1180	ret = wl_cfg80211_get_p2p_dev_addr(ndev, (struct ether_addr*)command);
1181	if (ret)
1182		return 0;
1183	bytes_written = sizeof(struct ether_addr);
1184	return bytes_written;
1185}
1186
1187#ifdef BCMCCX
1188static int wl_android_get_cckm_rn(struct net_device *dev, char *command)
1189{
1190	int error, rn;
1191
1192	WL_TRACE(("%s:wl_android_get_cckm_rn\n", dev->name));
1193
1194	error = wldev_iovar_getint(dev, "cckm_rn", &rn);
1195	if (unlikely(error)) {
1196		WL_ERR(("wl_android_get_cckm_rn error (%d)\n", error));
1197		return -1;
1198	}
1199	memcpy(command, &rn, sizeof(int));
1200
1201	return sizeof(int);
1202}
1203
1204static int wl_android_set_cckm_krk(struct net_device *dev, char *command)
1205{
1206	int error;
1207	unsigned char key[16];
1208	static char iovar_buf[WLC_IOCTL_MEDLEN];
1209
1210	WL_TRACE(("%s: wl_iw_set_cckm_krk\n", dev->name));
1211
1212	memset(iovar_buf, 0, sizeof(iovar_buf));
1213	memcpy(key, command+strlen("set cckm_krk")+1, 16);
1214
1215	error = wldev_iovar_setbuf(dev, "cckm_krk", key, sizeof(key),
1216		iovar_buf, WLC_IOCTL_MEDLEN, NULL);
1217	if (unlikely(error))
1218	{
1219		WL_ERR((" cckm_krk set error (%d)\n", error));
1220		return -1;
1221	}
1222	return 0;
1223}
1224
1225static int wl_android_get_assoc_res_ies(struct net_device *dev, char *command)
1226{
1227	int error;
1228	u8 buf[WL_ASSOC_INFO_MAX];
1229	wl_assoc_info_t assoc_info;
1230	u32 resp_ies_len = 0;
1231	int bytes_written = 0;
1232
1233	WL_TRACE(("%s: wl_iw_get_assoc_res_ies\n", dev->name));
1234
1235	error = wldev_iovar_getbuf(dev, "assoc_info", NULL, 0, buf, WL_ASSOC_INFO_MAX, NULL);
1236	if (unlikely(error)) {
1237		WL_ERR(("could not get assoc info (%d)\n", error));
1238		return -1;
1239	}
1240
1241	memcpy(&assoc_info, buf, sizeof(wl_assoc_info_t));
1242	assoc_info.req_len = htod32(assoc_info.req_len);
1243	assoc_info.resp_len = htod32(assoc_info.resp_len);
1244	assoc_info.flags = htod32(assoc_info.flags);
1245
1246	if (assoc_info.resp_len) {
1247		resp_ies_len = assoc_info.resp_len - sizeof(struct dot11_assoc_resp);
1248	}
1249
1250	/* first 4 bytes are ie len */
1251	memcpy(command, &resp_ies_len, sizeof(u32));
1252	bytes_written = sizeof(u32);
1253
1254	/* get the association resp IE's if there are any */
1255	if (resp_ies_len) {
1256		error = wldev_iovar_getbuf(dev, "assoc_resp_ies", NULL, 0,
1257			buf, WL_ASSOC_INFO_MAX, NULL);
1258		if (unlikely(error)) {
1259			WL_ERR(("could not get assoc resp_ies (%d)\n", error));
1260			return -1;
1261		}
1262
1263		memcpy(command+sizeof(u32), buf, resp_ies_len);
1264		bytes_written += resp_ies_len;
1265	}
1266	return bytes_written;
1267}
1268
1269#endif /* BCMCCX */
1270
1271/**
1272 * Global function definitions (declared in wl_android.h)
1273 */
1274
1275int wl_android_wifi_on(struct net_device *dev)
1276{
1277	int ret = 0;
1278	int retry = POWERUP_MAX_RETRY;
1279
1280	printk("%s in\n", __FUNCTION__);
1281	if (!dev) {
1282		DHD_ERROR(("%s: dev is null\n", __FUNCTION__));
1283		return -EINVAL;
1284	}
1285
1286	dhd_net_if_lock(dev);
1287	if (!g_wifi_on) {
1288		do {
1289			dhd_customer_gpio_wlan_ctrl(WLAN_RESET_ON);
1290			ret = sdioh_start(NULL, 0);
1291			if (ret == 0)
1292				break;
1293			DHD_ERROR(("\nfailed to power up wifi chip, retry again (%d left) **\n\n",
1294				retry+1));
1295			dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF);
1296		} while (retry-- >= 0);
1297		if (ret != 0) {
1298			DHD_ERROR(("\nfailed to power up wifi chip, max retry reached **\n\n"));
1299			goto exit;
1300		}
1301		ret = dhd_dev_reset(dev, FALSE);
1302		sdioh_start(NULL, 1);
1303		if (!ret) {
1304			if (dhd_dev_init_ioctl(dev) < 0)
1305				ret = -EFAULT;
1306		}
1307#if defined(PROP_TXSTATUS) && !defined(PROP_TXSTATUS_VSDB)
1308		dhd_wlfc_init(bcmsdh_get_drvdata());
1309#endif
1310		g_wifi_on = TRUE;
1311	}
1312
1313exit:
1314	dhd_net_if_unlock(dev);
1315
1316	return ret;
1317}
1318
1319int wl_android_wifi_off(struct net_device *dev)
1320{
1321	int ret = 0;
1322
1323	printk("%s in\n", __FUNCTION__);
1324	if (!dev) {
1325		DHD_TRACE(("%s: dev is null\n", __FUNCTION__));
1326		return -EINVAL;
1327	}
1328
1329	dhd_net_if_lock(dev);
1330	if (g_wifi_on) {
1331#if defined(PROP_TXSTATUS) && !defined(PROP_TXSTATUS_VSDB)
1332		dhd_wlfc_deinit(bcmsdh_get_drvdata());
1333#endif
1334		ret = dhd_dev_reset(dev, TRUE);
1335		sdioh_stop(NULL);
1336		dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF);
1337		g_wifi_on = FALSE;
1338	}
1339	dhd_net_if_unlock(dev);
1340
1341	return ret;
1342}
1343
1344static int wl_android_set_fwpath(struct net_device *net, char *command, int total_len)
1345{
1346	if ((strlen(command) - strlen(CMD_SETFWPATH)) > MOD_PARAM_PATHLEN)
1347		return -1;
1348	bcm_strncpy_s(fw_path, sizeof(fw_path),
1349		command + strlen(CMD_SETFWPATH) + 1, MOD_PARAM_PATHLEN - 1);
1350	if (strstr(fw_path, "apsta") != NULL) {
1351		DHD_INFO(("GOT APSTA FIRMWARE\n"));
1352		ap_fw_loaded = TRUE;
1353	} else {
1354		DHD_INFO(("GOT STA FIRMWARE\n"));
1355		ap_fw_loaded = FALSE;
1356	}
1357	return 0;
1358}
1359
1360
1361static int
1362wl_android_set_pmk(struct net_device *dev, char *command, int total_len)
1363{
1364	uchar pmk[33];
1365	int error = 0;
1366	char smbuf[WLC_IOCTL_SMLEN];
1367#ifdef OKC_DEBUG
1368	int i = 0;
1369#endif
1370
1371	bzero(pmk, sizeof(pmk));
1372	memcpy((char *)pmk, command + strlen("SET_PMK "), 32);
1373	error = wldev_iovar_setbuf(dev, "okc_info_pmk", pmk, 32, smbuf, sizeof(smbuf), NULL);
1374	if (error) {
1375		DHD_ERROR(("Failed to set PMK for OKC, error = %d\n", error));
1376	}
1377#ifdef OKC_DEBUG
1378	DHD_ERROR(("PMK is "));
1379	for (i = 0; i < 32; i++)
1380		DHD_ERROR(("%02X ", pmk[i]));
1381
1382	DHD_ERROR(("\n"));
1383#endif
1384	return error;
1385}
1386
1387static int
1388wl_android_okc_enable(struct net_device *dev, char *command, int total_len)
1389{
1390	int error = 0;
1391	char okc_enable = 0;
1392
1393	okc_enable = command[strlen(CMD_OKC_ENABLE) + 1] - '0';
1394	error = wldev_iovar_setint(dev, "okc_enable", okc_enable);
1395	if (error) {
1396		DHD_ERROR(("Failed to %s OKC, error = %d\n",
1397			okc_enable ? "enable" : "disable", error));
1398	}
1399
1400	wldev_iovar_setint(dev, "ccx_enable", 0);
1401
1402	return error;
1403}
1404
1405
1406#ifdef CUSTOMER_HW4
1407#ifdef SUPPORT_AMPDU_MPDU_CMD
1408/* CMD_AMPDU_MPDU */
1409static int
1410wl_android_set_ampdu_mpdu(struct net_device *dev, const char* string_num)
1411{
1412	int err = 0;
1413	int ampdu_mpdu;
1414
1415	ampdu_mpdu = bcm_atoi(string_num);
1416
1417	if (ampdu_mpdu > 32) {
1418		DHD_ERROR(("%s : ampdu_mpdu MAX value is 32.\n", __FUNCTION__));
1419		return -1;
1420	}
1421
1422	DHD_ERROR(("%s : ampdu_mpdu = %d\n", __FUNCTION__, ampdu_mpdu));
1423	err = wldev_iovar_setint(dev, "ampdu_mpdu", ampdu_mpdu);
1424	if (err < 0) {
1425		DHD_ERROR(("%s : ampdu_mpdu set error. %d\n", __FUNCTION__, err));
1426		return -1;
1427	}
1428
1429	return 0;
1430}
1431#endif /* SUPPORT_AMPDU_MPDU_CMD */
1432
1433/* SoftAP feature */
1434#ifdef SUPPORT_AUTO_CHANNEL
1435static int
1436wl_android_set_auto_channel(struct net_device *dev, const char* string_num,
1437	char* command, int total_len)
1438{
1439	int channel;
1440	int chosen = 0;
1441	int retry = 0;
1442	int ret = 0;
1443
1444	/* Restrict channel to 1 - 7: 2GHz, 20MHz BW, No SB */
1445	u32 req_buf[8] = {7, 0x2B01, 0x2B02, 0x2B03, 0x2B04, 0x2B05, 0x2B06,
1446		0x2B07};
1447
1448	/* Auto channel select */
1449	wl_uint32_list_t request;
1450
1451	channel = bcm_atoi(string_num);
1452	DHD_INFO(("%s : HAPD_AUTO_CHANNEL = %d\n", __FUNCTION__, channel));
1453
1454	if (channel == 20)
1455		ret = wldev_ioctl(dev, WLC_START_CHANNEL_SEL, (void *)&req_buf,
1456			sizeof(req_buf), true);
1457	else { /* channel == 0 */
1458		request.count = htod32(0);
1459		ret = wldev_ioctl(dev, WLC_START_CHANNEL_SEL, (void *)&request,
1460			sizeof(request), true);
1461	}
1462
1463	if (ret < 0) {
1464		DHD_ERROR(("%s: can't start auto channel scan, err = %d\n",
1465			__FUNCTION__, ret));
1466		channel = 0;
1467		goto done;
1468	}
1469
1470	/* Wait for auto channel selection, max 2500 ms */
1471	bcm_mdelay(500);
1472
1473	retry = 10;
1474	while (retry--) {
1475		ret = wldev_ioctl(dev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen),
1476			false);
1477		if (ret < 0 || dtoh32(chosen) == 0) {
1478			DHD_INFO(("%s: %d tried, ret = %d, chosen = %d\n",
1479				__FUNCTION__, (10 - retry), ret, chosen));
1480			bcm_mdelay(200);
1481		}
1482		else {
1483			channel = (u16)chosen & 0x00FF;
1484			DHD_ERROR(("%s: selected channel = %d\n", __FUNCTION__, channel));
1485			break;
1486		}
1487	}
1488
1489	if (retry == 0) {
1490		DHD_ERROR(("%s: auto channel timed out, failed\n", __FUNCTION__));
1491		channel = 0;
1492	}
1493
1494done:
1495	snprintf(command, 4, "%d", channel);
1496	DHD_INFO(("%s: command result is %s\n", __FUNCTION__, command));
1497
1498	return 4;
1499}
1500#endif /* SUPPORT_AUTO_CHANNEL */
1501
1502#ifdef SUPPORT_HIDDEN_AP
1503static int
1504wl_android_set_max_num_sta(struct net_device *dev, const char* string_num)
1505{
1506	int max_assoc;
1507
1508	max_assoc = bcm_atoi(string_num);
1509	DHD_INFO(("%s : HAPD_MAX_NUM_STA = %d\n", __FUNCTION__, max_assoc));
1510	wldev_iovar_setint(dev, "maxassoc", max_assoc);
1511	return 1;
1512}
1513
1514static int
1515wl_android_set_ssid(struct net_device *dev, const char* hapd_ssid)
1516{
1517	wlc_ssid_t ssid;
1518	s32 ret;
1519
1520	ssid.SSID_len = strlen(hapd_ssid);
1521	if (ssid.SSID_len > DOT11_MAX_SSID_LEN) {
1522		ssid.SSID_len = DOT11_MAX_SSID_LEN;
1523		DHD_ERROR(("%s : Too long SSID Length %d\n", __FUNCTION__, strlen(hapd_ssid)));
1524	}
1525	bcm_strncpy_s(ssid.SSID, sizeof(ssid.SSID), hapd_ssid, ssid.SSID_len);
1526	DHD_INFO(("%s: HAPD_SSID = %s\n", __FUNCTION__, ssid.SSID));
1527	ret = wldev_ioctl(dev, WLC_SET_SSID, &ssid, sizeof(wlc_ssid_t), true);
1528	if (ret < 0) {
1529		DHD_ERROR(("%s : WLC_SET_SSID Error:%d\n", __FUNCTION__, ret));
1530	}
1531	return 1;
1532
1533}
1534
1535static int
1536wl_android_set_hide_ssid(struct net_device *dev, const char* string_num)
1537{
1538	int hide_ssid;
1539	int enable = 0;
1540
1541	hide_ssid = bcm_atoi(string_num);
1542	DHD_INFO(("%s: HAPD_HIDE_SSID = %d\n", __FUNCTION__, hide_ssid));
1543	if (hide_ssid)
1544		enable = 1;
1545	wldev_iovar_setint(dev, "closednet", enable);
1546	return 1;
1547}
1548#endif /* SUPPORT_HIDDEN_AP */
1549
1550#ifdef SUPPORT_SOFTAP_SINGL_DISASSOC
1551static int
1552wl_android_sta_diassoc(struct net_device *dev, const char* straddr)
1553{
1554	scb_val_t scbval;
1555	int error  = 0;
1556
1557	DHD_INFO(("%s: deauth STA %s\n", __FUNCTION__, straddr));
1558
1559	/* Unspecified reason */
1560	scbval.val = htod32(1);
1561	bcm_ether_atoe(straddr, &scbval.ea);
1562
1563	DHD_ERROR(("%s: deauth STA: "MACDBG " scb_val.val %d\n", __FUNCTION__,
1564		MAC2STRDBG(scbval.ea.octet), scbval.val));
1565
1566	error = wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scbval,
1567		sizeof(scb_val_t), true);
1568	if (error) {
1569		DHD_ERROR(("Fail to DEAUTH station, error = %d\n", error));
1570	}
1571
1572	return 1;
1573}
1574#endif /* SUPPORT_SOFTAP_SINGL_DISASSOC */
1575
1576#ifdef SUPPORT_SET_LPC
1577static int
1578wl_android_set_lpc(struct net_device *dev, const char* string_num)
1579{
1580	int lpc_enabled, ret;
1581	s32 val = 1;
1582
1583	lpc_enabled = bcm_atoi(string_num);
1584	DHD_INFO(("%s : HAPD_LPC_ENABLED = %d\n", __FUNCTION__, lpc_enabled));
1585
1586	ret = wldev_ioctl(dev, WLC_DOWN, &val, sizeof(s32), true);
1587	if (ret < 0)
1588		DHD_ERROR(("WLC_DOWN error %d\n", ret));
1589
1590	wldev_iovar_setint(dev, "lpc", lpc_enabled);
1591
1592	ret = wldev_ioctl(dev, WLC_UP, &val, sizeof(s32), true);
1593	if (ret < 0)
1594		DHD_ERROR(("WLC_UP error %d\n", ret));
1595
1596	return 1;
1597}
1598#endif /* SUPPORT_SET_LPC */
1599
1600static int
1601wl_android_ch_res_rl(struct net_device *dev, bool change)
1602{
1603	int error = 0;
1604	s32 srl = 7;
1605	s32 lrl = 4;
1606	printk("%s enter\n", __FUNCTION__);
1607	if (change) {
1608		srl = 4;
1609		lrl = 2;
1610	}
1611	error = wldev_ioctl(dev, WLC_SET_SRL, &srl, sizeof(s32), true);
1612	if (error) {
1613		DHD_ERROR(("Failed to set SRL, error = %d\n", error));
1614	}
1615	error = wldev_ioctl(dev, WLC_SET_LRL, &lrl, sizeof(s32), true);
1616	if (error) {
1617		DHD_ERROR(("Failed to set LRL, error = %d\n", error));
1618	}
1619	return error;
1620}
1621#endif /* CUSTOMER_HW4 */
1622
1623int wl_android_set_roam_mode(struct net_device *dev, char *command, int total_len)
1624{
1625	int error = 0;
1626	int mode = 0;
1627
1628	if (sscanf(command, "%*s %d", &mode) != 1) {
1629		DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
1630		return -1;
1631	}
1632
1633	error = wldev_iovar_setint(dev, "roam_off", mode);
1634	if (error) {
1635		DHD_ERROR(("%s: Failed to set roaming Mode %d, error = %d\n",
1636		__FUNCTION__, mode, error));
1637		return -1;
1638	}
1639	else
1640		DHD_ERROR(("%s: succeeded to set roaming Mode %d, error = %d\n",
1641		__FUNCTION__, mode, error));
1642	return 0;
1643}
1644
1645int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
1646{
1647#ifdef CUSTOMER_HW4
1648/* DO NOT CHANGE THIS: Samsung JBP branch requires 16KB buffer size */
1649#define PRIVATE_COMMAND_MAX_LEN	16384
1650#else
1651#define PRIVATE_COMMAND_MAX_LEN	8192
1652#endif /* CUSTOMER_HW4 */
1653	int ret = 0;
1654	char *command = NULL;
1655	int bytes_written = 0;
1656	android_wifi_priv_cmd priv_cmd;
1657
1658	net_os_wake_lock(net);
1659
1660	if (!ifr->ifr_data) {
1661		ret = -EINVAL;
1662		goto exit;
1663	}
1664	if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(android_wifi_priv_cmd))) {
1665		ret = -EFAULT;
1666		goto exit;
1667	}
1668	if (priv_cmd.total_len > PRIVATE_COMMAND_MAX_LEN)
1669	{
1670		DHD_ERROR(("%s: too long priavte command\n", __FUNCTION__));
1671		ret = -EINVAL;
1672		goto exit;
1673	}
1674	command = kmalloc((priv_cmd.total_len + 1), GFP_KERNEL);
1675	if (!command)
1676	{
1677		DHD_ERROR(("%s: failed to allocate memory\n", __FUNCTION__));
1678		ret = -ENOMEM;
1679		goto exit;
1680	}
1681	if (copy_from_user(command, priv_cmd.buf, priv_cmd.total_len)) {
1682		ret = -EFAULT;
1683		goto exit;
1684	}
1685	command[priv_cmd.total_len] = '\0';
1686
1687	DHD_INFO(("%s: Android private cmd \"%s\" on %s\n", __FUNCTION__, command, ifr->ifr_name));
1688
1689	if (strnicmp(command, CMD_START, strlen(CMD_START)) == 0) {
1690		DHD_INFO(("%s, Received regular START command\n", __FUNCTION__));
1691#ifdef SUPPORT_DEEP_SLEEP
1692		trigger_deep_sleep = 1;
1693#else
1694		bytes_written = wl_android_wifi_on(net);
1695#endif /* SUPPORT_DEEP_SLEEP */
1696	}
1697	else if (strnicmp(command, CMD_SETFWPATH, strlen(CMD_SETFWPATH)) == 0) {
1698		bytes_written = wl_android_set_fwpath(net, command, priv_cmd.total_len);
1699	}
1700
1701	if (!g_wifi_on) {
1702		DHD_ERROR(("%s: Ignore private cmd \"%s\" - iface %s is down\n",
1703			__FUNCTION__, command, ifr->ifr_name));
1704		ret = 0;
1705		goto exit;
1706	}
1707
1708	if (strnicmp(command, CMD_STOP, strlen(CMD_STOP)) == 0) {
1709#ifdef SUPPORT_DEEP_SLEEP
1710		trigger_deep_sleep = 1;
1711#else
1712		bytes_written = wl_android_wifi_off(net);
1713#endif /* SUPPORT_DEEP_SLEEP */
1714	}
1715	else if (strnicmp(command, CMD_SCAN_ACTIVE, strlen(CMD_SCAN_ACTIVE)) == 0) {
1716		/* TBD: SCAN-ACTIVE */
1717	}
1718	else if (strnicmp(command, CMD_SCAN_PASSIVE, strlen(CMD_SCAN_PASSIVE)) == 0) {
1719		/* TBD: SCAN-PASSIVE */
1720	}
1721	else if (strnicmp(command, CMD_RSSI, strlen(CMD_RSSI)) == 0) {
1722		bytes_written = wl_android_get_rssi(net, command, priv_cmd.total_len);
1723	}
1724	else if (strnicmp(command, CMD_LINKSPEED, strlen(CMD_LINKSPEED)) == 0) {
1725		bytes_written = wl_android_get_link_speed(net, command, priv_cmd.total_len);
1726	}
1727#ifdef PKT_FILTER_SUPPORT
1728	else if (strnicmp(command, CMD_RXFILTER_START, strlen(CMD_RXFILTER_START)) == 0) {
1729		bytes_written = net_os_enable_packet_filter(net, 1);
1730	}
1731	else if (strnicmp(command, CMD_RXFILTER_STOP, strlen(CMD_RXFILTER_STOP)) == 0) {
1732		bytes_written = net_os_enable_packet_filter(net, 0);
1733	}
1734	else if (strnicmp(command, CMD_RXFILTER_ADD, strlen(CMD_RXFILTER_ADD)) == 0) {
1735		int filter_num = *(command + strlen(CMD_RXFILTER_ADD) + 1) - '0';
1736		bytes_written = net_os_rxfilter_add_remove(net, TRUE, filter_num);
1737	}
1738	else if (strnicmp(command, CMD_RXFILTER_REMOVE, strlen(CMD_RXFILTER_REMOVE)) == 0) {
1739		int filter_num = *(command + strlen(CMD_RXFILTER_REMOVE) + 1) - '0';
1740		bytes_written = net_os_rxfilter_add_remove(net, FALSE, filter_num);
1741	}
1742#endif /* PKT_FILTER_SUPPORT */
1743	else if (strnicmp(command, CMD_BTCOEXSCAN_START, strlen(CMD_BTCOEXSCAN_START)) == 0) {
1744		/* TBD: BTCOEXSCAN-START */
1745	}
1746	else if (strnicmp(command, CMD_BTCOEXSCAN_STOP, strlen(CMD_BTCOEXSCAN_STOP)) == 0) {
1747		/* TBD: BTCOEXSCAN-STOP */
1748	}
1749	else if (strnicmp(command, CMD_BTCOEXMODE, strlen(CMD_BTCOEXMODE)) == 0) {
1750#ifdef WL_CFG80211
1751		bytes_written = wl_cfg80211_set_btcoex_dhcp(net, command);
1752#else
1753#ifdef PKT_FILTER_SUPPORT
1754		uint mode = *(command + strlen(CMD_BTCOEXMODE) + 1) - '0';
1755
1756		if (mode == 1)
1757			net_os_enable_packet_filter(net, 0); /* DHCP starts */
1758		else
1759			net_os_enable_packet_filter(net, 1); /* DHCP ends */
1760#endif /* PKT_FILTER_SUPPORT */
1761#endif /* WL_CFG80211 */
1762	}
1763	else if (strnicmp(command, CMD_SETSUSPENDOPT, strlen(CMD_SETSUSPENDOPT)) == 0) {
1764		bytes_written = wl_android_set_suspendopt(net, command, priv_cmd.total_len);
1765	}
1766	else if (strnicmp(command, CMD_SETSUSPENDMODE, strlen(CMD_SETSUSPENDMODE)) == 0) {
1767		bytes_written = wl_android_set_suspendmode(net, command, priv_cmd.total_len);
1768	}
1769	else if (strnicmp(command, CMD_SETBAND, strlen(CMD_SETBAND)) == 0) {
1770		uint band = *(command + strlen(CMD_SETBAND) + 1) - '0';
1771#ifdef WL_HOST_BAND_MGMT
1772		s32 ret = 0;
1773		if ((ret = wl_cfg80211_set_band(net, band)) < 0) {
1774			if (ret == BCME_UNSUPPORTED) {
1775				/* If roam_var is unsupported, fallback to the original method */
1776				WL_ERR(("WL_HOST_BAND_MGMT defined, "
1777					"but roam_band iovar unsupported in the firmware\n"));
1778			} else {
1779				bytes_written = -1;
1780				goto exit;
1781			}
1782		}
1783		if ((band == WLC_BAND_AUTO) || (ret == BCME_UNSUPPORTED))
1784			bytes_written = wldev_set_band(net, band);
1785#else
1786		bytes_written = wldev_set_band(net, band);
1787#endif /* WL_HOST_BAND_MGMT */
1788	}
1789	else if (strnicmp(command, CMD_GETBAND, strlen(CMD_GETBAND)) == 0) {
1790		bytes_written = wl_android_get_band(net, command, priv_cmd.total_len);
1791	}
1792#ifdef WL_CFG80211
1793#ifndef CUSTOMER_SET_COUNTRY
1794	/* CUSTOMER_SET_COUNTRY feature is define for only GGSM model */
1795	else if (strnicmp(command, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) {
1796		char *country_code = command + strlen(CMD_COUNTRY) + 1;
1797		bytes_written = wldev_set_country(net, country_code);
1798	}
1799#endif /* CUSTOMER_SET_COUNTRY */
1800#endif /* WL_CFG80211 */
1801
1802#ifdef CUSTOMER_HW4
1803#ifdef ROAM_API
1804	else if (strnicmp(command, CMD_ROAMTRIGGER_SET,
1805		strlen(CMD_ROAMTRIGGER_SET)) == 0) {
1806		bytes_written = wl_android_set_roam_trigger(net, command,
1807		priv_cmd.total_len);
1808	} else if (strnicmp(command, CMD_ROAMTRIGGER_GET,
1809		strlen(CMD_ROAMTRIGGER_GET)) == 0) {
1810		bytes_written = wl_android_get_roam_trigger(net, command,
1811		priv_cmd.total_len);
1812	} else if (strnicmp(command, CMD_ROAMDELTA_SET,
1813		strlen(CMD_ROAMDELTA_SET)) == 0) {
1814		bytes_written = wl_android_set_roam_delta(net, command,
1815		priv_cmd.total_len);
1816	} else if (strnicmp(command, CMD_ROAMDELTA_GET,
1817		strlen(CMD_ROAMDELTA_GET)) == 0) {
1818		bytes_written = wl_android_get_roam_delta(net, command,
1819		priv_cmd.total_len);
1820	} else if (strnicmp(command, CMD_ROAMSCANPERIOD_SET,
1821		strlen(CMD_ROAMSCANPERIOD_SET)) == 0) {
1822		bytes_written = wl_android_set_roam_scan_period(net, command,
1823		priv_cmd.total_len);
1824	} else if (strnicmp(command, CMD_ROAMSCANPERIOD_GET,
1825		strlen(CMD_ROAMSCANPERIOD_GET)) == 0) {
1826		bytes_written = wl_android_get_roam_scan_period(net, command,
1827		priv_cmd.total_len);
1828	} else if (strnicmp(command, CMD_FULLROAMSCANPERIOD_SET,
1829		strlen(CMD_FULLROAMSCANPERIOD_SET)) == 0) {
1830		bytes_written = wl_android_set_full_roam_scan_period(net, command,
1831		priv_cmd.total_len);
1832	} else if (strnicmp(command, CMD_FULLROAMSCANPERIOD_GET,
1833		strlen(CMD_FULLROAMSCANPERIOD_GET)) == 0) {
1834		bytes_written = wl_android_get_full_roam_scan_period(net, command,
1835		priv_cmd.total_len);
1836	} else if (strnicmp(command, CMD_COUNTRYREV_SET,
1837		strlen(CMD_COUNTRYREV_SET)) == 0) {
1838		bytes_written = wl_android_set_country_rev(net, command,
1839		priv_cmd.total_len);
1840	} else if (strnicmp(command, CMD_COUNTRYREV_GET,
1841		strlen(CMD_COUNTRYREV_GET)) == 0) {
1842		bytes_written = wl_android_get_country_rev(net, command,
1843		priv_cmd.total_len);
1844	}
1845#endif /* ROAM_API */
1846#ifdef WES_SUPPORT
1847	else if (strnicmp(command, CMD_GETROAMSCANCONTROL, strlen(CMD_GETROAMSCANCONTROL)) == 0) {
1848		bytes_written = wl_android_get_roam_scan_control(net, command, priv_cmd.total_len);
1849	}
1850	else if (strnicmp(command, CMD_SETROAMSCANCONTROL, strlen(CMD_SETROAMSCANCONTROL)) == 0) {
1851		bytes_written = wl_android_set_roam_scan_control(net, command, priv_cmd.total_len);
1852	}
1853	else if (strnicmp(command, CMD_GETROAMSCANCHANNELS, strlen(CMD_GETROAMSCANCHANNELS)) == 0) {
1854		bytes_written = wl_android_get_roam_scan_channels(net, command, priv_cmd.total_len);
1855	}
1856	else if (strnicmp(command, CMD_SETROAMSCANCHANNELS, strlen(CMD_SETROAMSCANCHANNELS)) == 0) {
1857		bytes_written = wl_android_set_roam_scan_channels(net, command, priv_cmd.total_len);
1858	}
1859	else if (strnicmp(command, CMD_SENDACTIONFRAME, strlen(CMD_SENDACTIONFRAME)) == 0) {
1860		bytes_written = wl_android_send_action_frame(net, command, priv_cmd.total_len);
1861	}
1862	else if (strnicmp(command, CMD_REASSOC, strlen(CMD_REASSOC)) == 0) {
1863		bytes_written = wl_android_reassoc(net, command, priv_cmd.total_len);
1864	}
1865	else if (strnicmp(command, CMD_GETSCANCHANNELTIME, strlen(CMD_GETSCANCHANNELTIME)) == 0) {
1866		bytes_written = wl_android_get_scan_channel_time(net, command, priv_cmd.total_len);
1867	}
1868	else if (strnicmp(command, CMD_SETSCANCHANNELTIME, strlen(CMD_SETSCANCHANNELTIME)) == 0) {
1869		bytes_written = wl_android_set_scan_channel_time(net, command, priv_cmd.total_len);
1870	}
1871	else if (strnicmp(command, CMD_GETSCANHOMETIME, strlen(CMD_GETSCANHOMETIME)) == 0) {
1872		bytes_written = wl_android_get_scan_home_time(net, command, priv_cmd.total_len);
1873	}
1874	else if (strnicmp(command, CMD_SETSCANHOMETIME, strlen(CMD_SETSCANHOMETIME)) == 0) {
1875		bytes_written = wl_android_set_scan_home_time(net, command, priv_cmd.total_len);
1876	}
1877	else if (strnicmp(command, CMD_GETSCANHOMEAWAYTIME, strlen(CMD_GETSCANHOMEAWAYTIME)) == 0) {
1878		bytes_written = wl_android_get_scan_home_away_time(net, command,
1879			priv_cmd.total_len);
1880	}
1881	else if (strnicmp(command, CMD_SETSCANHOMEAWAYTIME, strlen(CMD_SETSCANHOMEAWAYTIME)) == 0) {
1882		bytes_written = wl_android_set_scan_home_away_time(net, command,
1883			priv_cmd.total_len);
1884	}
1885	else if (strnicmp(command, CMD_GETSCANNPROBES, strlen(CMD_GETSCANNPROBES)) == 0) {
1886		bytes_written = wl_android_get_scan_nprobes(net, command, priv_cmd.total_len);
1887	}
1888	else if (strnicmp(command, CMD_SETSCANNPROBES, strlen(CMD_SETSCANNPROBES)) == 0) {
1889		bytes_written = wl_android_set_scan_nprobes(net, command, priv_cmd.total_len);
1890	}
1891	else if (strnicmp(command, CMD_GETWESMODE, strlen(CMD_GETWESMODE)) == 0) {
1892		bytes_written = wl_android_get_wes_mode(net, command, priv_cmd.total_len);
1893	}
1894	else if (strnicmp(command, CMD_SETWESMODE, strlen(CMD_SETWESMODE)) == 0) {
1895		bytes_written = wl_android_set_wes_mode(net, command, priv_cmd.total_len);
1896	}
1897	else if (strnicmp(command, CMD_GETOKCMODE, strlen(CMD_GETOKCMODE)) == 0) {
1898		bytes_written = wl_android_get_okc_mode(net, command, priv_cmd.total_len);
1899	}
1900	else if (strnicmp(command, CMD_SETOKCMODE, strlen(CMD_SETOKCMODE)) == 0) {
1901		bytes_written = wl_android_set_okc_mode(net, command, priv_cmd.total_len);
1902	}
1903#endif /* WES_SUPPORT */
1904#endif /* CUSTOMER_HW4 */
1905
1906#if defined(PNO_SUPPORT) && !defined(WL_SCHED_SCAN)
1907	else if (strnicmp(command, CMD_PNOSSIDCLR_SET, strlen(CMD_PNOSSIDCLR_SET)) == 0) {
1908		bytes_written = dhd_dev_pno_reset(net);
1909	}
1910	else if (strnicmp(command, CMD_PNOSETUP_SET, strlen(CMD_PNOSETUP_SET)) == 0) {
1911		bytes_written = wl_android_set_pno_setup(net, command, priv_cmd.total_len);
1912	}
1913	else if (strnicmp(command, CMD_PNOENABLE_SET, strlen(CMD_PNOENABLE_SET)) == 0) {
1914		uint pfn_enabled = *(command + strlen(CMD_PNOENABLE_SET) + 1) - '0';
1915		bytes_written = dhd_dev_pno_enable(net, pfn_enabled);
1916	}
1917#endif /* PNO_SUPPORT && !WL_SCHED_SCAN */
1918	else if (strnicmp(command, CMD_P2P_DEV_ADDR, strlen(CMD_P2P_DEV_ADDR)) == 0) {
1919		bytes_written = wl_android_get_p2p_dev_addr(net, command, priv_cmd.total_len);
1920	}
1921	else if (strnicmp(command, CMD_P2P_SET_NOA, strlen(CMD_P2P_SET_NOA)) == 0) {
1922		int skip = strlen(CMD_P2P_SET_NOA) + 1;
1923		bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip,
1924			priv_cmd.total_len - skip);
1925	}
1926#if !defined WL_ENABLE_P2P_IF
1927	else if (strnicmp(command, CMD_P2P_GET_NOA, strlen(CMD_P2P_GET_NOA)) == 0) {
1928		bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len);
1929	}
1930#endif /* WL_ENABLE_P2P_IF */
1931	else if (strnicmp(command, CMD_P2P_SET_PS, strlen(CMD_P2P_SET_PS)) == 0) {
1932		int skip = strlen(CMD_P2P_SET_PS) + 1;
1933		bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip,
1934			priv_cmd.total_len - skip);
1935	}
1936#ifdef WL_CFG80211
1937	else if (strnicmp(command, CMD_SET_AP_WPS_P2P_IE,
1938		strlen(CMD_SET_AP_WPS_P2P_IE)) == 0) {
1939		int skip = strlen(CMD_SET_AP_WPS_P2P_IE) + 3;
1940		bytes_written = wl_cfg80211_set_wps_p2p_ie(net, command + skip,
1941			priv_cmd.total_len - skip, *(command + skip - 2) - '0');
1942	}
1943#endif /* WL_CFG80211 */
1944	else if (strnicmp(command, CMD_OKC_SET_PMK, strlen(CMD_OKC_SET_PMK)) == 0)
1945		bytes_written = wl_android_set_pmk(net, command, priv_cmd.total_len);
1946	else if (strnicmp(command, CMD_OKC_ENABLE, strlen(CMD_OKC_ENABLE)) == 0)
1947		bytes_written = wl_android_okc_enable(net, command, priv_cmd.total_len);
1948#ifdef BCMCCX
1949	else if (strnicmp(command, CMD_GETCCKM_RN, strlen(CMD_GETCCKM_RN)) == 0) {
1950		bytes_written = wl_android_get_cckm_rn(net, command);
1951	}
1952	else if (strnicmp(command, CMD_SETCCKM_KRK, strlen(CMD_SETCCKM_KRK)) == 0) {
1953		bytes_written = wl_android_set_cckm_krk(net, command);
1954	}
1955	else if (strnicmp(command, CMD_GET_ASSOC_RES_IES, strlen(CMD_GET_ASSOC_RES_IES)) == 0) {
1956		bytes_written = wl_android_get_assoc_res_ies(net, command);
1957	}
1958#endif /* BCMCCX */
1959#ifdef CUSTOMER_HW4
1960#ifdef SUPPORT_AMPDU_MPDU_CMD
1961	/* CMD_AMPDU_MPDU */
1962	else if (strnicmp(command, CMD_AMPDU_MPDU, strlen(CMD_AMPDU_MPDU)) == 0) {
1963		int skip = strlen(CMD_AMPDU_MPDU) + 1;
1964		bytes_written = wl_android_set_ampdu_mpdu(net, (const char*)command+skip);
1965	}
1966#endif /* SUPPORT_AMPDU_MPDU_CMD */
1967#ifdef SUPPORT_AUTO_CHANNEL
1968	else if (strnicmp(command, CMD_SET_HAPD_AUTO_CHANNEL,
1969		strlen(CMD_SET_HAPD_AUTO_CHANNEL)) == 0) {
1970		int skip = strlen(CMD_SET_HAPD_AUTO_CHANNEL) + 3;
1971		bytes_written = wl_android_set_auto_channel(net, (const char*)command+skip, command,
1972			priv_cmd.total_len);
1973	}
1974#endif /* SUPPORT_AUTO_CHANNEL */
1975#ifdef SUPPORT_HIDDEN_AP
1976	else if (strnicmp(command, CMD_SET_HAPD_MAX_NUM_STA,
1977		strlen(CMD_SET_HAPD_MAX_NUM_STA)) == 0) {
1978		int skip = strlen(CMD_SET_HAPD_MAX_NUM_STA) + 3;
1979		wl_android_set_max_num_sta(net, (const char*)command+skip);
1980	}
1981	else if (strnicmp(command, CMD_SET_HAPD_SSID,
1982		strlen(CMD_SET_HAPD_SSID)) == 0) {
1983		int skip = strlen(CMD_SET_HAPD_SSID) + 3;
1984		wl_android_set_ssid(net, (const char*)command+skip);
1985	}
1986	else if (strnicmp(command, CMD_SET_HAPD_HIDE_SSID,
1987		strlen(CMD_SET_HAPD_HIDE_SSID)) == 0) {
1988		int skip = strlen(CMD_SET_HAPD_HIDE_SSID) + 3;
1989		wl_android_set_hide_ssid(net, (const char*)command+skip);
1990	}
1991#endif /* SUPPORT_HIDDEN_AP */
1992#ifdef SUPPORT_SOFTAP_SINGL_DISASSOC
1993	else if (strnicmp(command, CMD_HAPD_STA_DISASSOC,
1994		strlen(CMD_HAPD_STA_DISASSOC)) == 0) {
1995		int skip = strlen(CMD_HAPD_STA_DISASSOC) + 1;
1996		wl_android_sta_diassoc(net, (const char*)command+skip);
1997	}
1998#endif /* SUPPORT_SOFTAP_SINGL_DISASSOC */
1999#ifdef SUPPORT_SET_LPC
2000	else if (strnicmp(command, CMD_HAPD_LPC_ENABLED,
2001		strlen(CMD_HAPD_LPC_ENABLED)) == 0) {
2002		int skip = strlen(CMD_HAPD_LPC_ENABLED) + 3;
2003		wl_android_set_lpc(net, (const char*)command+skip);
2004	}
2005#endif /* SUPPORT_SET_LPC */
2006#ifdef SUPPORT_TRIGGER_HANG_EVENT
2007	else if (strnicmp(command, CMD_TEST_FORCE_HANG,
2008		strlen(CMD_TEST_FORCE_HANG)) == 0) {
2009		net_os_send_hang_message(net);
2010	}
2011#endif /* SUPPORT_TRIGGER_HANG_EVENT */
2012	else if (strnicmp(command, CMD_CHANGE_RL, strlen(CMD_CHANGE_RL)) == 0)
2013		bytes_written = wl_android_ch_res_rl(net, true);
2014	else if (strnicmp(command, CMD_RESTORE_RL, strlen(CMD_RESTORE_RL)) == 0)
2015		bytes_written = wl_android_ch_res_rl(net, false);
2016#endif /* CUSTOMER_HW4 */
2017	else if (strnicmp(command, CMD_SETROAMMODE, strlen(CMD_SETROAMMODE)) == 0)
2018		bytes_written = wl_android_set_roam_mode(net, command, priv_cmd.total_len);
2019	else {
2020		DHD_ERROR(("Unknown PRIVATE command %s - ignored\n", command));
2021		snprintf(command, 3, "OK");
2022		bytes_written = strlen("OK");
2023	}
2024
2025	if (bytes_written >= 0) {
2026		if ((bytes_written == 0) && (priv_cmd.total_len > 0))
2027			command[0] = '\0';
2028		if (bytes_written >= priv_cmd.total_len) {
2029			DHD_ERROR(("%s: bytes_written = %d\n", __FUNCTION__, bytes_written));
2030			bytes_written = priv_cmd.total_len;
2031		} else {
2032			bytes_written++;
2033		}
2034		priv_cmd.used_len = bytes_written;
2035		if (copy_to_user(priv_cmd.buf, command, bytes_written)) {
2036			DHD_ERROR(("%s: failed to copy data to user buffer\n", __FUNCTION__));
2037			ret = -EFAULT;
2038		}
2039	}
2040	else {
2041		ret = bytes_written;
2042	}
2043
2044exit:
2045	net_os_wake_unlock(net);
2046	if (command) {
2047		kfree(command);
2048	}
2049
2050	return ret;
2051}
2052
2053int wl_android_init(void)
2054{
2055	int ret = 0;
2056
2057#ifdef ENABLE_INSMOD_NO_FW_LOAD
2058	dhd_download_fw_on_driverload = FALSE;
2059#endif /* ENABLE_INSMOD_NO_FW_LOAD */
2060#if defined(CUSTOMER_HW2) || defined(CUSTOMER_HW4)
2061	if (!iface_name[0]) {
2062		memset(iface_name, 0, IFNAMSIZ);
2063		bcm_strncpy_s(iface_name, IFNAMSIZ, "wlan", IFNAMSIZ);
2064	}
2065#endif /* CUSTOMER_HW2 || CUSTOMER_HW4 */
2066
2067#ifdef WL_GENL
2068	wl_genl_init();
2069#endif
2070
2071	return ret;
2072}
2073
2074int wl_android_exit(void)
2075{
2076	int ret = 0;
2077
2078#ifdef WL_GENL
2079	wl_genl_deinit();
2080#endif /* WL_GENL */
2081
2082	return ret;
2083}
2084
2085void wl_android_post_init(void)
2086{
2087#ifdef ENABLE_4335BT_WAR
2088	bcm_bt_unlock(lock_cookie_wifi);
2089	printk("%s: btlock released\n", __FUNCTION__);
2090#endif /* ENABLE_4335BT_WAR */
2091
2092	if (!dhd_download_fw_on_driverload) {
2093		/* Call customer gpio to turn off power with WL_REG_ON signal */
2094		dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF);
2095		g_wifi_on = 0;
2096	}
2097}
2098
2099#ifdef WL_GENL
2100/* Generic Netlink Initializaiton */
2101static int wl_genl_init(void)
2102{
2103	int ret;
2104
2105	WL_DBG(("GEN Netlink Init\n\n"));
2106
2107	/* register new family */
2108	ret = genl_register_family(&wl_genl_family);
2109	if (ret != 0)
2110		goto failure;
2111
2112	/* register functions (commands) of the new family */
2113	ret = genl_register_ops(&wl_genl_family, &wl_genl_ops);
2114	if (ret != 0) {
2115		WL_ERR(("register ops failed: %i\n", ret));
2116		genl_unregister_family(&wl_genl_family);
2117		goto failure;
2118	}
2119
2120	ret = genl_register_mc_group(&wl_genl_family, &wl_genl_mcast);
2121	if (ret != 0) {
2122		WL_ERR(("register mc_group failed: %i\n", ret));
2123		genl_unregister_ops(&wl_genl_family, &wl_genl_ops);
2124		genl_unregister_family(&wl_genl_family);
2125		goto failure;
2126	}
2127
2128	return 0;
2129
2130failure:
2131	WL_ERR(("Registering Netlink failed!!\n"));
2132	return -1;
2133}
2134
2135/* Generic netlink deinit */
2136static int wl_genl_deinit(void)
2137{
2138	if (genl_unregister_ops(&wl_genl_family, &wl_genl_ops) < 0)
2139		WL_ERR(("Unregister wl_genl_ops failed\n"));
2140
2141	if (genl_unregister_family(&wl_genl_family) < 0)
2142		WL_ERR(("Unregister wl_genl_ops failed\n"));
2143
2144	return 0;
2145}
2146
2147s32 wl_event_to_bcm_event(u16 event_type)
2148{
2149	u16 event = -1;
2150
2151	switch (event_type) {
2152		case WLC_E_SERVICE_FOUND:
2153			event = BCM_E_SVC_FOUND;
2154			break;
2155		case WLC_E_P2PO_ADD_DEVICE:
2156			event = BCM_E_DEV_FOUND;
2157			break;
2158		case WLC_E_P2PO_DEL_DEVICE:
2159			event = BCM_E_DEV_LOST;
2160			break;
2161	/* Above events are supported from BCM Supp ver 47 Onwards */
2162
2163		default:
2164			WL_ERR(("Event not supported\n"));
2165	}
2166
2167	return event;
2168}
2169
2170s32
2171wl_genl_send_msg(
2172	struct net_device *ndev,
2173	u32 event_type,
2174	u8 *buf,
2175	u16 len,
2176	u8 *subhdr,
2177	u16 subhdr_len)
2178{
2179	int ret = 0;
2180	struct sk_buff *skb;
2181	void *msg;
2182	u32 attr_type = 0;
2183	bcm_event_hdr_t *hdr = NULL;
2184	int mcast = 1; /* By default sent as mutlicast type */
2185	int pid = 0;
2186	u8 *ptr = NULL, *p = NULL;
2187	u32 tot_len = sizeof(bcm_event_hdr_t) + subhdr_len + len;
2188	u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
2189
2190
2191	WL_DBG(("Enter \n"));
2192
2193	/* Decide between STRING event and Data event */
2194	if (event_type == 0)
2195		attr_type = BCM_GENL_ATTR_STRING;
2196	else
2197		attr_type = BCM_GENL_ATTR_MSG;
2198
2199	skb = genlmsg_new(NLMSG_GOODSIZE, kflags);
2200	if (skb == NULL) {
2201		ret = -ENOMEM;
2202		goto out;
2203	}
2204
2205	msg = genlmsg_put(skb, 0, 0, &wl_genl_family, 0, BCM_GENL_CMD_MSG);
2206	if (msg == NULL) {
2207		ret = -ENOMEM;
2208		goto out;
2209	}
2210
2211
2212	if (attr_type == BCM_GENL_ATTR_STRING) {
2213		/* Add a BCM_GENL_MSG attribute. Since it is specified as a string.
2214		 * make sure it is null terminated
2215		 */
2216		if (subhdr || subhdr_len) {
2217			WL_ERR(("No sub hdr support for the ATTR STRING type \n"));
2218			ret =  -EINVAL;
2219			goto out;
2220		}
2221
2222		ret = nla_put_string(skb, BCM_GENL_ATTR_STRING, buf);
2223		if (ret != 0) {
2224			WL_ERR(("nla_put_string failed\n"));
2225			goto out;
2226		}
2227	} else {
2228		/* ATTR_MSG */
2229
2230		/* Create a single buffer for all */
2231		p = ptr = kzalloc(tot_len, kflags);
2232		if (!ptr) {
2233			ret = -ENOMEM;
2234			WL_ERR(("ENOMEM!!\n"));
2235			goto out;
2236		}
2237
2238		/* Include the bcm event header */
2239		hdr = (bcm_event_hdr_t *)ptr;
2240		hdr->event_type = wl_event_to_bcm_event(event_type);
2241		hdr->len = len + subhdr_len;
2242		ptr += sizeof(bcm_event_hdr_t);
2243
2244		/* Copy subhdr (if any) */
2245		if (subhdr && subhdr_len) {
2246			memcpy(ptr, subhdr, subhdr_len);
2247			ptr += subhdr_len;
2248		}
2249
2250		/* Copy the data */
2251		if (buf && len) {
2252			memcpy(ptr, buf, len);
2253		}
2254
2255		ret = nla_put(skb, BCM_GENL_ATTR_MSG, tot_len, p);
2256		if (ret != 0) {
2257			WL_ERR(("nla_put_string failed\n"));
2258			goto out;
2259		}
2260	}
2261
2262	if (mcast) {
2263		int err = 0;
2264		/* finalize the message */
2265		genlmsg_end(skb, msg);
2266		/* NETLINK_CB(skb).dst_group = 1; */
2267		if ((err = genlmsg_multicast(skb, 0, wl_genl_mcast.id, GFP_ATOMIC)) < 0)
2268			WL_ERR(("genlmsg_multicast for attr(%d) failed. Error:%d \n",
2269				attr_type, err));
2270		else
2271			WL_DBG(("Multicast msg sent successfully. attr_type:%d len:%d \n",
2272				attr_type, tot_len));
2273	} else {
2274		NETLINK_CB(skb).dst_group = 0; /* Not in multicast group */
2275
2276		/* finalize the message */
2277		genlmsg_end(skb, msg);
2278
2279		/* send the message back */
2280		if (genlmsg_unicast(&init_net, skb, pid) < 0)
2281			WL_ERR(("genlmsg_unicast failed\n"));
2282	}
2283
2284out:
2285	if (p)
2286		kfree(p);
2287	if (ret)
2288		nlmsg_free(skb);
2289
2290	return ret;
2291}
2292
2293static s32
2294wl_genl_handle_msg(
2295	struct sk_buff *skb,
2296	struct genl_info *info)
2297{
2298	struct nlattr *na;
2299	u8 *data = NULL;
2300
2301	WL_DBG(("Enter \n"));
2302
2303	if (info == NULL) {
2304		return -EINVAL;
2305	}
2306
2307	na = info->attrs[BCM_GENL_ATTR_MSG];
2308	if (!na) {
2309		WL_ERR(("nlattribute NULL\n"));
2310		return -EINVAL;
2311	}
2312
2313	data = (char *)nla_data(na);
2314	if (!data) {
2315		WL_ERR(("Invalid data\n"));
2316		return -EINVAL;
2317	} else {
2318		/* Handle the data */
2319		WL_DBG(("Data received from pid (%d) \n", info->snd_pid));
2320	}
2321
2322	return 0;
2323}
2324#endif /* WL_GENL */
2325
2326/**
2327 * Functions for Android WiFi card detection
2328 */
2329#if defined(CONFIG_WIFI_CONTROL_FUNC)
2330
2331bool g_wifi_poweron = FALSE;
2332static int g_wifidev_registered = 0;
2333static struct semaphore wifi_control_sem;
2334static struct wifi_platform_data *wifi_control_data = NULL;
2335static struct resource *wifi_irqres = NULL;
2336
2337static int wifi_add_dev(void);
2338static void wifi_del_dev(void);
2339
2340int wl_android_wifictrl_func_add(void)
2341{
2342	int ret = 0;
2343	sema_init(&wifi_control_sem, 0);
2344
2345	ret = wifi_add_dev();
2346	if (ret) {
2347		DHD_ERROR(("%s: platform_driver_register failed\n", __FUNCTION__));
2348		return ret;
2349	}
2350	g_wifidev_registered = 1;
2351
2352	/* Waiting callback after platform_driver_register is done or exit with error */
2353	if (down_timeout(&wifi_control_sem,  msecs_to_jiffies(1000)) != 0) {
2354		ret = -EINVAL;
2355		DHD_ERROR(("%s: platform_driver_register timeout\n", __FUNCTION__));
2356	}
2357
2358	return ret;
2359}
2360
2361void wl_android_wifictrl_func_del(void)
2362{
2363	if (g_wifidev_registered)
2364	{
2365		wifi_del_dev();
2366		g_wifidev_registered = 0;
2367	}
2368}
2369
2370void* wl_android_prealloc(int section, unsigned long size)
2371{
2372	void *alloc_ptr = NULL;
2373	if (wifi_control_data && wifi_control_data->mem_prealloc) {
2374		alloc_ptr = wifi_control_data->mem_prealloc(section, size);
2375		if (alloc_ptr) {
2376			DHD_INFO(("success alloc section %d\n", section));
2377			if (size != 0L)
2378				bzero(alloc_ptr, size);
2379			return alloc_ptr;
2380		}
2381	}
2382
2383	DHD_ERROR(("can't alloc section %d\n", section));
2384	return NULL;
2385}
2386
2387int wifi_get_irq_number(unsigned long *irq_flags_ptr)
2388{
2389	if (wifi_irqres) {
2390		*irq_flags_ptr = wifi_irqres->flags & IRQF_TRIGGER_MASK;
2391		return (int)wifi_irqres->start;
2392	}
2393#ifdef CUSTOM_OOB_GPIO_NUM
2394	return CUSTOM_OOB_GPIO_NUM;
2395#else
2396	return -1;
2397#endif
2398}
2399
2400int wifi_set_power(int on, unsigned long msec)
2401{
2402	int ret = 0;
2403	DHD_ERROR(("%s = %d\n", __FUNCTION__, on));
2404	if (wifi_control_data && wifi_control_data->set_power) {
2405#ifdef ENABLE_4335BT_WAR
2406		if (on) {
2407			printk("WiFi: trying to acquire BT lock\n");
2408			if (bcm_bt_lock(lock_cookie_wifi) != 0)
2409				printk("** WiFi: timeout in acquiring bt lock**\n");
2410			printk("%s: btlock acquired\n", __FUNCTION__);
2411		}
2412		else {
2413			/* For a exceptional case, release btlock */
2414			bcm_bt_unlock(lock_cookie_wifi);
2415		}
2416#endif /* ENABLE_4335BT_WAR */
2417		ret = wifi_control_data->set_power(on);
2418	}
2419
2420	if (msec && !ret)
2421		msleep(msec);
2422	return ret;
2423}
2424
2425#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
2426int wifi_get_mac_addr(unsigned char *buf)
2427{
2428	DHD_ERROR(("%s\n", __FUNCTION__));
2429	if (!buf)
2430		return -EINVAL;
2431	if (wifi_control_data && wifi_control_data->get_mac_addr) {
2432		return wifi_control_data->get_mac_addr(buf);
2433	}
2434	return -EOPNOTSUPP;
2435}
2436#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) */
2437
2438#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
2439void *wifi_get_country_code(char *ccode)
2440{
2441	DHD_TRACE(("%s\n", __FUNCTION__));
2442	if (!ccode)
2443		return NULL;
2444	if (wifi_control_data && wifi_control_data->get_country_code) {
2445		return wifi_control_data->get_country_code(ccode);
2446	}
2447	return NULL;
2448}
2449#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) */
2450
2451static int wifi_set_carddetect(int on)
2452{
2453	DHD_ERROR(("%s = %d\n", __FUNCTION__, on));
2454	if (wifi_control_data && wifi_control_data->set_carddetect) {
2455		wifi_control_data->set_carddetect(on);
2456	}
2457	return 0;
2458}
2459
2460static int wifi_probe(struct platform_device *pdev)
2461{
2462	int err;
2463	struct wifi_platform_data *wifi_ctrl =
2464		(struct wifi_platform_data *)(pdev->dev.platform_data);
2465
2466	wifi_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcmdhd_wlan_irq");
2467	if (wifi_irqres == NULL)
2468		wifi_irqres = platform_get_resource_byname(pdev,
2469			IORESOURCE_IRQ, "bcm4329_wlan_irq");
2470	wifi_control_data = wifi_ctrl;
2471	err = wifi_set_power(1, 200);	/* Power On */
2472	if (unlikely(err)) {
2473		DHD_ERROR(("%s: set_power failed. err=%d\n", __FUNCTION__, err));
2474		wifi_set_power(0, WIFI_TURNOFF_DELAY);
2475		/* WL_REG_ON state unknown, Power off forcely */
2476	} else {
2477		wifi_set_carddetect(1);	/* CardDetect (0->1) */
2478		g_wifi_poweron = TRUE;
2479	}
2480
2481	up(&wifi_control_sem);
2482	return 0;
2483}
2484
2485static int wifi_remove(struct platform_device *pdev)
2486{
2487	struct wifi_platform_data *wifi_ctrl =
2488		(struct wifi_platform_data *)(pdev->dev.platform_data);
2489
2490	DHD_ERROR(("## %s\n", __FUNCTION__));
2491	wifi_control_data = wifi_ctrl;
2492
2493	if (g_wifi_poweron) {
2494		wifi_set_power(0, WIFI_TURNOFF_DELAY);	/* Power Off */
2495		wifi_set_carddetect(0);	/* CardDetect (1->0) */
2496		g_wifi_poweron = FALSE;
2497	}
2498
2499	up(&wifi_control_sem);
2500	return 0;
2501}
2502
2503static int wifi_suspend(struct platform_device *pdev, pm_message_t state)
2504{
2505	DHD_TRACE(("##> %s\n", __FUNCTION__));
2506#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY) && 1
2507	bcmsdh_oob_intr_set(0);
2508#endif /* (OOB_INTR_ONLY) */
2509	return 0;
2510}
2511
2512static int wifi_resume(struct platform_device *pdev)
2513{
2514	DHD_TRACE(("##> %s\n", __FUNCTION__));
2515#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY) && 1
2516	if (dhd_os_check_if_up(bcmsdh_get_drvdata()))
2517		bcmsdh_oob_intr_set(1);
2518#endif /* (OOB_INTR_ONLY) */
2519	return 0;
2520}
2521
2522static struct platform_driver wifi_device = {
2523	.probe          = wifi_probe,
2524	.remove         = wifi_remove,
2525	.suspend        = wifi_suspend,
2526	.resume         = wifi_resume,
2527	.driver         = {
2528	.name   = "bcmdhd_wlan",
2529	}
2530};
2531
2532static struct platform_driver wifi_device_legacy = {
2533	.probe          = wifi_probe,
2534	.remove         = wifi_remove,
2535	.suspend        = wifi_suspend,
2536	.resume         = wifi_resume,
2537	.driver         = {
2538	.name   = "bcm4329_wlan",
2539	}
2540};
2541
2542static int wifi_add_dev(void)
2543{
2544	int ret = 0;
2545	DHD_TRACE(("## Calling platform_driver_register\n"));
2546	ret = platform_driver_register(&wifi_device);
2547	if (ret)
2548		return ret;
2549
2550	ret = platform_driver_register(&wifi_device_legacy);
2551	return ret;
2552}
2553
2554static void wifi_del_dev(void)
2555{
2556	DHD_TRACE(("## Unregister platform_driver_register\n"));
2557	platform_driver_unregister(&wifi_device);
2558	platform_driver_unregister(&wifi_device_legacy);
2559}
2560#endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */