Exemple #1
0
int rtw_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
{
	int ret = 0;
	char *command = NULL;
	int cmd_num;
	int bytes_written = 0;
	android_wifi_priv_cmd priv_cmd;

	rtw_lock_suspend();

	if (!ifr->ifr_data) {
		ret = -EINVAL;
		goto exit;
	}
	if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(android_wifi_priv_cmd))) {
		ret = -EFAULT;
		goto exit;
	}
	
	//DBG_871X("%s priv_cmd.buf=%p priv_cmd.total_len=%d  priv_cmd.used_len=%d\n",__func__,priv_cmd.buf,priv_cmd.total_len,priv_cmd.used_len);
	command = rtw_zmalloc(priv_cmd.total_len);
	if (!command)
	{
		DBG_871X("%s: failed to allocate memory\n", __FUNCTION__);
		ret = -ENOMEM;
		goto exit;
	}

	if (!access_ok(VERIFY_READ, priv_cmd.buf, priv_cmd.total_len)){
	 	DBG_871X("%s: failed to access memory\n", __FUNCTION__);
		ret = -EFAULT;
		goto exit;
	 }
	if (copy_from_user(command, (void *)priv_cmd.buf, priv_cmd.total_len)) {
		ret = -EFAULT;
		goto exit;
	}

	DBG_871X("%s: Android private cmd \"%s\" on %s\n"
		, __FUNCTION__, command, ifr->ifr_name);

	cmd_num = rtw_android_cmdstr_to_num(command);
	
	switch(cmd_num) {
	case ANDROID_WIFI_CMD_START:
		//bytes_written = wl_android_wifi_on(net);
		goto response;
	case ANDROID_WIFI_CMD_SETFWPATH:
		goto response;
	}

	if (!g_wifi_on) {
		DBG_871X("%s: Ignore private cmd \"%s\" - iface %s is down\n"
			,__FUNCTION__, command, ifr->ifr_name);
		ret = 0;
		goto exit;
	}

	switch(cmd_num) {

	case ANDROID_WIFI_CMD_STOP:
		//bytes_written = wl_android_wifi_off(net);
		break;
		
	case ANDROID_WIFI_CMD_SCAN_ACTIVE:
		//rtw_set_scan_mode((_adapter *)rtw_netdev_priv(net), SCAN_ACTIVE);
#ifdef CONFIG_PLATFORM_MSTAR		
#ifdef CONFIG_IOCTL_CFG80211
		(wdev_to_priv(net->ieee80211_ptr))->bandroid_scan = _TRUE;	
#endif //CONFIG_IOCTL_CFG80211
#endif //CONFIG_PLATFORM_MSTAR
		break;
	case ANDROID_WIFI_CMD_SCAN_PASSIVE:
		//rtw_set_scan_mode((_adapter *)rtw_netdev_priv(net), SCAN_PASSIVE);
		break;
		
	case ANDROID_WIFI_CMD_RSSI:
		bytes_written = rtw_android_get_rssi(net, command, priv_cmd.total_len);
		break;
	case ANDROID_WIFI_CMD_LINKSPEED:
		bytes_written = rtw_android_get_link_speed(net, command, priv_cmd.total_len);
		break;

	case ANDROID_WIFI_CMD_MACADDR:
		bytes_written = rtw_android_get_macaddr(net, command, priv_cmd.total_len);
		break;
		
	case ANDROID_WIFI_CMD_BLOCK:
		bytes_written = rtw_android_set_block(net, command, priv_cmd.total_len);
		break;
		
	case ANDROID_WIFI_CMD_RXFILTER_START:
		//bytes_written = net_os_set_packet_filter(net, 1);
		break;
	case ANDROID_WIFI_CMD_RXFILTER_STOP:
		//bytes_written = net_os_set_packet_filter(net, 0);
		break;
	case ANDROID_WIFI_CMD_RXFILTER_ADD:
		//int filter_num = *(command + strlen(CMD_RXFILTER_ADD) + 1) - '0';
		//bytes_written = net_os_rxfilter_add_remove(net, TRUE, filter_num);
		break;
	case ANDROID_WIFI_CMD_RXFILTER_REMOVE:
		//int filter_num = *(command + strlen(CMD_RXFILTER_REMOVE) + 1) - '0';
		//bytes_written = net_os_rxfilter_add_remove(net, FALSE, filter_num);
		break;
		
	case ANDROID_WIFI_CMD_BTCOEXSCAN_START:
		/* TBD: BTCOEXSCAN-START */
		break;
	case ANDROID_WIFI_CMD_BTCOEXSCAN_STOP:
		/* TBD: BTCOEXSCAN-STOP */
		break;
	case ANDROID_WIFI_CMD_BTCOEXMODE:
		#if 0
		uint mode = *(command + strlen(CMD_BTCOEXMODE) + 1) - '0';
		if (mode == 1)
			net_os_set_packet_filter(net, 0); /* DHCP starts */
		else
			net_os_set_packet_filter(net, 1); /* DHCP ends */
#ifdef WL_CFG80211
		bytes_written = wl_cfg80211_set_btcoex_dhcp(net, command);
#endif
		#endif
		break;
		
	case ANDROID_WIFI_CMD_SETSUSPENDOPT:
		//bytes_written = wl_android_set_suspendopt(net, command, priv_cmd.total_len);
		break;
		
	case ANDROID_WIFI_CMD_SETBAND:
	{
		uint band = *(command + strlen("SETBAND") + 1) - '0';
		_adapter*	padapter = ( _adapter * ) rtw_netdev_priv(net);

		if (padapter->chip_type == RTL8192D)
			padapter->setband = band;

		break;
	}
	case ANDROID_WIFI_CMD_GETBAND:
		//bytes_written = wl_android_get_band(net, command, priv_cmd.total_len);
		break;
		
	case ANDROID_WIFI_CMD_COUNTRY:
		bytes_written = rtw_android_set_country(net, command, priv_cmd.total_len);
		break;
		
#ifdef PNO_SUPPORT
	case ANDROID_WIFI_CMD_PNOSSIDCLR_SET:
		//bytes_written = dhd_dev_pno_reset(net);
		break;
	case ANDROID_WIFI_CMD_PNOSETUP_SET:
		//bytes_written = wl_android_set_pno_setup(net, command, priv_cmd.total_len);
		break;
	case ANDROID_WIFI_CMD_PNOENABLE_SET:
		//uint pfn_enabled = *(command + strlen(CMD_PNOENABLE_SET) + 1) - '0';
		//bytes_written = dhd_dev_pno_enable(net, pfn_enabled);
		break;
#endif

	case ANDROID_WIFI_CMD_P2P_DEV_ADDR:
		bytes_written = rtw_android_get_p2p_dev_addr(net, command, priv_cmd.total_len);
		break;
	case ANDROID_WIFI_CMD_P2P_SET_NOA:
		//int skip = strlen(CMD_P2P_SET_NOA) + 1;
		//bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip, priv_cmd.total_len - skip);
		break;
	case ANDROID_WIFI_CMD_P2P_GET_NOA:
		//bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len);
		break;
	case ANDROID_WIFI_CMD_P2P_SET_PS:
		//int skip = strlen(CMD_P2P_SET_PS) + 1;
		//bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip, priv_cmd.total_len - skip);
		break;
		
#ifdef CONFIG_IOCTL_CFG80211
	case ANDROID_WIFI_CMD_SET_AP_WPS_P2P_IE:
	{
		int skip = strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_SET_AP_WPS_P2P_IE]) + 3;
		bytes_written = rtw_cfg80211_set_mgnt_wpsp2pie(net, command + skip, priv_cmd.total_len - skip, *(command + skip - 2) - '0');
		break;
	}
