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; }