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; } }
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; }
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; }
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; } }
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; }