#endif //CONFIG_IOCTL_CFG80211

#ifdef CONFIG_WFD
	case ANDROID_WIFI_CMD_WFD_ENABLE:
	{
		//	Commented by Albert 2012/07/24
		//	We can enable the WFD function by using the following command:
		//	wpa_cli driver wfd-enable
		
		struct wifi_display_info		*pwfd_info;
		_adapter*	padapter = ( _adapter * ) rtw_netdev_priv(net);
	
		pwfd_info = &padapter->wfd_info;
		if( padapter->wdinfo.driver_interface == DRIVER_CFG80211 )
			pwfd_info->wfd_enable = _TRUE;
		break;
	}

	case ANDROID_WIFI_CMD_WFD_DISABLE:
	{
		//	Commented by Albert 2012/07/24
		//	We can disable the WFD function by using the following command:
		//	wpa_cli driver wfd-disable
				
		struct wifi_display_info		*pwfd_info;
		_adapter*	padapter = ( _adapter * ) rtw_netdev_priv(net);
	
		pwfd_info = &padapter->wfd_info;
		if( padapter->wdinfo.driver_interface == DRIVER_CFG80211 )
			pwfd_info->wfd_enable = _FALSE;
		break;
	}
	case ANDROID_WIFI_CMD_WFD_SET_TCPPORT:
	{
		//	Commented by Albert 2012/07/24
		//	We can set the tcp port number by using the following command:
		//	wpa_cli driver wfd-set-tcpport = 554
		
		struct wifi_display_info		*pwfd_info;
		_adapter*	padapter = ( _adapter * ) rtw_netdev_priv(net);
	
		pwfd_info = &padapter->wfd_info;
		if( padapter->wdinfo.driver_interface == DRIVER_CFG80211 )
			pwfd_info->rtsp_ctrlport = ( u16 ) get_int_from_command( priv_cmd.buf );
		break;
	}
	case ANDROID_WIFI_CMD_WFD_SET_MAX_TPUT:
	{
		
		
		break;
	}
	case ANDROID_WIFI_CMD_WFD_SET_DEVTYPE:
	{
		//	Commented by Albert 2012/08/28
		//	Specify the WFD device type ( WFD source/primary sink )
		
		struct wifi_display_info		*pwfd_info;
		_adapter*	padapter = ( _adapter * ) rtw_netdev_priv(net);
	
		pwfd_info = &padapter->wfd_info;
		if( padapter->wdinfo.driver_interface == DRIVER_CFG80211 )
		{
			pwfd_info->wfd_device_type = ( u8 ) get_int_from_command( priv_cmd.buf );
		
			pwfd_info->wfd_device_type &= WFD_DEVINFO_DUAL;
		}
		break;
	}
