/* * Copyright (c) 2014 Redpine Signals Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/** * rsi_is_cipher_wep() - This function determines if the cipher is WEP or not. * @common: Pointer to the driver private structure. * * Return: If cipher type is WEP, a value of 1 is returned, else 0.
*/
/** * rsi_register_rates_channels() - This function registers channels and rates. * @adapter: Pointer to the adapter structure. * @band: Operating band to be set. * * Return: int - 0 on success, negative error on failure.
*/ staticint rsi_register_rates_channels(struct rsi_hw *adapter, int band)
{ struct ieee80211_supported_band *sbands = &adapter->sbands[band]; void *channels = NULL;
/** * rsi_mac80211_detach() - This function is used to de-initialize the * Mac80211 stack. * @adapter: Pointer to the adapter structure. * * Return: None.
*/ void rsi_mac80211_detach(struct rsi_hw *adapter)
{ struct ieee80211_hw *hw = adapter->hw; enum nl80211_band band;
if (hw) {
ieee80211_stop_queues(hw);
ieee80211_unregister_hw(hw);
ieee80211_free_hw(hw);
adapter->hw = NULL;
}
for (band = 0; band < NUM_NL80211_BANDS; band++) { struct ieee80211_supported_band *sband =
&adapter->sbands[band];
/** * rsi_mac80211_tx() - This is the handler that 802.11 module calls for each * transmitted frame.SKB contains the buffer starting * from the IEEE 802.11 header. * @hw: Pointer to the ieee80211_hw structure. * @control: Pointer to the ieee80211_tx_control structure * @skb: Pointer to the socket buffer structure. * * Return: None
*/ staticvoid rsi_mac80211_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb)
{ struct rsi_hw *adapter = hw->priv; struct rsi_common *common = adapter->priv; struct ieee80211_hdr *wlh = (struct ieee80211_hdr *)skb->data;
if (ieee80211_is_auth(wlh->frame_control))
common->mac_ops_resumed = false;
rsi_core_xmit(common, skb);
}
/** * rsi_mac80211_start() - This is first handler that 802.11 module calls, since * the driver init is complete by then, just * returns success. * @hw: Pointer to the ieee80211_hw structure. * * Return: 0 as success.
*/ staticint rsi_mac80211_start(struct ieee80211_hw *hw)
{ struct rsi_hw *adapter = hw->priv; struct rsi_common *common = adapter->priv;
/** * rsi_mac80211_stop() - This is the last handler that 802.11 module calls. * @hw: Pointer to the ieee80211_hw structure. * @suspend: true if the this was called from suspend flow. * * Return: None.
*/ staticvoid rsi_mac80211_stop(struct ieee80211_hw *hw, bool suspend)
{ struct rsi_hw *adapter = hw->priv; struct rsi_common *common = adapter->priv;
rsi_dbg(ERR_ZONE, "===> Interface DOWN <===\n");
mutex_lock(&common->mutex);
common->iface_down = true;
wiphy_rfkill_stop_polling(hw->wiphy);
/* Block all rx frames */
rsi_send_rx_filter_frame(common, 0xffff);
mutex_unlock(&common->mutex);
}
staticint rsi_map_intf_mode(enum nl80211_iftype vif_type)
{ switch (vif_type) { case NL80211_IFTYPE_STATION: return RSI_OPMODE_STA; case NL80211_IFTYPE_AP: return RSI_OPMODE_AP; case NL80211_IFTYPE_P2P_DEVICE: return RSI_OPMODE_P2P_CLIENT; case NL80211_IFTYPE_P2P_CLIENT: return RSI_OPMODE_P2P_CLIENT; case NL80211_IFTYPE_P2P_GO: return RSI_OPMODE_P2P_GO; default: return RSI_OPMODE_UNSUPPORTED;
}
}
/** * rsi_mac80211_add_interface() - This function is called when a netdevice * attached to the hardware is enabled. * @hw: Pointer to the ieee80211_hw structure. * @vif: Pointer to the ieee80211_vif structure. * * Return: ret: 0 on success, negative error code on failure.
*/ staticint rsi_mac80211_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{ struct rsi_hw *adapter = hw->priv; struct rsi_common *common = adapter->priv; struct vif_priv *vif_info = (struct vif_priv *)vif->drv_priv; enum opmode intf_mode; enum vap_status vap_status; int vap_idx = -1, i;
intf_mode = rsi_map_intf_mode(vif->type); if (intf_mode == RSI_OPMODE_UNSUPPORTED) {
rsi_dbg(ERR_ZONE, "%s: Interface type %d not supported\n", __func__,
vif->type);
mutex_unlock(&common->mutex); return -EOPNOTSUPP;
} if ((vif->type == NL80211_IFTYPE_P2P_DEVICE) ||
(vif->type == NL80211_IFTYPE_P2P_CLIENT) ||
(vif->type == NL80211_IFTYPE_P2P_GO))
common->p2p_enabled = true;
/* Get free vap index */ for (i = 0; i < RSI_MAX_VIFS; i++) { if (!adapter->vifs[i] ||
!memcmp(vif->addr, adapter->vifs[i]->addr, ETH_ALEN)) {
vap_idx = i; break;
}
} if (vap_idx < 0) {
rsi_dbg(ERR_ZONE, "Reject: Max VAPs reached\n");
mutex_unlock(&common->mutex); return -EOPNOTSUPP;
}
vif_info->vap_id = vap_idx;
adapter->vifs[vap_idx] = vif;
adapter->sc_nvifs++;
vap_status = VAP_ADD;
if (rsi_set_vap_capabilities(common, intf_mode, vif->addr,
vif_info->vap_id, vap_status)) {
rsi_dbg(ERR_ZONE, "Failed to set VAP capabilities\n");
mutex_unlock(&common->mutex); return -EINVAL;
}
if ((vif->type == NL80211_IFTYPE_AP) ||
(vif->type == NL80211_IFTYPE_P2P_GO)) {
rsi_send_rx_filter_frame(common, DISALLOW_BEACONS); for (i = 0; i < common->max_stations; i++)
common->stations[i].sta = NULL;
}
mutex_unlock(&common->mutex);
return 0;
}
/** * rsi_mac80211_remove_interface() - This function notifies driver that an * interface is going down. * @hw: Pointer to the ieee80211_hw structure. * @vif: Pointer to the ieee80211_vif structure. * * Return: None.
*/ staticvoid rsi_mac80211_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{ struct rsi_hw *adapter = hw->priv; struct rsi_common *common = adapter->priv; enum opmode opmode; int i;
rsi_dbg(INFO_ZONE, "Remove Interface Called\n");
mutex_lock(&common->mutex);
if (adapter->sc_nvifs <= 0) {
mutex_unlock(&common->mutex); return;
}
opmode = rsi_map_intf_mode(vif->type); if (opmode == RSI_OPMODE_UNSUPPORTED) {
rsi_dbg(ERR_ZONE, "Opmode error : %d\n", opmode);
mutex_unlock(&common->mutex); return;
} for (i = 0; i < RSI_MAX_VIFS; i++) { if (!adapter->vifs[i]) continue; if (vif == adapter->vifs[i]) {
rsi_set_vap_capabilities(common, opmode, vif->addr,
i, VAP_DELETE);
adapter->sc_nvifs--;
adapter->vifs[i] = NULL;
}
}
mutex_unlock(&common->mutex);
}
/** * rsi_channel_change() - This function is a performs the checks * required for changing a channel and sets * the channel accordingly. * @hw: Pointer to the ieee80211_hw structure. * * Return: 0 on success, negative error code on failure.
*/ staticint rsi_channel_change(struct ieee80211_hw *hw)
{ struct rsi_hw *adapter = hw->priv; struct rsi_common *common = adapter->priv; int status = -EOPNOTSUPP; struct ieee80211_channel *curchan = hw->conf.chandef.chan;
u16 channel = curchan->hw_value; struct ieee80211_vif *vif; bool assoc = false; int i;
for (i = 0; i < RSI_MAX_VIFS; i++) {
vif = adapter->vifs[i]; if (!vif) continue; if (vif->type == NL80211_IFTYPE_STATION) { if (vif->cfg.assoc) {
assoc = true; break;
}
}
} if (assoc) { if (!common->hw_data_qs_blocked &&
(rsi_get_connected_channel(vif) != channel)) {
rsi_dbg(INFO_ZONE, "blk data q %d\n", channel); if (!rsi_send_block_unblock_frame(common, true))
common->hw_data_qs_blocked = true;
}
}
status = rsi_band_check(common, curchan); if (!status)
status = rsi_set_channel(adapter->priv, curchan);
if (assoc) { if (common->hw_data_qs_blocked &&
(rsi_get_connected_channel(vif) == channel)) {
rsi_dbg(INFO_ZONE, "unblk data q %d\n", channel); if (!rsi_send_block_unblock_frame(common, false))
common->hw_data_qs_blocked = false;
}
}
return status;
}
/** * rsi_config_power() - This function configures tx power to device * @hw: Pointer to the ieee80211_hw structure. * * Return: 0 on success, negative error code on failure.
*/ staticint rsi_config_power(struct ieee80211_hw *hw)
{ struct rsi_hw *adapter = hw->priv; struct rsi_common *common = adapter->priv; struct ieee80211_conf *conf = &hw->conf;
if (adapter->sc_nvifs <= 0) {
rsi_dbg(ERR_ZONE, "%s: No virtual interface found\n", __func__); return -EINVAL;
}
rsi_dbg(INFO_ZONE, "%s: Set tx power: %d dBM\n", __func__, conf->power_level);
if (conf->power_level == common->tx_power) return 0;
common->tx_power = conf->power_level;
return rsi_send_radio_params_update(common);
}
/** * rsi_mac80211_config() - This function is a handler for configuration * requests. The stack calls this function to * change hardware configuration, e.g., channel. * @hw: Pointer to the ieee80211_hw structure. * @radio_idx: Radio index. * @changed: Changed flags set. * * Return: 0 on success, negative error code on failure.
*/ staticint rsi_mac80211_config(struct ieee80211_hw *hw, int radio_idx,
u32 changed)
{ struct rsi_hw *adapter = hw->priv; struct rsi_common *common = adapter->priv; struct ieee80211_conf *conf = &hw->conf; int status = -EOPNOTSUPP;
mutex_lock(&common->mutex);
if (changed & IEEE80211_CONF_CHANGE_CHANNEL)
status = rsi_channel_change(hw);
/* tx power */ if (changed & IEEE80211_CONF_CHANGE_POWER) {
rsi_dbg(INFO_ZONE, "%s: Configuring Power\n", __func__);
status = rsi_config_power(hw);
}
/* Power save parameters */ if ((changed & IEEE80211_CONF_CHANGE_PS) &&
!common->mac_ops_resumed) { struct ieee80211_vif *vif, *sta_vif = NULL; unsignedlong flags; int i, set_ps = 1;
for (i = 0; i < RSI_MAX_VIFS; i++) {
vif = adapter->vifs[i]; if (!vif) continue; /* Don't go to power save if AP vap exists */ if ((vif->type == NL80211_IFTYPE_AP) ||
(vif->type == NL80211_IFTYPE_P2P_GO)) {
set_ps = 0; break;
} if ((vif->type == NL80211_IFTYPE_STATION ||
vif->type == NL80211_IFTYPE_P2P_CLIENT) &&
(!sta_vif || vif->cfg.assoc))
sta_vif = vif;
} if (set_ps && sta_vif) {
spin_lock_irqsave(&adapter->ps_lock, flags); if (conf->flags & IEEE80211_CONF_PS)
rsi_enable_ps(adapter, sta_vif); else
rsi_disable_ps(adapter, sta_vif);
spin_unlock_irqrestore(&adapter->ps_lock, flags);
}
}
/* RTS threshold */ if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
rsi_dbg(INFO_ZONE, "RTS threshold\n"); if ((common->rts_threshold) <= IEEE80211_MAX_RTS_THRESHOLD) {
rsi_dbg(INFO_ZONE, "%s: Sending vap updates....\n", __func__);
status = rsi_send_vap_dynamic_update(common);
}
}
mutex_unlock(&common->mutex);
return status;
}
/** * rsi_get_connected_channel() - This function is used to get the current * connected channel number. * @vif: Pointer to the ieee80211_vif structure. * * Return: Current connected AP's channel number is returned.
*/
u16 rsi_get_connected_channel(struct ieee80211_vif *vif)
{ struct ieee80211_bss_conf *bss; struct ieee80211_channel *channel;
switch (action) { case IEEE80211_AMPDU_RX_START:
status = rsi_send_aggregation_params_frame(common,
tid,
seq_no,
buf_size,
STA_RX_ADDBA_DONE,
sta_id); break;
case IEEE80211_AMPDU_RX_STOP:
status = rsi_send_aggregation_params_frame(common,
tid,
0,
buf_size,
STA_RX_DELBA,
sta_id); break;
case IEEE80211_AMPDU_TX_START: if ((vif->type == NL80211_IFTYPE_STATION) ||
(vif->type == NL80211_IFTYPE_P2P_CLIENT))
common->vif_info[ii].seq_start = seq_no; elseif ((vif->type == NL80211_IFTYPE_AP) ||
(vif->type == NL80211_IFTYPE_P2P_GO))
rsta->seq_start[tid] = seq_no;
status = IEEE80211_AMPDU_TX_START_IMMEDIATE; break;
case IEEE80211_AMPDU_TX_STOP_CONT: case IEEE80211_AMPDU_TX_STOP_FLUSH: case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
status = rsi_send_aggregation_params_frame(common,
tid,
seq_no,
buf_size,
STA_TX_DELBA,
sta_id); if (!status)
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break;
for (i = 0; i < RSI_MAX_VIFS; i++) {
vif = adapter->vifs[i]; if (!vif) continue; if (vif->type == NL80211_IFTYPE_STATION) {
bss = &vif->bss_conf; break;
}
} if (!bss) return; /* CQM only for connected AP beacons, the RSSI is a weighted avg */ if (vif->cfg.assoc && !(memcmp(bss->bssid, hdr->addr2, ETH_ALEN))) { if (ieee80211_is_beacon(hdr->frame_control))
rsi_perform_cqm(common, hdr->addr2, rxs->signal, vif);
}
return;
}
/** * rsi_indicate_pkt_to_os() - This function sends received packet to mac80211. * @common: Pointer to the driver private structure. * @skb: Pointer to the socket buffer structure. * * Return: None.
*/ void rsi_indicate_pkt_to_os(struct rsi_common *common, struct sk_buff *skb)
{ struct rsi_hw *adapter = common->priv; struct ieee80211_hw *hw = adapter->hw; struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
if ((common->iface_down) || (!adapter->sc_nvifs)) {
dev_kfree_skb(skb); return;
}
/* filling in the ieee80211_rx_status flags */
rsi_fill_rx_status(hw, skb, common, rx_status);
ieee80211_rx_irqsafe(hw, skb);
}
/** * rsi_mac80211_sta_add() - This function notifies driver about a peer getting * connected. * @hw: pointer to the ieee80211_hw structure. * @vif: Pointer to the ieee80211_vif structure. * @sta: Pointer to the ieee80211_sta structure. * * Return: 0 on success, negative error codes on failure.
*/ staticint rsi_mac80211_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta)
{ struct rsi_hw *adapter = hw->priv; struct rsi_common *common = adapter->priv; bool sta_exist = false; struct rsi_sta *rsta; int status = 0;
/** * rsi_mac80211_set_antenna() - This function is used to configure * tx and rx antennas. * @hw: Pointer to the ieee80211_hw structure. * @radio_idx: Radio index * @tx_ant: Bitmap for tx antenna * @rx_ant: Bitmap for rx antenna * * Return: 0 on success, Negative error code on failure.
*/ staticint rsi_mac80211_set_antenna(struct ieee80211_hw *hw, int radio_idx,
u32 tx_ant, u32 rx_ant)
{ struct rsi_hw *adapter = hw->priv; struct rsi_common *common = adapter->priv;
u8 antenna = 0;
if (tx_ant > 1 || rx_ant > 1) {
rsi_dbg(ERR_ZONE, "Invalid antenna selection (tx: %d, rx:%d)\n",
tx_ant, rx_ant);
rsi_dbg(ERR_ZONE, "Use 0 for int_ant, 1 for ext_ant\n"); return -EINVAL;
}
/** * rsi_mac80211_get_antenna() - This function is used to configure * tx and rx antennas. * * @hw: Pointer to the ieee80211_hw structure. * @radio_idx: Radio index * @tx_ant: Bitmap for tx antenna * @rx_ant: Bitmap for rx antenna * * Return: 0 on success, negative error codes on failure.
*/ staticint rsi_mac80211_get_antenna(struct ieee80211_hw *hw, int radio_idx,
u32 *tx_ant, u32 *rx_ant)
{ struct rsi_hw *adapter = hw->priv; struct rsi_common *common = adapter->priv;
if (common->hibernate_resume) {
common->mac_ops_resumed = true; /* Device need a complete restart of all MAC operations. * returning 1 will serve this purpose.
*/ return 1;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.