void host_htc_eptx_comp(void *context, wbuf_t skb, HTC_ENDPOINT_ID epid) { /* for HTC, since we don't have the "real" tx-status, we do them here. */ struct ath_softc_net80211 *scn = (struct ath_softc_net80211 *)context; ath_dev_t sc_dev = scn->sc_dev; struct ath_softc *sc = ATH_DEV_TO_SC(sc_dev); u_int16_t min_len_req_by_stats = sizeof(ath_data_hdr_t)+sizeof(struct ieee80211_frame); if( wbuf_get_pktlen(skb)> min_len_req_by_stats && wbuf_get_tid(skb) < ATH_HTC_WME_NUM_TID &&( epid == sc->sc_data_BE_ep || epid == sc->sc_data_BK_ep || epid == sc->sc_data_VI_ep || epid == sc->sc_data_VO_ep )){ struct ieee80211_node *ni = wbuf_get_node(skb); struct ieee80211vap *vap = ni->ni_vap; struct ieee80211_frame *wh; struct ieee80211_tx_status ts; struct ieee80211_mac_stats *mac_stats; u_int8_t type, subtype; u_int8_t is_mcast; wh = (struct ieee80211_frame *)(wbuf_header(skb)+sizeof(ath_data_hdr_t)); type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; /* we fake ts becuase we don't have ts in HTC tx */ ts.ts_flags = 0; ts.ts_retries = 0; ieee80211_update_stats(vap, skb, wh, type, subtype, &ts); /* patch: HTC tx only ath_data_hdr length */ is_mcast = IEEE80211_IS_MULTICAST(wh->i_addr1) ? 1 : 0; mac_stats = is_mcast ? &vap->iv_multicast_stats : &vap->iv_unicast_stats; mac_stats->ims_tx_bytes -= sizeof(ath_data_hdr_t); } ieee80211_free_node(wbuf_get_node(skb)); }
/* * Searches for the presence of a protocol header and returns protocol type. * proto_len and proto_log are modified to return length (in bytes) and * contents of header (in host byte order), if one is found. */ static int pktlog_proto(struct ath_softc *sc, u_int32_t proto_log[PKTLOG_MAX_PROTO_WORDS], void *log_data, pktlog_proto_desc_t ds_type, int *proto_len, HAL_BOOL *isSack) { #define IPHDRLEN 20 struct llc *llc = NULL; struct log_tx *tx_log; struct log_rx *rx_log; wbuf_t wbuf = NULL; static const int pktlog_proto_min_hlen = sizeof(struct ieee80211_frame) + sizeof(struct llc) + IPHDRLEN; switch (ds_type) { case PKTLOG_PROTO_TX_DESC: tx_log = (struct log_tx *)log_data; wbuf = (wbuf_t)(tx_log->bf->bf_mpdu); if (wbuf_get_pktlen((wbuf_t)(tx_log->bf->bf_mpdu)) < pktlog_proto_min_hlen) { return PKTLOG_PROTO_NONE; } llc = (struct llc *)sc->sc_ieee_ops->parse_frm(sc->sc_ieee, wbuf, wbuf_get_node((wbuf_t)(tx_log->bf->bf_mpdu)), tx_log->bf->bf_vdata, 0); break; case PKTLOG_PROTO_RX_DESC: rx_log = (struct log_rx *)log_data; if (rx_log->status->rs_datalen < pktlog_proto_min_hlen) { return PKTLOG_PROTO_NONE; } llc = (struct llc *)sc->sc_ieee_ops->parse_frm(sc->sc_ieee, NULL, NULL, rx_log->bf->bf_vdata, rx_log->status->rs_keyix); break; default: return PKTLOG_PROTO_NONE; } if(!llc) { return PKTLOG_PROTO_NONE; } return pktlog_tcpip(sc, wbuf, llc, proto_log, proto_len, isSack); #undef IPHDRLEN }
/* * This routine picks an AMSDU buffer, calls the platform specific 802.11 layer for * WLAN encapsulation and then dispatches it to hardware for transmit. */ void ath_amsdu_stageq_flush(struct ath_softc_net80211 *scn, struct ath_amsdu_tx *amsdutx) { struct ieee80211_node *ni; struct ieee80211com *ic; wbuf_t wbuf; ATH_AMSDU_TXQ_LOCK(scn); wbuf = amsdutx->amsdu_tx_buf; if (!wbuf) { ATH_AMSDU_TXQ_UNLOCK(scn); return; } amsdutx->amsdu_tx_buf = NULL; ATH_AMSDU_TXQ_UNLOCK(scn); ni = wbuf_get_node(wbuf); ic = ni->ni_ic; /* * Encapsulate the packet for transmission */ wbuf = ieee80211_encap(ni, wbuf); if (wbuf == NULL) { printk("%s[%d] : ERROR: ieee80211_encap ret NULL\n", __func__, __LINE__); return; } /* There is only one wbuf to send */ if (wbuf != NULL) { int error = 0; ATH_DEFINE_TXCTL(txctl, wbuf); HTC_WBUF_TX_DELCARE /* prepare this frame */ if (ath_tx_prepare(scn, wbuf, 0, txctl) != 0) { goto bad; } HTC_WBUF_TX_DATA_PREPARE(ic, scn); if (error == 0) { /* send this frame to hardware */ txctl->an = (ATH_NODE_NET80211(ni))->an_sta; if (scn->sc_ops->tx(scn->sc_dev, wbuf, txctl) != 0) { goto bad; } else { HTC_WBUF_TX_DATA_COMPLETE_STATUS(ic); } } }
/* * callback hadlers: Action frames TX Complete. */ void ath_action_tx_event(void *Context, int8_t tx_status) { struct ath_softc_net80211 *scn = (struct ath_softc_net80211 *)Context; struct ath_usb_p2p_action_queue *p2p_action_wbuf; IEEE80211_STATE_P2P_ACTION_LOCK_IRQ(scn); if (scn->sc_p2p_action_queue_head) { ieee80211_vap_complete_buf_handler handler; void *arg; wbuf_t wbuf; p2p_action_wbuf = scn->sc_p2p_action_queue_head; if (scn->sc_p2p_action_queue_head == scn->sc_p2p_action_queue_tail) { scn->sc_p2p_action_queue_head = scn->sc_p2p_action_queue_tail = NULL; } else { scn->sc_p2p_action_queue_head = scn->sc_p2p_action_queue_head->next; } wbuf = p2p_action_wbuf->wbuf; if (!p2p_action_wbuf->deleted) { wbuf_get_complete_handler(wbuf,(void **)&handler, &arg); if (handler) { struct ieee80211_node *ni = wbuf_get_node(wbuf); struct ieee80211_frame *wh = (struct ieee80211_frame *)wbuf_header(wbuf); wlan_if_t vap = ni->ni_vap; struct ieee80211_tx_status ts; ts.ts_flags = tx_status; ts.ts_retries = 0; handler(vap, wbuf, arg, wh->i_addr1, wh->i_addr2, wh->i_addr3, &ts); } } else { #ifndef MAGPIE_HIF_GMAC printk("### action frame %p marked as deleted\n", wbuf); #endif } wbuf_release(scn->sc_osdev, p2p_action_wbuf->wbuf); OS_FREE(p2p_action_wbuf); //printk("### %s (%d) : Action TX EVENT DONE...\n", __FUNCTION__, __LINE__); } IEEE80211_STATE_P2P_ACTION_UNLOCK_IRQ(scn); }
u_int8_t ath_htc_find_tgt_node_index(wbuf_t wbuf) { struct ieee80211_node *ni = wbuf_get_node(wbuf); return ath_find_tgt_node_index(ni); }
/* * Add privacy headers appropriate for the specified key. */ static int ccmp_encap(struct ieee80211_key *k, wbuf_t wbuf, u_int8_t keyid) { struct ccmp_ctx *ctx = k->wk_private; struct ieee80211com *ic = ctx->cc_ic; u_int8_t *ivp; int hdrlen; int is4addr, isqos, owl_wdswar; struct ieee80211_frame *wh; struct ieee80211_node *ni = wbuf_get_node(wbuf); wh = (struct ieee80211_frame *)wbuf_header(wbuf); is4addr = ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) ? 1 : 0; isqos = IEEE80211_QOS_HAS_SEQ(wh); owl_wdswar = (ni->ni_flags & IEEE80211_NODE_OWL_WDSWAR); hdrlen = ieee80211_hdrspace(ic, wbuf_header(wbuf)); /* * Copy down 802.11 header and add the IV, KeyID, and ExtIV. */ #ifndef __CARRIER_PLATFORM__ ivp = (u_int8_t *)wbuf_push(wbuf, ccmp.ic_header); /* * refresh the wh pointer, * wbuf header pointer is changed with wbuf_push. */ wh = (struct ieee80211_frame *) wbuf_header(wbuf); /* recompute wh */ memmove(ivp, ivp + ccmp.ic_header, hdrlen); #else if (wbuf_is_encap_done(wbuf)) { ivp = (u_int8_t *)wbuf_header(wbuf); } else { ivp = (u_int8_t *)wbuf_push(wbuf, ccmp.ic_header); memmove(ivp, ivp + ccmp.ic_header, hdrlen); /* * refresh the wh pointer, * wbuf header pointer is changed with wbuf_push. */ wh = (struct ieee80211_frame *) wbuf_header(wbuf); /* recompute wh */ } #endif ivp += hdrlen; /* * Due to OWL specific HW bug, increment key tsc by 16, since * we're copying the TID into bits [3:0] of IV0. * XXX: Need logic to not implement workaround for SOWL or greater. */ if (is4addr && isqos && owl_wdswar) k->wk_keytsc += 16; else k->wk_keytsc++; /* XXX wrap at 48 bits */ ivp[0] = k->wk_keytsc >> 0; /* PN0 */ ivp[1] = k->wk_keytsc >> 8; /* PN1 */ ivp[2] = 0; /* Reserved */ ivp[3] = keyid | IEEE80211_WEP_EXTIV; /* KeyID | ExtID */ ivp[4] = k->wk_keytsc >> 16; /* PN2 */ ivp[5] = k->wk_keytsc >> 24; /* PN3 */ ivp[6] = k->wk_keytsc >> 32; /* PN4 */ ivp[7] = k->wk_keytsc >> 40; /* PN5 */ /* * Finally, do software encrypt if neeed. */ if (k->wk_flags & IEEE80211_KEY_SWCRYPT) { if (!ccmp_encrypt(k, wbuf, hdrlen, 0)) { return 0; } } if ((k->wk_flags & IEEE80211_KEY_MFP) && IEEE80211_IS_MFP_FRAME(wh)) { if (ic->ic_get_mfpsupport(ic) != IEEE80211_MFP_HW_CRYPTO) { /* HW MFP is not enabled - do software encrypt */ if (!ccmp_encrypt(k, wbuf, hdrlen, 1)) { return 0; } } } return 1; }