#endif
	default:
		DBG_871X("Unknown PRIVATE command %s - ignored\n", command);
		snprintf(command, 3, "OK");
		bytes_written = strlen("OK");
	}

response:
	if (bytes_written >= 0) {
		if ((bytes_written == 0) && (priv_cmd.total_len > 0))
			command[0] = '\0';
		if (bytes_written >= priv_cmd.total_len) {
			DBG_871X("%s: bytes_written = %d\n", __FUNCTION__, bytes_written);
			bytes_written = priv_cmd.total_len;
		} else {
			bytes_written++;
		}
		priv_cmd.used_len = bytes_written;
		if (copy_to_user((void *)priv_cmd.buf, command, bytes_written)) {
			DBG_871X("%s: failed to copy data to user buffer\n", __FUNCTION__);
			ret = -EFAULT;
		}
	}
	else {
		ret = bytes_written;
	}

exit:
	rtw_unlock_suspend();
	if (command) {
		rtw_mfree(command, priv_cmd.total_len);
	}

	return ret;
}
Exemple #2
0
int rtw_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
{
	int ret = 0;
	char *command = NULL;
	int cmd_num;
	int bytes_written = 0;
#ifdef CONFIG_PNO_SUPPORT
	uint cmdlen = 0;
	uint pno_enable = 0;
#endif
	android_wifi_priv_cmd priv_cmd;
	_adapter*	padapter = ( _adapter * ) rtw_netdev_priv(net);
#ifdef CONFIG_WFD
	struct wifi_display_info		*pwfd_info;
#endif
	rtw_lock_suspend();

	if (!ifr->ifr_data) {
		ret = -EINVAL;
		goto exit;
	}
	if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(android_wifi_priv_cmd))) {
		ret = -EFAULT;
		goto exit;
	}
	if ( padapter->registrypriv.mp_mode == 1) {
		ret = -EFAULT;
		goto exit;
	}
	//DBG_871X("%s priv_cmd.buf=%p priv_cmd.total_len=%d  priv_cmd.used_len=%d\n",__func__,priv_cmd.buf,priv_cmd.total_len,priv_cmd.used_len);
	command = rtw_zmalloc(priv_cmd.total_len);
	if (!command)
	{
		DBG_871X("%s: failed to allocate memory\n", __FUNCTION__);
		ret = -ENOMEM;
		goto exit;
	}

	if (!access_ok(VERIFY_READ, priv_cmd.buf, priv_cmd.total_len)){
	 	DBG_871X("%s: failed to access memory\n", __FUNCTION__);
		ret = -EFAULT;
		goto exit;
	 }
