static wlan_btamp_conn_sm_t ieee80211_btamp_get_smhandle(wlan_btamp_conn_sm_t *smhandle, u_int8_t *peer_addr, int cur_state) { u_int8_t phyLink; wlan_btamp_conn_sm_t sm = NULL; for (phyLink = 0; phyLink < AMP_MAX_PHY_LINKS; phyLink++) { if (!smhandle[phyLink]) continue; sm = smhandle[phyLink]; if (peer_addr && OS_MEMCMP(sm->peer, peer_addr, IEEE80211_ADDR_LEN) == 0) break; if (!peer_addr && ieee80211_sm_get_curstate(sm->hsm_handle) == cur_state) break; } if (phyLink >= AMP_MAX_PHY_LINKS) sm = NULL; return sm; }
/** * visCheckProject * * Verifies if the currently loaded project ID of this library instance is still * the same as of the project ID of the attached ATCMControl Run Time System. * * Important: If this function fails, all stored addresses must be abandoned and * reloaded again from the attached RTS. (Possibly a new download to the remote * RTS has been done.) * * return OK if successful, else error number. * */ VIS_UINT visCheckProject(void) { SVisInfo *pVI = &g_VI; IEC_UINT uRes = OK; IEC_DATA *pProjectID; if (pVI->bInitialized == FALSE) { RETURN(ERR_INIT); } if (pVI->bLogin == FALSE) { RETURN(ERR_LOGIN); } uRes = domGetProjVersion(pVI, &pProjectID); if (uRes != OK) { RETURN(uRes); } uRes = (IEC_UINT)(OS_MEMCMP(pVI->pProjectID, pProjectID, VMM_GUID) == 0 ? OK : ERR_WRONG_PROJECT); osFree(&pProjectID); return uRes; }
mi_node_t * mi_tbl_lkup2(mi_node_t *root, u_int8_t *ip, int ipver) { int i, len = mi_ip_len(ipver); for (i = 0; i < NUM_MITBL_ENTRIES; i++) { if (!mi_node_is_free(&mi_tbl[i]) && (mi_tbl[i].ip_ver == ipver) && (OS_MEMCMP(ip, mi_tbl[i].ip, len) == 0)) { return &mi_tbl[i]; } } return NULL; }
int ieee80211_vap_match_ssid(struct ieee80211vap *vap, const u_int8_t *ssid, u_int8_t ssidlen) { int i; for (i = 0; i < vap->iv_des_nssid; i++) { if ((vap->iv_des_ssid[i].len == ssidlen) && (OS_MEMCMP(vap->iv_des_ssid[i].ssid, ssid, ssidlen) == 0)) { /* find a matching entry */ return 1; } } return 0; }
static void ieee80211_vap_iter_find_connection(void *arg, struct ieee80211vap *vap, bool is_last_vap) { struct ieee80211_mlme_find_connection *pmlme_find_connection_data = arg; UNREFERENCED_PARAMETER(is_last_vap); /* * If we haven't found a connection yet, check to see if current VAP is * connected to the specified AP. */ if (! pmlme_find_connection_data->connection_found) { /* * Since ieee80211_mlme_get_bss_entry is not implemented, compare * iv_bss's and scan_entry's SSID and BSSID. */ struct ieee80211_node *bss_node = ieee80211vap_get_bssnode(vap); if (bss_node != NULL) { /* * Check for BSSID match first; SSID matching is a more expensive * operation and should be checked last. */ if (IEEE80211_ADDR_EQ(wlan_node_getbssid(bss_node), wlan_scan_entry_bssid(pmlme_find_connection_data->scan_entry))) { ieee80211_ssid bss_ssid; u_int8_t scan_entry_ssid_len; u_int8_t *scan_entry_ssid; /* * BSSID matched, let's check the SSID */ wlan_get_bss_essid(vap, &bss_ssid); scan_entry_ssid = wlan_scan_entry_ssid(pmlme_find_connection_data->scan_entry, &scan_entry_ssid_len); if (scan_entry_ssid != NULL) { pmlme_find_connection_data->connection_found = (scan_entry_ssid_len == bss_ssid.len) && (OS_MEMCMP(scan_entry_ssid, bss_ssid.ssid, bss_ssid.len) == 0); } } } } }
v_BOOL_t vos_is_mmie_valid(v_U8_t *igtk, v_U8_t *ipn, v_U8_t* frm, v_U8_t* efrm) { struct ieee80211_mmie *mmie; struct ieee80211_frame *wh; v_U8_t *rx_ipn, aad[AAD_LEN], mic[CMAC_TLEN], *input; v_U16_t nBytes = 0; int ret = 0; struct crypto_cipher *tfm; /* Check if frame is invalid length */ if ((efrm < frm) || ((efrm - frm) < sizeof(*wh))) { VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "Invalid frame length"); return VOS_FALSE; } mmie = (struct ieee80211_mmie *)(efrm - sizeof(*mmie)); /* Check Element ID */ if ((mmie->element_id != IEEE80211_ELEMID_MMIE) || (mmie->length != (sizeof(*mmie)-2))) { VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "IE is not Mgmt MIC IE or Invalid length"); /* IE is not Mgmt MIC IE or invalid length */ return VOS_FALSE; } /* Validate IPN */ rx_ipn = mmie->sequence_number; if (OS_MEMCMP(rx_ipn, ipn, CMAC_IPN_LEN) <= 0) { /* Replay error */ VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "Replay error mmie ipn %02X %02X %02X %02X %02X %02X" " drvr ipn %02X %02X %02X %02X %02X %02X", rx_ipn[0], rx_ipn[1], rx_ipn[2], rx_ipn[3], rx_ipn[4], rx_ipn[5], ipn[0], ipn[1], ipn[2], ipn[3], ipn[4], ipn[5]); return VOS_FALSE; } #if !defined(CONFIG_CNSS) && (defined(HIF_USB) || defined(HIF_SDIO)) tfm = crypto_alloc_cipher( "aes", 0, CRYPTO_ALG_ASYNC); #else tfm = wcnss_wlan_crypto_alloc_cipher( "aes", 0, CRYPTO_ALG_ASYNC); #endif if (IS_ERR(tfm)) { ret = PTR_ERR(tfm); tfm = NULL; VOS_TRACE(VOS_MODULE_ID_VOSS,VOS_TRACE_LEVEL_ERROR, "crypto_alloc_cipher failed (%d)", ret); goto err_tfm; } ret = crypto_cipher_setkey(tfm, igtk, AES_KEYSIZE_128); if (ret) { VOS_TRACE(VOS_MODULE_ID_VOSS,VOS_TRACE_LEVEL_ERROR, "crypto_cipher_setkey failed (%d)", ret); goto err_tfm; } /* Construct AAD */ wh = (struct ieee80211_frame *)frm; /* Generate BIP AAD: FC(masked) || A1 || A2 || A3 */ /* FC type/subtype */ aad[0] = wh->i_fc[0]; /* Mask FC Retry, PwrMgt, MoreData flags to zero */ aad[1] = wh->i_fc[1] & ~(IEEE80211_FC1_RETRY | IEEE80211_FC1_PWR_MGT | IEEE80211_FC1_MORE_DATA); /* A1 || A2 || A3 */ vos_mem_copy(aad + 2, wh->i_addr_all, 3 * IEEE80211_ADDR_LEN); /* MIC = AES-128-CMAC(IGTK, AAD || Management Frame Body || MMIE, 64) */ nBytes = AAD_LEN + (efrm - (v_U8_t*)(wh+1)); input = (v_U8_t *)vos_mem_malloc(nBytes); if (NULL == input) { VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "Memory allocation failed"); ret = VOS_STATUS_E_NOMEM; goto err_tfm; } /* Copy the AAD, MMIE with 8 bit MIC zeroed out */ vos_mem_zero(input, nBytes); vos_mem_copy(input, aad, AAD_LEN); vos_mem_copy(input+AAD_LEN, (v_U8_t*)(wh+1), nBytes - AAD_LEN - CMAC_TLEN); #if !defined(CONFIG_CNSS) && (defined(HIF_USB) || defined(HIF_SDIO)) cmac_calc_mic(tfm, input, nBytes, mic); #else wcnss_wlan_cmac_calc_mic(tfm, input, nBytes, mic); #endif vos_mem_free(input); VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "CMAC(T)= %02X %02X %02X %02X %02X %02X %02X %02X", mic[0], mic[1], mic[2], mic[3], mic[4], mic[5], mic[6], mic[7]); if (OS_MEMCMP(mic, mmie->mic, CMAC_TLEN) != 0) { /* MMIE MIC mismatch */ VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "BC/MC MGMT frame MMIE MIC check Failed" " rmic %02X %02X %02X %02X %02X %02X %02X %02X" " cmic %02X %02X %02X %02X %02X %02X %02X %02X", mmie->mic[0], mmie->mic[1], mmie->mic[2], mmie->mic[3], mmie->mic[4], mmie->mic[5], mmie->mic[6], mmie->mic[7], mic[0], mic[1], mic[2], mic[3], mic[4], mic[5], mic[6], mic[7]); return VOS_FALSE; } /* Update IPN */ vos_mem_copy(ipn, rx_ipn, CMAC_IPN_LEN); err_tfm: if (tfm) #if !defined(CONFIG_CNSS) && (defined(HIF_USB) || defined(HIF_SDIO)) crypto_free_cipher(tfm); #else wcnss_wlan_crypto_free_cipher(tfm); #endif return !ret?VOS_TRUE:VOS_FALSE; }
void ieee80211_recv_beacon_ibss(struct ieee80211_node *ni, wbuf_t wbuf, int subtype, struct ieee80211_rx_status *rs, ieee80211_scan_entry_t scan_entry) { struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; u_int16_t capinfo; int ibssmerge = 0; struct ieee80211_channelswitch_ie *chanie = NULL; struct ieee80211_extendedchannelswitch_ie *echanie = NULL; struct ieee80211_frame *wh; u_int64_t tsf; u_int8_t *quiet_elm = NULL; bool free_node = FALSE; #if ATH_SUPPORT_IBSS_DFS struct ieee80211_ibssdfs_ie *ibssdfsie = NULL; #endif /* ATH_SUPPORT_IBSS_DFS */ wh = (struct ieee80211_frame *)wbuf_header(wbuf); capinfo = ieee80211_scan_entry_capinfo(scan_entry); if (!(capinfo & IEEE80211_CAPINFO_IBSS)) return; OS_MEMCPY((u_int8_t *)&tsf, ieee80211_scan_entry_tsf(scan_entry), sizeof(tsf)); if (ni != ni->ni_bss_node) { OS_MEMCPY(ni->ni_tstamp.data, &tsf, sizeof(ni->ni_tstamp)); /* update activity indication */ ni->ni_beacon_rstamp = OS_GET_TIMESTAMP(); ni->ni_probe_ticks = 0; } /* * Check BBSID before updating our beacon configuration to make * sure the received beacon really belongs to our Adhoc network. */ if ((subtype == IEEE80211_FC0_SUBTYPE_BEACON) && ieee80211_vap_ready_is_set(vap) && (IEEE80211_ADDR_EQ(wh->i_addr3, ieee80211_node_get_bssid(vap->iv_bss)))) { /* * if the neighbor is not in the list, add it to the list. */ if (ni == ni->ni_bss_node) { ni = ieee80211_add_neighbor(ni, scan_entry); if (ni == NULL) { return; } OS_MEMCPY(ni->ni_tstamp.data, &tsf, sizeof(ni->ni_tstamp)); free_node = TRUE; } ni->ni_rssi = rs->rs_rssi; /* * record tsf of last beacon into bss node */ OS_MEMCPY(ni->ni_bss_node->ni_tstamp.data, &tsf, sizeof(ni->ni_tstamp)); /* * record absolute time of last beacon */ vap->iv_last_beacon_time = OS_GET_TIMESTAMP(); ic->ic_beacon_update(ni, rs->rs_rssi); #if ATH_SUPPORT_IBSS_WMM /* * check for WMM parameters */ if ((ieee80211_scan_entry_wmeparam_ie(scan_entry) != NULL) || (ieee80211_scan_entry_wmeinfo_ie(scan_entry) != NULL)) { /* Node is WMM-capable if WME IE (either subtype) is present */ ni->ni_ext_caps |= IEEE80211_NODE_C_QOS; /* QOS-enable */ ieee80211node_set_flag(ni, IEEE80211_NODE_QOS); } else { /* If WME IE not present node is not WMM capable */ ni->ni_ext_caps &= ~IEEE80211_NODE_C_QOS; ieee80211node_clear_flag(ni, IEEE80211_NODE_QOS); } #endif #if ATH_SUPPORT_IBSS_DFS if (ic->ic_curchan->ic_flagext & IEEE80211_CHAN_DFS) { //check and see if we need to update other info for ibss_dfsie ibssdfsie = (struct ieee80211_ibssdfs_ie *)ieee80211_scan_entry_ibssdfs_ie(scan_entry); if(ibssdfsie) { if (ieee80211_check_and_update_ibss_dfs(vap, ibssdfsie)) { ieee80211_ibss_beacon_update_start(ic); } } /* update info from DFS owner */ if(ibssdfsie){ if(IEEE80211_ADDR_EQ(wh->i_addr2, ibssdfsie->owner)) { if(OS_MEMCMP(ibssdfsie, &vap->iv_ibssdfs_ie_data, MIN_IBSS_DFS_IE_CONTENT_SIZE)) { if(le64_to_cpu(tsf) >= rs->rs_tstamp.tsf){ IEEE80211_ADDR_COPY(vap->iv_ibssdfs_ie_data.owner, ibssdfsie->owner); vap->iv_ibssdfs_ie_data.rec_interval = ibssdfsie->rec_interval; ieee80211_ibss_beacon_update_start(ic); } } } } /* check if owner and it is not transmitting ibssIE */ else if(IEEE80211_ADDR_EQ(wh->i_addr2, vap->iv_ibssdfs_ie_data.owner)){ IEEE80211_ADDR_COPY(vap->iv_ibssdfs_ie_data.owner, vap->iv_myaddr); vap->iv_ibssdfs_state = IEEE80211_IBSSDFS_OWNER; ieee80211_ibss_beacon_update_start(ic); } } #endif /* ATH_SUPPORT_IBSS_DFS */ /* * check for spectrum management */ if (capinfo & IEEE80211_CAPINFO_SPECTRUM_MGMT) { chanie = (struct ieee80211_channelswitch_ie *) ieee80211_scan_entry_csa(scan_entry); #if ATH_SUPPORT_IBSS_DFS if(chanie) { OS_MEMCPY(&vap->iv_channelswitch_ie_data, chanie, sizeof(struct ieee80211_channelswitch_ie)); ieee80211_ibss_beacon_update_start(ic); } #endif /* ATH_SUPPORT_IBSS_DFS */ echanie = (struct ieee80211_extendedchannelswitch_ie *) ieee80211_scan_entry_xcsa(scan_entry); if ((!chanie) && (!echanie)) { quiet_elm = ieee80211_scan_entry_quiet(scan_entry); } } } /* * Handle ibss merge as needed; check the tsf on the * frame before attempting the merge. The 802.11 spec * says the station should change its bssid to match * the oldest station with the same ssid, where oldest * is determined by the tsf. Note that hardware * reconfiguration happens through callback to * ath as the state machine will go from * RUN -> RUN when this happens. */ if (ieee80211_vap_ready_is_set(vap) && (le64_to_cpu(tsf) >= rs->rs_tstamp.tsf)) { ibssmerge = ieee80211_ibss_merge(ni,scan_entry); } if (ibssmerge) { ieee80211_mlme_adhoc_merge_start(ni); } /* * RNWF-specific: indicate to NDIS about the potential association. * It should be done after IBSS merge, which is called from ath_beacon_update(). */ if (IEEE80211_ADDR_EQ(wh->i_addr3, ieee80211_node_get_bssid(ni))) { /* Indicate node joined IBSS */ if ((capinfo & IEEE80211_CAPINFO_RADIOMEAS) && ieee80211_vap_rrm_is_set(vap)) { if(ni->ni_assoc_state != IEEE80211_NODE_ADHOC_STATE_AUTH_ASSOC) ieee80211_set_node_rrm(ni,TRUE); } else { ieee80211_set_node_rrm(ni,FALSE); } ieee80211_mlme_adhoc_join_indication(ni, wbuf); /* notify mlme of beacon reception */ ieee80211_mlme_join_complete_adhoc(ni); } if (ibssmerge) { ieee80211_mlme_adhoc_merge_completion(ni); } if (quiet_elm) { ic->ic_set_quiet(ni, quiet_elm); } if (free_node == TRUE) { ieee80211_free_node(ni); } }
/* Interface functions */ static struct ieee80211_node * ol_ath_node_alloc(struct ieee80211vap *vap, const u_int8_t *macaddr, bool tmpnode) { struct ieee80211com *ic = vap->iv_ic; struct ol_ath_vap_net80211 *avn = OL_ATH_VAP_NET80211(vap); struct ol_ath_softc_net80211 *scn = OL_ATH_SOFTC_NET80211(ic); struct ol_ath_node_net80211 *anode; adf_os_spin_lock_bh(&scn->scn_lock); scn->peer_count++; if (scn->peer_count > scn->wlan_resource_config.num_peers) { adf_os_spin_unlock_bh(&scn->scn_lock); printk("%s: vap (%p) scn (%p) the peer count exceeds the supported number %d \n", __func__, vap, scn, scn->wlan_resource_config.num_peers); goto err_node_alloc; } adf_os_spin_unlock_bh(&scn->scn_lock); anode = (struct ol_ath_node_net80211 *)OS_MALLOC(scn->sc_osdev, sizeof(struct ol_ath_node_net80211), GFP_ATOMIC); if (anode == NULL) goto err_node_alloc; OS_MEMZERO(anode, sizeof(struct ol_ath_node_net80211)); anode->an_node.ni_vap = vap; /* do not create/delete peer on target for temp nodes and self-peers */ if (!tmpnode && !is_node_self_peer(vap, macaddr)) { if (wmi_unified_peer_create_send(scn->wmi_handle, macaddr,avn->av_if_id)) { printk("%s : Unable to create peer in Target \n", __func__); OS_FREE(anode); goto err_node_alloc; } adf_os_spin_lock_bh(&scn->scn_lock); anode->an_txrx_handle = ol_txrx_peer_attach(scn->pdev_txrx_handle, avn->av_txrx_handle, (u_int8_t *) macaddr); if (anode->an_txrx_handle == NULL) { adf_os_spin_unlock_bh(&scn->scn_lock); printk("%s : Unable to attach txrx peer\n", __func__); OS_FREE(anode); goto err_node_alloc; } adf_os_spin_unlock_bh(&scn->scn_lock); /* static wep keys stored in vap needs to be * pushed to all nodes except self node */ if(IEEE80211_VAP_IS_PRIVACY_ENABLED(vap) && (OS_MEMCMP(macaddr,vap->iv_myaddr,IEEE80211_ADDR_LEN) != 0 )) { set_node_wep_keys(vap,macaddr); } } return &anode->an_node; err_node_alloc: adf_os_spin_lock_bh(&scn->scn_lock); scn->peer_count--; adf_os_spin_unlock_bh(&scn->scn_lock); return NULL; }
/* * 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; }