static void rtl_op_stop(struct ieee80211_hw *hw)
{
	struct rtl_priv *rtlpriv = rtl_priv(hw);
	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));

	if (is_hal_stop(rtlhal))
		return;

	if (unlikely(ppsc->rfpwr_state == ERFOFF)) {
		rtl_ips_nic_on(hw);
		mdelay(1);
	}

	mutex_lock(&rtlpriv->locks.conf_mutex);

	mac->link_state = MAC80211_NOLINK;
	memset(mac->bssid, 0, 6);
	mac->vendor = PEER_UNKNOWN;

	/*reset sec info */
	rtl_cam_reset_sec_info(hw);

	rtl_deinit_deferred_work(hw);
	rtlpriv->intf_ops->adapter_stop(hw);

	mutex_unlock(&rtlpriv->locks.conf_mutex);
}
static void rtl_op_stop( struct ieee80211_hw *hw )
{
	struct rtl_priv *rtlpriv = rtl_priv( hw );
	struct rtl_mac *mac = rtl_mac( rtl_priv( hw ) );
	struct rtl_hal *rtlhal = rtl_hal( rtl_priv( hw ) );
	struct rtl_ps_ctl *ppsc = rtl_psc( rtl_priv( hw ) );

	if ( is_hal_stop( rtlhal ) )
		return;

	/* here is must, because adhoc do stop and start,
	 * but stop with RFOFF may cause something wrong,
	 * like adhoc TP
	 */
	if ( unlikely( ppsc->rfpwr_state == ERFOFF ) ) {
		rtl_ips_nic_on( hw );
	}

	mutex_lock( &rtlpriv->locks.conf_mutex );

	mac->link_state = MAC80211_NOLINK;
	memset( mac->bssid, 0, ETH_ALEN );
	mac->vendor = PEER_UNKNOWN;

	/*reset sec info */
	rtl_cam_reset_sec_info( hw );

	rtl_deinit_deferred_work( hw );
	rtlpriv->intf_ops->adapter_stop( hw );

	mutex_unlock( &rtlpriv->locks.conf_mutex );
}
static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
			     struct ieee80211_vif *vif,
			     struct ieee80211_bss_conf *bss_conf, u32 changed)
{
	struct rtl_priv *rtlpriv = rtl_priv(hw);
	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
	struct ieee80211_sta *sta = NULL;