#ifdef CONFIG_COMPAT
	if (copy_from_user(command, compat_ptr(priv_cmd.buf), (unsigned long) priv_cmd.total_len)) {
#else
	if (copy_from_user(command, (void *)priv_cmd.buf, priv_cmd.total_len)) {
#endif
		ret = -EFAULT;
		goto exit;
	}

	DBG_871X("%s: Android private cmd \"%s\" on %s\n"
		, __FUNCTION__, command, ifr->ifr_name);

	cmd_num = rtw_android_cmdstr_to_num(command);
	
	switch(cmd_num) {
	case ANDROID_WIFI_CMD_START:
		//bytes_written = wl_android_wifi_on(net);
		goto response;
	case ANDROID_WIFI_CMD_SETFWPATH:
		goto response;
	}

	if (!g_wifi_on) {
		DBG_871X("%s: Ignore private cmd \"%s\" - iface %s is down\n"
			,__FUNCTION__, command, ifr->ifr_name);
		ret = 0;
		goto exit;
	}

	switch(cmd_num) {

	case ANDROID_WIFI_CMD_STOP:
		//bytes_written = wl_android_wifi_off(net);
		break;
		
	case ANDROID_WIFI_CMD_SCAN_ACTIVE:
		//rtw_set_scan_mode((_adapter *)rtw_netdev_priv(net), SCAN_ACTIVE);
#ifdef CONFIG_PLATFORM_MSTAR
#ifdef CONFIG_IOCTL_CFG80211
		adapter_wdev_data((_adapter *)rtw_netdev_priv(net))->bandroid_scan = _TRUE;
#endif //CONFIG_IOCTL_CFG80211
#endif //CONFIG_PLATFORM_MSTAR
		break;
	case ANDROID_WIFI_CMD_SCAN_PASSIVE:
		//rtw_set_scan_mode((_adapter *)rtw_netdev_priv(net), SCAN_PASSIVE);
		break;
		
	case ANDROID_WIFI_CMD_RSSI:
		bytes_written = rtw_android_get_rssi(net, command, priv_cmd.total_len);
		break;
	case ANDROID_WIFI_CMD_LINKSPEED:
		bytes_written = rtw_android_get_link_speed(net, command, priv_cmd.total_len);
		break;

	case ANDROID_WIFI_CMD_MACADDR:
		bytes_written = rtw_android_get_macaddr(net, command, priv_cmd.total_len);
		break;
		
	case ANDROID_WIFI_CMD_BLOCK:
		bytes_written = rtw_android_set_block(net, command, priv_cmd.total_len);
		break;
		
	case ANDROID_WIFI_CMD_RXFILTER_START:
		//bytes_written = net_os_set_packet_filter(net, 1);
		break;
	case ANDROID_WIFI_CMD_RXFILTER_STOP:
		//bytes_written = net_os_set_packet_filter(net, 0);
		break;
	case ANDROID_WIFI_CMD_RXFILTER_ADD:
		//int filter_num = *(command + strlen(CMD_RXFILTER_ADD) + 1) - '0';
		//bytes_written = net_os_rxfilter_add_remove(net, TRUE, filter_num);
		break;
	case ANDROID_WIFI_CMD_RXFILTER_REMOVE:
		//int filter_num = *(command + strlen(CMD_RXFILTER_REMOVE) + 1) - '0';
		//bytes_written = net_os_rxfilter_add_remove(net, FALSE, filter_num);
		break;
		
	case ANDROID_WIFI_CMD_BTCOEXSCAN_START:
		/* TBD: BTCOEXSCAN-START */
		break;
	case ANDROID_WIFI_CMD_BTCOEXSCAN_STOP:
		/* TBD: BTCOEXSCAN-STOP */
		break;
	case ANDROID_WIFI_CMD_BTCOEXMODE:
		#if 0
		uint mode = *(command + strlen(CMD_BTCOEXMODE) + 1) - '0';
		if (mode == 1)
			net_os_set_packet_filter(net, 0); /* DHCP starts */
		else
			net_os_set_packet_filter(net, 1); /* DHCP ends */
#ifdef WL_CFG80211
		bytes_written = wl_cfg80211_set_btcoex_dhcp(net, command);
#endif
		#endif
		break;
		
	case ANDROID_WIFI_CMD_SETSUSPENDOPT:
		//bytes_written = wl_android_set_suspendopt(net, command, priv_cmd.total_len);
		break;
		
	case ANDROID_WIFI_CMD_SETBAND:
		bytes_written = rtw_android_setband(net, command, priv_cmd.total_len);
		break;

	case ANDROID_WIFI_CMD_GETBAND:
		bytes_written = rtw_android_getband(net, command, priv_cmd.total_len);
		break;
		
	case ANDROID_WIFI_CMD_COUNTRY:
		bytes_written = rtw_android_set_country(net, command, priv_cmd.total_len);
		break;
		
#ifdef CONFIG_PNO_SUPPORT
	case ANDROID_WIFI_CMD_PNOSSIDCLR_SET:
		//bytes_written = dhd_dev_pno_reset(net);
		break;
	case ANDROID_WIFI_CMD_PNOSETUP_SET:
		bytes_written = rtw_android_pno_setup(net, command, priv_cmd.total_len);
		break;
	case ANDROID_WIFI_CMD_PNOENABLE_SET:
		cmdlen = strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_PNOENABLE_SET]);
		pno_enable = *(command + cmdlen + 1) - '0';
		bytes_written = rtw_android_pno_enable(net, pno_enable);
		break;
