ol_rx_fwd.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. /*
  2. * Copyright (c) 2011, 2014-2015 The Linux Foundation. All rights reserved.
  3. *
  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. * This file was originally distributed by Qualcomm Atheros, Inc.
  23. * under proprietary terms before Copyright ownership was assigned
  24. * to the Linux Foundation.
  25. */
  26. /* standard header files */
  27. #include <cdf_nbuf.h> /* cdf_nbuf_map */
  28. #include <cdf_memory.h> /* cdf_mem_compare */
  29. /* external header files */
  30. #include <ol_cfg.h> /* wlan_op_mode_ap, etc. */
  31. #include <ol_htt_rx_api.h> /* htt_rx_msdu_desc_retrieve */
  32. #include <cds_ieee80211_common.h> /* ieee80211_frame, etc. */
  33. /* internal header files */
  34. #include <ol_txrx_types.h> /* ol_txrx_dev_t, etc. */
  35. #include <ol_rx_fwd.h> /* our own defs */
  36. #include <ol_rx.h> /* ol_rx_deliver */
  37. #include <ol_txrx_internal.h> /* TXRX_ASSERT1 */
  38. #include <ol_tx.h>
  39. /*
  40. * Porting from Ap11PrepareForwardedPacket.
  41. * This routine is called when a RX data frame from an associated station is
  42. * to be forwarded to another associated station. We will prepare the
  43. * received packet so that it is suitable for transmission again.
  44. * Check that this Packet is suitable for forwarding. If yes, then
  45. * prepare the new 802.11 header.
  46. */
  47. static inline void ol_ap_fwd_check(struct ol_txrx_vdev_t *vdev, cdf_nbuf_t msdu)
  48. {
  49. struct ieee80211_frame *mac_header;
  50. unsigned char tmp_addr[IEEE80211_ADDR_LEN];
  51. unsigned char type;
  52. unsigned char subtype;
  53. unsigned char fromds;
  54. unsigned char tods;
  55. mac_header = (struct ieee80211_frame *)(cdf_nbuf_data(msdu));
  56. TXRX_ASSERT1(mac_header);
  57. type = mac_header->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
  58. subtype = mac_header->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
  59. tods = mac_header->i_fc[1] & IEEE80211_FC1_DIR_TODS;
  60. fromds = mac_header->i_fc[1] & IEEE80211_FC1_DIR_FROMDS;
  61. /*
  62. * Make sure no QOS or any other non-data subtype
  63. * Should be a ToDs data frame.
  64. * Make sure that this frame is unicast and not for us.
  65. * These packets should come up through the normal rx path and
  66. * not forwarded.
  67. */
  68. if (type != IEEE80211_FC0_TYPE_DATA ||
  69. subtype != 0x0 ||
  70. ((tods != 1) || (fromds != 0)) ||
  71. (cdf_mem_compare
  72. (mac_header->i_addr3, vdev->mac_addr.raw,
  73. IEEE80211_ADDR_LEN) == 0)) {
  74. #ifdef DEBUG_HOST_RC
  75. TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1,
  76. "Exit: %s | Unnecessary to adjust mac header\n",
  77. __func__);
  78. #endif
  79. } else {
  80. /* Flip the ToDs bit to FromDs */
  81. mac_header->i_fc[1] &= 0xfe;
  82. mac_header->i_fc[1] |= 0x2;
  83. /*
  84. * Flip the addresses
  85. * (ToDs, addr1, RA=BSSID) move to (FrDs, addr2, TA=BSSID)
  86. * (ToDs, addr2, SA) move to (FrDs, addr3, SA)
  87. * (ToDs, addr3, DA) move to (FrDs, addr1, DA)
  88. */
  89. memcpy(tmp_addr, mac_header->i_addr2, sizeof(tmp_addr));
  90. memcpy(mac_header->i_addr2,
  91. mac_header->i_addr1, sizeof(tmp_addr));
  92. memcpy(mac_header->i_addr1,
  93. mac_header->i_addr3, sizeof(tmp_addr));
  94. memcpy(mac_header->i_addr3, tmp_addr, sizeof(tmp_addr));
  95. }
  96. }
  97. static inline void ol_rx_fwd_to_tx(struct ol_txrx_vdev_t *vdev, cdf_nbuf_t msdu)
  98. {
  99. struct ol_txrx_pdev_t *pdev = vdev->pdev;
  100. if (pdev->frame_format == wlan_frm_fmt_native_wifi)
  101. ol_ap_fwd_check(vdev, msdu);
  102. /*
  103. * Map the netbuf, so it's accessible to the DMA that
  104. * sends it to the target.
  105. */
  106. cdf_nbuf_map_single(pdev->osdev, msdu, CDF_DMA_TO_DEVICE);
  107. cdf_nbuf_set_next(msdu, NULL); /* add NULL terminator */
  108. msdu = OL_TX_LL(vdev, msdu);
  109. if (msdu) {
  110. /*
  111. * The frame was not accepted by the tx.
  112. * We could store the frame and try again later,
  113. * but the simplest solution is to discard the frames.
  114. */
  115. cdf_nbuf_unmap_single(pdev->osdev, msdu, CDF_DMA_TO_DEVICE);
  116. cdf_nbuf_tx_free(msdu, NBUF_PKT_ERROR);
  117. }
  118. }
  119. void
  120. ol_rx_fwd_check(struct ol_txrx_vdev_t *vdev,
  121. struct ol_txrx_peer_t *peer, unsigned tid, cdf_nbuf_t msdu_list)
  122. {
  123. struct ol_txrx_pdev_t *pdev = vdev->pdev;
  124. cdf_nbuf_t deliver_list_head = NULL;
  125. cdf_nbuf_t deliver_list_tail = NULL;
  126. cdf_nbuf_t msdu;
  127. msdu = msdu_list;
  128. while (msdu) {
  129. struct ol_txrx_vdev_t *tx_vdev;
  130. void *rx_desc;
  131. /*
  132. * Remember the next list elem, because our processing
  133. * may cause the MSDU to get linked into a different list.
  134. */
  135. msdu_list = cdf_nbuf_next(msdu);
  136. rx_desc = htt_rx_msdu_desc_retrieve(pdev->htt_pdev, msdu);
  137. if (!vdev->disable_intrabss_fwd &&
  138. htt_rx_msdu_forward(pdev->htt_pdev, rx_desc)) {
  139. /*
  140. * Use the same vdev that received the frame to
  141. * transmit the frame.
  142. * This is exactly what we want for intra-BSS
  143. * forwarding, like STA-to-STA forwarding and
  144. * multicast echo.
  145. * If this is a intra-BSS forwarding case (which is not
  146. * currently supported), then the tx vdev is different
  147. * from the rx vdev.
  148. * On the LL host the vdevs are not actually used
  149. * for tx, so it would still work to use the rx vdev
  150. * rather than the tx vdev.
  151. * For HL, the tx classification searches for the DA
  152. * within the given vdev, so we would want to get the DA
  153. * peer ID from the target, so we can locate
  154. * the tx vdev.
  155. */
  156. tx_vdev = vdev;
  157. /*
  158. * Copying TID value of RX packet to forwarded
  159. * packet if the tid is other than non qos tid.
  160. * But for non qos tid fill invalid tid so that
  161. * Fw will take care of filling proper tid.
  162. */
  163. if (tid != HTT_NON_QOS_TID) {
  164. cdf_nbuf_set_tid(msdu, tid);
  165. } else {
  166. cdf_nbuf_set_tid(msdu,
  167. ADF_NBUF_TX_EXT_TID_INVALID);
  168. }
  169. /*
  170. * This MSDU needs to be forwarded to the tx path.
  171. * Check whether it also needs to be sent to the OS
  172. * shim, in which case we need to make a copy
  173. * (or clone?).
  174. */
  175. if (htt_rx_msdu_discard(pdev->htt_pdev, rx_desc)) {
  176. htt_rx_msdu_desc_free(pdev->htt_pdev, msdu);
  177. cdf_net_buf_debug_release_skb(msdu);
  178. ol_rx_fwd_to_tx(tx_vdev, msdu);
  179. msdu = NULL; /* already handled this MSDU */
  180. TXRX_STATS_ADD(pdev,
  181. pub.rx.intra_bss_fwd.packets_fwd, 1);
  182. } else {
  183. cdf_nbuf_t copy;
  184. copy = cdf_nbuf_copy(msdu);
  185. if (copy)
  186. ol_rx_fwd_to_tx(tx_vdev, copy);
  187. TXRX_STATS_ADD(pdev,
  188. pub.rx.intra_bss_fwd.packets_stack_n_fwd, 1);
  189. }
  190. } else {
  191. TXRX_STATS_ADD(pdev,
  192. pub.rx.intra_bss_fwd.packets_stack, 1);
  193. }
  194. if (msdu) {
  195. /* send this frame to the OS */
  196. OL_TXRX_LIST_APPEND(deliver_list_head,
  197. deliver_list_tail, msdu);
  198. }
  199. msdu = msdu_list;
  200. }
  201. if (deliver_list_head) {
  202. /* add NULL terminator */
  203. cdf_nbuf_set_next(deliver_list_tail, NULL);
  204. if (ol_cfg_is_full_reorder_offload(pdev->ctrl_pdev)) {
  205. ol_rx_in_order_deliver(vdev, peer, tid,
  206. deliver_list_head);
  207. } else {
  208. ol_rx_deliver(vdev, peer, tid, deliver_list_head);
  209. }
  210. }
  211. }