	mutex_lock(&rtlpriv->locks.conf_mutex);
	if ((vif->type == NL80211_IFTYPE_ADHOC) ||
	    (vif->type == NL80211_IFTYPE_AP) ||
	    (vif->type == NL80211_IFTYPE_MESH_POINT)) {
		if ((changed & BSS_CHANGED_BEACON) ||
		    (changed & BSS_CHANGED_BEACON_ENABLED &&
		     bss_conf->enable_beacon)) {
			if (mac->beacon_enabled == 0) {
				RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
					 ("BSS_CHANGED_BEACON_ENABLED\n"));

				/*start hw beacon interrupt. */
				/*rtlpriv->cfg->ops->set_bcn_reg(hw); */
				mac->beacon_enabled = 1;
				rtlpriv->cfg->ops->update_interrupt_mask(hw,
						rtlpriv->cfg->maps
						[RTL_IBSS_INT_MASKS],
						0);

				if (rtlpriv->cfg->ops->linked_set_reg)
					rtlpriv->cfg->ops->linked_set_reg(hw);
			}
		}
		if ((changed & BSS_CHANGED_BEACON_ENABLED &&
			!bss_conf->enable_beacon)) {
			if (mac->beacon_enabled == 1) {
				RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
					 ("ADHOC DISABLE BEACON\n"));

				mac->beacon_enabled = 0;
				rtlpriv->cfg->ops->update_interrupt_mask(hw, 0,
						rtlpriv->cfg->maps
						[RTL_IBSS_INT_MASKS]);
			}
		}
		if (changed & BSS_CHANGED_BEACON_INT) {
			RT_TRACE(rtlpriv, COMP_BEACON, DBG_TRACE,
				 ("BSS_CHANGED_BEACON_INT\n"));
			mac->beacon_interval = bss_conf->beacon_int;
			rtlpriv->cfg->ops->set_bcn_intv(hw);
		}
	}

	/*TODO: reference to enum ieee80211_bss_change */
	if (changed & BSS_CHANGED_ASSOC) {
		if (bss_conf->assoc) {
			/* we should reset all sec info & cam
			 * before set cam after linked, we should not
			 * reset in disassoc, that will cause tkip->wep
			 * fail because some flag will be wrong */
			/* reset sec info */
			rtl_cam_reset_sec_info(hw);
			/* reset cam to fix wep fail issue
			 * when change from wpa to wep */
			rtl_cam_reset_all_entry(hw);

			mac->link_state = MAC80211_LINKED;
			mac->cnt_after_linked = 0;
			mac->assoc_id = bss_conf->aid;
			memcpy(mac->bssid, bss_conf->bssid, 6);

			if (rtlpriv->cfg->ops->linked_set_reg)
				rtlpriv->cfg->ops->linked_set_reg(hw);
			if (mac->opmode == NL80211_IFTYPE_STATION && sta)
				rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0);
			RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
				 ("BSS_CHANGED_ASSOC\n"));
		} else {
			if (mac->link_state == MAC80211_LINKED)
				rtl_lps_leave(hw);

			mac->link_state = MAC80211_NOLINK;
			memset(mac->bssid, 0, 6);
			mac->vendor = PEER_UNKNOWN;

			RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
				 ("BSS_CHANGED_UN_ASSOC\n"));
		}
	}

	if (changed & BSS_CHANGED_ERP_CTS_PROT) {
		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
			 ("BSS_CHANGED_ERP_CTS_PROT\n"));
		mac->use_cts_protect = bss_conf->use_cts_prot;
	}

	if (changed & BSS_CHANGED_ERP_PREAMBLE) {
		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
			 ("BSS_CHANGED_ERP_PREAMBLE use short preamble:%x\n",
			  bss_conf->use_short_preamble));

		mac->short_preamble = bss_conf->use_short_preamble;
		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ACK_PREAMBLE,
					      (u8 *) (&mac->short_preamble));
	}

	if (changed & BSS_CHANGED_ERP_SLOT) {
		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
			 ("BSS_CHANGED_ERP_SLOT\n"));

		if (bss_conf->use_short_slot)
			mac->slot_time = RTL_SLOT_TIME_9;
		else
			mac->slot_time = RTL_SLOT_TIME_20;

		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME,
					      (u8 *) (&mac->slot_time));
	}

	if (changed & BSS_CHANGED_HT) {
		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
			 ("BSS_CHANGED_HT\n"));
		rcu_read_lock();
		sta = get_sta(hw, vif, (u8 *)bss_conf->bssid);
		if (sta) {
			if (sta->ht_cap.ampdu_density >
			    mac->current_ampdu_density)
				mac->current_ampdu_density =
				    sta->ht_cap.ampdu_density;
			if (sta->ht_cap.ampdu_factor <
			    mac->current_ampdu_factor)
				mac->current_ampdu_factor =
				    sta->ht_cap.ampdu_factor;
		}
		rcu_read_unlock();

		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SHORTGI_DENSITY,
					      (u8 *) (&mac->max_mss_density));
		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AMPDU_FACTOR,
					      &mac->current_ampdu_factor);
		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AMPDU_MIN_SPACE,
					      &mac->current_ampdu_density);
	}

	if (changed & BSS_CHANGED_BSSID) {
		u32 basic_rates;

		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BSSID,
					      (u8 *) bss_conf->bssid);

		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
			 (MAC_FMT "\n", MAC_ARG(bss_conf->bssid)));

		mac->vendor = PEER_UNKNOWN;
		memcpy(mac->bssid, bss_conf->bssid, 6);
		rtlpriv->cfg->ops->set_network_type(hw, vif->type);

		rcu_read_lock();
		sta = get_sta(hw, vif, (u8 *)bss_conf->bssid);
		if (!sta) {
			rcu_read_unlock();
			goto out;
		}

		if (rtlhal->current_bandtype == BAND_ON_5G) {
			mac->mode = WIRELESS_MODE_A;
		} else {
			if (sta->supp_rates[0] <= 0xf)
				mac->mode = WIRELESS_MODE_B;
			else
				mac->mode = WIRELESS_MODE_G;
		}

		if (sta->ht_cap.ht_supported) {
			if (rtlhal->current_bandtype == BAND_ON_2_4G)
				mac->mode = WIRELESS_MODE_N_24G;
			else
				mac->mode = WIRELESS_MODE_N_5G;
		}

		/* just station need it, because ibss & ap mode will
		 * set in sta_add, and will be NULL here */
		if (mac->opmode == NL80211_IFTYPE_STATION) {
			struct rtl_sta_info *sta_entry;
			sta_entry = (struct rtl_sta_info *) sta->drv_priv;
			sta_entry->wireless_mode = mac->mode;
		}

		if (sta->ht_cap.ht_supported) {
			mac->ht_enable = true;

			/*
			 * for cisco 1252 bw20 it's wrong
			 * if (ht_cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) {
			 *	mac->bw_40 = true;
			 * }
			 * */
		}

		if (changed & BSS_CHANGED_BASIC_RATES) {
			/* for 5G must << RATE_6M_INDEX=4,
			 * because 5G have no cck rate*/
			if (rtlhal->current_bandtype == BAND_ON_5G)
				basic_rates = sta->supp_rates[1] << 4;
			else
				basic_rates = sta->supp_rates[0];

			mac->basic_rates = basic_rates;
			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE,
					(u8 *) (&basic_rates));
		}
		rcu_read_unlock();
	}

	/*
	 * For FW LPS:
	 * To tell firmware we have connected
	 * to an AP. For 92SE/CE power save v2.
	 */
	if (changed & BSS_CHANGED_ASSOC) {
		if (bss_conf->assoc) {
			if (ppsc->fwctrl_lps) {
				u8 mstatus = RT_MEDIA_CONNECT;
				rtlpriv->cfg->ops->set_hw_reg(hw,
						      HW_VAR_H2C_FW_JOINBSSRPT,
						      (u8 *) (&mstatus));
				ppsc->report_linked = true;
			}
		} else {
			if (ppsc->fwctrl_lps) {
				u8 mstatus = RT_MEDIA_DISCONNECT;
				rtlpriv->cfg->ops->set_hw_reg(hw,
						      HW_VAR_H2C_FW_JOINBSSRPT,
						      (u8 *)(&mstatus));
				ppsc->report_linked = false;
			}
		}
	}