#endif

	case ANDROID_WIFI_CMD_P2P_DEV_ADDR:
		bytes_written = rtw_android_get_p2p_dev_addr(net, command, priv_cmd.total_len);
		break;
	case ANDROID_WIFI_CMD_P2P_SET_NOA:
		//int skip = strlen(CMD_P2P_SET_NOA) + 1;
		//bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip, priv_cmd.total_len - skip);
		break;
	case ANDROID_WIFI_CMD_P2P_GET_NOA:
		//bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len);
		break;
	case ANDROID_WIFI_CMD_P2P_SET_PS:
		//int skip = strlen(CMD_P2P_SET_PS) + 1;
		//bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip, priv_cmd.total_len - skip);
		break;
		
#ifdef CONFIG_IOCTL_CFG80211
	case ANDROID_WIFI_CMD_SET_AP_WPS_P2P_IE:
	{
		int skip = strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_SET_AP_WPS_P2P_IE]) + 3;
		bytes_written = rtw_cfg80211_set_mgnt_wpsp2pie(net, command + skip, priv_cmd.total_len - skip, *(command + skip - 2) - '0');
		break;
	}
#endif //CONFIG_IOCTL_CFG80211

#ifdef CONFIG_WFD
	case ANDROID_WIFI_CMD_WFD_ENABLE:
	{
		//	Commented by Albert 2012/07/24
		//	We can enable the WFD function by using the following command:
		//	wpa_cli driver wfd-enable

		pwfd_info = &padapter->wfd_info;
		if( padapter->wdinfo.driver_interface == DRIVER_CFG80211 )
			pwfd_info->wfd_enable = _TRUE;
		break;
	}

	case ANDROID_WIFI_CMD_WFD_DISABLE:
	{
		//	Commented by Albert 2012/07/24
		//	We can disable the WFD function by using the following command:
		//	wpa_cli driver wfd-disable

		pwfd_info = &padapter->wfd_info;
		if( padapter->wdinfo.driver_interface == DRIVER_CFG80211 )
			pwfd_info->wfd_enable = _FALSE;
		break;
	}
	case ANDROID_WIFI_CMD_WFD_SET_TCPPORT:
	{
		//	Commented by Albert 2012/07/24
		//	We can set the tcp port number by using the following command:
		//	wpa_cli driver wfd-set-tcpport = 554

		pwfd_info = &padapter->wfd_info;
		if( padapter->wdinfo.driver_interface == DRIVER_CFG80211 )
		{
#ifdef CONFIG_COMPAT
			pwfd_info->rtsp_ctrlport = ( u16 ) get_int_from_command( compat_ptr(priv_cmd.buf) );
#else
			pwfd_info->rtsp_ctrlport = ( u16 ) get_int_from_command( priv_cmd.buf );
#endif
		}
		break;
	}
	case ANDROID_WIFI_CMD_WFD_SET_MAX_TPUT:
	{
		break;
	}
	case ANDROID_WIFI_CMD_WFD_SET_DEVTYPE:
	{
		//	Commented by Albert 2012/08/28
		//	Specify the WFD device type ( WFD source/primary sink )

		pwfd_info = &padapter->wfd_info;
		if( padapter->wdinfo.driver_interface == DRIVER_CFG80211 )
		{
#ifdef CONFIG_COMPAT
			pwfd_info->wfd_device_type = ( u8 ) get_int_from_command( compat_ptr(priv_cmd.buf) );
#else
			pwfd_info->wfd_device_type = ( u8 ) get_int_from_command( priv_cmd.buf );
#endif
		
			pwfd_info->wfd_device_type &= WFD_DEVINFO_DUAL;
		}
		break;
	}
