blob: 7653928fb231cbd7682ebd5a81c70719382b3a99 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Anurag Chouhan6d760662016-02-20 16:05:43 +05302 * Copyright (c) 2011, 2014-2016 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/* standard header files */
Nirav Shahcbc6d722016-03-01 16:24:53 +053029#include <qdf_nbuf.h> /* qdf_nbuf_map */
Anurag Chouhan600c3a02016-03-01 10:33:54 +053030#include <qdf_mem.h> /* qdf_mem_cmp */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080031
32/* external header files */
33#include <ol_cfg.h> /* wlan_op_mode_ap, etc. */
34#include <ol_htt_rx_api.h> /* htt_rx_msdu_desc_retrieve */
35#include <cds_ieee80211_common.h> /* ieee80211_frame, etc. */
36
37/* internal header files */
38#include <ol_txrx_types.h> /* ol_txrx_dev_t, etc. */
39#include <ol_rx_fwd.h> /* our own defs */
40#include <ol_rx.h> /* ol_rx_deliver */
41#include <ol_txrx_internal.h> /* TXRX_ASSERT1 */
42#include <ol_tx.h>
43/*
44 * Porting from Ap11PrepareForwardedPacket.
45 * This routine is called when a RX data frame from an associated station is
46 * to be forwarded to another associated station. We will prepare the
47 * received packet so that it is suitable for transmission again.
48 * Check that this Packet is suitable for forwarding. If yes, then
49 * prepare the new 802.11 header.
50 */
Nirav Shahcbc6d722016-03-01 16:24:53 +053051static inline void ol_ap_fwd_check(struct ol_txrx_vdev_t *vdev, qdf_nbuf_t msdu)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080052{
53 struct ieee80211_frame *mac_header;
54 unsigned char tmp_addr[IEEE80211_ADDR_LEN];
55 unsigned char type;
56 unsigned char subtype;
57 unsigned char fromds;
58 unsigned char tods;
59
Nirav Shahcbc6d722016-03-01 16:24:53 +053060 mac_header = (struct ieee80211_frame *)(qdf_nbuf_data(msdu));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080061 TXRX_ASSERT1(mac_header);
62
63 type = mac_header->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
64 subtype = mac_header->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
65 tods = mac_header->i_fc[1] & IEEE80211_FC1_DIR_TODS;
66 fromds = mac_header->i_fc[1] & IEEE80211_FC1_DIR_FROMDS;
67
68 /*
69 * Make sure no QOS or any other non-data subtype
70 * Should be a ToDs data frame.
71 * Make sure that this frame is unicast and not for us.
72 * These packets should come up through the normal rx path and
73 * not forwarded.
74 */
75 if (type != IEEE80211_FC0_TYPE_DATA ||
76 subtype != 0x0 ||
77 ((tods != 1) || (fromds != 0)) ||
Anurag Chouhan600c3a02016-03-01 10:33:54 +053078 (qdf_mem_cmp
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080079 (mac_header->i_addr3, vdev->mac_addr.raw,
Anurag Chouhan600c3a02016-03-01 10:33:54 +053080 IEEE80211_ADDR_LEN) != 0)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080081#ifdef DEBUG_HOST_RC
82 TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1,
83 "Exit: %s | Unnecessary to adjust mac header\n",
84 __func__);
85#endif
86 } else {
87 /* Flip the ToDs bit to FromDs */
88 mac_header->i_fc[1] &= 0xfe;
89 mac_header->i_fc[1] |= 0x2;
90
91 /*
92 * Flip the addresses
93 * (ToDs, addr1, RA=BSSID) move to (FrDs, addr2, TA=BSSID)
94 * (ToDs, addr2, SA) move to (FrDs, addr3, SA)
95 * (ToDs, addr3, DA) move to (FrDs, addr1, DA)
96 */
97
98 memcpy(tmp_addr, mac_header->i_addr2, sizeof(tmp_addr));
99
100 memcpy(mac_header->i_addr2,
101 mac_header->i_addr1, sizeof(tmp_addr));
102
103 memcpy(mac_header->i_addr1,
104 mac_header->i_addr3, sizeof(tmp_addr));
105
106 memcpy(mac_header->i_addr3, tmp_addr, sizeof(tmp_addr));
107 }
108}
109
Nirav Shahcbc6d722016-03-01 16:24:53 +0530110static inline void ol_rx_fwd_to_tx(struct ol_txrx_vdev_t *vdev, qdf_nbuf_t msdu)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800111{
112 struct ol_txrx_pdev_t *pdev = vdev->pdev;
113
114 if (pdev->frame_format == wlan_frm_fmt_native_wifi)
115 ol_ap_fwd_check(vdev, msdu);
116
117 /*
118 * Map the netbuf, so it's accessible to the DMA that
119 * sends it to the target.
120 */
Nirav Shahcbc6d722016-03-01 16:24:53 +0530121 qdf_nbuf_map_single(pdev->osdev, msdu, QDF_DMA_TO_DEVICE);
122 qdf_nbuf_set_next(msdu, NULL); /* add NULL terminator */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800123
124 msdu = OL_TX_LL(vdev, msdu);
125
126 if (msdu) {
127 /*
128 * The frame was not accepted by the tx.
129 * We could store the frame and try again later,
130 * but the simplest solution is to discard the frames.
131 */
Nirav Shahcbc6d722016-03-01 16:24:53 +0530132 qdf_nbuf_unmap_single(pdev->osdev, msdu, QDF_DMA_TO_DEVICE);
133 qdf_nbuf_tx_free(msdu, QDF_NBUF_PKT_ERROR);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800134 }
135}
136
137void
138ol_rx_fwd_check(struct ol_txrx_vdev_t *vdev,
Nirav Shahcbc6d722016-03-01 16:24:53 +0530139 struct ol_txrx_peer_t *peer, unsigned tid, qdf_nbuf_t msdu_list)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800140{
141 struct ol_txrx_pdev_t *pdev = vdev->pdev;
Nirav Shahcbc6d722016-03-01 16:24:53 +0530142 qdf_nbuf_t deliver_list_head = NULL;
143 qdf_nbuf_t deliver_list_tail = NULL;
144 qdf_nbuf_t msdu;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800145
146 msdu = msdu_list;
147 while (msdu) {
148 struct ol_txrx_vdev_t *tx_vdev;
149 void *rx_desc;
150 /*
151 * Remember the next list elem, because our processing
152 * may cause the MSDU to get linked into a different list.
153 */
Nirav Shahcbc6d722016-03-01 16:24:53 +0530154 msdu_list = qdf_nbuf_next(msdu);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800155
156 rx_desc = htt_rx_msdu_desc_retrieve(pdev->htt_pdev, msdu);
157
158 if (!vdev->disable_intrabss_fwd &&
159 htt_rx_msdu_forward(pdev->htt_pdev, rx_desc)) {
160 /*
161 * Use the same vdev that received the frame to
162 * transmit the frame.
163 * This is exactly what we want for intra-BSS
164 * forwarding, like STA-to-STA forwarding and
165 * multicast echo.
166 * If this is a intra-BSS forwarding case (which is not
167 * currently supported), then the tx vdev is different
168 * from the rx vdev.
169 * On the LL host the vdevs are not actually used
170 * for tx, so it would still work to use the rx vdev
171 * rather than the tx vdev.
172 * For HL, the tx classification searches for the DA
173 * within the given vdev, so we would want to get the DA
174 * peer ID from the target, so we can locate
175 * the tx vdev.
176 */
177 tx_vdev = vdev;
178 /*
179 * Copying TID value of RX packet to forwarded
180 * packet if the tid is other than non qos tid.
181 * But for non qos tid fill invalid tid so that
182 * Fw will take care of filling proper tid.
183 */
184 if (tid != HTT_NON_QOS_TID) {
Nirav Shahcbc6d722016-03-01 16:24:53 +0530185 qdf_nbuf_set_tid(msdu, tid);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800186 } else {
Nirav Shahcbc6d722016-03-01 16:24:53 +0530187 qdf_nbuf_set_tid(msdu,
Anurag Chouhanc73697b2016-02-21 15:05:43 +0530188 QDF_NBUF_TX_EXT_TID_INVALID);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800189 }
190 /*
191 * This MSDU needs to be forwarded to the tx path.
192 * Check whether it also needs to be sent to the OS
193 * shim, in which case we need to make a copy
194 * (or clone?).
195 */
196 if (htt_rx_msdu_discard(pdev->htt_pdev, rx_desc)) {
197 htt_rx_msdu_desc_free(pdev->htt_pdev, msdu);
Nirav Shahcbc6d722016-03-01 16:24:53 +0530198 qdf_net_buf_debug_release_skb(msdu);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800199 ol_rx_fwd_to_tx(tx_vdev, msdu);
200 msdu = NULL; /* already handled this MSDU */
201 TXRX_STATS_ADD(pdev,
202 pub.rx.intra_bss_fwd.packets_fwd, 1);
203 } else {
Nirav Shahcbc6d722016-03-01 16:24:53 +0530204 qdf_nbuf_t copy;
205 copy = qdf_nbuf_copy(msdu);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800206 if (copy)
207 ol_rx_fwd_to_tx(tx_vdev, copy);
208 TXRX_STATS_ADD(pdev,
209 pub.rx.intra_bss_fwd.packets_stack_n_fwd, 1);
210 }
211 } else {
212 TXRX_STATS_ADD(pdev,
213 pub.rx.intra_bss_fwd.packets_stack, 1);
214 }
215 if (msdu) {
216 /* send this frame to the OS */
217 OL_TXRX_LIST_APPEND(deliver_list_head,
218 deliver_list_tail, msdu);
219 }
220 msdu = msdu_list;
221 }
222 if (deliver_list_head) {
223 /* add NULL terminator */
Nirav Shahcbc6d722016-03-01 16:24:53 +0530224 qdf_nbuf_set_next(deliver_list_tail, NULL);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800225 if (ol_cfg_is_full_reorder_offload(pdev->ctrl_pdev)) {
226 ol_rx_in_order_deliver(vdev, peer, tid,
227 deliver_list_head);
228 } else {
229 ol_rx_deliver(vdev, peer, tid, deliver_list_head);
230 }
231 }
232}