예제 #1
0
static inline void
ol_rx_decap_to_native_wifi(
    struct ol_txrx_vdev_t *vdev,
    adf_nbuf_t msdu,
    struct ol_rx_decap_info_t *info,
    struct ethernet_hdr_t *ethr_hdr)
{
    struct ieee80211_frame_addr4 *wh;
    u_int16_t hdsize;

    /*
     * we need to remove Qos control field and HT control.
     * MSFT: http://msdn.microsoft.com/en-us/library/windows/hardware/ff552608(v=vs.85).aspx
     */
    wh = (struct ieee80211_frame_addr4 *)info->hdr;
    if ( (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) {
        hdsize = sizeof(struct ieee80211_frame_addr4);
    }
    else {
        hdsize = sizeof(struct ieee80211_frame);
    }
    wh = (struct ieee80211_frame_addr4 *) adf_nbuf_push_head(msdu, hdsize);
    TXRX_ASSERT2(wh != NULL);
    TXRX_ASSERT2(hdsize <= info->hdr_len);
    adf_os_mem_copy ((u_int8_t *)wh, info->hdr, hdsize);

    /* amsdu subfrm handling if ethr_hdr is not NULL  */
    if (ethr_hdr != NULL) {
        switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
        case IEEE80211_FC1_DIR_NODS:
            adf_os_mem_copy(wh->i_addr1, ethr_hdr->dest_addr, ETHERNET_ADDR_LEN);
            adf_os_mem_copy(wh->i_addr2, ethr_hdr->src_addr, ETHERNET_ADDR_LEN);
            break;
        case IEEE80211_FC1_DIR_TODS:
            adf_os_mem_copy(wh->i_addr2, ethr_hdr->src_addr, ETHERNET_ADDR_LEN);
            adf_os_mem_copy(wh->i_addr3, ethr_hdr->dest_addr, ETHERNET_ADDR_LEN);
            break;
        case IEEE80211_FC1_DIR_FROMDS:
            adf_os_mem_copy(wh->i_addr1, ethr_hdr->dest_addr, ETHERNET_ADDR_LEN);
            adf_os_mem_copy(wh->i_addr3, ethr_hdr->src_addr, ETHERNET_ADDR_LEN);
            break;
        case IEEE80211_FC1_DIR_DSTODS:
            adf_os_mem_copy(wh->i_addr3, ethr_hdr->dest_addr, ETHERNET_ADDR_LEN);
            adf_os_mem_copy(wh->i_addr4, ethr_hdr->src_addr, ETHERNET_ADDR_LEN);
            break;
        }
    }
    if (IEEE80211_QOS_HAS_SEQ(wh) ) {
        if (wh->i_fc[1] & IEEE80211_FC1_ORDER) {
            wh->i_fc[1] &= ~IEEE80211_FC1_ORDER;
        }
        wh->i_fc[0] &= ~IEEE80211_FC0_SUBTYPE_QOS;
    }
}
예제 #2
0
void
ol_rx_addba_handler(
    ol_txrx_pdev_handle pdev,
    u_int16_t peer_id,
    u_int8_t tid,
    u_int8_t win_sz)
{
    unsigned round_pwr2_win_sz, array_size;
    struct ol_txrx_peer_t *peer;
    struct ol_rx_reorder_t *rx_reorder;

    peer = ol_txrx_peer_find_by_id(pdev, peer_id);
    if (peer == NULL) {
        return;
    }
    rx_reorder = &peer->tids_rx_reorder[tid];

    TXRX_ASSERT2(win_sz <= 64);
    round_pwr2_win_sz = OL_RX_REORDER_ROUND_PWR2(win_sz);
    array_size = round_pwr2_win_sz * sizeof(struct ol_rx_reorder_array_elem_t);
    rx_reorder->array = adf_os_mem_alloc(pdev->osdev, array_size);
    TXRX_ASSERT1(rx_reorder->array);
    adf_os_mem_set(rx_reorder->array, 0x0, array_size);

    rx_reorder->win_sz_mask = round_pwr2_win_sz - 1;
}
예제 #3
0
int
ol_rx_reorder_store(
    struct ol_txrx_pdev_t *pdev,
    struct ol_txrx_peer_t *peer,
    unsigned tid,
    unsigned seq_num,
    adf_nbuf_t head_msdu,
    adf_nbuf_t tail_msdu)
{
    struct ol_rx_reorder_array_elem_t *rx_reorder_array_elem;
    TXRX_ASSERT2(tid < OL_TXRX_NUM_EXT_TIDS);

    /*
     * if host duplicate detection is enabled and aggregation is not
     * on, check if the incoming sequence number is a duplication of
     * the one just received.
     */
    if (pdev->rx.flags.dup_check && peer->tids_rx_reorder[tid].win_sz_mask == 0) {
        /*
         * TBDXXX: should we check the retry bit is set or not? A strict
         * duplicate packet should be the one with retry bit set;
         * however, since many implementations do not set the retry bit,
         * ignore the check for now.
         */
        if (seq_num == peer->tids_last_seq[tid]) {
            return -1;
        } 

    }

    peer->tids_last_seq[tid] = seq_num;

    seq_num &= peer->tids_rx_reorder[tid].win_sz_mask;
    rx_reorder_array_elem = &peer->tids_rx_reorder[tid].array[seq_num];
    if (rx_reorder_array_elem->head) {
        adf_nbuf_set_next(rx_reorder_array_elem->tail, head_msdu);
    } else {
        rx_reorder_array_elem->head = head_msdu;
    }
    rx_reorder_array_elem->tail = tail_msdu;

    return 0;
}
예제 #4
0
static inline void
ol_tx_set_ether_type(
    A_UINT8 *datap,
    struct ol_txrx_msdu_info_t *tx_msdu_info)
{
    A_UINT16 typeorlength;
    A_UINT8 * ptr;
    A_UINT8 *l3_data_ptr;

