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_sw_scan_start( struct ieee80211_hw *hw ) { struct rtl_priv *rtlpriv = rtl_priv( hw ); struct rtl_mac *mac = rtl_mac( rtl_priv( hw ) ); RT_TRACE( rtlpriv, COMP_MAC80211, DBG_LOUD, "\n" ); mac->act_scanning = true; if ( rtlpriv->link_info.higher_busytraffic ) { mac->skip_scan = true; return; } if ( rtlpriv->dm.supp_phymode_switch ) { if ( rtlpriv->cfg->ops->chk_switch_dmdp ) rtlpriv->cfg->ops->chk_switch_dmdp( hw ); } if ( mac->link_state == MAC80211_LINKED ) { rtlpriv->enter_ps = false; schedule_work( &rtlpriv->works.lps_change_work ); mac->link_state = MAC80211_LINKED_SCANNING; } else { rtl_ips_nic_on( hw ); } /* Dual mac */ rtlpriv->rtlhal.load_imrandiqk_setting_for2g = false; rtlpriv->cfg->ops->led_control( hw, LED_CTL_SITE_SURVEY ); rtlpriv->cfg->ops->scan_operation_backup( hw, SCAN_OPT_BACKUP ); }
static void rtl_op_sw_scan_start(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); RT_TRACE(COMP_MAC80211, DBG_LOUD, ("\n")); mac->act_scanning = true; /*rtlpriv->btcops->btc_scan_notify(rtlpriv, 0); */ if (rtlpriv->link_info.b_higher_busytraffic) { mac->skip_scan = true; return; } if (rtlpriv->dm.supp_phymode_switch) { if (rtlpriv->cfg->ops->check_switch_to_dmdp) rtlpriv->cfg->ops->check_switch_to_dmdp(hw); } if (mac->link_state == MAC80211_LINKED) { rtl_lps_leave(hw); mac->link_state = MAC80211_LINKED_SCANNING; } else { rtl_ips_nic_on(hw); } /* Dul mac */ rtlpriv->rtlhal.b_load_imrandiqk_setting_for2g = false; rtlpriv->cfg->ops->led_control(hw, LED_CTL_SITE_SURVEY); rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_BACKUP); }
static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, struct ieee80211_sta *sta, struct sk_buff *skb, u16 hw_queue) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct rtl_tx_desc *pdesc = NULL; struct rtl_tcb_desc tcb_desc; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); __le16 fc = hdr->frame_control; u8 *pda_addr = hdr->addr1; /* ssn */ u8 *qc = NULL; u8 tid = 0; u16 seq_number = 0; memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); if (ieee80211_is_auth(fc)) { RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, "MAC80211_LINKING\n"); rtl_ips_nic_on(hw); } if (rtlpriv->psc.sw_ps_enabled) { if (ieee80211_is_data(fc) && !ieee80211_is_nullfunc(fc) && !ieee80211_has_pm(fc)) hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); } rtl_action_proc(hw, skb, true); if (is_multicast_ether_addr(pda_addr)) rtlpriv->stats.txbytesmulticast += skb->len; else if (is_broadcast_ether_addr(pda_addr)) rtlpriv->stats.txbytesbroadcast += skb->len; else rtlpriv->stats.txbytesunicast += skb->len; if (ieee80211_is_data_qos(fc)) { qc = ieee80211_get_qos_ctl(hdr); tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; seq_number += 1; seq_number <<= 4; } rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc, NULL, info, sta, skb, hw_queue, &tcb_desc); if (!ieee80211_has_morefrags(hdr->frame_control)) { if (qc) mac->tids[tid].seq_number = seq_number; } if (ieee80211_is_data(fc)) rtlpriv->cfg->ops->led_control(hw, LED_CTL_TX); }
bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb) { struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_priv *rtlpriv = rtl_priv(hw); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); u16 fc = le16_to_cpu(hdr->frame_control); if (ieee80211_is_auth(fc)) { RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, ("MAC80211_LINKING\n")); rtl_ips_nic_on(hw); mac->link_state = MAC80211_LINKING; } return true; }
static void rtl_op_sw_scan_start(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); mac->act_scanning = true; RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("\n")); if (mac->link_state == MAC80211_LINKED) { rtl_lps_leave(hw); mac->link_state = MAC80211_LINKED_SCANNING; } else { rtl_ips_nic_on(hw); } /* Dual mac */ rtlpriv->rtlhal.load_imrandiqk_setting_for2g = false; rtlpriv->cfg->ops->led_control(hw, LED_CTL_SITE_SURVEY); rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_BACKUP); }
bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb) { struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_priv *rtlpriv = rtl_priv(hw); __le16 fc = rtl_get_fc(skb); if (rtlpriv->dm.supp_phymode_switch && mac->link_state < MAC80211_LINKED && (ieee80211_is_auth(fc) || ieee80211_is_probe_req(fc))) { if (rtlpriv->cfg->ops->check_switch_to_dmdp) rtlpriv->cfg->ops->check_switch_to_dmdp(hw); } if (ieee80211_is_auth(fc)) { RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, "MAC80211_LINKING\n"); rtl_ips_nic_on(hw); mac->link_state = MAC80211_LINKING; /* Dual mac */ rtlpriv->phy.need_iqk = true; } return true; }
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 }; u8 zero_addr[ETH_ALEN] = { 0 }; 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 */ } 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; 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 * ke 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 (mac->opmode == NL80211_IFTYPE_AP) { 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; memcpy(mac_addr, zero_addr, ETH_ALEN); } 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 withnot" "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; break; case DISABLE_KEY: RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("disable key delete one entry\n")); /*set local buf about wep key. */ if (mac->opmode == NL80211_IFTYPE_AP) { 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; memcpy(mac_addr, zero_addr, ETH_ALEN); /* *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); 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; }
static int rtl_op_config(struct ieee80211_hw *hw, u32 changed) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); struct ieee80211_conf *conf = &hw->conf; mutex_lock(&rtlpriv->locks.conf_mutex); if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) { /*BIT(2)*/ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("IEEE80211_CONF_CHANGE_LISTEN_INTERVAL\n")); } /*For IPS */ if (changed & IEEE80211_CONF_CHANGE_IDLE) { if (hw->conf.flags & IEEE80211_CONF_IDLE) rtl_ips_nic_off(hw); else rtl_ips_nic_on(hw); } else { /* *although rfoff may not cause by ips, but we will *check the reason in set_rf_power_state function */ if (unlikely(ppsc->rfpwr_state == ERFOFF)) rtl_ips_nic_on(hw); } /*For LPS */ if (changed & IEEE80211_CONF_CHANGE_PS) { cancel_delayed_work(&rtlpriv->works.ps_work); cancel_delayed_work(&rtlpriv->works.ps_rfon_wq); if (conf->flags & IEEE80211_CONF_PS) { rtlpriv->psc.sw_ps_enabled = true; /* sleep here is must, or we may recv the beacon and * cause mac80211 into wrong ps state, this will cause * power save nullfunc send fail, and further cause * pkt loss, So sleep must quickly but not immediatly * because that will cause nullfunc send by mac80211 * fail, and cause pkt loss, we have tested that 5mA * is worked very well */ if (!rtlpriv->psc.multi_buffered) queue_delayed_work(rtlpriv->works.rtl_wq, &rtlpriv->works.ps_work, MSECS(5)); } else { rtl_swlps_rf_awake(hw); rtlpriv->psc.sw_ps_enabled = false; } } if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) { RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("IEEE80211_CONF_CHANGE_RETRY_LIMITS %x\n", hw->conf.long_frame_max_tx_count)); mac->retry_long = hw->conf.long_frame_max_tx_count; mac->retry_short = hw->conf.long_frame_max_tx_count; rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RETRY_LIMIT, (u8 *) (&hw->conf. long_frame_max_tx_count)); } if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { struct ieee80211_channel *channel = hw->conf.channel; u8 wide_chan = (u8) channel->hw_value; /* *because we should back channel to *current_network.chan in in scanning, *So if set_chan == current_network.chan *we should set it. *because mac80211 tell us wrong bw40 *info for cisco1253 bw20, so we modify *it here based on UPPER & LOWER */ switch (hw->conf.channel_type) { case NL80211_CHAN_HT20: case NL80211_CHAN_NO_HT: /* SC */ mac->cur_40_prime_sc = PRIME_CHNL_OFFSET_DONT_CARE; rtlphy->current_chan_bw = HT_CHANNEL_WIDTH_20; mac->bw_40 = false; break; case NL80211_CHAN_HT40MINUS: /* SC */ mac->cur_40_prime_sc = PRIME_CHNL_OFFSET_UPPER; rtlphy->current_chan_bw = HT_CHANNEL_WIDTH_20_40; mac->bw_40 = true; /*wide channel */ wide_chan -= 2; break; case NL80211_CHAN_HT40PLUS: /* SC */ mac->cur_40_prime_sc = PRIME_CHNL_OFFSET_LOWER; rtlphy->current_chan_bw = HT_CHANNEL_WIDTH_20_40; mac->bw_40 = true; /*wide channel */ wide_chan += 2; break; default: mac->bw_40 = false; RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("switch case not processed\n")); break; } if (wide_chan <= 0) wide_chan = 1; /* In scanning, before we go offchannel we may send a ps=1 null * to AP, and then we may send a ps = 0 null to AP quickly, but * first null may have caused AP to put lots of packet to hw tx * buffer. These packets must be tx'd before we go off channel * so we must delay more time to let AP flush these packets * before going offchannel, or dis-association or delete BA will * happen by AP */ if (rtlpriv->mac80211.offchan_deley) { rtlpriv->mac80211.offchan_deley = false; mdelay(50); } rtlphy->current_channel = wide_chan; rtlpriv->cfg->ops->switch_channel(hw); rtlpriv->cfg->ops->set_channel_access(hw); rtlpriv->cfg->ops->set_bw_mode(hw, hw->conf.channel_type); } mutex_unlock(&rtlpriv->locks.conf_mutex); return 0; }
static int rtl_op_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); int err = 0; if (mac->vif) { RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, ("vif has been set!! mac->vif = 0x%p\n", mac->vif)); return -EOPNOTSUPP; } rtl_ips_nic_on(hw); mutex_lock(&rtlpriv->locks.conf_mutex); switch (vif->type) { case NL80211_IFTYPE_STATION: if (mac->beacon_enabled == 1) { RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("NL80211_IFTYPE_STATION\n")); mac->beacon_enabled = 0; rtlpriv->cfg->ops->update_interrupt_mask(hw, 0, rtlpriv->cfg->maps [RTL_IBSS_INT_MASKS]); } break; case NL80211_IFTYPE_ADHOC: RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("NL80211_IFTYPE_ADHOC\n")); mac->link_state = MAC80211_LINKED; rtlpriv->cfg->ops->set_bcn_reg(hw); if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) mac->basic_rates = 0xfff; else mac->basic_rates = 0xff0; rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE, (u8 *) (&mac->basic_rates)); break; case NL80211_IFTYPE_AP: RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("NL80211_IFTYPE_AP\n")); mac->link_state = MAC80211_LINKED; rtlpriv->cfg->ops->set_bcn_reg(hw); if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) mac->basic_rates = 0xfff; else mac->basic_rates = 0xff0; rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE, (u8 *) (&mac->basic_rates)); break; default: RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("operation mode %d is not support!\n", vif->type)); err = -EOPNOTSUPP; goto out; } mac->vif = vif; mac->opmode = vif->type; rtlpriv->cfg->ops->set_network_type(hw, vif->type); memcpy(mac->mac_addr, vif->addr, ETH_ALEN); rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, mac->mac_addr); out: mutex_unlock(&rtlpriv->locks.conf_mutex); return err; }
static int rtl_op_add_interface( struct ieee80211_hw *hw, struct ieee80211_vif *vif ) { struct rtl_priv *rtlpriv = rtl_priv( hw ); struct rtl_mac *mac = rtl_mac( rtl_priv( hw ) ); int err = 0; vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; if ( mac->vif ) { RT_TRACE( rtlpriv, COMP_ERR, DBG_WARNING, "vif has been set!! mac->vif = 0x%p\n", mac->vif ); return -EOPNOTSUPP; } rtl_ips_nic_on( hw ); mutex_lock( &rtlpriv->locks.conf_mutex ); switch ( ieee80211_vif_type_p2p( vif ) ) { case NL80211_IFTYPE_P2P_CLIENT: mac->p2p = P2P_ROLE_CLIENT; /*fall through*/ case NL80211_IFTYPE_STATION: if ( mac->beacon_enabled == 1 ) { RT_TRACE( rtlpriv, COMP_MAC80211, DBG_LOUD, "NL80211_IFTYPE_STATION\n" ); mac->beacon_enabled = 0; rtlpriv->cfg->ops->update_interrupt_mask( hw, 0, rtlpriv->cfg->maps [RTL_IBSS_INT_MASKS] ); } mac->link_state = MAC80211_LINKED; break; case NL80211_IFTYPE_ADHOC: RT_TRACE( rtlpriv, COMP_MAC80211, DBG_LOUD, "NL80211_IFTYPE_ADHOC\n" ); mac->link_state = MAC80211_LINKED; rtlpriv->cfg->ops->set_bcn_reg( hw ); if ( rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G ) mac->basic_rates = 0xfff; else mac->basic_rates = 0xff0; rtlpriv->cfg->ops->set_hw_reg( hw, HW_VAR_BASIC_RATE, ( u8 * ) ( &mac->basic_rates ) ); break; case NL80211_IFTYPE_P2P_GO: mac->p2p = P2P_ROLE_GO; /*fall through*/ case NL80211_IFTYPE_AP: RT_TRACE( rtlpriv, COMP_MAC80211, DBG_LOUD, "NL80211_IFTYPE_AP\n" ); mac->link_state = MAC80211_LINKED; rtlpriv->cfg->ops->set_bcn_reg( hw ); if ( rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G ) mac->basic_rates = 0xfff; else mac->basic_rates = 0xff0; rtlpriv->cfg->ops->set_hw_reg( hw, HW_VAR_BASIC_RATE, ( u8 * ) ( &mac->basic_rates ) ); break; case NL80211_IFTYPE_MESH_POINT: RT_TRACE( rtlpriv, COMP_MAC80211, DBG_LOUD, "NL80211_IFTYPE_MESH_POINT\n" ); mac->link_state = MAC80211_LINKED; rtlpriv->cfg->ops->set_bcn_reg( hw ); if ( rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G ) mac->basic_rates = 0xfff; else mac->basic_rates = 0xff0; rtlpriv->cfg->ops->set_hw_reg( hw, HW_VAR_BASIC_RATE, ( u8 * )( &mac->basic_rates ) ); break; default: RT_TRACE( rtlpriv, COMP_ERR, DBG_EMERG, "operation mode %d is not supported!\n", vif->type ); err = -EOPNOTSUPP; goto out; } if ( mac->p2p ) { RT_TRACE( rtlpriv, COMP_MAC80211, DBG_LOUD, "p2p role %x\n", vif->type ); mac->basic_rates = 0xff0;/*disable cck rate for p2p*/ rtlpriv->cfg->ops->set_hw_reg( hw, HW_VAR_BASIC_RATE, ( u8 * )( &mac->basic_rates ) ); } mac->vif = vif; mac->opmode = vif->type; rtlpriv->cfg->ops->set_network_type( hw, vif->type ); memcpy( mac->mac_addr, vif->addr, ETH_ALEN ); rtlpriv->cfg->ops->set_hw_reg( hw, HW_VAR_ETHER_ADDR, mac->mac_addr ); out: mutex_unlock( &rtlpriv->locks.conf_mutex ); return err; }
static int rtl_op_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); int err = 0; if (mac->vif) { RT_TRACE(COMP_ERR, DBG_WARNING, ("vif has been set!! mac->vif = 0x%p\n", mac->vif)); return -EOPNOTSUPP; } /*This flag is not defined before kernel 3.4*/ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0)) vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; #endif rtl_ips_nic_on(hw); mutex_lock(&rtlpriv->locks.conf_mutex); /*<delete in kernel start>*/ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) switch (ieee80211_vif_type_p2p(vif)) { case NL80211_IFTYPE_P2P_CLIENT: mac->p2p = P2P_ROLE_CLIENT; /*fall through*/ #else /*<delete in kernel end>*/ switch (vif->type) { /*<delete in kernel start>*/ #endif /*<delete in kernel end>*/ case NL80211_IFTYPE_STATION: if (mac->beacon_enabled == 1) { RT_TRACE(COMP_MAC80211, DBG_LOUD, ("NL80211_IFTYPE_STATION \n")); mac->beacon_enabled = 0; rtlpriv->cfg->ops->update_interrupt_mask(hw, 0, rtlpriv->cfg->maps[RTL_IBSS_INT_MASKS]); } break; case NL80211_IFTYPE_ADHOC: RT_TRACE(COMP_MAC80211, DBG_LOUD, ("NL80211_IFTYPE_ADHOC \n")); mac->link_state = MAC80211_LINKED; rtlpriv->cfg->ops->set_bcn_reg(hw); if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) mac->basic_rates = 0xfff; else mac->basic_rates = 0xff0; rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE, (u8 *) (&mac->basic_rates)); break; /*<delete in kernel start>*/ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) case NL80211_IFTYPE_P2P_GO: mac->p2p = P2P_ROLE_GO; /*fall through*/ #endif /*<delete in kernel end>*/ case NL80211_IFTYPE_AP: RT_TRACE(COMP_MAC80211, DBG_LOUD, ("NL80211_IFTYPE_AP \n")); mac->link_state = MAC80211_LINKED; rtlpriv->cfg->ops->set_bcn_reg(hw); if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) mac->basic_rates = 0xfff; else mac->basic_rates = 0xff0; rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE, (u8 *) (&mac->basic_rates)); break; case NL80211_IFTYPE_MESH_POINT: RT_TRACE(COMP_MAC80211, DBG_LOUD, ("NL80211_IFTYPE_MESH_POINT \n")); mac->link_state = MAC80211_LINKED; rtlpriv->cfg->ops->set_bcn_reg(hw); if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) mac->basic_rates = 0xfff; else mac->basic_rates = 0xff0; rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE, (u8 *) (&mac->basic_rates)); break; default: RT_TRACE(COMP_ERR, DBG_EMERG, ("operation mode %d is not support!\n", vif->type)); err = -EOPNOTSUPP; goto out; } #ifdef VIF_TODO if (!rtl_set_vif_info(hw, vif)) goto out; #endif if (mac->p2p) { RT_TRACE(COMP_MAC80211, DBG_LOUD, ("p2p role %x \n",vif->type)); mac->basic_rates = 0xff0;/*disable cck rate for p2p*/ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE, (u8 *) (&mac->basic_rates)); } mac->vif = vif; mac->opmode = vif->type; rtlpriv->cfg->ops->set_network_type(hw, vif->type); memcpy(mac->mac_addr, vif->addr, ETH_ALEN); rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, mac->mac_addr); out: mutex_unlock(&rtlpriv->locks.conf_mutex); return err; } static void rtl_op_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); mutex_lock(&rtlpriv->locks.conf_mutex); /* Free beacon resources */ if ((vif->type == NL80211_IFTYPE_AP) || (vif->type == NL80211_IFTYPE_ADHOC) || (vif->type == NL80211_IFTYPE_MESH_POINT)) { if (mac->beacon_enabled == 1) { mac->beacon_enabled = 0; rtlpriv->cfg->ops->update_interrupt_mask(hw, 0, rtlpriv->cfg->maps[RTL_IBSS_INT_MASKS]); } } /* *Note: We assume NL80211_IFTYPE_UNSPECIFIED as *NO LINK for our hardware. */ mac->p2p = 0; mac->vif = NULL; mac->link_state = MAC80211_NOLINK; memset(mac->bssid, 0, 6); mac->vendor = PEER_UNKNOWN; mac->opmode = NL80211_IFTYPE_UNSPECIFIED; rtlpriv->cfg->ops->set_network_type(hw, mac->opmode); mutex_unlock(&rtlpriv->locks.conf_mutex); } /*<delete in kernel start>*/ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) /*<delete in kernel end>*/ static int rtl_op_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum nl80211_iftype new_type, bool p2p) { struct rtl_priv *rtlpriv = rtl_priv(hw); int ret; rtl_op_remove_interface(hw, vif); vif->type = new_type; vif->p2p = p2p; ret = rtl_op_add_interface(hw, vif); RT_TRACE(COMP_MAC80211, DBG_LOUD, (" p2p %x\n",p2p)); return ret; } /*<delete in kernel start>*/ #endif /*<delete in kernel end>*/ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); struct ieee80211_conf *conf = &hw->conf; if (mac->skip_scan) return 1; mutex_lock(&rtlpriv->locks.conf_mutex); if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) { /* BIT(2) */ RT_TRACE(COMP_MAC80211, DBG_LOUD, ("IEEE80211_CONF_CHANGE_LISTEN_INTERVAL\n")); } /*For IPS */ if (changed & IEEE80211_CONF_CHANGE_IDLE) { if (hw->conf.flags & IEEE80211_CONF_IDLE) rtl_ips_nic_off(hw); else rtl_ips_nic_on(hw); } else { /* *although rfoff may not cause by ips, but we will *check the reason in set_rf_power_state function */ if (unlikely(ppsc->rfpwr_state == ERFOFF)) rtl_ips_nic_on(hw); } /*For LPS */ if (changed & IEEE80211_CONF_CHANGE_PS) { cancel_delayed_work(&rtlpriv->works.ps_work); cancel_delayed_work(&rtlpriv->works.ps_rfon_wq); if (conf->flags & IEEE80211_CONF_PS) { rtlpriv->psc.sw_ps_enabled = true; /* sleep here is must, or we may recv the beacon and * cause mac80211 into wrong ps state, this will cause * power save nullfunc send fail, and further cause * pkt loss, So sleep must quickly but not immediatly * because that will cause nullfunc send by mac80211 * fail, and cause pkt loss, we have tested that 5mA * is worked very well */ if (!rtlpriv->psc.multi_buffered) queue_delayed_work(rtlpriv->works.rtl_wq, &rtlpriv->works.ps_work, MSECS(5)); } else { rtl_swlps_rf_awake(hw); rtlpriv->psc.sw_ps_enabled = false; } } if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) { RT_TRACE(COMP_MAC80211, DBG_LOUD, ("IEEE80211_CONF_CHANGE_RETRY_LIMITS %x\n", hw->conf.long_frame_max_tx_count)); mac->retry_long = hw->conf.long_frame_max_tx_count; mac->retry_short = hw->conf.long_frame_max_tx_count; rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RETRY_LIMIT, (u8 *) (&hw->conf.long_frame_max_tx_count)); } if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)) struct ieee80211_channel *channel = hw->conf.chandef.chan; enum nl80211_channel_type channel_type = cfg80211_get_chandef_type(&(hw->conf.chandef)); #else struct ieee80211_channel *channel = hw->conf.channel; enum nl80211_channel_type channel_type = hw->conf.channel_type; #endif u8 wide_chan = (u8) channel->hw_value; if (mac->act_scanning) mac->n_channels++; if (rtlpriv->dm.supp_phymode_switch && mac->link_state < MAC80211_LINKED && !mac->act_scanning) { if (rtlpriv->cfg->ops->check_switch_to_dmdp) rtlpriv->cfg->ops->check_switch_to_dmdp(hw); } /* *because we should back channel to *current_network.chan in in scanning, *So if set_chan == current_network.chan *we should set it. *because mac80211 tell us wrong bw40 *info for cisco1253 bw20, so we modify *it here based on UPPER & LOWER */ switch (channel_type) { case NL80211_CHAN_HT20: case NL80211_CHAN_NO_HT: /* SC */ mac->cur_40_prime_sc = PRIME_CHNL_OFFSET_DONT_CARE; rtlphy->current_chan_bw = HT_CHANNEL_WIDTH_20; mac->bw_40 = false; break; case NL80211_CHAN_HT40MINUS: /* SC */ mac->cur_40_prime_sc = PRIME_CHNL_OFFSET_UPPER; rtlphy->current_chan_bw = HT_CHANNEL_WIDTH_20_40; mac->bw_40 = true; /*wide channel */ wide_chan -= 2; break; case NL80211_CHAN_HT40PLUS: /* SC */ mac->cur_40_prime_sc = PRIME_CHNL_OFFSET_LOWER; rtlphy->current_chan_bw = HT_CHANNEL_WIDTH_20_40; mac->bw_40 = true; /*wide channel */ wide_chan += 2; break; default: mac->bw_40 = false; RT_TRACE(COMP_ERR, DBG_EMERG, ("switch case not processed \n")); break; } if (wide_chan <= 0) wide_chan = 1; /* in scanning, when before we offchannel we may send a ps=1 * null to AP, and then we may send a ps = 0 null to AP quickly, * but first null have cause AP's put lots of packet to hw tx * buffer, these packet must be tx before off channel so we must * delay more time to let AP flush these packets before * offchannel, or dis-association or delete BA will happen by AP */ if (rtlpriv->mac80211.offchan_deley) { rtlpriv->mac80211.offchan_deley = false; mdelay(50); } rtlphy->current_channel = wide_chan; rtlpriv->cfg->ops->switch_channel(hw); rtlpriv->cfg->ops->set_channel_access(hw); rtlpriv->cfg->ops->set_bw_mode(hw, channel_type); } mutex_unlock(&rtlpriv->locks.conf_mutex); return 0; } static void rtl_op_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *new_flags, u64 multicast) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); *new_flags &= RTL_SUPPORTED_FILTERS; if (0 == changed_flags) return; /*TODO: we disable broadcase now, so enable here */ if (changed_flags & FIF_ALLMULTI) { if (*new_flags & FIF_ALLMULTI) { mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_AM] | rtlpriv->cfg->maps[MAC_RCR_AB]; RT_TRACE(COMP_MAC80211, DBG_LOUD, ("Enable receive multicast frame.\n")); } else { mac->rx_conf &= ~(rtlpriv->cfg->maps[MAC_RCR_AM] | rtlpriv->cfg->maps[MAC_RCR_AB]); RT_TRACE(COMP_MAC80211, DBG_LOUD, ("Disable receive multicast frame.\n")); } } if (changed_flags & FIF_FCSFAIL) { if (*new_flags & FIF_FCSFAIL) { mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACRC32]; RT_TRACE(COMP_MAC80211, DBG_LOUD, ("Enable receive FCS error frame.\n")); } else { mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACRC32]; RT_TRACE(COMP_MAC80211, DBG_LOUD, ("Disable receive FCS error frame.\n")); } } /* if ssid not set to hw don't check bssid * here just used for linked scanning, & linked * and nolink check bssid is set in set network_type */ if ((changed_flags & FIF_BCN_PRBRESP_PROMISC) && (mac->link_state >= MAC80211_LINKED)) { if (mac->opmode != NL80211_IFTYPE_AP && mac->opmode != NL80211_IFTYPE_MESH_POINT) { if (*new_flags & FIF_BCN_PRBRESP_PROMISC) { rtlpriv->cfg->ops->set_chk_bssid(hw, false); } else { rtlpriv->cfg->ops->set_chk_bssid(hw, true); } } } if (changed_flags & FIF_CONTROL) { if (*new_flags & FIF_CONTROL) { mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACF]; RT_TRACE(COMP_MAC80211, DBG_LOUD, ("Enable receive control frame.\n")); } else { mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACF]; RT_TRACE(COMP_MAC80211, DBG_LOUD, ("Disable receive control frame.\n")); } } if (changed_flags & FIF_OTHER_BSS) { if (*new_flags & FIF_OTHER_BSS) { mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_AAP]; RT_TRACE(COMP_MAC80211, DBG_LOUD, ("Enable receive other BSS's frame.\n")); } else { mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_AAP]; RT_TRACE(COMP_MAC80211, DBG_LOUD, ("Disable receive other BSS's frame.\n")); } } } static int rtl_op_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_hal *rtlhal= rtl_hal(rtl_priv(hw)); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_sta_info *sta_entry; if (sta) { sta_entry = (struct rtl_sta_info *) sta->drv_priv; spin_lock_bh(&rtlpriv->locks.entry_list_lock); list_add_tail(&sta_entry->list, &rtlpriv->entry_list); spin_unlock_bh(&rtlpriv->locks.entry_list_lock); if (rtlhal->current_bandtype == BAND_ON_2_4G) { sta_entry->wireless_mode = WIRELESS_MODE_G; if (sta->supp_rates[0] <= 0xf) sta_entry->wireless_mode = WIRELESS_MODE_B; if (sta->ht_cap.ht_supported == true) sta_entry->wireless_mode = WIRELESS_MODE_N_24G; if (vif->type == NL80211_IFTYPE_ADHOC) sta_entry->wireless_mode = WIRELESS_MODE_G; } else if (rtlhal->current_bandtype == BAND_ON_5G) { sta_entry->wireless_mode = WIRELESS_MODE_A; if (sta->ht_cap.ht_supported == true) sta_entry->wireless_mode = WIRELESS_MODE_N_24G; if (vif->type == NL80211_IFTYPE_ADHOC) sta_entry->wireless_mode = WIRELESS_MODE_A; } /*disable cck rate for p2p*/ if (mac->p2p) sta->supp_rates[0] &= 0xfffffff0; memcpy(sta_entry->mac_addr, sta->addr, ETH_ALEN); RT_TRACE(COMP_MAC80211, DBG_DMESG, ("Add sta addr is %pM\n",sta->addr)); rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0); } return 0; } static int rtl_op_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_sta_info *sta_entry; if (sta) { RT_TRACE(COMP_MAC80211, DBG_DMESG, ("Remove sta addr is %pM\n",sta->addr)); sta_entry = (struct rtl_sta_info *) sta->drv_priv; sta_entry->wireless_mode = 0; sta_entry->ratr_index = 0; spin_lock_bh(&rtlpriv->locks.entry_list_lock); list_del(&sta_entry->list); spin_unlock_bh(&rtlpriv->locks.entry_list_lock); } return 0; } static int _rtl_get_hal_qnum(u16 queue) { int qnum; switch (queue) { case 0: qnum = AC3_VO; break; case 1: qnum = AC2_VI; break; case 2: qnum = AC0_BE; break; case 3: qnum = AC1_BK; break; default: qnum = AC0_BE; break; } return qnum; }