/* This function will dispatch amsdu packet and forward it to kernel/upper * layer.
*/ staticint mwifiex_11n_dispatch_amsdu_pkt(struct mwifiex_private *priv, struct sk_buff *skb)
{ struct rxpd *local_rx_pd = (struct rxpd *)(skb->data); int ret;
if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
ret = mwifiex_uap_recv_packet(priv, rx_skb); else
ret = mwifiex_recv_packet(priv, rx_skb); if (ret == -1)
mwifiex_dbg(priv->adapter, ERROR, "Rx of A-MSDU failed");
} return 0;
}
return -1;
}
/* This function will process the rx packet and forward it to kernel/upper * layer.
*/ staticint mwifiex_11n_dispatch_pkt(struct mwifiex_private *priv, struct sk_buff *payload)
{
int ret;
if (!payload) {
mwifiex_dbg(priv->adapter, INFO, "info: fw drop data\n"); return 0;
}
ret = mwifiex_11n_dispatch_amsdu_pkt(priv, payload); if (!ret) return 0;
if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) return mwifiex_handle_uap_rx_forward(priv, payload);
/* * This function dispatches all packets in the Rx reorder table until the * start window. * * There could be holes in the buffer, which are skipped by the function. * Since the buffer is linear, the function uses rotation to simulate * circular buffer.
*/ staticvoid
mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv, struct mwifiex_rx_reorder_tbl *tbl, int start_win)
{ struct sk_buff_head list; struct sk_buff *skb; int pkt_to_send, i;
for (i = 0; i < pkt_to_send; ++i) { if (tbl->rx_reorder_ptr[i]) {
skb = tbl->rx_reorder_ptr[i];
__skb_queue_tail(&list, skb);
tbl->rx_reorder_ptr[i] = NULL;
}
}
/* * We don't have a circular buffer, hence use rotation to simulate * circular buffer
*/ for (i = 0; i < tbl->win_size - pkt_to_send; ++i) {
tbl->rx_reorder_ptr[i] = tbl->rx_reorder_ptr[pkt_to_send + i];
tbl->rx_reorder_ptr[pkt_to_send + i] = NULL;
}
while ((skb = __skb_dequeue(&list)))
mwifiex_11n_dispatch_pkt(priv, skb);
}
/* * This function dispatches all packets in the Rx reorder table until * a hole is found. * * The start window is adjusted automatically when a hole is located. * Since the buffer is linear, the function uses rotation to simulate * circular buffer.
*/ staticvoid
mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv, struct mwifiex_rx_reorder_tbl *tbl)
{ struct sk_buff_head list; struct sk_buff *skb; int i, j, xchg;
for (i = 0; i < tbl->win_size; ++i) { if (!tbl->rx_reorder_ptr[i]) break;
skb = tbl->rx_reorder_ptr[i];
__skb_queue_tail(&list, skb);
tbl->rx_reorder_ptr[i] = NULL;
}
/* * We don't have a circular buffer, hence use rotation to simulate * circular buffer
*/ if (i > 0) {
xchg = tbl->win_size - i; for (j = 0; j < xchg; ++j) {
tbl->rx_reorder_ptr[j] = tbl->rx_reorder_ptr[i + j];
tbl->rx_reorder_ptr[i + j] = NULL;
}
}
tbl->start_win = (tbl->start_win + i) & (MAX_TID_VALUE - 1);
spin_unlock_bh(&priv->rx_reorder_tbl_lock);
while ((skb = __skb_dequeue(&list)))
mwifiex_11n_dispatch_pkt(priv, skb);
}
/* * This function deletes the Rx reorder table and frees the memory. * * The function stops the associated timer and dispatches all the * pending packets in the Rx reorder table before deletion.
*/ staticvoid
mwifiex_del_rx_reorder_entry(struct mwifiex_private *priv, struct mwifiex_rx_reorder_tbl *tbl)
{ int start_win;
/* * This function returns the pointer to an entry in Rx reordering * table which matches the given TA/TID pair.
*/ struct mwifiex_rx_reorder_tbl *
mwifiex_11n_get_rx_reorder_tbl(struct mwifiex_private *priv, int tid, u8 *ta)
{ struct mwifiex_rx_reorder_tbl *tbl;
spin_lock_bh(&priv->rx_reorder_tbl_lock);
list_for_each_entry(tbl, &priv->rx_reorder_tbl_ptr, list) { if (!memcmp(tbl->ta, ta, ETH_ALEN) && tbl->tid == tid) {
spin_unlock_bh(&priv->rx_reorder_tbl_lock); return tbl;
}
}
spin_unlock_bh(&priv->rx_reorder_tbl_lock);
return NULL;
}
/* This function retrieves the pointer to an entry in Rx reordering * table which matches the given TA and deletes it.
*/ void mwifiex_11n_del_rx_reorder_tbl_by_ta(struct mwifiex_private *priv, u8 *ta)
{ struct mwifiex_rx_reorder_tbl *tbl, *tmp;
if (!ta) return;
spin_lock_bh(&priv->rx_reorder_tbl_lock);
list_for_each_entry_safe(tbl, tmp, &priv->rx_reorder_tbl_ptr, list) { if (!memcmp(tbl->ta, ta, ETH_ALEN)) {
spin_unlock_bh(&priv->rx_reorder_tbl_lock);
mwifiex_del_rx_reorder_entry(priv, tbl);
spin_lock_bh(&priv->rx_reorder_tbl_lock);
}
}
spin_unlock_bh(&priv->rx_reorder_tbl_lock);
return;
}
/* * This function finds the last sequence number used in the packets * buffered in Rx reordering table.
*/ staticint
mwifiex_11n_find_last_seq_num(struct reorder_tmr_cnxt *ctx)
{ struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr = ctx->ptr; struct mwifiex_private *priv = ctx->priv; int i;
spin_lock_bh(&priv->rx_reorder_tbl_lock); for (i = rx_reorder_tbl_ptr->win_size - 1; i >= 0; --i) { if (rx_reorder_tbl_ptr->rx_reorder_ptr[i]) {
spin_unlock_bh(&priv->rx_reorder_tbl_lock); return i;
}
}
spin_unlock_bh(&priv->rx_reorder_tbl_lock);
return -1;
}
/* * This function flushes all the packets in Rx reordering table. * * The function checks if any packets are currently buffered in the * table or not. In case there are packets available, it dispatches * them and then dumps the Rx reordering table.
*/ staticvoid
mwifiex_flush_data(struct timer_list *t)
{ struct reorder_tmr_cnxt *ctx =
timer_container_of(ctx, t, timer); int start_win, seq_num;
/* * This function creates an entry in Rx reordering table for the * given TA/TID. * * The function also initializes the entry with sequence number, window * size as well as initializes the timer. * * If the received TA/TID pair is already present, all the packets are * dispatched and the window size is moved until the SSN.
*/ staticvoid
mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta, int tid, int win_size, int seq_num)
{ int i; struct mwifiex_rx_reorder_tbl *tbl, *new_node;
u16 last_seq = 0; struct mwifiex_sta_node *node;
/* * If we get a TID, ta pair which is already present dispatch all * the packets and move the window size until the ssn
*/
tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta); if (tbl) {
mwifiex_11n_dispatch_pkt_until_start_win(priv, tbl, seq_num); return;
} /* if !tbl then create one */
new_node = kzalloc(sizeof(struct mwifiex_rx_reorder_tbl), GFP_KERNEL); if (!new_node) return;
/* * This function prepares command for adding a BA request. * * Preparation includes - * - Setting command ID and proper size * - Setting add BA request buffer * - Ensuring correct endian-ness
*/ int mwifiex_cmd_11n_addba_req(struct host_cmd_ds_command *cmd, void *data_buf)
{ struct host_cmd_ds_11n_addba_req *add_ba_req = &cmd->params.add_ba_req;
/* * This function prepares command for deleting a BA request. * * Preparation includes - * - Setting command ID and proper size * - Setting del BA request buffer * - Ensuring correct endian-ness
*/ int mwifiex_cmd_11n_delba(struct host_cmd_ds_command *cmd, void *data_buf)
{ struct host_cmd_ds_11n_delba *del_ba = &cmd->params.del_ba;
/* * This function identifies if Rx reordering is needed for a received packet. * * In case reordering is required, the function will do the reordering * before sending it to kernel. * * The Rx reorder table is checked first with the received TID/TA pair. If * not found, the received packet is dispatched immediately. But if found, * the packet is reordered and all the packets in the updated Rx reordering * table is dispatched until a hole is found. * * For sequence number less than the starting window, the packet is dropped.
*/ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,
u16 seq_num, u16 tid,
u8 *ta, u8 pkt_type, void *payload)
{ struct mwifiex_rx_reorder_tbl *tbl; int prev_start_win, start_win, end_win, win_size;
u16 pkt_index; bool init_window_shift = false; int ret = 0;
tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta); if (!tbl) { if (pkt_type != PKT_TYPE_BAR)
mwifiex_11n_dispatch_pkt(priv, payload); return ret;
}
if (tbl->flags & RXREOR_FORCE_NO_DROP) {
mwifiex_dbg(priv->adapter, INFO, "RXREOR_FORCE_NO_DROP when HS is activated\n");
tbl->flags &= ~RXREOR_FORCE_NO_DROP;
} elseif (init_window_shift && seq_num < start_win &&
seq_num >= tbl->init_win) {
mwifiex_dbg(priv->adapter, INFO, "Sender TID sequence number reset %d->%d for SSN %d\n",
start_win, seq_num, tbl->init_win);
tbl->start_win = start_win = seq_num;
end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1);
} else { /* * If seq_num is less then starting win then ignore and drop * the packet
*/ if ((start_win + TWOPOW11) > (MAX_TID_VALUE - 1)) { if (seq_num >= ((start_win + TWOPOW11) &
(MAX_TID_VALUE - 1)) &&
seq_num < start_win) {
ret = -1; goto done;
}
} elseif ((seq_num < start_win) ||
(seq_num >= (start_win + TWOPOW11))) {
ret = -1; goto done;
}
}
/* * If this packet is a BAR we adjust seq_num as * WinStart = seq_num
*/ if (pkt_type == PKT_TYPE_BAR)
seq_num = ((seq_num + win_size) - 1) & (MAX_TID_VALUE - 1);
if (pkt_type != PKT_TYPE_BAR) { if (seq_num >= start_win)
pkt_index = seq_num - start_win; else
pkt_index = (seq_num+MAX_TID_VALUE) - start_win;
if (tbl->rx_reorder_ptr[pkt_index]) {
ret = -1; goto done;
}
tbl->rx_reorder_ptr[pkt_index] = payload;
}
/* * Dispatch all packets sequentially from start_win until a * hole is found and adjust the start_win appropriately
*/
mwifiex_11n_scan_and_dispatch(priv, tbl);
/* * This function deletes an entry for a given TID/TA pair. * * The TID/TA are taken from del BA event body.
*/ void
mwifiex_del_ba_tbl(struct mwifiex_private *priv, int tid, u8 *peer_mac,
u8 type, int initiator)
{ struct mwifiex_rx_reorder_tbl *tbl; struct mwifiex_tx_ba_stream_tbl *ptx_tbl; struct mwifiex_ra_list_tbl *ra_list;
u8 cleanup_rx_reorder_tbl; int tid_down;
if (cleanup_rx_reorder_tbl) {
tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid,
peer_mac); if (!tbl) {
mwifiex_dbg(priv->adapter, EVENT, "event: TID, TA not found in table\n"); return;
}
mwifiex_del_rx_reorder_entry(priv, tbl);
} else {
ptx_tbl = mwifiex_get_ba_tbl(priv, tid, peer_mac); if (!ptx_tbl) {
mwifiex_dbg(priv->adapter, EVENT, "event: TID, RA not found in table\n"); return;
}
/* * This function handles the command response of an add BA response. * * Handling includes changing the header fields into CPU format and * creating the stream, provided the add BA is accepted.
*/ int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv, struct host_cmd_ds_command *resp)
{ struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = &resp->params.add_ba_rsp; int tid, win_size; struct mwifiex_rx_reorder_tbl *tbl;
uint16_t block_ack_param_set;
tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK)
>> BLOCKACKPARAM_TID_POS; /* * Check if we had rejected the ADDBA, if yes then do not create * the stream
*/ if (le16_to_cpu(add_ba_rsp->status_code) != BA_RESULT_SUCCESS) {
mwifiex_dbg(priv->adapter, ERROR, "ADDBA RSP: failed %pM tid=%d)\n",
add_ba_rsp->peer_mac_addr, tid);
tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid,
add_ba_rsp->peer_mac_addr); if (tbl)
mwifiex_del_rx_reorder_entry(priv, tbl);
/* * This function handles BA stream timeout event by preparing and sending * a command to the firmware.
*/ void mwifiex_11n_ba_stream_timeout(struct mwifiex_private *priv, struct host_cmd_ds_11n_batimeout *event)
{ struct host_cmd_ds_11n_delba delba;
/* * This function cleans up the Rx reorder table by deleting all the entries * and re-initializing.
*/ void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv)
{ struct mwifiex_rx_reorder_tbl *del_tbl_ptr, *tmp_node;
/* This function update all the rx_win_size based on coex flag
*/ staticvoid mwifiex_update_ampdu_rxwinsize(struct mwifiex_adapter *adapter, bool coex_flag)
{
u8 i;
u32 rx_win_size; struct mwifiex_private *priv;
for (i = 0; i < adapter->priv_num; i++) {
priv = adapter->priv[i];
rx_win_size = priv->add_ba_param.rx_win_size; if (coex_flag) { if (priv->bss_type == MWIFIEX_BSS_TYPE_STA)
priv->add_ba_param.rx_win_size =
MWIFIEX_STA_COEX_AMPDU_DEF_RXWINSIZE; if (priv->bss_type == MWIFIEX_BSS_TYPE_P2P)
priv->add_ba_param.rx_win_size =
MWIFIEX_STA_COEX_AMPDU_DEF_RXWINSIZE; if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP)
priv->add_ba_param.rx_win_size =
MWIFIEX_UAP_COEX_AMPDU_DEF_RXWINSIZE;
} else { if (priv->bss_type == MWIFIEX_BSS_TYPE_STA)
priv->add_ba_param.rx_win_size =
MWIFIEX_STA_AMPDU_DEF_RXWINSIZE; if (priv->bss_type == MWIFIEX_BSS_TYPE_P2P)
priv->add_ba_param.rx_win_size =
MWIFIEX_STA_AMPDU_DEF_RXWINSIZE; if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP)
priv->add_ba_param.rx_win_size =
MWIFIEX_UAP_AMPDU_DEF_RXWINSIZE;
}
if (adapter->coex_win_size && adapter->coex_rx_win_size)
priv->add_ba_param.rx_win_size =
adapter->coex_rx_win_size;
if (rx_win_size != priv->add_ba_param.rx_win_size) { if (!priv->media_connected) continue; for (i = 0; i < MAX_NUM_TID; i++)
mwifiex_11n_delba(priv, i);
}
}
}
/* This function check coex for RX BA
*/ void mwifiex_coex_ampdu_rxwinsize(struct mwifiex_adapter *adapter)
{
u8 i; struct mwifiex_private *priv;
u8 count = 0;
for (i = 0; i < adapter->priv_num; i++) {
priv = adapter->priv[i]; if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) { if (priv->media_connected)
count++;
} if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) { if (priv->bss_started)
count++;
}
if (count >= MWIFIEX_BSS_COEX_COUNT) break;
} if (count >= MWIFIEX_BSS_COEX_COUNT)
mwifiex_update_ampdu_rxwinsize(adapter, true); else
mwifiex_update_ampdu_rxwinsize(adapter, false);
}
/* This function handles rxba_sync event
*/ void mwifiex_11n_rxba_sync_event(struct mwifiex_private *priv,
u8 *event_buf, u16 len)
{ struct mwifiex_ie_types_rxba_sync *tlv_rxba = (void *)event_buf;
u16 tlv_type, tlv_len; struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr;
u8 i, j;
u16 seq_num, tlv_seq_num, tlv_bitmap_len; int tlv_buf_left = len; int ret;
u8 *tmp;
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.