    if (tx_msdu_info->htt.info.l2_hdr_type == htt_pkt_type_raw) {
         /* adjust hdr_ptr to RA */
        struct ieee80211_frame *wh = (struct ieee80211_frame *)datap;

        if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) {
            struct llc_snap_hdr_t *llc;
            /* dot11 encapsulated frame */
            struct ieee80211_qosframe *whqos = (struct ieee80211_qosframe *)datap;
            if (whqos->i_fc[0] & IEEE80211_FC0_SUBTYPE_QOS) {
                tx_msdu_info->htt.info.l3_hdr_offset =
                    sizeof(struct ieee80211_qosframe);
            } else {
                tx_msdu_info->htt.info.l3_hdr_offset =
                    sizeof(struct ieee80211_frame);
            }
            llc = (struct llc_snap_hdr_t *)
                (datap + tx_msdu_info->htt.info.l3_hdr_offset);
            tx_msdu_info->htt.info.ethertype =
                (llc->ethertype[0] << 8) | llc->ethertype[1];
            /*
             * l3_hdr_offset refers to the end of the 802.3 or 802.11 header,
             * which may be a LLC/SNAP header rather than the IP header.
             * Thus, don't increment l3_hdr_offset += sizeof(*llc); rather,
             * leave it as is.
             */
        } else {
            /*
             * This function should only be applied to data frames.
             * For management frames, we already know to use HTT_TX_EXT_TID_MGMT.
             */
            TXRX_ASSERT2(0);
        }
    } else if (tx_msdu_info->htt.info.l2_hdr_type == htt_pkt_type_ethernet) {
        ptr = (datap + ETHERNET_ADDR_LEN * 2);
        typeorlength = (ptr[0] << 8) | ptr[1];
        l3_data_ptr = datap + sizeof(struct ethernet_hdr_t);//ETHERNET_HDR_LEN;

        if (typeorlength == ETHERTYPE_VLAN) {
            ptr = (datap + ETHERNET_ADDR_LEN * 2 + ETHERTYPE_VLAN_LEN);
            typeorlength = (ptr[0] << 8) | ptr[1];
            l3_data_ptr += ETHERTYPE_VLAN_LEN;
        }

        if (!IS_ETHERTYPE(typeorlength)) { // 802.3 header
            struct llc_snap_hdr_t *llc_hdr = (struct llc_snap_hdr_t *) l3_data_ptr;
            typeorlength = (llc_hdr->ethertype[0] << 8) | llc_hdr->ethertype[1];
            l3_data_ptr += sizeof(struct llc_snap_hdr_t);
        }

        tx_msdu_info->htt.info.l3_hdr_offset = (A_UINT8)(l3_data_ptr - datap);
        tx_msdu_info->htt.info.ethertype = typeorlength;
    }
}
예제 #5
0
static inline void
ol_rx_decap_to_8023 (
    struct ol_txrx_vdev_t *vdev,
    adf_nbuf_t msdu,
    struct ol_rx_decap_info_t *info,
    struct ethernet_hdr_t *ethr_hdr)
{
    struct llc_snap_hdr_t *llc_hdr;
    u_int16_t ether_type;
    u_int16_t l2_hdr_space;
    struct ieee80211_frame_addr4 *wh;
    u_int8_t local_buf[ETHERNET_HDR_LEN];
    u_int8_t *buf;

