示例#1
0
void
ol_rx_fwd_check(
    struct ol_txrx_vdev_t *vdev,
    struct ol_txrx_peer_t *peer,
    unsigned tid,
    adf_nbuf_t msdu_list)
{
    struct ol_txrx_pdev_t *pdev = vdev->pdev;
    adf_nbuf_t deliver_list_head = NULL;
    adf_nbuf_t deliver_list_tail = NULL;
    adf_nbuf_t msdu;

    if (OL_CFG_RAW_RX_LIKELINESS(pdev->rx_decap_mode == htt_pkt_type_raw)) {
        /* Forwarding is not handled since keys would reside on Access
         * Controller.
         *
         * Full fledged Mixed VAP functionality can add requisite exceptions in
         * this function.
         */
        ol_rx_deliver(vdev, peer, tid, msdu_list);
        return;
    }
    
    msdu = msdu_list;
    while (msdu) {
        struct ol_txrx_vdev_t *tx_vdev;
        void *rx_desc;
        /*
         * Remember the next list elem, because our processing
         * may cause the MSDU to get linked into a different list.
         */
        msdu_list = adf_nbuf_next(msdu);

        rx_desc = htt_rx_msdu_desc_retrieve(pdev->htt_pdev, msdu);

        if (htt_rx_msdu_forward(pdev->htt_pdev, rx_desc)) {
            /*
             * Use the same vdev that received the frame to
             * transmit the frame.
             * This is exactly what we want for intra-BSS forwarding,
             * like STA-to-STA forwarding and multicast echo.
             * If this is a intra-BSS forwarding case (which is not
             * currently supported), then the tx vdev is different
             * from the rx vdev.
             * On the LL host the vdevs are not actually used for tx,
             * so it would still work to use the rx vdev rather than
             * the tx vdev.
             * For HL, the tx classification searches for the DA within
             * the given vdev, so we would want to get the DA peer ID
             * from the target, so we can locate the tx vdev.
             */
            tx_vdev = vdev;
            /*
             * This MSDU needs to be forwarded to the tx path.
             * Check whether it also needs to be sent to the OS shim,
             * in which case we need to make a copy (or clone?).
             */
            if (htt_rx_msdu_discard(pdev->htt_pdev, rx_desc)) {
                htt_rx_msdu_desc_free(pdev->htt_pdev, msdu);
                ol_rx_fwd_to_tx(tx_vdev, msdu);
                msdu = NULL; /* already handled this MSDU */
            } else {
                adf_nbuf_t copy;
                copy = adf_nbuf_copy(msdu);
                if (copy) {
                    ol_rx_fwd_to_tx(tx_vdev, copy);
                }
            }
        }
        if (msdu) {
            /* send this frame to the OS */
            OL_TXRX_LIST_APPEND(deliver_list_head, deliver_list_tail, msdu);
        }
        msdu = msdu_list;
    }
    if (deliver_list_head) {
        adf_nbuf_set_next(deliver_list_tail, NULL); /* add NULL terminator */
        ol_rx_deliver(vdev, peer, tid, deliver_list_head);
    }
}
void
ol_rx_fwd_check(
    struct ol_txrx_vdev_t *vdev,
    struct ol_txrx_peer_t *peer,
    unsigned tid,
    adf_nbuf_t msdu_list)
{
    struct ol_txrx_pdev_t *pdev = vdev->pdev;
    adf_nbuf_t deliver_list_head = NULL;
    adf_nbuf_t deliver_list_tail = NULL;
    adf_nbuf_t msdu;

    msdu = msdu_list;
    while (msdu) {
        struct ol_txrx_vdev_t *tx_vdev;
        void *rx_desc;
        /*
         * Remember the next list elem, because our processing
         * may cause the MSDU to get linked into a different list.
         */
        msdu_list = adf_nbuf_next(msdu);

        rx_desc = htt_rx_msdu_desc_retrieve(pdev->htt_pdev, msdu);

        if (!vdev->disable_intrabss_fwd &&
            htt_rx_msdu_forward(pdev->htt_pdev, rx_desc)) {
#ifdef QCA_ARP_SPOOFING_WAR
            void *filter_cb;
#endif
            int do_not_fwd = 0;
            /*
             * Use the same vdev that received the frame to
             * transmit the frame.
             * This is exactly what we want for intra-BSS forwarding,
             * like STA-to-STA forwarding and multicast echo.
             * If this is a intra-BSS forwarding case (which is not
             * currently supported), then the tx vdev is different
             * from the rx vdev.
             * On the LL host the vdevs are not actually used for tx,
             * so it would still work to use the rx vdev rather than
             * the tx vdev.
             * For HL, the tx classification searches for the DA within
             * the given vdev, so we would want to get the DA peer ID
             * from the target, so we can locate the tx vdev.
             */
            tx_vdev = vdev;
            /*
             * Copying TID value of RX packet to forwarded
             * packet if the tid is other than non qos tid.
             * But for non qos tid fill invalid tid so that
             * Fw will take care of filling proper tid.
             */
            if (tid != HTT_NON_QOS_TID) {
                adf_nbuf_set_tid(msdu, tid);
            } else {
                adf_nbuf_set_tid(msdu, ADF_NBUF_TX_EXT_TID_INVALID);
            }

#ifdef QCA_ARP_SPOOFING_WAR
            filter_cb = (void *)NBUF_CB_PTR(msdu);
            if (filter_cb) {
                do_not_fwd = (*(hdd_filter_cb_t)filter_cb)(vdev->vdev_id, msdu,
                        RX_INTRA_BSS_FWD);
            }
#endif
            /*
             * This MSDU needs to be forwarded to the tx path.
             * Check whether it also needs to be sent to the OS shim,
             * in which case we need to make a copy (or clone?).
             */
            if (!do_not_fwd) {
                if (htt_rx_msdu_discard(pdev->htt_pdev, rx_desc)) {
                        htt_rx_msdu_desc_free(pdev->htt_pdev, msdu);
                        adf_net_buf_debug_release_skb(msdu);
                        ol_rx_fwd_to_tx(tx_vdev, msdu);
                        msdu = NULL; /* already handled this MSDU */
                        tx_vdev->fwd_tx_packets++;
                        vdev->fwd_rx_packets++;
                        TXRX_STATS_ADD(pdev, pub.rx.intra_bss_fwd.packets_fwd,
                                1);
                } else {
                        adf_nbuf_t copy;
                        copy = adf_nbuf_copy(msdu);
                        if (copy) {
                            ol_rx_fwd_to_tx(tx_vdev, copy);
                            tx_vdev->fwd_tx_packets++;
                        }
                        TXRX_STATS_ADD(pdev,
                                pub.rx.intra_bss_fwd.packets_stack_n_fwd, 1);
                }
            }
        } else {
            TXRX_STATS_ADD(pdev, pub.rx.intra_bss_fwd.packets_stack, 1);
        }
        if (msdu) {
            /* send this frame to the OS */
            OL_TXRX_LIST_APPEND(deliver_list_head, deliver_list_tail, msdu);
        }
        msdu = msdu_list;
    }
    if (deliver_list_head) {
        adf_nbuf_set_next(deliver_list_tail, NULL); /* add NULL terminator */
        if (ol_cfg_is_full_reorder_offload(pdev->ctrl_pdev)) {
            ol_rx_in_order_deliver(vdev, peer, tid, deliver_list_head);
        } else {
            ol_rx_deliver(vdev, peer, tid, deliver_list_head);
        }
    }
}