#endif
	case ANDROID_WIFI_CMD_CHANGE_DTIM:
		{
#ifdef CONFIG_LPS
			u8 dtim;
			u8 *ptr = (u8 *) &priv_cmd.buf;
			
			ptr += 9;//string command length of  "SET_DTIM";

			dtim = rtw_atoi(ptr);

			DBG_871X("DTIM=%d\n", dtim);

			rtw_lps_change_dtim_cmd(padapter, dtim);			
#endif			
		}		
		break;
	case ANDROID_WIFI_CMD_HOSTAPD_SET_MACADDR_ACL:
	{
		padapter->stapriv.acl_list.mode = ( u8 ) get_int_from_command(command);
		DBG_871X("%s ANDROID_WIFI_CMD_HOSTAPD_SET_MACADDR_ACL mode:%d\n", __FUNCTION__, padapter->stapriv.acl_list.mode);
		break;
	}
	case ANDROID_WIFI_CMD_HOSTAPD_ACL_ADD_STA:
	{
		u8 addr[ETH_ALEN] = {0x00};
		macstr2num(addr, command+strlen("HOSTAPD_ACL_ADD_STA")+3);	// 3 is space bar + "=" + space bar these 3 chars
		rtw_acl_add_sta(padapter, addr);
		break;
	}
	case ANDROID_WIFI_CMD_HOSTAPD_ACL_REMOVE_STA:
	{
		u8 addr[ETH_ALEN] = {0x00};
		macstr2num(addr, command+strlen("HOSTAPD_ACL_REMOVE_STA")+3);	// 3 is space bar + "=" + space bar these 3 chars
		rtw_acl_remove_sta(padapter, addr);
		break;
	}
#ifdef CONFIG_GTK_OL
	case ANDROID_WIFI_CMD_GTK_REKEY_OFFLOAD:
		rtw_gtk_offload(net, priv_cmd.buf);
		break;
#endif //CONFIG_GTK_OL		
	case ANDROID_WIFI_CMD_P2P_DISABLE:
	{
		struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;	
		struct wifidirect_info 	*pwdinfo= &(padapter->wdinfo);
		u8 channel, ch_offset;
		u16 bwmode;

		rtw_p2p_enable(padapter, P2P_ROLE_DISABLE);
		break;
	}
	default:
		DBG_871X("Unknown PRIVATE command %s - ignored\n", command);
		snprintf(command, 3, "OK");
		bytes_written = strlen("OK");
	}

response:
	if (bytes_written >= 0) {
		if ((bytes_written == 0) && (priv_cmd.total_len > 0))
			command[0] = '\0';
		if (bytes_written >= priv_cmd.total_len) {
			DBG_871X("%s: bytes_written = %d\n", __FUNCTION__, bytes_written);
			bytes_written = priv_cmd.total_len;
		} else {
			bytes_written++;
		}
		priv_cmd.used_len = bytes_written;
#ifdef CONFIG_COMPAT
		if (copy_to_user(compat_ptr(priv_cmd.buf), command, bytes_written)) {
#else
		if (copy_to_user((void *)priv_cmd.buf, command, bytes_written)) {
#endif
			DBG_871X("%s: failed to copy data to user buffer\n", __FUNCTION__);
			ret = -EFAULT;
		}
	}
	else {
		ret = bytes_written;
	}

exit:
	rtw_unlock_suspend();
	if (command) {
		rtw_mfree(command, priv_cmd.total_len);
	}

	return ret;
}


/**
 * Functions for Android WiFi card detection
 */
#if defined(RTW_ENABLE_WIFI_CONTROL_FUNC)

static int g_wifidev_registered = 0;
static struct semaphore wifi_control_sem;
static struct wifi_platform_data *wifi_control_data = NULL;
static struct resource *wifi_irqres = NULL;

static int wifi_add_dev(void);
static void wifi_del_dev(void);

int rtw_android_wifictrl_func_add(void)
{
	int ret = 0;
	sema_init(&wifi_control_sem, 0);

	ret = wifi_add_dev();
	if (ret) {
		DBG_871X("%s: platform_driver_register failed\n", __FUNCTION__);
		return ret;
	}
	g_wifidev_registered = 1;

	/* Waiting callback after platform_driver_register is done or exit with error */
	if (down_timeout(&wifi_control_sem,  msecs_to_jiffies(1000)) != 0) {
		ret = -EINVAL;
		DBG_871X("%s: platform_driver_register timeout\n", __FUNCTION__);
	}

	return ret;
}