    /*
    * populate Ethernet header,
    * if ethr_hdr is null, rx frame is 802.11 format(HW ft disabled)
    * if ethr_hdr is not null, rx frame is "subfrm of amsdu".
    */
    buf = (u_int8_t *)adf_nbuf_data(msdu);
    llc_hdr = (struct llc_snap_hdr_t *)buf;
    ether_type = (llc_hdr->ethertype[0] << 8)|llc_hdr->ethertype[1];
    /* do llc remove if needed */
    l2_hdr_space = 0;
    if (IS_SNAP(llc_hdr)) {
        if (IS_BTEP(llc_hdr)) {
            /* remove llc*/
            l2_hdr_space += sizeof(struct llc_snap_hdr_t);
            llc_hdr = NULL;
        }
        else if (IS_RFC1042(llc_hdr)) {
            if ( !(ether_type == ETHERTYPE_AARP ||
                  ether_type == ETHERTYPE_IPX) ) {
                /* remove llc*/
                l2_hdr_space += sizeof(struct llc_snap_hdr_t);
                llc_hdr = NULL;
            }
        }
    }
    if (l2_hdr_space > ETHERNET_HDR_LEN) {
        buf = adf_nbuf_pull_head(msdu, l2_hdr_space - ETHERNET_HDR_LEN);
    }
    else if (l2_hdr_space <  ETHERNET_HDR_LEN) {
        buf = adf_nbuf_push_head(msdu, ETHERNET_HDR_LEN - l2_hdr_space);
    }

    /* normal msdu(non-subfrm of A-MSDU) if ethr_hdr is null */
    if (ethr_hdr == NULL) {
        /* mpdu hdr should be present in info,re-create ethr_hdr based on mpdu hdr*/
        TXRX_ASSERT2(info->hdr_len != 0);
        wh = (struct ieee80211_frame_addr4 *)info->hdr;
        ethr_hdr = (struct ethernet_hdr_t *)local_buf;
        switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
        case IEEE80211_FC1_DIR_NODS:
            adf_os_mem_copy(ethr_hdr->dest_addr, wh->i_addr1, ETHERNET_ADDR_LEN);
            adf_os_mem_copy(ethr_hdr->src_addr, wh->i_addr2, ETHERNET_ADDR_LEN);
            break;
        case IEEE80211_FC1_DIR_TODS:
            adf_os_mem_copy(ethr_hdr->dest_addr, wh->i_addr3, ETHERNET_ADDR_LEN);
            adf_os_mem_copy(ethr_hdr->src_addr, wh->i_addr2, ETHERNET_ADDR_LEN);
            break;
        case IEEE80211_FC1_DIR_FROMDS:
            adf_os_mem_copy(ethr_hdr->dest_addr, wh->i_addr1, ETHERNET_ADDR_LEN);
            adf_os_mem_copy(ethr_hdr->src_addr, wh->i_addr3, ETHERNET_ADDR_LEN);
            break;
        case IEEE80211_FC1_DIR_DSTODS:
            adf_os_mem_copy(ethr_hdr->dest_addr, wh->i_addr3, ETHERNET_ADDR_LEN);
            adf_os_mem_copy(ethr_hdr->src_addr, wh->i_addr4, ETHERNET_ADDR_LEN);
            break;
        }
    }
    if (llc_hdr == NULL) {
        ethr_hdr->ethertype[0] = (ether_type >> 8) & 0xff;
        ethr_hdr->ethertype[1] = (ether_type) & 0xff;
    }