out:
	mutex_unlock(&rtlpriv->locks.conf_mutex);
}
static int rtl_op_set_key( struct ieee80211_hw *hw, enum set_key_cmd cmd,
			  struct ieee80211_vif *vif, struct ieee80211_sta *sta,
			  struct ieee80211_key_conf *key )
{
	struct rtl_priv *rtlpriv = rtl_priv( hw );
	struct rtl_mac *mac = rtl_mac( rtl_priv( hw ) );
	u8 key_type = NO_ENCRYPTION;
	u8 key_idx;
	bool group_key = false;
	bool wep_only = false;
	int err = 0;
	u8 mac_addr[ETH_ALEN];
	u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };

	if ( rtlpriv->cfg->mod_params->sw_crypto || rtlpriv->sec.use_sw_sec ) {
		RT_TRACE( rtlpriv, COMP_ERR, DBG_WARNING,
			 "not open hw encryption\n" );
		return -ENOSPC;	/*User disabled HW-crypto */
	}
	/* To support IBSS, use sw-crypto for GTK */
	if ( ( ( vif->type == NL80211_IFTYPE_ADHOC ) ||
	     ( vif->type == NL80211_IFTYPE_MESH_POINT ) ) &&
	      !( key->flags & IEEE80211_KEY_FLAG_PAIRWISE ) )
		return -ENOSPC;
	RT_TRACE( rtlpriv, COMP_SEC, DBG_DMESG,
		 "%s hardware based encryption for keyidx: %d, mac: %pM\n",
		 cmd == SET_KEY ? "Using" : "Disabling", key->keyidx,
		 sta ? sta->addr : bcast_addr );
	rtlpriv->sec.being_setkey = true;
	rtl_ips_nic_on( hw );
	mutex_lock( &rtlpriv->locks.conf_mutex );
	/* <1> get encryption alg */

	switch ( key->cipher ) {
	case WLAN_CIPHER_SUITE_WEP40:
		key_type = WEP40_ENCRYPTION;
		RT_TRACE( rtlpriv, COMP_SEC, DBG_DMESG, "alg:WEP40\n" );
		break;
	case WLAN_CIPHER_SUITE_WEP104:
		RT_TRACE( rtlpriv, COMP_SEC, DBG_DMESG, "alg:WEP104\n" );
		key_type = WEP104_ENCRYPTION;
		break;
	case WLAN_CIPHER_SUITE_TKIP:
		key_type = TKIP_ENCRYPTION;
		RT_TRACE( rtlpriv, COMP_SEC, DBG_DMESG, "alg:TKIP\n" );
		break;
	case WLAN_CIPHER_SUITE_CCMP:
		key_type = AESCCMP_ENCRYPTION;
		RT_TRACE( rtlpriv, COMP_SEC, DBG_DMESG, "alg:CCMP\n" );
		break;
	case WLAN_CIPHER_SUITE_AES_CMAC:
		/*HW doesn't support CMAC encryption, use software CMAC */
		key_type = AESCMAC_ENCRYPTION;
		RT_TRACE( rtlpriv, COMP_SEC, DBG_DMESG, "alg:CMAC\n" );
		RT_TRACE( rtlpriv, COMP_SEC, DBG_DMESG,
			 "HW don't support CMAC encryption, use software CMAC\n" );
		err = -EOPNOTSUPP;
		goto out_unlock;
	default:
		RT_TRACE( rtlpriv, COMP_ERR, DBG_EMERG, "alg_err:%x!!!!\n",
			 key->cipher );
		goto out_unlock;
	}
	if ( key_type == WEP40_ENCRYPTION ||
			key_type == WEP104_ENCRYPTION ||
			mac->opmode == NL80211_IFTYPE_ADHOC )
		rtlpriv->sec.use_defaultkey = true;

	/* <2> get key_idx */
	key_idx = ( u8 ) ( key->keyidx );
	if ( key_idx > 3 )
		goto out_unlock;
	/* <3> if pairwise key enable_hw_sec */
	group_key = !( key->flags & IEEE80211_KEY_FLAG_PAIRWISE );

	/* wep always be group key, but there are two conditions:
	 * 1 ) wep only: is just for wep enc, in this condition
	 * rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION
	 * will be true & enable_hw_sec will be set when wep
	 * key setting.
	 * 2 ) wep( group ) + AES( pairwise ): some AP like cisco
	 * may use it, in this condition enable_hw_sec will not
	 * be set when wep key setting */
	/* we must reset sec_info after lingked before set key,
	 * or some flag will be wrong*/
	if ( vif->type == NL80211_IFTYPE_AP ||
	    vif->type == NL80211_IFTYPE_MESH_POINT ) {
		if ( !group_key || key_type == WEP40_ENCRYPTION ||
			key_type == WEP104_ENCRYPTION ) {
			if ( group_key )
				wep_only = true;
			rtlpriv->cfg->ops->enable_hw_sec( hw );
		}
	} else {
		if ( ( !group_key ) || ( mac->opmode == NL80211_IFTYPE_ADHOC ) ||
		     rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION ) {
			if ( rtlpriv->sec.pairwise_enc_algorithm ==
			    NO_ENCRYPTION &&
			    ( key_type == WEP40_ENCRYPTION ||
			    key_type == WEP104_ENCRYPTION ) )
				wep_only = true;
			rtlpriv->sec.pairwise_enc_algorithm = key_type;
			RT_TRACE( rtlpriv, COMP_SEC, DBG_DMESG,
				 "set enable_hw_sec, key_type:%x(OPEN:0 WEP40:1 TKIP:2 AES:4 WEP104:5)\n",
				 key_type );
			rtlpriv->cfg->ops->enable_hw_sec( hw );
		}
	}
	/* <4> set key based on cmd */
	switch ( cmd ) {
	case SET_KEY:
		if ( wep_only ) {
			RT_TRACE( rtlpriv, COMP_SEC, DBG_DMESG,
				 "set WEP(group/pairwise) key\n" );
			/* Pairwise key with an assigned MAC address. */
			rtlpriv->sec.pairwise_enc_algorithm = key_type;
			rtlpriv->sec.group_enc_algorithm = key_type;
			/*set local buf about wep key. */
			memcpy( rtlpriv->sec.key_buf[key_idx],
			       key->key, key->keylen );
			rtlpriv->sec.key_len[key_idx] = key->keylen;
			eth_zero_addr( mac_addr );
		} else if ( group_key ) {	/* group key */
			RT_TRACE( rtlpriv, COMP_SEC, DBG_DMESG,
				 "set group key\n" );
			/* group key */
			rtlpriv->sec.group_enc_algorithm = key_type;
			/*set local buf about group key. */
			memcpy( rtlpriv->sec.key_buf[key_idx],
			       key->key, key->keylen );
			rtlpriv->sec.key_len[key_idx] = key->keylen;
			memcpy( mac_addr, bcast_addr, ETH_ALEN );
		} else {	/* pairwise key */
			RT_TRACE( rtlpriv, COMP_SEC, DBG_DMESG,
				 "set pairwise key\n" );
			if ( !sta ) {
				RT_ASSERT( false,
					  "pairwise key without mac_addr\n" );

				err = -EOPNOTSUPP;
				goto out_unlock;
			}
			/* Pairwise key with an assigned MAC address. */
			rtlpriv->sec.pairwise_enc_algorithm = key_type;
			/*set local buf about pairwise key. */
			memcpy( rtlpriv->sec.key_buf[PAIRWISE_KEYIDX],
			       key->key, key->keylen );
			rtlpriv->sec.key_len[PAIRWISE_KEYIDX] = key->keylen;
			rtlpriv->sec.pairwise_key =
			    rtlpriv->sec.key_buf[PAIRWISE_KEYIDX];
			memcpy( mac_addr, sta->addr, ETH_ALEN );
		}
		rtlpriv->cfg->ops->set_key( hw, key_idx, mac_addr,
					   group_key, key_type, wep_only,
					   false );
		/* <5> tell mac80211 do something: */
		/*must use sw generate IV, or can not work !!!!. */
		key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
		key->hw_key_idx = key_idx;
		if ( key_type == TKIP_ENCRYPTION )
			key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
		/*use software CCMP encryption for management frames ( MFP ) */
		if ( key_type == AESCCMP_ENCRYPTION )
			key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
		break;
	case DISABLE_KEY:
		RT_TRACE( rtlpriv, COMP_SEC, DBG_DMESG,
			 "disable key delete one entry\n" );
		/*set local buf about wep key. */
		if ( vif->type == NL80211_IFTYPE_AP ||
		    vif->type == NL80211_IFTYPE_MESH_POINT ) {
			if ( sta )
				rtl_cam_del_entry( hw, sta->addr );
		}
		memset( rtlpriv->sec.key_buf[key_idx], 0, key->keylen );
		rtlpriv->sec.key_len[key_idx] = 0;
		eth_zero_addr( mac_addr );
		/*
		 *mac80211 will delete entrys one by one,
		 *so don't use rtl_cam_reset_all_entry
		 *or clear all entry here.
		 */
		rtl_cam_delete_one_entry( hw, mac_addr, key_idx );

		rtl_cam_reset_sec_info( hw );

		break;
	default:
		RT_TRACE( rtlpriv, COMP_ERR, DBG_EMERG,
			 "cmd_err:%x!!!!\n", cmd );
	}
out_unlock:
	mutex_unlock( &rtlpriv->locks.conf_mutex );
	rtlpriv->sec.being_setkey = false;
	return err;
}