void rtw_android_wifictrl_func_del(void)
{
	if (g_wifidev_registered)
	{
		wifi_del_dev();
		g_wifidev_registered = 0;
	}
}

void *wl_android_prealloc(int section, unsigned long size)
{
	void *alloc_ptr = NULL;
	if (wifi_control_data && wifi_control_data->mem_prealloc) {
		alloc_ptr = wifi_control_data->mem_prealloc(section, size);
		if (alloc_ptr) {
			DBG_871X("success alloc section %d\n", section);
			if (size != 0L)
				memset(alloc_ptr, 0, size);
			return alloc_ptr;
		}
	}

	DBG_871X("can't alloc section %d\n", section);
	return NULL;
}
int rtw_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
{
	int ret = 0;
	char *command = NULL;
	int cmd_num;
	int bytes_written = 0;
	android_wifi_priv_cmd priv_cmd;

	rtw_lock_suspend();

	if (!ifr->ifr_data) {
		ret = -EINVAL;
		goto exit;
	}
	if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(android_wifi_priv_cmd))) {
		ret = -EFAULT;
		goto exit;
	}
	command = kmalloc(priv_cmd.total_len, GFP_KERNEL);
	if (!command)
	{
		DBG_871X("%s: failed to allocate memory\n", __FUNCTION__);
		ret = -ENOMEM;
		goto exit;
	}
	if (copy_from_user(command, priv_cmd.buf, priv_cmd.total_len)) {
		ret = -EFAULT;
		goto exit;
	}

	DBG_871X("%s: Android private cmd \"%s\" on %s\n"
		, __FUNCTION__, command, ifr->ifr_name);

	cmd_num = rtw_android_cmdstr_to_num(command);
	
	switch(cmd_num) {
	case ANDROID_WIFI_CMD_START:
		//bytes_written = wl_android_wifi_on(net);
		goto response;
	case ANDROID_WIFI_CMD_SETFWPATH:
		goto response;
	}

	if (!g_wifi_on) {
		DBG_871X("%s: Ignore private cmd \"%s\" - iface %s is down\n"
			,__FUNCTION__, command, ifr->ifr_name);
		ret = 0;
		goto exit;
	}

	switch(cmd_num) {

	case ANDROID_WIFI_CMD_STOP:
		//bytes_written = wl_android_wifi_off(net);
		break;
		
	case ANDROID_WIFI_CMD_SCAN_ACTIVE:
		rtw_set_scan_mode((_adapter *)rtw_netdev_priv(net), SCAN_ACTIVE);
		break;
	case ANDROID_WIFI_CMD_SCAN_PASSIVE:
		rtw_set_scan_mode((_adapter *)rtw_netdev_priv(net), SCAN_PASSIVE);
		break;
		
	case ANDROID_WIFI_CMD_RSSI:
		bytes_written = rtw_android_get_rssi(net, command, priv_cmd.total_len);
		break;
	case ANDROID_WIFI_CMD_LINKSPEED:
		bytes_written = rtw_android_get_link_speed(net, command, priv_cmd.total_len);
		break;

	case ANDROID_WIFI_CMD_MACADDR:
		bytes_written = rtw_android_get_macaddr(net, command, priv_cmd.total_len);
		break;
		
	case ANDROID_WIFI_CMD_BLOCK:
		bytes_written = rtw_android_set_block(net, command, priv_cmd.total_len);
		break;
		
	case ANDROID_WIFI_CMD_RXFILTER_START:
		//bytes_written = net_os_set_packet_filter(net, 1);
		break;
	case ANDROID_WIFI_CMD_RXFILTER_STOP:
		//bytes_written = net_os_set_packet_filter(net, 0);
		break;
	case ANDROID_WIFI_CMD_RXFILTER_ADD:
		//int filter_num = *(command + strlen(CMD_RXFILTER_ADD) + 1) - '0';
		//bytes_written = net_os_rxfilter_add_remove(net, TRUE, filter_num);
		break;
	case ANDROID_WIFI_CMD_RXFILTER_REMOVE:
		//int filter_num = *(command + strlen(CMD_RXFILTER_REMOVE) + 1) - '0';
		//bytes_written = net_os_rxfilter_add_remove(net, FALSE, filter_num);
		break;
		
	case ANDROID_WIFI_CMD_BTCOEXSCAN_START:
		/* TBD: BTCOEXSCAN-START */
		break;
	case ANDROID_WIFI_CMD_BTCOEXSCAN_STOP:
		/* TBD: BTCOEXSCAN-STOP */
		break;
	case ANDROID_WIFI_CMD_BTCOEXMODE:
		#if 0
		uint mode = *(command + strlen(CMD_BTCOEXMODE) + 1) - '0';
		if (mode == 1)
			net_os_set_packet_filter(net, 0); /* DHCP starts */
		else
			net_os_set_packet_filter(net, 1); /* DHCP ends */
#ifdef WL_CFG80211
		bytes_written = wl_cfg80211_set_btcoex_dhcp(net, command);
#endif
		#endif
		break;
		
	case ANDROID_WIFI_CMD_SETSUSPENDOPT:
		//bytes_written = wl_android_set_suspendopt(net, command, priv_cmd.total_len);
		break;
		
	case ANDROID_WIFI_CMD_SETBAND:
		//uint band = *(command + strlen(CMD_SETBAND) + 1) - '0';
		//bytes_written = wldev_set_band(net, band);
		break;
	case ANDROID_WIFI_CMD_GETBAND:
		//bytes_written = wl_android_get_band(net, command, priv_cmd.total_len);
		break;
		
	case ANDROID_WIFI_CMD_COUNTRY:
		bytes_written = rtw_android_set_country(net, command, priv_cmd.total_len);
		break;
		
#ifdef PNO_SUPPORT
	case ANDROID_WIFI_CMD_PNOSSIDCLR_SET:
		//bytes_written = dhd_dev_pno_reset(net);
		break;
	case ANDROID_WIFI_CMD_PNOSETUP_SET:
		//bytes_written = wl_android_set_pno_setup(net, command, priv_cmd.total_len);
		break;
	case ANDROID_WIFI_CMD_PNOENABLE_SET:
		//uint pfn_enabled = *(command + strlen(CMD_PNOENABLE_SET) + 1) - '0';
		//bytes_written = dhd_dev_pno_enable(net, pfn_enabled);
		break;
#endif

	case ANDROID_WIFI_CMD_P2P_DEV_ADDR:
		bytes_written = rtw_android_get_p2p_dev_addr(net, command, priv_cmd.total_len);
		break;
	case ANDROID_WIFI_CMD_P2P_SET_NOA:
		//int skip = strlen(CMD_P2P_SET_NOA) + 1;
		//bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip, priv_cmd.total_len - skip);
		break;
	case ANDROID_WIFI_CMD_P2P_GET_NOA:
		//bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len);
		break;
	case ANDROID_WIFI_CMD_P2P_SET_PS:
		//int skip = strlen(CMD_P2P_SET_PS) + 1;
		//bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip, priv_cmd.total_len - skip);
		break;
		
#ifdef CONFIG_IOCTL_CFG80211
	case ANDROID_WIFI_CMD_SET_AP_WPS_P2P_IE:
	{
		int skip = strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_SET_AP_WPS_P2P_IE]) + 3;
		bytes_written = rtw_cfg80211_set_mgnt_wpsp2pie(net, command + skip, priv_cmd.total_len - skip, *(command + skip - 2) - '0');
		break;
	}
#endif //CONFIG_IOCTL_CFG80211

	default:
		DBG_871X("Unknown PRIVATE command %s - ignored\n", command);
		snprintf(command, 3, "OK");
		bytes_written = strlen("OK");
	}

response:
	if (bytes_written >= 0) {
		if ((bytes_written == 0) && (priv_cmd.total_len > 0))
			command[0] = '\0';
		if (bytes_written >= priv_cmd.total_len) {
			DBG_871X("%s: bytes_written = %d\n", __FUNCTION__, bytes_written);
			bytes_written = priv_cmd.total_len;
		} else {
			bytes_written++;
		}
		priv_cmd.used_len = bytes_written;
		if (copy_to_user(priv_cmd.buf, command, bytes_written)) {
			DBG_871X("%s: failed to copy data to user buffer\n", __FUNCTION__);
			ret = -EFAULT;
		}
	}
	else {
		ret = bytes_written;
	}

exit:
	rtw_unlock_suspend();
	if (command) {
		kfree(command);
	}

	return ret;
}