/* * handle build REPLY_TX command notification. */ static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv, struct sk_buff *skb, struct iwl_tx_cmd *tx_cmd, struct ieee80211_tx_info *info, struct ieee80211_hdr *hdr, u8 sta_id) { __le16 fc = hdr->frame_control; __le32 tx_flags = tx_cmd->tx_flags; tx_cmd->stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) tx_flags |= TX_CMD_FLG_ACK_MSK; else tx_flags &= ~TX_CMD_FLG_ACK_MSK; if (ieee80211_is_probe_resp(fc)) tx_flags |= TX_CMD_FLG_TSF_MSK; else if (ieee80211_is_back_req(fc)) tx_flags |= TX_CMD_FLG_ACK_MSK | TX_CMD_FLG_IMM_BA_RSP_MASK; else if (info->band == IEEE80211_BAND_2GHZ && cfg(priv)->bt_params && cfg(priv)->bt_params->advanced_bt_coexist && (ieee80211_is_auth(fc) || ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc) || skb->protocol == cpu_to_be16(ETH_P_PAE))) tx_flags |= TX_CMD_FLG_IGNORE_BT; tx_cmd->sta_id = sta_id; if (ieee80211_has_morefrags(fc)) tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK; if (ieee80211_is_data_qos(fc)) { u8 *qc = ieee80211_get_qos_ctl(hdr); tx_cmd->tid_tspec = qc[0] & 0xf; tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK; } else { if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; else tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK; } iwlagn_tx_cmd_protection(priv, info, fc, &tx_flags); tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK); if (ieee80211_is_mgmt(fc)) { if (ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc)) tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(3); else tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(2); } else { tx_cmd->timeout.pm_frame_timeout = 0; } tx_cmd->driver_txop = 0; tx_cmd->tx_flags = tx_flags; tx_cmd->next_frame_len = 0; }
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); __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; }
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; }
void cfg80211_rx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct ieee80211_mgmt *mgmt = (void *)buf; ASSERT_WDEV_LOCK(wdev); trace_cfg80211_rx_mlme_mgmt(dev, buf, len); if (WARN_ON(len < 2)) return; if (ieee80211_is_auth(mgmt->frame_control)) cfg80211_process_auth(wdev, buf, len); else if (ieee80211_is_deauth(mgmt->frame_control)) cfg80211_process_deauth(wdev, buf, len); else if (ieee80211_is_disassoc(mgmt->frame_control)) cfg80211_process_disassoc(wdev, buf, len); }
void mwl_rx_recv(unsigned long data) { struct ieee80211_hw *hw = (struct ieee80211_hw *)data; struct mwl_priv *priv; struct mwl_rx_desc *curr_desc; int work_done = 0; struct sk_buff *prx_skb = NULL; int pkt_len; struct ieee80211_rx_status status; struct mwl_vif *mwl_vif = NULL; struct ieee80211_hdr *wh; u32 status_mask; WLDBG_ENTER(DBG_LEVEL_4); BUG_ON(!hw); priv = hw->priv; BUG_ON(!priv); curr_desc = priv->desc_data[0].pnext_rx_desc; if (curr_desc == NULL) { status_mask = readl(priv->iobase1 + MACREG_REG_A2H_INTERRUPT_STATUS_MASK); writel(status_mask | MACREG_A2HRIC_BIT_RX_RDY, priv->iobase1 + MACREG_REG_A2H_INTERRUPT_STATUS_MASK); priv->is_rx_schedule = false; WLDBG_EXIT_INFO(DBG_LEVEL_4, "busy or no receiving packets"); return; } while ((curr_desc->rx_control == EAGLE_RXD_CTRL_DMA_OWN) && (work_done < priv->recv_limit)) { prx_skb = curr_desc->psk_buff; if (prx_skb == NULL) goto out; pci_unmap_single(priv->pdev, ENDIAN_SWAP32(curr_desc->pphys_buff_data), priv->desc_data[0].rx_buf_size, PCI_DMA_FROMDEVICE); pkt_len = curr_desc->pkt_len; if (skb_tailroom(prx_skb) < pkt_len) { WLDBG_PRINT("Critical error: not enough tail room =%x pkt_len=%x, curr_desc=%x, curr_desc_data=%x", skb_tailroom(prx_skb), pkt_len, curr_desc, curr_desc->pbuff_data); dev_kfree_skb_any(prx_skb); goto out; } if (curr_desc->channel != hw->conf.chandef.chan->hw_value) { dev_kfree_skb_any(prx_skb); goto out; } mwl_rx_prepare_status(curr_desc, &status); priv->noise = -curr_desc->noise_floor; wh = &((struct mwl_dma_data *)prx_skb->data)->wh; if (ieee80211_has_protected(wh->frame_control)) { /* Check if hw crypto has been enabled for * this bss. If yes, set the status flags * accordingly */ if (ieee80211_has_tods(wh->frame_control)) mwl_vif = mwl_rx_find_vif_bss(&priv->vif_list, wh->addr1); else mwl_vif = mwl_rx_find_vif_bss(&priv->vif_list, wh->addr2); if (mwl_vif != NULL && mwl_vif->is_hw_crypto_enabled) { /* * When MMIC ERROR is encountered * by the firmware, payload is * dropped and only 32 bytes of * mwl8k Firmware header is sent * to the host. * * We need to add four bytes of * key information. In it * MAC80211 expects keyidx set to * 0 for triggering Counter * Measure of MMIC failure. */ if (status.flag & RX_FLAG_MMIC_ERROR) { struct mwl_dma_data *tr; tr = (struct mwl_dma_data *)prx_skb->data; memset((void *)&(tr->data), 0, 4); pkt_len += 4; } if (!ieee80211_is_auth(wh->frame_control)) status.flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_DECRYPTED | RX_FLAG_MMIC_STRIPPED; } } skb_put(prx_skb, pkt_len); mwl_rx_remove_dma_header(prx_skb, curr_desc->qos_ctrl); memcpy(IEEE80211_SKB_RXCB(prx_skb), &status, sizeof(status)); ieee80211_rx(hw, prx_skb); out: mwl_rx_refill(priv, curr_desc); curr_desc->rx_control = EAGLE_RXD_CTRL_DRIVER_OWN; curr_desc->qos_ctrl = 0; curr_desc = curr_desc->pnext; work_done++; } priv->desc_data[0].pnext_rx_desc = curr_desc; status_mask = readl(priv->iobase1 + MACREG_REG_A2H_INTERRUPT_STATUS_MASK); writel(status_mask | MACREG_A2HRIC_BIT_RX_RDY, priv->iobase1 + MACREG_REG_A2H_INTERRUPT_STATUS_MASK); priv->is_rx_schedule = false; WLDBG_EXIT(DBG_LEVEL_4); }
/** * iwl_dbg_report_frame - dump frame to syslog during debug sessions * * You may hack this function to show different aspects of received frames, * including selective frame dumps. * group100 parameter selects whether to show 1 out of 100 good data frames. * All beacon and probe response frames are printed. */ static void iwl_dbg_report_frame(struct iwl_priv *priv, struct iwl_rx_phy_res *phy_res, u16 length, struct ieee80211_hdr *header, int group100) { u32 to_us; u32 print_summary = 0; u32 print_dump = 0; /* set to 1 to dump all frames' contents */ u32 hundred = 0; u32 dataframe = 0; __le16 fc; u16 seq_ctl; u16 channel; u16 phy_flags; u32 rate_n_flags; u32 tsf_low; int rssi; if (likely(!(iwl_get_debug_level(priv) & IWL_DL_RX))) return; /* MAC header */ fc = header->frame_control; seq_ctl = le16_to_cpu(header->seq_ctrl); /* metadata */ channel = le16_to_cpu(phy_res->channel); phy_flags = le16_to_cpu(phy_res->phy_flags); rate_n_flags = le32_to_cpu(phy_res->rate_n_flags); /* signal statistics */ rssi = iwl_calc_rssi(priv, phy_res); tsf_low = le64_to_cpu(phy_res->timestamp) & 0x0ffffffff; to_us = !compare_ether_addr(header->addr1, priv->mac_addr); /* if data frame is to us and all is good, * (optionally) print summary for only 1 out of every 100 */ if (to_us && (fc & ~cpu_to_le16(IEEE80211_FCTL_PROTECTED)) == cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) { dataframe = 1; if (!group100) print_summary = 1; /* print each frame */ else if (priv->framecnt_to_us < 100) { priv->framecnt_to_us++; print_summary = 0; } else { priv->framecnt_to_us = 0; print_summary = 1; hundred = 1; } } else { /* print summary for all other frames */ print_summary = 1; } if (print_summary) { char *title; int rate_idx; u32 bitrate; if (hundred) title = "100Frames"; else if (ieee80211_has_retry(fc)) title = "Retry"; else if (ieee80211_is_assoc_resp(fc)) title = "AscRsp"; else if (ieee80211_is_reassoc_resp(fc)) title = "RasRsp"; else if (ieee80211_is_probe_resp(fc)) { title = "PrbRsp"; print_dump = 1; /* dump frame contents */ } else if (ieee80211_is_beacon(fc)) { title = "Beacon"; print_dump = 1; /* dump frame contents */ } else if (ieee80211_is_atim(fc)) title = "ATIM"; else if (ieee80211_is_auth(fc)) title = "Auth"; else if (ieee80211_is_deauth(fc)) title = "DeAuth"; else if (ieee80211_is_disassoc(fc)) title = "DisAssoc"; else title = "Frame"; rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags); if (unlikely((rate_idx < 0) || (rate_idx >= IWL_RATE_COUNT))) { bitrate = 0; WARN_ON_ONCE(1); } else { bitrate = iwl_rates[rate_idx].ieee / 2; } /* print frame summary. * MAC addresses show just the last byte (for brevity), * but you can hack it to show more, if you'd like to. */ if (dataframe) IWL_DEBUG_RX(priv, "%s: mhd=0x%04x, dst=0x%02x, " "len=%u, rssi=%d, chnl=%d, rate=%u, \n", title, le16_to_cpu(fc), header->addr1[5], length, rssi, channel, bitrate); else { /* src/dst addresses assume managed mode */ IWL_DEBUG_RX(priv, "%s: 0x%04x, dst=0x%02x, src=0x%02x, " "len=%u, rssi=%d, tim=%lu usec, " "phy=0x%02x, chnl=%d\n", title, le16_to_cpu(fc), header->addr1[5], header->addr3[5], length, rssi, tsf_low - priv->scan_start_tsf, phy_flags, channel); } } if (print_dump) iwl_print_hex_dump(priv, IWL_DL_RX, header, length); }
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 {
/* * start REPLY_TX command process */ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl_station_priv *sta_priv = NULL; struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; struct iwl_device_cmd *dev_cmd = NULL; struct iwl_tx_cmd *tx_cmd; __le16 fc; u8 hdr_len; u16 len; u8 sta_id; unsigned long flags; bool is_agg = false; if (info->control.vif) ctx = iwl_rxon_ctx_from_vif(info->control.vif); spin_lock_irqsave(&priv->shrd->lock, flags); if (iwl_is_rfkill(priv->shrd)) { IWL_DEBUG_DROP(priv, "Dropping - RF KILL\n"); goto drop_unlock_priv; } fc = hdr->frame_control; #ifdef CONFIG_IWLWIFI_DEBUG if (ieee80211_is_auth(fc)) IWL_DEBUG_TX(priv, "Sending AUTH frame\n"); else if (ieee80211_is_assoc_req(fc)) IWL_DEBUG_TX(priv, "Sending ASSOC frame\n"); else if (ieee80211_is_reassoc_req(fc)) IWL_DEBUG_TX(priv, "Sending REASSOC frame\n"); #endif if (unlikely(ieee80211_is_probe_resp(fc))) { struct iwl_wipan_noa_data *noa_data = rcu_dereference(priv->noa_data); if (noa_data && pskb_expand_head(skb, 0, noa_data->length, GFP_ATOMIC) == 0) { memcpy(skb_put(skb, noa_data->length), noa_data->data, noa_data->length); hdr = (struct ieee80211_hdr *)skb->data; } } hdr_len = ieee80211_hdrlen(fc); /* For management frames use broadcast id to do not break aggregation */ if (!ieee80211_is_data(fc)) sta_id = ctx->bcast_sta_id; else { /* Find index into station table for destination station */ sta_id = iwl_sta_id_or_broadcast(priv, ctx, info->control.sta); if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", hdr->addr1); goto drop_unlock_priv; } } IWL_DEBUG_TX(priv, "station Id %d\n", sta_id); if (info->control.sta) sta_priv = (void *)info->control.sta->drv_priv; if (sta_priv && sta_priv->asleep && (info->flags & IEEE80211_TX_CTL_POLL_RESPONSE)) { /* * This sends an asynchronous command to the device, * but we can rely on it being processed before the * next frame is processed -- and the next frame to * this station is the one that will consume this * counter. * For now set the counter to just 1 since we do not * support uAPSD yet. */ iwl_sta_modify_sleep_tx_count(priv, sta_id, 1); } if (info->flags & IEEE80211_TX_CTL_AMPDU) is_agg = true; /* irqs already disabled/saved above when locking priv->shrd->lock */ spin_lock(&priv->shrd->sta_lock); dev_cmd = kmem_cache_alloc(priv->tx_cmd_pool, GFP_ATOMIC); if (unlikely(!dev_cmd)) goto drop_unlock_sta; memset(dev_cmd, 0, sizeof(*dev_cmd)); tx_cmd = (struct iwl_tx_cmd *) dev_cmd->payload; /* Total # bytes to be transmitted */ len = (u16)skb->len; tx_cmd->len = cpu_to_le16(len); if (info->control.hw_key) iwlagn_tx_cmd_build_hwcrypto(priv, info, tx_cmd, skb, sta_id); /* TODO need this for burst mode later on */ iwlagn_tx_cmd_build_basic(priv, skb, tx_cmd, info, hdr, sta_id); iwl_dbg_log_tx_data_frame(priv, len, hdr); iwlagn_tx_cmd_build_rate(priv, tx_cmd, info, fc); iwl_update_stats(priv, true, fc, len); memset(&info->status, 0, sizeof(info->status)); info->driver_data[0] = ctx; info->driver_data[1] = dev_cmd; if (iwl_trans_tx(trans(priv), skb, dev_cmd, ctx->ctxid, sta_id)) goto drop_unlock_sta; spin_unlock(&priv->shrd->sta_lock); spin_unlock_irqrestore(&priv->shrd->lock, flags); /* * Avoid atomic ops if it isn't an associated client. * Also, if this is a packet for aggregation, don't * increase the counter because the ucode will stop * aggregation queues when their respective station * goes to sleep. */ if (sta_priv && sta_priv->client && !is_agg) atomic_inc(&sta_priv->pending_frames); return 0; drop_unlock_sta: if (dev_cmd) kmem_cache_free(priv->tx_cmd_pool, dev_cmd); spin_unlock(&priv->shrd->sta_lock); drop_unlock_priv: spin_unlock_irqrestore(&priv->shrd->lock, flags); return -1; }