static int mwl_mac80211_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mwl_priv *priv = hw->priv; struct mwl_vif *mwl_vif; struct mwl_sta *sta_info; struct ieee80211_key_conf *key; int rc; int i; mwl_vif = mwl_dev_get_vif(vif); sta_info = mwl_dev_get_sta(sta); memset(sta_info, 0, sizeof(*sta_info)); if (vif->type == NL80211_IFTYPE_MESH_POINT) { sta_info->is_mesh_node = true; /* Patch mesh interface for HT based on 88W8897. When authsae or * wpa_supplicant is used for mesh security, HT capbility wan't * be set. This would be removed if problem is fixed. */ sta->ht_cap.ht_supported = true; sta->ht_cap.cap = 0x6f; sta->ht_cap.mcs.rx_mask[0] = 0xff; sta->ht_cap.mcs.rx_mask[1] = 0xff; sta->ht_cap.ampdu_factor = 0x3; sta->ht_cap.ampdu_density = 0x5; } if (sta->ht_cap.ht_supported) { sta_info->is_ampdu_allowed = true; sta_info->is_amsdu_allowed = false; if (sta->ht_cap.cap & IEEE80211_HT_CAP_MAX_AMSDU) sta_info->amsdu_ctrl.cap = MWL_AMSDU_SIZE_8K; else sta_info->amsdu_ctrl.cap = MWL_AMSDU_SIZE_4K; } sta_info->iv16 = 1; sta_info->iv32 = 0; spin_lock_init(&sta_info->amsdu_lock); spin_lock_bh(&priv->sta_lock); list_add_tail(&sta_info->list, &priv->sta_list); spin_unlock_bh(&priv->sta_lock); if (vif->type == NL80211_IFTYPE_STATION) mwl_fwcmd_set_new_stn_del(hw, vif, sta->addr); rc = mwl_fwcmd_set_new_stn_add(hw, vif, sta); for (i = 0; i < NUM_WEP_KEYS; i++) { key = (struct ieee80211_key_conf *)mwl_vif->wep_key_conf[i].key; if (mwl_vif->wep_key_conf[i].enabled) mwl_mac80211_set_key(hw, SET_KEY, vif, sta, key); } return rc; }
static int mwl_mac80211_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd_param, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key) { struct mwl_vif *mwl_vif; int rc = 0; u8 encr_type; u8 *addr; mwl_vif = mwl_dev_get_vif(vif); if (!sta) { addr = vif->addr; } else { addr = sta->addr; if (vif->type == NL80211_IFTYPE_STATION) ether_addr_copy(mwl_vif->bssid, addr); } if (cmd_param == SET_KEY) { rc = mwl_fwcmd_encryption_set_key(hw, vif, addr, key); if (rc) goto out; if ((key->cipher == WLAN_CIPHER_SUITE_WEP40) || (key->cipher == WLAN_CIPHER_SUITE_WEP104)) { encr_type = ENCR_TYPE_WEP; } else if (key->cipher == WLAN_CIPHER_SUITE_CCMP) { encr_type = ENCR_TYPE_AES; if ((key->flags & IEEE80211_KEY_FLAG_PAIRWISE) == 0) { if (vif->type != NL80211_IFTYPE_STATION) mwl_vif->keyidx = key->keyidx; } } else if (key->cipher == WLAN_CIPHER_SUITE_TKIP) { encr_type = ENCR_TYPE_TKIP; } else { encr_type = ENCR_TYPE_DISABLE; } rc = mwl_fwcmd_update_encryption_enable(hw, vif, addr, encr_type); if (rc) goto out; mwl_vif->is_hw_crypto_enabled = true; } else { rc = mwl_fwcmd_encryption_remove_key(hw, vif, addr, key); if (rc) goto out; } out: return rc; }
static void mwl_mac80211_remove_vif(struct mwl_priv *priv, struct ieee80211_vif *vif) { struct mwl_vif *mwl_vif = mwl_dev_get_vif(vif); if (!priv->macids_used) return; mwl_tx_del_pkts_via_vif(priv->hw, vif); priv->macids_used &= ~(1 << mwl_vif->macid); spin_lock_bh(&priv->vif_lock); list_del(&mwl_vif->list); spin_unlock_bh(&priv->vif_lock); }
static inline void mwl_tx_skb(struct mwl_priv *priv, int desc_num, struct sk_buff *tx_skb) { struct ieee80211_tx_info *tx_info; struct mwl_tx_ctrl *tx_ctrl; struct mwl_tx_hndl *tx_hndl; struct mwl_tx_desc *tx_desc; struct ieee80211_sta *sta; struct ieee80211_vif *vif; struct mwl_vif *mwl_vif; struct ieee80211_key_conf *k_conf; bool ccmp = false; struct mwl_dma_data *dma_data; struct ieee80211_hdr *wh; dma_addr_t dma; if (WARN_ON(!tx_skb)) return; tx_info = IEEE80211_SKB_CB(tx_skb); tx_ctrl = (struct mwl_tx_ctrl *)&tx_info->status; sta = (struct ieee80211_sta *)tx_ctrl->sta; vif = (struct ieee80211_vif *)tx_ctrl->vif; mwl_vif = mwl_dev_get_vif(vif); k_conf = (struct ieee80211_key_conf *)tx_ctrl->k_conf; mwl_tx_encapsulate_frame(priv, tx_skb, k_conf, &ccmp); dma_data = (struct mwl_dma_data *)tx_skb->data; wh = &dma_data->wh; if (ieee80211_is_data(wh->frame_control) || (ieee80211_is_mgmt(wh->frame_control) && ieee80211_has_protected(wh->frame_control) && !is_multicast_ether_addr(wh->addr1))) { if (is_multicast_ether_addr(wh->addr1)) { if (ccmp) { mwl_tx_insert_ccmp_hdr(dma_data->data, mwl_vif->keyidx, mwl_vif->iv16, mwl_vif->iv32); INCREASE_IV(mwl_vif->iv16, mwl_vif->iv32); } } else { if (ccmp) { if (vif->type == NL80211_IFTYPE_STATION) { mwl_tx_insert_ccmp_hdr(dma_data->data, mwl_vif->keyidx, mwl_vif->iv16, mwl_vif->iv32); INCREASE_IV(mwl_vif->iv16, mwl_vif->iv32); } else { struct mwl_sta *sta_info; sta_info = mwl_dev_get_sta(sta); mwl_tx_insert_ccmp_hdr(dma_data->data, 0, sta_info->iv16, sta_info->iv32); INCREASE_IV(sta_info->iv16, sta_info->iv32); } } } } tx_hndl = priv->desc_data[desc_num].pnext_tx_hndl; tx_hndl->psk_buff = tx_skb; tx_desc = tx_hndl->pdesc; tx_desc->tx_priority = tx_ctrl->tx_priority; tx_desc->qos_ctrl = cpu_to_le16(tx_ctrl->qos_ctrl); tx_desc->pkt_len = cpu_to_le16(tx_skb->len); tx_desc->packet_info = 0; tx_desc->data_rate = 0; tx_desc->type = tx_ctrl->type; tx_desc->xmit_control = tx_ctrl->xmit_control; tx_desc->sap_pkt_info = 0; dma = pci_map_single(priv->pdev, tx_skb->data, tx_skb->len, PCI_DMA_TODEVICE); if (pci_dma_mapping_error(priv->pdev, dma)) { dev_kfree_skb_any(tx_skb); wiphy_err(priv->hw->wiphy, "failed to map pci memory!\n"); return; } tx_desc->pkt_ptr = cpu_to_le32(dma); tx_desc->status = cpu_to_le32(EAGLE_TXD_STATUS_FW_OWNED); /* make sure all the memory transactions done by cpu were completed */ wmb(); /*Data Memory Barrier*/ writel(MACREG_H2ARIC_BIT_PPA_READY, priv->iobase1 + MACREG_REG_H2A_INTERRUPT_EVENTS); priv->desc_data[desc_num].pnext_tx_hndl = tx_hndl->pnext; priv->fw_desc_cnt[desc_num]++; }
static int mwl_mac80211_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mwl_priv *priv = hw->priv; struct mwl_vif *mwl_vif; u32 macids_supported; int macid; switch (vif->type) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_MESH_POINT: macids_supported = priv->ap_macids_supported; break; case NL80211_IFTYPE_STATION: macids_supported = priv->sta_macids_supported; break; default: return -EINVAL; } macid = ffs(macids_supported & ~priv->macids_used); if (!macid) { wiphy_warn(hw->wiphy, "no macid can be allocated\n"); return -EBUSY; } macid--; /* Setup driver private area. */ mwl_vif = mwl_dev_get_vif(vif); memset(mwl_vif, 0, sizeof(*mwl_vif)); mwl_vif->macid = macid; mwl_vif->seqno = 0; mwl_vif->is_hw_crypto_enabled = false; mwl_vif->beacon_info.valid = false; mwl_vif->iv16 = 1; mwl_vif->iv32 = 0; mwl_vif->keyidx = 0; switch (vif->type) { case NL80211_IFTYPE_AP: ether_addr_copy(mwl_vif->bssid, vif->addr); mwl_fwcmd_set_new_stn_add_self(hw, vif); break; case NL80211_IFTYPE_MESH_POINT: ether_addr_copy(mwl_vif->bssid, vif->addr); mwl_fwcmd_set_new_stn_add_self(hw, vif); break; case NL80211_IFTYPE_STATION: ether_addr_copy(mwl_vif->sta_mac, vif->addr); mwl_fwcmd_bss_start(hw, vif, true); mwl_fwcmd_set_infra_mode(hw, vif); mwl_fwcmd_set_mac_addr_client(hw, vif, vif->addr); break; default: return -EINVAL; } priv->macids_used |= 1 << mwl_vif->macid; spin_lock_bh(&priv->vif_lock); list_add_tail(&mwl_vif->list, &priv->vif_list); spin_unlock_bh(&priv->vif_lock); return 0; }
void pcie_tx_xmit_ndp(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb) { struct mwl_priv *priv = hw->priv; struct pcie_priv *pcie_priv = priv->hif.priv; struct ieee80211_tx_info *tx_info; struct ieee80211_key_conf *k_conf; struct mwl_vif *mwl_vif; int index; struct ieee80211_sta *sta; struct mwl_sta *sta_info; struct ieee80211_hdr *wh; u8 *da; u16 qos; u8 tid = 0; struct mwl_ampdu_stream *stream = NULL; u16 tx_que_priority; bool mgmtframe = false; struct ieee80211_mgmt *mgmt; bool eapol_frame = false; bool start_ba_session = false; struct pcie_tx_ctrl_ndp *tx_ctrl; tx_info = IEEE80211_SKB_CB(skb); k_conf = tx_info->control.hw_key; mwl_vif = mwl_dev_get_vif(tx_info->control.vif); index = skb_get_queue_mapping(skb); sta = control->sta; sta_info = sta ? mwl_dev_get_sta(sta) : NULL; wh = (struct ieee80211_hdr *)skb->data; if (ieee80211_is_data_qos(wh->frame_control)) qos = le16_to_cpu(*((__le16 *)ieee80211_get_qos_ctl(wh))); else qos = 0xFFFF; if (skb->protocol == cpu_to_be16(ETH_P_PAE)) { index = IEEE80211_AC_VO; eapol_frame = true; } if (ieee80211_is_mgmt(wh->frame_control)) { mgmtframe = true; mgmt = (struct ieee80211_mgmt *)skb->data; } if (mgmtframe) { u16 capab; if (unlikely(ieee80211_is_action(wh->frame_control) && mgmt->u.action.category == WLAN_CATEGORY_BACK && mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ)) { capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; index = utils_tid_to_ac(tid); } if (unlikely(ieee80211_is_assoc_req(wh->frame_control))) utils_add_basic_rates(hw->conf.chandef.chan->band, skb); if (ieee80211_is_probe_req(wh->frame_control) || ieee80211_is_probe_resp(wh->frame_control)) tx_que_priority = PROBE_RESPONSE_TXQNUM; else { if (( (mwl_vif->macid == SYSADPT_NUM_OF_AP) && (!ieee80211_has_protected(wh->frame_control) || (ieee80211_has_protected(wh->frame_control) && ieee80211_is_auth(wh->frame_control))) ) || !sta || ieee80211_is_auth(wh->frame_control) || ieee80211_is_assoc_req(wh->frame_control) || ieee80211_is_assoc_resp(wh->frame_control)) tx_que_priority = MGMT_TXQNUM; else { if (is_multicast_ether_addr(wh->addr1) && (mwl_vif->macid != SYSADPT_NUM_OF_AP)) tx_que_priority = mwl_vif->macid * SYSADPT_MAX_TID; else tx_que_priority = SYSADPT_MAX_TID * (sta_info->stnid + QUEUE_STAOFFSET) + 6; } } if (ieee80211_is_assoc_resp(wh->frame_control) || ieee80211_is_reassoc_resp(wh->frame_control)) { struct sk_buff *ack_skb; struct ieee80211_tx_info *ack_info; ack_skb = skb_copy(skb, GFP_ATOMIC); ack_info = IEEE80211_SKB_CB(ack_skb); pcie_tx_prepare_info(priv, 0, ack_info); ieee80211_tx_status(hw, ack_skb); } pcie_tx_encapsulate_frame(priv, skb, k_conf, NULL); } else {