void wep_dump(struct ieee80211_key *k, wbuf_t wbuf, int hdrlen) { struct ieee80211_frame *wh; struct wep_ctx *ctx = k->wk_private; struct ieee80211vap *vap = ctx->wc_vap; unsigned int iv,idx,icv; unsigned char *ptr; unsigned char kbuf[64]; wh = (struct ieee80211_frame *)wbuf_header(wbuf); ptr = (unsigned char*)wh; idx = iv = 0; memcpy(&iv, ptr+hdrlen, 3); idx = ptr[hdrlen+3]; memcpy(&icv, ptr+wbuf_get_pktlen(wbuf)-4, 4); memcpy(kbuf, k->wk_key, k->wk_keylen); IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr1, "%s and seq=%02x-%02x\n", "addr1", wh->i_seq[0], wh->i_seq[1]); IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr3, "%s", "addr3"); IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2, "IV=%08x idx=%d ICV=%08x, hdrlen=%d",iv, idx&0xff, icv, hdrlen); printk("key dump:len=%d\n", k->wk_keylen); dump_hex_buf(kbuf, (int)k->wk_keylen); printk("packet dump:pktlen=%d,len=%d\n", wbuf_get_pktlen(wbuf), wbuf_get_len(wbuf)); dump_hex_buf((uint8_t*)ptr/*wbuf_raw_data(wbuf)*/, (int)wbuf_get_pktlen(wbuf)); }
/* * Temporarily added to support older WMI events. We should move all events to unified * when the target is ready to support it. */ void wmi_control_rx(void *ctx, HTC_PACKET *htc_packet) { u_int16_t id; u_int8_t *data; u_int32_t len; int status = EOK; wmi_buf_t evt_buf; struct wmi_unified *wmi_handle = (struct wmi_unified *) ctx; evt_buf = (wmi_buf_t) htc_packet->pPktContext; /** * This is a HACK due to a Hack/WAR in HTC !!. * the head of the wbuf still contains the HTC header * but the length excludes htc header. */ wbuf_set_pktlen(evt_buf, htc_packet->ActualLength + HTC_HEADER_LEN); wbuf_pull(evt_buf, HTC_HEADER_LEN); id = WMI_GET_FIELD(wbuf_header(evt_buf), WMI_CMD_HDR, COMMANDID); if ((id >= WMI_START_EVENTID) && (id <= WMI_END_EVENTID)) { status = wmi_unified_event_rx(wmi_handle, evt_buf); return ; } if (wbuf_pull(evt_buf, sizeof(WMI_CMD_HDR)) == NULL) { status = -1; goto end; } data = wbuf_header(evt_buf); len = wbuf_get_pktlen(evt_buf); switch(id) { default: printk("%s: Unhandled WMI command %d\n", __func__, id); break; case WMI_SERVICE_READY_EVENTID: status = wmi_service_ready_event_rx(wmi_handle, data, len); break; case WMI_READY_EVENTID: status = wmi_ready_event_rx(wmi_handle, data, len); break; case WMI_WLAN_VERSION_EVENTID: printk("%s: Handle WMI_VERSION_EVENTID\n", __func__); break; case WMI_REGDOMAIN_EVENTID: printk("%s: Handle WMI_REGDOMAIN_EVENTID\n", __func__); break; case WMI_DEBUG_MESG_EVENTID: dbglog_message_handler(wmi_handle->scn_handle, evt_buf); return; } end: wbuf_free(evt_buf); }
/* * 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 }
int wlan_frm_haswscie(const wbuf_t wbuf) { const u_int8_t *frm = ((u_int8_t *)wbuf_header(wbuf) + sizeof(struct ieee80211_frame)); const u_int8_t *efrm = ((u_int8_t *)wbuf_header(wbuf) + wbuf_get_pktlen(wbuf)); while (frm < efrm) { switch (*frm) { case IEEE80211_ELEMID_VENDOR: if (iswpsoui((u_int8_t *)frm)) return 1; break; default: break; } frm += frm[1] + 2; } return 0; }
static int wmi_unified_event_rx(struct wmi_unified *wmi_handle, wmi_buf_t evt_buf) { u_int16_t id; u_int8_t *event; u_int16_t len; int status = -1; u_int16_t handler_id; ASSERT(evt_buf != NULL); id = WMI_GET_FIELD(wbuf_header(evt_buf), WMI_CMD_HDR, COMMANDID); handler_id = (id - WMI_START_EVENTID); if (wbuf_pull(evt_buf, sizeof(WMI_CMD_HDR)) == NULL) { //A_DPRINTF(DBG_WMI, (DBGFMT "bad packet 1\n", DBGARG)); //wmip->wmi_stats.cmd_len_err++; goto end; } if (handler_id >= WMI_UNIFIED_MAX_EVENT) { printk("%s : unkown event id : 0x%x event handler id 0x%x \n", __func__, id, handler_id); goto end; } event = wbuf_header(evt_buf); len = wbuf_get_pktlen(evt_buf); if (!wmi_handle->event_handler[handler_id]) { printk("%s : no registered event handler : event id 0x%x \n", __func__, id); goto end; } /* Call the WMI registered event handler */ status = wmi_handle->event_handler[handler_id](wmi_handle->scn_handle, event, len, wmi_handle->event_handler_cookie[handler_id]); end: wbuf_free(evt_buf); return status; }
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)); }
/* * processes data frames. * ieee80211_wow_magic_parser parses the wbuf to check if match magic packet. */ void ieee80211_wow_magic_parser(struct ieee80211_node *ni, wbuf_t wbuf) { struct ieee80211vap *vap = ni->ni_vap; a_uint8_t i_addr[IEEE80211_ADDR_LEN]; a_int32_t left_len = wbuf_get_pktlen(wbuf); a_uint8_t *cur_ptr; a_uint32_t dup_cnt, is_match = FALSE, is_bcast = FALSE; //wow_dump_pkt(wbuf->data, wbuf->len); if (left_len < IEEE80211_WOW_MAGIC_PKTLEN) return; cur_ptr = wbuf_header(wbuf); IEEE80211_ADDR_COPY(i_addr, vap->iv_myaddr); /* parse whole pkt */ while (cur_ptr && (left_len>0) && (!is_match)) { /* left len is less than magic pkt size, give up */ if (left_len < IEEE80211_WOW_MAGIC_PKTLEN) break; /* to skip continuous 0xFF and to match last 6 bytes of 0xFF */ while (IEEE80211_IS_BROADCAST(cur_ptr) && (left_len>=IEEE80211_WOW_MAGIC_PKTLEN)) { is_bcast = TRUE; cur_ptr += IEEE80211_ADDR_LEN; left_len -= IEEE80211_ADDR_LEN; } /* 6 bytes of 0xFF matched, to check if 16 duplications of the IEEE address */ if (is_bcast) { dup_cnt = 0; /* if 0xFF exists at head, skip it */ while ((cur_ptr[0]==0xFF) && (left_len>=IEEE80211_WOW_MAGIC_DUPLEN)) { cur_ptr++; left_len--; } /* left len is less than duplication size, give up */ if (left_len < IEEE80211_WOW_MAGIC_DUPLEN) break; /* to check if 16 duplications of the IEEE address */ while (cur_ptr && (left_len>=IEEE80211_ADDR_LEN) && IEEE80211_ADDR_EQ(cur_ptr, i_addr)) { cur_ptr += IEEE80211_ADDR_LEN; left_len -= IEEE80211_ADDR_LEN; dup_cnt++; if (dup_cnt >= IEEE80211_WOW_MAGIC_DUPCNT) { is_match = TRUE; break; } } /* not match magic pkt, keep parsing */ is_bcast = FALSE; } else { cur_ptr++; left_len--; } } if (is_match) { adf_os_print("Magic packet received...\n"); ieee80211_wow_set_gpio(vap); } }
int ccmp_encrypt(struct ieee80211_key *key, wbuf_t wbuf0, int hdrlen, int mfp) { struct ccmp_ctx *ctx = key->wk_private; struct ieee80211_frame *wh; wbuf_t wbuf = wbuf0; int data_len, i, space; uint8_t aad[2 * AES_BLOCK_LEN], b0[AES_BLOCK_LEN], b[AES_BLOCK_LEN], e[AES_BLOCK_LEN], s0[AES_BLOCK_LEN]; uint8_t *pos; ctx->cc_vap->iv_stats.is_crypto_ccmp++; wh = (struct ieee80211_frame *)wbuf_header(wbuf); data_len = wbuf_get_pktlen(wbuf) - (hdrlen + ccmp.ic_header); ccmp_init_blocks(&ctx->cc_aes, wh, key->wk_keytsc, data_len, b0, aad, b, s0, mfp); i = 1; pos = (u_int8_t *)wbuf_header(wbuf) + hdrlen + ccmp.ic_header; /* NB: assumes header is entirely in first mbuf */ space = wbuf_get_pktlen(wbuf) - (hdrlen + ccmp.ic_header); for (;;) { if (space > data_len) space = data_len; /* * Do full blocks. */ while (space >= AES_BLOCK_LEN) { CCMP_ENCRYPT(i, b, b0, pos, e, AES_BLOCK_LEN); pos += AES_BLOCK_LEN, space -= AES_BLOCK_LEN; data_len -= AES_BLOCK_LEN; i++; } if (data_len <= 0) /* no more data */ break; wbuf = wbuf_next(wbuf); if (wbuf == NULL) { /* last buffer */ if (space != 0) { /* * Short last block. */ CCMP_ENCRYPT(i, b, b0, pos, e, space); } break; } #if 1 /* assume only one chunk */ break; #else if (space != 0) { uint8_t *pos_next; int space_next; int len, dl, sp; wbuf_t wbufi_new; /* * Block straddles one or more mbufs, gather data * into the block buffer b, apply the cipher, then * scatter the results back into the mbuf chain. * The buffer will automatically get space bytes * of data at offset 0 copied in+out by the * CCMP_ENCRYPT request so we must take care of * the remaining data. */ wbuf_new = wbuf; dl = data_len; sp = space; for (;;) { pos_next = (u_int8_t *)wbuf_header(wbuf_new); len = min(dl, AES_BLOCK_LEN); space_next = len > sp ? len - sp : 0; if (wbuf_get_len(wbuf_new) >= space_next) { /* * This mbuf has enough data; just grab * what we need and stop. */ xor_block(b+sp, pos_next, space_next); break; } /* * This mbuf's contents are insufficient, * take 'em all and prepare to advance to * the next mbuf. */ xor_block(b+sp, pos_next, n->m_len); sp += wbuf_get_len(wbuf_new), dl -= wbuf_get_len(wbuf_new); wbuf_next = m_next; if (n == NULL) break; } CCMP_ENCRYPT(i, b, b0, pos, e, space); /* NB: just like above, but scatter data to mbufs */ dl = data_len; sp = space; for (;;) { pos_next = mtod(m, uint8_t *); len = min(dl, AES_BLOCK_LEN); space_next = len > sp ? len - sp : 0; if (m->m_len >= space_next) { xor_block(pos_next, e+sp, space_next); break; } xor_block(pos_next, e+sp, m->m_len); sp += m->m_len, dl -= m->m_len; m = m->m_next; if (m == NULL) goto done; } /* * Do bookkeeping. m now points to the last mbuf * we grabbed data from. We know we consumed a * full block of data as otherwise we'd have hit * the end of the mbuf chain, so deduct from data_len. * Otherwise advance the block number (i) and setup * pos+space to reflect contents of the new mbuf. */ data_len -= AES_BLOCK_LEN; i++; pos = pos_next + space_next; space = m->m_len - space_next; } else {
int ieee80211_recv_asreq(struct ieee80211_node *ni, wbuf_t wbuf, int subtype) { struct ieee80211com *ic = ni->ni_ic; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211_frame *wh; u_int8_t *frm, *efrm; u_int16_t capinfo, bintval; struct ieee80211_rsnparms rsn; u_int8_t reason; int reassoc, resp; u_int8_t *ssid, *rates, *xrates, *wpa, *wme, *ath, *htcap,*vendor_ie, *wps; u_int8_t *athextcap; if (vap->iv_opmode != IEEE80211_M_HOSTAP && vap->iv_opmode != IEEE80211_M_BTAMP) { vap->iv_stats.is_rx_mgtdiscard++; return -EINVAL; } wh = (struct ieee80211_frame *) wbuf_header(wbuf); frm = (u_int8_t *)&wh[1]; efrm = wbuf_header(wbuf) + wbuf_get_pktlen(wbuf); if (subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) { reassoc = 1; resp = IEEE80211_FC0_SUBTYPE_REASSOC_RESP; /*zhaoyang1 transplant from 717*/ /*pengruofeng add start for management frame stats 2011-5-9*/ vap->iv_stats.is_rx_reassoc++; /*pengruofeng add end 2011-5-9*/ /*zhaoyang1 transplant end*/ } else { reassoc = 0; resp = IEEE80211_FC0_SUBTYPE_ASSOC_RESP; } /* * asreq frame format * [2] capability information * [2] listen interval * [6*] current AP address (reassoc only) * [tlv] ssid * [tlv] supported rates * [tlv] extended supported rates * [tlv] WPA or RSN * [tlv] WME * [tlv] HT Capabilities * [tlv] Atheros capabilities */ IEEE80211_VERIFY_LENGTH(efrm - frm, (reassoc ? 10 : 4)); if (!IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_bss->ni_bssid)) { IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY, wh, ieee80211_mgt_subtype_name[subtype >> IEEE80211_FC0_SUBTYPE_SHIFT], "%s\n", "wrong bssid"); /*zhaoyang1 transplant from 717*/ /*pengruofeng add start for management frame stats 2011-5-9*/ if (reassoc) { vap->iv_stats.is_rx_reassoc_bss++; } else { vap->iv_stats.is_rx_assoc_bss++; } /*pengruofeng add end 2011-5-9*/ /*zhaoyang1 transplant end*/ return -EINVAL; }
int ieee80211_recv_probereq(struct ieee80211_node *ni, wbuf_t wbuf, int subtype) { struct ieee80211com *ic = ni->ni_ic; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211_frame *wh; u_int8_t *frm, *efrm; u_int8_t *ssid, *rates, *ven; #if ATH_SUPPORT_AP_WDS_COMBO if (vap->iv_opmode == IEEE80211_M_STA || !ieee80211_vap_ready_is_set(vap) || vap->iv_no_beacon) { #else if (vap->iv_opmode == IEEE80211_M_STA || !ieee80211_vap_ready_is_set(vap)) { #endif vap->iv_stats.is_rx_mgtdiscard++; /* XXX stat */ return -EINVAL; } wh = (struct ieee80211_frame *) wbuf_header(wbuf); frm = (u_int8_t *)&wh[1]; efrm = wbuf_header(wbuf) + wbuf_get_pktlen(wbuf); /*zhaoyang1 add start for probe request REQUIREMENTS-340*/ if (vap->iv_probe_request) { switch (vap->iv_probe_request) { case IEEE80211_BROADCAST_PROBE: if (IEEE80211_IS_BROADCAST(wh->i_addr1)) { vap->iv_stats.is_rx_mgtdiscard++; /* XXX stat */ return -EINVAL; } break; case IEEE80211_ALL_PROBE: vap->iv_stats.is_rx_mgtdiscard++; /* XXX stat */ return -EINVAL; default: printk("Probe_req value is wrong, iv_probe_request = %d\n", vap->iv_probe_request); break; } } /*zhaoyang1 add end*/ if (IEEE80211_IS_MULTICAST(wh->i_addr2)) { /* frame must be directed */ vap->iv_stats.is_rx_mgtdiscard++; /* XXX stat */ return -EINVAL; } /* * prreq frame format * [tlv] ssid * [tlv] supported rates * [tlv] extended supported rates * [tlv] Atheros Advanced Capabilities */ ssid = rates = NULL; while (((frm+1) < efrm) && (frm + frm[1] + 1 < efrm)) { switch (*frm) { case IEEE80211_ELEMID_SSID: ssid = frm; break; case IEEE80211_ELEMID_RATES: rates = frm; break; case IEEE80211_ELEMID_VENDOR: if (vap->iv_venie && vap->iv_venie->ven_oui_set) { ven = frm; if (ven[2] == vap->iv_venie->ven_oui[0] && ven[3] == vap->iv_venie->ven_oui[1] && ven[4] == vap->iv_venie->ven_oui[2]) { vap->iv_venie->ven_ie_len = MIN(ven[1] + 2, IEEE80211_MAX_IE_LEN); OS_MEMCPY(vap->iv_venie->ven_ie, ven, vap->iv_venie->ven_ie_len); } } break; } frm += frm[1] + 2; } if (frm > efrm) { return -EINVAL; } IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_MAXSIZE); IEEE80211_VERIFY_ELEMENT(ssid, IEEE80211_NWID_LEN); IEEE80211_VERIFY_SSID(vap->iv_bss, ssid); if (IEEE80211_VAP_IS_HIDESSID_ENABLED(vap) && (ssid[1] == 0)) { IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, wh, ieee80211_mgt_subtype_name[ subtype >> IEEE80211_FC0_SUBTYPE_SHIFT], "%s", "no ssid with ssid suppression enabled"); vap->iv_stats.is_rx_ssidmismatch++; /*XXX*/ return -EINVAL; } /* * Skip Probe Requests received while the scan algorithm is setting a new * channel, or while in a foreign channel. * Trying to transmit a frame (Probe Response) during a channel change * (which includes a channel reset) can cause a NMI due to invalid HW * addresses. * Trying to transmit the Probe Response while in a foreign channel * wouldn't do us any good either. */ if (ieee80211_scan_can_transmit(ic->ic_scanner)) ieee80211_send_proberesp(ni, wh->i_addr2, NULL,0); return 0; }
int ieee80211_recv_asreq(struct ieee80211_node *ni, wbuf_t wbuf, int subtype) { struct ieee80211com *ic = ni->ni_ic; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211_frame *wh; u_int8_t *frm, *efrm; u_int16_t capinfo, bintval; struct ieee80211_rsnparms rsn; u_int8_t reason; int reassoc, resp; u_int8_t *ssid, *rates, *xrates, *wpa, *wme, *ath, *htcap,*vendor_ie, *wps, *aow; u_int8_t *athextcap; #if UMAC_SUPPORT_WNM u_int8_t *timbcast; timbcast = NULL; #endif if (vap->iv_opmode != IEEE80211_M_HOSTAP && vap->iv_opmode != IEEE80211_M_BTAMP) { vap->iv_stats.is_rx_mgtdiscard++; return -EINVAL; } wh = (struct ieee80211_frame *) wbuf_header(wbuf); frm = (u_int8_t *)&wh[1]; efrm = wbuf_header(wbuf) + wbuf_get_pktlen(wbuf); if (subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) { reassoc = 1; resp = IEEE80211_FC0_SUBTYPE_REASSOC_RESP; uranus_report_wireless_event(ni->ni_vap, ni, WEVENT_AUTH_STATUS_REASSOC_REQ); } else { reassoc = 0; resp = IEEE80211_FC0_SUBTYPE_ASSOC_RESP; } /* * asreq frame format * [2] capability information * [2] listen interval * [6*] current AP address (reassoc only) * [tlv] ssid * [tlv] supported rates * [tlv] extended supported rates * [tlv] WPA or RSN * [tlv] WME * [tlv] HT Capabilities * [tlv] Atheros capabilities */ IEEE80211_VERIFY_LENGTH(efrm - frm, (reassoc ? 10 : 4)); if (!IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_bss->ni_bssid)) { IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY, wh, ieee80211_mgt_subtype_name[subtype >> IEEE80211_FC0_SUBTYPE_SHIFT], "%s\n", "wrong bssid"); vap->iv_stats.is_rx_assoc_bss++; uranus_report_wireless_event(ni->ni_vap, ni, WEVENT_AUTH_STATUS_ASSOC_FAILED); return -EINVAL; }
static int ath_rx_assemble_buf(struct ath_softc *sc, wbuf_t *wbuf, ieee80211_rx_status_t *status, u_int16_t keyix) { struct ath_buf *bf = NULL; struct sk_buff *kb = NULL; wbuf_t nwbuf; if (wbuf_next(*wbuf)) { /* for linux multiple receive buffer */ bf = ATH_GET_RX_CONTEXT_BUF(wbuf_next(*wbuf)); bf->bf_mpdu = wbuf_next(*wbuf); /* unlink the top half buffer and bottom half buffer */ wbuf_setnextpkt(*wbuf, NULL); /* use skb_copy_expand for combining two buffer, nwbuf = wbuf##twbuf */ nwbuf = skb_copy_expand((struct sk_buff *)*wbuf, 0, wbuf_get_pktlen(*wbuf)+wbuf_get_pktlen(bf->bf_mpdu), GFP_ATOMIC); if (nwbuf != NULL) { skb_copy_bits(bf->bf_mpdu, 0, wbuf_header(nwbuf) + wbuf_get_pktlen(*wbuf), wbuf_get_pktlen(bf->bf_mpdu)); kb = (struct sk_buff *)nwbuf; ((struct ieee80211_cb *)kb->cb)->context = &(((struct ieee80211_cb *)kb->cb)[1]); skb_put(nwbuf,wbuf_get_pktlen(bf->bf_mpdu)); wbuf_free(bf->bf_mpdu); bf->bf_mpdu = nwbuf; ATH_SET_RX_CONTEXT_BUF(nwbuf, bf); } else { ATH_GET_RX_CONTEXT_BUF(*wbuf)->bf_status |= ATH_BUFSTATUS_FREE; if (sc->sc_enhanceddmasupport) { wbuf_push(*wbuf, sc->sc_rxstatuslen); wbuf_push(bf->bf_mpdu, sc->sc_rxstatuslen); } wbuf_trim(bf->bf_mpdu, wbuf_get_pktlen(bf->bf_mpdu)); wbuf_trim(*wbuf, wbuf_get_pktlen(*wbuf)); bf->bf_buf_addr[0] = wbuf_map_single(sc->sc_osdev, bf->bf_mpdu, BUS_DMA_FROMDEVICE, OS_GET_DMA_MEM_CONTEXT(bf, bf_dmacontext)); /* relink unused wbuf to H/W */ ath_rx_requeue(sc, *wbuf); ath_rx_requeue(sc, bf->bf_mpdu); return -1; } ATH_GET_RX_CONTEXT_BUF(*wbuf)->bf_status |= ATH_BUFSTATUS_FREE; if (sc->sc_enhanceddmasupport) { wbuf_push(*wbuf, sc->sc_rxstatuslen); } wbuf_trim(*wbuf, wbuf_get_pktlen(*wbuf)); /* relink unused wbuf to H/W */ ath_rx_requeue(sc, *wbuf); *wbuf = bf->bf_mpdu; } return 0; }
/* * Log Tx data - logs into adapter's buffer if sc is not NULL; * logs into system-wide buffer if sc is NULL. */ void pktlog_txctl(struct ath_softc *sc, struct log_tx *log_data, u_int16_t iflags) { struct ath_pktlog_txctl *tx_log; int i, proto = PKTLOG_PROTO_NONE, proto_len = 0; u_int8_t misc_cnt; struct ath_pktlog_info *pl_info; struct ieee80211_frame *wh; u_int8_t dir; u_int32_t *ds_words, proto_hdr[PKTLOG_MAX_PROTO_WORDS]; HAL_DESC_INFO desc_info; u_int32_t flags = iflags; HAL_BOOL isSack = FALSE; wbuf_t wbuf; int frmlen; u_int32_t *proto_hdrp, *misc_p; if ((NULL == log_data->bf) || (NULL == log_data->bf->bf_mpdu)) { return; } if (g_pktlog_mode == PKTLOG_MODE_ADAPTER) pl_info = sc->pl_info; else pl_info = g_pktlog_info; if ((pl_info->log_state & ATH_PKTLOG_TX)== 0 || log_data->bf->bf_vdata == 0) { return; } misc_cnt = flags & PHFLAGS_MISCCNT_MASK; flags |= (((sc->ah_mac_rev << PHFLAGS_MACREV_SFT) & PHFLAGS_MACREV_MASK) | ((sc->ah_mac_version << PHFLAGS_MACVERSION_SFT) & PHFLAGS_MACVERSION_MASK)); #ifndef REMOVE_PKTLOG_PROTO if (pl_info->options & ATH_PKTLOG_PROTO) { proto = pktlog_proto(sc, proto_hdr, log_data, PKTLOG_PROTO_TX_DESC, &proto_len, &isSack); flags |= (proto << PHFLAGS_PROTO_SFT) & PHFLAGS_PROTO_MASK; } #endif tx_log = (struct ath_pktlog_txctl *)pktlog_getbuf(sc, pl_info, PKTLOG_TYPE_TXCTL, sizeof(*tx_log) + misc_cnt * sizeof(tx_log->misc[0]) + proto_len, flags); proto_hdrp = (u_int32_t *)&tx_log->proto_hdr; misc_p = (u_int32_t *) ((char *) proto_hdrp + roundup(proto_len,sizeof(int))); wh = (struct ieee80211_frame *) (wbuf_header(log_data->bf->bf_mpdu)); tx_log->framectrl = *(u_int16_t *)(wh->i_fc); tx_log->seqctrl = *(u_int16_t *)(wh->i_seq); dir = (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK); if(dir == IEEE80211_FC1_DIR_TODS) { tx_log->bssid_tail = (wh->i_addr1[IEEE80211_ADDR_LEN-2] << 8) | (wh->i_addr1[IEEE80211_ADDR_LEN-1]); tx_log->sa_tail = (wh->i_addr2[IEEE80211_ADDR_LEN-2] << 8) | (wh->i_addr2[IEEE80211_ADDR_LEN-1]); tx_log->da_tail = (wh->i_addr3[IEEE80211_ADDR_LEN-2] << 8) | (wh->i_addr3[IEEE80211_ADDR_LEN-1]); } else if(dir == IEEE80211_FC1_DIR_FROMDS) { tx_log->bssid_tail = (wh->i_addr2[IEEE80211_ADDR_LEN-2] << 8) | (wh->i_addr2[IEEE80211_ADDR_LEN-1]); tx_log->sa_tail = (wh->i_addr3[IEEE80211_ADDR_LEN-2] << 8) | (wh->i_addr3[IEEE80211_ADDR_LEN-1]); tx_log->da_tail = (wh->i_addr1[IEEE80211_ADDR_LEN-2] << 8) | (wh->i_addr1[IEEE80211_ADDR_LEN-1]); } else { tx_log->bssid_tail = (wh->i_addr3[IEEE80211_ADDR_LEN-2] << 8) | (wh->i_addr3[IEEE80211_ADDR_LEN-1]); tx_log->sa_tail = (wh->i_addr2[IEEE80211_ADDR_LEN-2] << 8) | (wh->i_addr2[IEEE80211_ADDR_LEN-1]); tx_log->da_tail = (wh->i_addr1[IEEE80211_ADDR_LEN-2] << 8) | (wh->i_addr1[IEEE80211_ADDR_LEN-1]); } ath_hal_getdescinfo(sc->sc_ah, &desc_info); ds_words = (u_int32_t *)(log_data->firstds) + desc_info.txctl_offset; for(i = 0; i < desc_info.txctl_numwords; i++) tx_log->txdesc_ctl[i] = ds_words[i]; for (i = 0; i < misc_cnt; i++) misc_p[i] = log_data->misc[i]; if ((pl_info->options & ATH_PKTLOG_TRIGGER_THRUPUT)) { wbuf = (wbuf_t)(log_data->bf->bf_mpdu); frmlen = wbuf_get_pktlen((wbuf_t)(log_data->bf->bf_mpdu)); pl_info->pktlen += frmlen; } if (proto != PKTLOG_PROTO_NONE) { OS_MEMCPY(proto_hdrp, proto_hdr, proto_len); if ((proto == PKTLOG_PROTO_TCP) && (pl_info->options & ATH_PKTLOG_TRIGGER_SACK)) { pktlog_trigger_sack(isSack, pl_info); } } }
/* * Update the dynamic parts of a beacon frame based on the current state. */ int ieee80211_beacon_update(struct ieee80211_node *ni, struct ieee80211_beacon_offsets *bo, wbuf_t wbuf, int mcast) { struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; int len_changed = 0; u_int16_t capinfo; struct ieee80211_frame *wh = (struct ieee80211_frame *)wbuf_header(wbuf); int enable_htrates; bool update_beacon_copy = false; #if ATH_SUPPORT_IBSS_DFS struct ieee80211_ibssdfs_ie *ibss_ie = NULL; #endif /* ATH_SUPPORT_IBSS_DFS */ /* If Beacon Tx is suspended, then don't send this beacon */ if (ieee80211_mlme_beacon_suspend_state(vap)) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s: skip Tx beacon during to suspend.\n", __func__); return -1; } /* * if vap is paused do not send any beacons to prevent transmitting beacons on wrong channel. */ if (ieee80211_vap_is_paused(vap)) return -1; /* use the non-QoS sequence number space for BSS node */ /* to avoid sw generated frame sequence the same as H/W generated frame, * the value lower than min_sw_seq is reserved for HW generated frame */ if ((ni->ni_txseqs[IEEE80211_NON_QOS_SEQ]& IEEE80211_SEQ_MASK) < MIN_SW_SEQ){ ni->ni_txseqs[IEEE80211_NON_QOS_SEQ] = MIN_SW_SEQ; } *(u_int16_t *)&wh->i_seq[0] = htole16(ni->ni_txseqs[IEEE80211_NON_QOS_SEQ] << IEEE80211_SEQ_SEQ_SHIFT); ni->ni_txseqs[IEEE80211_NON_QOS_SEQ]++; /* Check if channel change due to CW interference needs to be done. * Since this is a drastic channel change, we do not wait for the TBTT interval to expair and * do not send Channel change flag in beacon */ /* AUTELAN-Added-Begin : &tuqiang for openessid*/ if(openessid_param & OPENESSID_ENABLE_MASK) vap->channel_change_done = 1; /* AUTELAN-Added-End : [email protected] */ if (vap->channel_change_done) { u_int8_t *frm; IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH, "%s: reinit beacon\n", __func__); /* * NB: iv_bsschan is in the DSPARMS beacon IE, so must set this * prior to the beacon re-init, below. */ frm = (u_int8_t *) wbuf_header(wbuf) + sizeof(struct ieee80211_frame); frm = ieee80211_beacon_init(ni, bo, frm); update_beacon_copy = true; wbuf_set_pktlen(wbuf, (frm - (u_int8_t *)wbuf_header(wbuf))); len_changed = 1; vap->channel_change_done = 0; if ( ic->cw_inter_found) ic->cw_inter_found = 0; } if (ieee80211_ic_doth_is_set(ic) && (vap->iv_flags & IEEE80211_F_CHANSWITCH) && (vap->iv_chanchange_count == ic->ic_chanchange_tbtt) #ifdef MAGPIE_HIF_GMAC && !ic->ic_chanchange_cnt) { #else ) { #endif u_int8_t *frm; struct ieee80211_channel *c; vap->iv_chanchange_count = 0; IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH, "%s: reinit beacon\n", __func__); /* * NB: iv_bsschan is in the DSPARMS beacon IE, so must set this * prior to the beacon re-init, below. */ c = ieee80211_doth_findchan(vap, ic->ic_chanchange_chan); if (c == NULL) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH, "%s: find channel failure\n", __func__); return 0; } vap->iv_bsschan = c; frm = (u_int8_t *) wbuf_header(wbuf) + sizeof(struct ieee80211_frame); frm = ieee80211_beacon_init(ni, bo, frm); update_beacon_copy = true; wbuf_set_pktlen(wbuf, (frm - (u_int8_t *)wbuf_header(wbuf))); vap->iv_flags &= ~IEEE80211_F_CHANSWITCH; #ifdef MAGPIE_HIF_GMAC vap->iv_chanswitch = 0; #endif ic->ic_flags &= ~IEEE80211_F_CHANSWITCH; #if ATH_SUPPORT_IBSS_DFS if(vap->iv_opmode == IEEE80211_M_IBSS) { if (IEEE80211_ADDR_EQ(vap->iv_ibssdfs_ie_data.owner, vap->iv_myaddr)) { vap->iv_ibssdfs_state = IEEE80211_IBSSDFS_OWNER; } else { vap->iv_ibssdfs_state = IEEE80211_IBSSDFS_JOINER; } } #endif /* NB: only for the first VAP to get here */ if (ic->ic_curchan != c) { ieee80211_set_channel(ic, c); } len_changed = 1; } /*Begin:zhanghu added for beacon_frame rate support*/ else if(ic->ic_rate_mask != ic->ic_rate_mask_bak || \ ic->ic_mcs_mask != ic->ic_mcs_mask_bak){ u_int8_t *frm = NULL; frm = (u_int8_t *) wbuf_header(wbuf) + sizeof(struct ieee80211_frame); frm = ieee80211_beacon_init(ni, bo, frm); update_beacon_copy = true; wbuf_set_pktlen(wbuf, (frm - (u_int8_t *)wbuf_header(wbuf))); len_changed = 1; } /*End:zhanghu added for beacon_frame rate support*/ /* XXX faster to recalculate entirely or just changes? */ if (vap->iv_opmode == IEEE80211_M_IBSS) capinfo = IEEE80211_CAPINFO_IBSS; else capinfo = IEEE80211_CAPINFO_ESS; if (IEEE80211_VAP_IS_PRIVACY_ENABLED(vap)) capinfo |= IEEE80211_CAPINFO_PRIVACY; if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && IEEE80211_IS_CHAN_2GHZ(vap->iv_bsschan)) capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; if (ic->ic_flags & IEEE80211_F_SHSLOT) capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; if (ieee80211_ic_doth_is_set(ic) && ieee80211_vap_doth_is_set(vap)) capinfo |= IEEE80211_CAPINFO_SPECTRUM_MGMT; if (IEEE80211_VAP_IS_PUREB_ENABLED(vap)){ capinfo &= ~IEEE80211_CAPINFO_SHORT_SLOTTIME; } *bo->bo_caps = htole16(capinfo); if (ieee80211_vap_wme_is_set(vap) && #if ATH_SUPPORT_IBSS_WMM (vap->iv_opmode == IEEE80211_M_HOSTAP || vap->iv_opmode == IEEE80211_M_IBSS)) { #else vap->iv_opmode == IEEE80211_M_HOSTAP) { #endif struct ieee80211_wme_state *wme = &ic->ic_wme; /* XXX multi-bss */ if (vap->iv_flags & IEEE80211_F_WMEUPDATE) { (void) ieee80211_add_wme_param(bo->bo_wme, wme, IEEE80211_VAP_IS_UAPSD_ENABLED(vap)); update_beacon_copy = true; vap->iv_flags &= ~IEEE80211_F_WMEUPDATE; } } enable_htrates = ieee80211vap_htallowed(vap); /* * HT cap. check for vap is done in ieee80211vap_htallowed. * TBD: remove iv_bsschan check to support multiple channel operation. */ if (IEEE80211_IS_CHAN_11N(vap->iv_bsschan) && enable_htrates) { struct ieee80211_ie_htinfo_cmn *htinfo; struct ieee80211_ie_obss_scan *obss_scan; #if IEEE80211_BEACON_NOISY IEEE80211_DPRINTF(vap, IEEE80211_MSG_11N, "%s: AP: updating HT Info IE (ANA) for %s\n", __func__, ether_sprintf(ni->ni_macaddr)); if (bo->bo_htinfo[0] != IEEE80211_ELEMID_HTINFO_ANA) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_11N, "%s: AP: HT Info IE (ANA) beacon offset askew %s " "expected 0x%02x, found 0x%02x\n", __func__, ether_sprintf(ni->ni_macaddr), IEEE80211_ELEMID_HTINFO_ANA, bo->bo_htinfo[0] ); } #endif htinfo = &((struct ieee80211_ie_htinfo *)bo->bo_htinfo)->hi_ie; if (bo->bo_htinfo) ieee80211_update_htinfo_cmn(htinfo, ni); if (bo->bo_htcap) ieee80211_add_htcap(bo->bo_htcap, ni, IEEE80211_FC0_SUBTYPE_BEACON); if (!(ic->ic_flags & IEEE80211_F_COEXT_DISABLE)) { obss_scan = (struct ieee80211_ie_obss_scan *)bo->bo_obss_scan; /*Beginning:Modified by zhaoyang1 for APVXI-30 2013-03-04*/ if (obss_scan) ieee80211_update_obss_scan(obss_scan, ni); /*Ending:Modified by zhaoyang1 for APVXI-30 2013-03-04*/ } if (IEEE80211_IS_HTVIE_ENABLED(ic)) { #if IEEE80211_BEACON_NOISY IEEE80211_DPRINTF(vap, IEEE80211_MSG_11N, "%s: AP: updating HT Info IE (Vendor Specific) for %s\n", __func__, ether_sprintf(ni->ni_macaddr)); if (bo->bo_htinfo_vendor_specific[5] != IEEE80211_ELEMID_HTINFO) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_11N, "%s: AP: HT Info IE (Vendor Specific) beacon offset askew %s ", "expected 0x%02x, found 0x%02x\n", __func__, ether_sprintf(ni->ni_macaddr), IEEE80211_ELEMID_HTINFO_ANA, bo->bo_htinfo_vendor_specific[5] ); } #endif htinfo = &((struct vendor_ie_htinfo *)bo->bo_htinfo_vendor_specific)->hi_ie; ieee80211_update_htinfo_cmn(htinfo, ni); } } if (vap->iv_opmode == IEEE80211_M_HOSTAP || vap->iv_opmode == IEEE80211_M_IBSS) { struct ieee80211_tim_ie *tie = (struct ieee80211_tim_ie *) bo->bo_tim; if (IEEE80211_VAP_IS_TIMUPDATE_ENABLED(vap) && vap->iv_opmode == IEEE80211_M_HOSTAP) { u_int timlen, timoff, i; /* * ATIM/DTIM needs updating. If it fits in the * current space allocated then just copy in the * new bits. Otherwise we need to move any trailing * data to make room. Note that we know there is * contiguous space because ieee80211_beacon_allocate * insures there is space in the wbuf to write a * maximal-size virtual bitmap (based on ic_max_aid). */ /* * Calculate the bitmap size and offset, copy any * trailer out of the way, and then copy in the * new bitmap and update the information element. * Note that the tim bitmap must contain at least * one byte and any offset must be even. */ if (vap->iv_ps_pending != 0) { timoff = 128; /* impossibly large */ for (i = 0; i < vap->iv_tim_len; i++) { if (vap->iv_tim_bitmap[i]) { timoff = i &~ 1; break; } } KASSERT(timoff != 128, ("tim bitmap empty!")); for (i = vap->iv_tim_len-1; i >= timoff; i--) if (vap->iv_tim_bitmap[i]) break; timlen = 1 + (i - timoff); } else { timoff = 0; timlen = 1; } tie->tim_bitctl = timoff; if (timlen != bo->bo_tim_len) { int trailer_adjust = (tie->tim_bitmap+timlen) - bo->bo_tim_trailer; /* copy up/down trailer */ OS_MEMCPY(tie->tim_bitmap+timlen, bo->bo_tim_trailer, bo->bo_tim_trailerlen); bo->bo_tim_trailer = tie->tim_bitmap+timlen; bo->bo_chanswitch += trailer_adjust; bo->bo_wme += trailer_adjust; bo->bo_erp += trailer_adjust; bo->bo_ath_caps += trailer_adjust; bo->bo_appie_buf += trailer_adjust; bo->bo_xr += trailer_adjust; /*zhaoyang1 transplant from 717*/ /*Begin:Added by duanmingzhe for adjust pointer*/ bo->bo_htcap +=trailer_adjust; bo->bo_obss_scan +=trailer_adjust; bo->bo_extcap +=trailer_adjust; /*End:Added by duanmingzhe for adjust pointer*/ /*zhaoyang1 transplant end*/ #ifdef E_CSA bo->bo_extchanswitch += trailer_adjust; #endif /* E_CSA */ #if ATH_SUPPORT_IBSS_DFS bo->bo_ibssdfs += trailer_adjust; #endif /* ATH_SUPPORT_IBSS_DFS */ bo->bo_htinfo += trailer_adjust; bo->bo_htinfo_pre_ana += trailer_adjust; bo->bo_htinfo_vendor_specific += trailer_adjust; if (timlen > bo->bo_tim_len) wbuf_append(wbuf, timlen - bo->bo_tim_len); else wbuf_trim(wbuf, bo->bo_tim_len - timlen); bo->bo_tim_len = timlen; /* update information element */ tie->tim_len = 3 + timlen; len_changed = 1; } OS_MEMCPY(tie->tim_bitmap, vap->iv_tim_bitmap + timoff, bo->bo_tim_len); IEEE80211_VAP_TIMUPDATE_DISABLE(vap); IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, "%s: TIM updated, pending %u, off %u, len %u\n", __func__, vap->iv_ps_pending, timoff, timlen); } if (vap->iv_opmode == IEEE80211_M_HOSTAP) { /* count down DTIM period */ if (tie->tim_count == 0) tie->tim_count = tie->tim_period - 1; else tie->tim_count--; /* update state for buffered multicast frames on DTIM */ if (mcast && (tie->tim_count == 0 || tie->tim_period == 1)) tie->tim_bitctl |= 1; else tie->tim_bitctl &= ~1; } if (ieee80211_ic_doth_is_set(ic) && (ic->ic_flags & IEEE80211_F_CHANSWITCH) #ifdef MAGPIE_HIF_GMAC && (!vap->iv_chanswitch)) { #else ) { #endif if (!vap->iv_chanchange_count) { u_int8_t * tempbuf; vap->iv_flags |= IEEE80211_F_CHANSWITCH; /* copy out trailer to open up a slot */ tempbuf = OS_MALLOC(vap->iv_ic->ic_osdev, bo->bo_chanswitch_trailerlen , GFP_KERNEL); OS_MEMCPY(tempbuf,bo->bo_chanswitch, bo->bo_chanswitch_trailerlen); OS_MEMCPY(bo->bo_chanswitch + IEEE80211_CHANSWITCHANN_BYTES, tempbuf, bo->bo_chanswitch_trailerlen); OS_FREE(tempbuf); /* add ie in opened slot */ bo->bo_chanswitch[0] = IEEE80211_ELEMID_CHANSWITCHANN; bo->bo_chanswitch[1] = 3; /* fixed length */ bo->bo_chanswitch[2] = 1; /* stas get off for now */ bo->bo_chanswitch[3] = ic->ic_chanchange_chan; bo->bo_chanswitch[4] = ic->ic_chanchange_tbtt; /* update the trailer lens */ bo->bo_chanswitch_trailerlen += IEEE80211_CHANSWITCHANN_BYTES; #if ATH_SUPPORT_IBSS_DFS bo->bo_ibssdfs += IEEE80211_CHANSWITCHANN_BYTES; #endif /* ATH_SUPPORT_IBSS_DFS */ bo->bo_tim_trailerlen += IEEE80211_CHANSWITCHANN_BYTES; bo->bo_wme += IEEE80211_CHANSWITCHANN_BYTES; bo->bo_erp += IEEE80211_CHANSWITCHANN_BYTES; bo->bo_ath_caps += IEEE80211_CHANSWITCHANN_BYTES; bo->bo_appie_buf += IEEE80211_CHANSWITCHANN_BYTES; bo->bo_xr += IEEE80211_CHANSWITCHANN_BYTES; #ifdef E_CSA bo->bo_extchanswitch += IEEE80211_CHANSWITCHANN_BYTES; #endif /* E_CSA */ bo->bo_htinfo += IEEE80211_CHANSWITCHANN_BYTES; bo->bo_htinfo_pre_ana += IEEE80211_CHANSWITCHANN_BYTES; bo->bo_htinfo_vendor_specific += IEEE80211_CHANSWITCHANN_BYTES; bo->bo_htcap += IEEE80211_CHANSWITCHANN_BYTES; bo->bo_extcap += IEEE80211_CHANSWITCHANN_BYTES; bo->bo_obss_scan += IEEE80211_CHANSWITCHANN_BYTES; /* indicate new beacon length so other layers may manage memory */ wbuf_append(wbuf, IEEE80211_CHANSWITCHANN_BYTES); len_changed = 1; } else { #ifdef MAGPIE_HIF_GMAC if(vap->iv_chanchange_count != ic->ic_chanchange_tbtt) bo->bo_chanswitch[4]--; #else bo->bo_chanswitch[4]--; #endif } #ifdef MAGPIE_HIF_GMAC if(vap->iv_chanchange_count != ic->ic_chanchange_tbtt) { vap->iv_chanchange_count++; ic->ic_chanchange_cnt--; } if(vap->iv_chanchange_count == ic->ic_chanchange_tbtt) vap->iv_chanswitch = 1; #else vap->iv_chanchange_count++; #endif IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH, "%s: CHANSWITCH IE, change in %d \n", __func__, bo->bo_chanswitch[4]); } } #if ATH_SUPPORT_IBSS_DFS if (vap->iv_opmode == IEEE80211_M_IBSS && (ic->ic_curchan->ic_flagext & IEEE80211_CHAN_DFS)) { /*reset action frames counts for measrep and csa action */ vap->iv_measrep_action_count_per_tbtt = 0; vap->iv_csa_action_count_per_tbtt = 0; if(vap->iv_ibssdfs_state == IEEE80211_IBSSDFS_OWNER) { vap->iv_ibssdfs_ie_data.rec_interval = vap->iv_ibss_dfs_enter_recovery_threshold_in_tbtt; } ibss_ie =(struct ieee80211_ibssdfs_ie *) bo->bo_ibssdfs; if(ibss_ie) { if (OS_MEMCMP(bo->bo_ibssdfs, &vap->iv_ibssdfs_ie_data, ibss_ie->len + sizeof(struct ieee80211_ie_header))) { int trailer_adjust = vap->iv_ibssdfs_ie_data.len - ibss_ie->len; /* copy up/down trailer */ if(trailer_adjust > 0) { u_int8_t * tempbuf; tempbuf = OS_MALLOC(vap->iv_ic->ic_osdev, bo->bo_ibssdfs_trailerlen , GFP_KERNEL); if (tempbuf == NULL) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_ANY, "%s: Unable to alloc ibssdfs copy buf. Size=%d\n", __func__, bo->bo_ibssdfs_trailerlen); return -1; } OS_MEMCPY(tempbuf,bo->bo_ibssdfs + sizeof(struct ieee80211_ie_header) + ibss_ie->len, bo->bo_ibssdfs_trailerlen); OS_MEMCPY(bo->bo_ibssdfs + sizeof(struct ieee80211_ie_header) + vap->iv_ibssdfs_ie_data.len, tempbuf, bo->bo_ibssdfs_trailerlen); OS_FREE(tempbuf); } else { OS_MEMCPY(bo->bo_ibssdfs + sizeof(struct ieee80211_ie_header) + vap->iv_ibssdfs_ie_data.len , bo->bo_ibssdfs + sizeof(struct ieee80211_ie_header) + ibss_ie->len, bo->bo_ibssdfs_trailerlen); } bo->bo_tim_trailerlen += trailer_adjust; bo->bo_chanswitch_trailerlen += trailer_adjust; bo->bo_wme += trailer_adjust; bo->bo_erp += trailer_adjust; bo->bo_ath_caps += trailer_adjust; bo->bo_appie_buf += trailer_adjust; bo->bo_xr += trailer_adjust; #ifdef E_CSA bo->bo_extchanswitch += trailer_adjust; #endif /* E_CSA */ bo->bo_htinfo += trailer_adjust; bo->bo_htinfo_pre_ana += trailer_adjust; bo->bo_htinfo_vendor_specific += trailer_adjust; bo->bo_htcap += trailer_adjust; bo->bo_extcap += trailer_adjust; bo->bo_obss_scan += trailer_adjust; if (trailer_adjust > 0) { wbuf_append(wbuf, trailer_adjust); } else { wbuf_trim(wbuf, -trailer_adjust); } OS_MEMCPY(bo->bo_ibssdfs, &vap->iv_ibssdfs_ie_data, sizeof(struct ieee80211_ie_header) + vap->iv_ibssdfs_ie_data.len); len_changed = 1; } } if (vap->iv_ibssdfs_state == IEEE80211_IBSSDFS_JOINER || vap->iv_ibssdfs_state == IEEE80211_IBSSDFS_OWNER) { vap->iv_ibssdfs_recovery_count = vap->iv_ibssdfs_ie_data.rec_interval; ieee80211_ibss_beacon_update_stop(ic); } else if (vap->iv_ibssdfs_state == IEEE80211_IBSSDFS_WAIT_RECOVERY) { vap->iv_ibssdfs_recovery_count --; if(vap->iv_ibssdfs_recovery_count == 0) { IEEE80211_ADDR_COPY(vap->iv_ibssdfs_ie_data.owner, vap->iv_myaddr); vap->iv_ibssdfs_state = IEEE80211_IBSSDFS_OWNER; vap->iv_ibssdfs_recovery_count = vap->iv_ibssdfs_ie_data.rec_interval; ieee80211_dfs_action(vap, NULL); } } } #endif /* ATH_SUPPORT_IBSS_DFS */ if (vap->iv_opmode == IEEE80211_M_HOSTAP || vap->iv_opmode == IEEE80211_M_BTAMP) { /* No IBSS Support */ if (ieee80211_vap_erpupdate_is_set(vap) && bo->bo_erp) { (void) ieee80211_add_erp(bo->bo_erp, ic); ieee80211_vap_erpupdate_clear(vap); } } #ifdef E_CSA if (ieee80211_ic_doth_is_set(ic) && (ic->ic_flags & IEEE80211_F_CHANSWITCH)) { if (!vap->iv_chanchange_count) { /* copy out trailer to open up a slot */ OS_MEMCPY(bo->bo_extchanswitch + IEEE80211_EXTCHANSWITCHANN_BYTES, bo->bo_extchanswitch, bo->bo_extchanswitch_trailerlen); /* add ie in opened slot */ bo->bo_extchanswitch[0] = IEEE80211_ELEMID_EXTCHANSWITCHANN; bo->bo_extchanswitch[1] = 4; /* fixed length */ bo->bo_extchanswitch[2] = 1; /* stations get off for now */ /* * XXX: bo_extchanswitch[3] should be regulatory class instead * of country code. Currently there is no functionality to retrieve * the regulatory classe from HAL. Need to correct this later when * we fix the IEEE80211_ELEMID_EXTCHANSWITCHANN to ANA defined * value. */ bo->bo_extchanswitch[3] = ic->ic_country_code; bo->bo_extchanswitch[4] = ic->ic_chanchange_chan; bo->bo_extchanswitch[5] = ic->ic_chanchange_tbtt; /* update the trailer lens */ bo->bo_extchanswitch_trailerlen += IEEE80211_EXTCHANSWITCHANN_BYTES; bo->bo_ath_caps += IEEE80211_EXTCHANSWITCHANN_BYTES; bo->bo_appie_buf += IEEE80211_EXTCHANSWITCHANN_BYTES; #if ATH_SUPPORT_IBSS_DFS bo->bo_ibssdfs_trailerlen += IEEE80211_EXTCHANSWITCHANN_BYTES; #endif /* indicate new beacon length so other layers may manage memory */ wbuf_append(skb, IEEE80211_EXTCHANSWITCHANN_BYTES); len_changed = 1; } else { bo->bo_extchanswitch[5]--; } IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH, "%s: EXT CHANSWITCH IE, change in %d\n", __func__, bo->bo_extchanswitch[5]); } #endif /* E_CSA */ /* add APP_IE buffer if app updated it */ #ifdef ATH_BEACON_DEFERRED_PROC IEEE80211_VAP_LOCK(vap); #endif if (IEEE80211_VAP_IS_APPIE_UPDATE_ENABLED(vap)) { /* adjust the buffer size if the size is changed */ u_int8_t *frm; u_int32_t newlen = vap->iv_app_ie[IEEE80211_FRAME_TYPE_BEACON].length; /* Also add the length from the new App IE module */ newlen += vap->iv_app_ie_list[IEEE80211_FRAME_TYPE_BEACON].total_ie_len; if (newlen != bo->bo_appie_buf_len) { int diff_len; diff_len = newlen - bo->bo_appie_buf_len; bo->bo_appie_buf_len = (u_int16_t) newlen; /* update the trailer lens */ bo->bo_chanswitch_trailerlen += diff_len; bo->bo_tim_trailerlen += diff_len; if (diff_len > 0) wbuf_append(wbuf, diff_len); else wbuf_trim(wbuf, -(diff_len)); len_changed = 1; } if (vap->iv_app_ie[IEEE80211_FRAME_TYPE_BEACON].length) { OS_MEMCPY(bo->bo_appie_buf, vap->iv_app_ie[IEEE80211_FRAME_TYPE_BEACON].ie, vap->iv_app_ie[IEEE80211_FRAME_TYPE_BEACON].length); } /* Add the Application IE's */ if (vap->iv_app_ie_list[IEEE80211_FRAME_TYPE_BEACON].total_ie_len) { frm = bo->bo_appie_buf + vap->iv_app_ie[IEEE80211_FRAME_TYPE_BEACON].length; frm = ieee80211_mlme_app_ie_append(vap, IEEE80211_FRAME_TYPE_BEACON, frm); } IEEE80211_VAP_APPIE_UPDATE_DISABLE(vap); update_beacon_copy = true; } #ifdef ATH_BEACON_DEFERRED_PROC IEEE80211_VAP_UNLOCK(vap); #endif if (update_beacon_copy && ieee80211_vap_copy_beacon_is_set(vap)) { store_beacon_frame(vap, (u_int8_t *)wbuf_header(wbuf), wbuf_get_pktlen(wbuf)); } return len_changed; } int wlan_copy_ap_beacon_frame(wlan_if_t vaphandle, u_int32_t in_buf_size, u_int32_t *required_buf_size, void *buffer) { struct ieee80211vap *vap = vaphandle; void *beacon_buf; *required_buf_size = 0; /* Make sure that this VAP is SoftAP */ if (vap->iv_opmode != IEEE80211_M_HOSTAP) { return EPERM ; } if (!vap->iv_beacon_copy_buf) { /* Error: no beacon buffer */ return EPERM ; } if (in_buf_size < vap->iv_beacon_copy_len) { /* Input buffer too small */ *required_buf_size = vap->iv_beacon_copy_len; return ENOMEM ; } *required_buf_size = vap->iv_beacon_copy_len; beacon_buf = (void *)vap->iv_beacon_copy_buf; OS_MEMCPY(buffer, beacon_buf, vap->iv_beacon_copy_len); return EOK; }