int wlan_vap_get_bssid(wlan_if_t vaphandle, u_int8_t *bssid) { /* need locking to prevent changing the iv_bss */ IEEE80211_VAP_LOCK(vaphandle); if (vaphandle->iv_bss) { IEEE80211_ADDR_COPY(bssid, vaphandle->iv_bss->ni_bssid); IEEE80211_VAP_UNLOCK(vaphandle); return EOK; } IEEE80211_VAP_UNLOCK(vaphandle); return -EINVAL; }
/* Set optional application defined IEs */ int wlan_mlme_set_optie(wlan_if_t vaphandle, u_int8_t *buf, u_int16_t buflen) { struct ieee80211vap *vap = vaphandle; struct ieee80211com *ic = vap->iv_ic; int error = 0; u_int8_t *iebuf = NULL; bool alloc_iebuf = FALSE; IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s\n", __func__); if (buflen > vap->iv_opt_ie_maxlen) { /* Allocate ie buffer */ iebuf = OS_MALLOC(ic->ic_osdev, buflen, 0); if (iebuf == NULL) { error = -ENOMEM; goto exit; } alloc_iebuf = TRUE; vap->iv_opt_ie_maxlen = buflen; } else { iebuf = vap->iv_opt_ie.ie; } IEEE80211_VAP_LOCK(vap); /* Free existing buffer */ if (alloc_iebuf == TRUE && vap->iv_opt_ie.ie) { OS_FREE(vap->iv_opt_ie.ie); } vap->iv_opt_ie.ie = iebuf; vap->iv_opt_ie.length = buflen; if (buflen) { ASSERT(buf); if (buf == NULL) { IEEE80211_VAP_UNLOCK(vap); error = -EINVAL; goto exit; } /* Copy app ie contents and save pointer/length */ OS_MEMCPY(iebuf, buf, buflen); } IEEE80211_VAP_UNLOCK(vap); exit: return error; }
/* Get optional application defined IEs */ int wlan_mlme_get_optie(wlan_if_t vaphandle, u_int8_t *buf, u_int32_t *ielen, u_int32_t buflen) { struct ieee80211vap *vap = vaphandle; int error = 0; IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s\n", __func__); *ielen = vap->iv_opt_ie.length; /* verify output buffer is large enough */ if (buflen < vap->iv_opt_ie.length) { error = -EOVERFLOW; goto exit; } IEEE80211_VAP_LOCK(vap); /* copy opt ie contents to output buffer */ if (*ielen) { OS_MEMCPY(buf, vap->iv_opt_ie.ie, vap->iv_opt_ie.length); } IEEE80211_VAP_UNLOCK(vap); exit: return error; }
/* Get application defined IEs */ int wlan_mlme_get_appie(wlan_if_t vaphandle, ieee80211_frame_type ftype, u_int8_t *buf, u_int32_t *ielen, u_int32_t buflen) { struct ieee80211vap *vap = vaphandle; int error = 0; IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s\n", __func__); ASSERT(ftype < IEEE80211_FRAME_TYPE_MAX); if (ftype >= IEEE80211_FRAME_TYPE_MAX) { error = -EINVAL; goto exit; } *ielen = vap->iv_app_ie[ftype].length; /* verify output buffer is large enough */ if (buflen < vap->iv_app_ie[ftype].length) { error = -EOVERFLOW; goto exit; } IEEE80211_VAP_LOCK(vap); /* copy app ie contents to output buffer */ if (*ielen) { OS_MEMCPY(buf, vap->iv_app_ie[ftype].ie, vap->iv_app_ie[ftype].length); } IEEE80211_VAP_UNLOCK(vap); exit: return error; }
/** * @register a vap event handler. * ARGS : * ieee80211_vap_event_handler : vap event handler * arg : argument passed back via the evnt handler * RETURNS: * on success returns 0. * on failure returns a negative value. * allows more than one event handler to be registered. */ int ieee80211_vap_unregister_event_handler(ieee80211_vap_t vap,ieee80211_vap_event_handler evhandler, void *arg) { int i; IEEE80211_VAP_LOCK(vap); for (i=0;i<IEEE80211_MAX_VAP_EVENT_HANDLERS; ++i) { if ( vap->iv_event_handler[i] == evhandler && vap->iv_event_handler_arg[i] == arg ) { vap->iv_event_handler[i] = NULL; vap->iv_event_handler_arg[i] = NULL; IEEE80211_VAP_UNLOCK(vap); return 0; } } IEEE80211_VAP_UNLOCK(vap); return EEXIST; }
int ieee80211_vap_unregister_misc_events(struct ieee80211vap *vap,os_handle_t oshandle, wlan_misc_event_handler_table *evtab) { int i; IEEE80211_VAP_LOCK(vap); for (i=0;i<IEEE80211_MAX_MISC_EVENT_HANDLERS; ++i) { if ( vap->iv_misc_evtable[i] == evtab && vap->iv_misc_arg[i] == oshandle) { vap->iv_misc_evtable[i] = NULL; vap->iv_misc_arg[i] = NULL; IEEE80211_VAP_UNLOCK(vap); return 0; } } IEEE80211_VAP_UNLOCK(vap); return EEXIST; }
/** * unregister a mlme event handler. * @param vap : handle to vap object * @param evhandler : event handler function. * @param arg : argument passed back via the evnt handler * @return EOK if success, EINVAL if failed. */ int ieee80211_mlme_unregister_event_handler(ieee80211_vap_t vap,ieee80211_mlme_event_handler evhandler, void *arg) { int i; struct ieee80211_mlme_priv *mlme_priv = vap->iv_mlme_priv; IEEE80211_VAP_LOCK(vap); for (i=0;i<IEEE80211_MAX_MLME_EVENT_HANDLERS; ++i) { if ( mlme_priv->im_event_handler[i] == evhandler && mlme_priv->im_event_handler_arg[i] == arg ) { mlme_priv->im_event_handler[i] = NULL; mlme_priv->im_event_handler_arg[i] = NULL; IEEE80211_VAP_UNLOCK(vap); return EOK; } } IEEE80211_VAP_UNLOCK(vap); return EINVAL; }
int ieee80211_vap_unregister_mlme_events(struct ieee80211vap *vap,os_handle_t oshandle, wlan_mlme_event_handler_table *evtab) { int i; IEEE80211_VAP_LOCK(vap); for (i=0;i<IEEE80211_MAX_VAP_MLME_EVENT_HANDLERS; ++i) { if ( vap->iv_mlme_evtable[i] == evtab && vap->iv_misc_arg[i] == oshandle) { vap->iv_mlme_evtable[i] = NULL; vap->iv_mlme_arg[i] = NULL; IEEE80211_VAP_UNLOCK(vap); return 0; } } IEEE80211_VAP_UNLOCK(vap); IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s The handler is not in the evtable.\n", __func__); return EEXIST; }
void ieee80211_vap_deliver_event(struct ieee80211vap *vap, ieee80211_vap_event *event) { int i; void *arg; ieee80211_vap_event_handler evhandler; IEEE80211_VAP_LOCK(vap); for(i=0;i<IEEE80211_MAX_VAP_EVENT_HANDLERS; ++i) { if (vap->iv_event_handler[i]) { evhandler = vap->iv_event_handler[i]; arg = vap->iv_event_handler_arg[i]; IEEE80211_VAP_UNLOCK(vap); (* evhandler) (vap, event,arg); IEEE80211_VAP_LOCK(vap); } } IEEE80211_VAP_UNLOCK(vap); }
/** * @unregister a vap event handler. * ARGS : * ieee80211_vap_event_handler : vap event handler * arg : argument passed back via the evnt handler * RETURNS: * on success returns 0. * on failure returns a negative value. */ int ieee80211_vap_register_event_handler(ieee80211_vap_t vap,ieee80211_vap_event_handler evhandler, void *arg) { int i; /* unregister if there exists one already */ ieee80211_vap_unregister_event_handler(vap,evhandler,arg); IEEE80211_VAP_LOCK(vap); for (i=0;i<IEEE80211_MAX_VAP_EVENT_HANDLERS; ++i) { if ( vap->iv_event_handler[i] == NULL) { vap->iv_event_handler[i] = evhandler; vap->iv_event_handler_arg[i] = arg; IEEE80211_VAP_UNLOCK(vap); return 0; } } IEEE80211_VAP_UNLOCK(vap); return ENOMEM; }
int ieee80211_vap_register_misc_events(struct ieee80211vap *vap, os_handle_t oshandle, wlan_misc_event_handler_table *evtab) { int i; /* unregister if there exists one already */ ieee80211_vap_unregister_misc_events(vap,oshandle,evtab); IEEE80211_VAP_LOCK(vap); for (i=0;i<IEEE80211_MAX_MISC_EVENT_HANDLERS; ++i) { if ( vap->iv_misc_evtable[i] == NULL) { vap->iv_misc_evtable[i] = evtab; vap->iv_misc_arg[i] = oshandle; IEEE80211_VAP_UNLOCK(vap); return 0; } } IEEE80211_VAP_UNLOCK(vap); return ENOMEM; }
void ieee80211_mlme_deliver_event(struct ieee80211_mlme_priv *mlme_priv, ieee80211_mlme_event *event) { int i; void *arg; ieee80211_mlme_event_handler evhandler; struct ieee80211vap *vap = mlme_priv->im_vap; IEEE80211_VAP_LOCK(vap); for(i=0;i<IEEE80211_MAX_MLME_EVENT_HANDLERS; ++i) { if (mlme_priv->im_event_handler[i]) { evhandler = mlme_priv->im_event_handler[i]; arg = mlme_priv->im_event_handler_arg[i]; IEEE80211_VAP_UNLOCK(vap); (* evhandler) (vap, event,arg); IEEE80211_VAP_LOCK(vap); } } IEEE80211_VAP_UNLOCK(vap); }
int ieee80211_vap_register_mlme_events(struct ieee80211vap *vap, os_handle_t oshandle, wlan_mlme_event_handler_table *evtab) { int i; /* unregister if there exists one already */ ieee80211_vap_unregister_mlme_events(vap,oshandle,evtab); IEEE80211_VAP_LOCK(vap); for (i=0;i<IEEE80211_MAX_VAP_MLME_EVENT_HANDLERS; ++i) { if ( vap->iv_mlme_evtable[i] == NULL) { vap->iv_mlme_evtable[i] = evtab; vap->iv_mlme_arg[i] = oshandle; IEEE80211_VAP_UNLOCK(vap); return 0; } } IEEE80211_VAP_UNLOCK(vap); IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s mlme evtable is full.\n", __func__); return ENOMEM; }
/** * register a mlme event handler. * @param vap : handle to vap object * @param evhandler : event handler function. * @param arg : argument passed back via the event handler * @return EOK if success, EINVAL if failed, ENOMEM if runs out of memory. * allows more than one event handler to be registered. */ int ieee80211_mlme_register_event_handler(ieee80211_vap_t vap,ieee80211_mlme_event_handler evhandler, void *arg) { int i; struct ieee80211_mlme_priv *mlme_priv = vap->iv_mlme_priv; /* unregister if there exists one already */ ieee80211_mlme_unregister_event_handler(vap,evhandler,arg); IEEE80211_VAP_LOCK(vap); for (i=0;i<IEEE80211_MAX_MLME_EVENT_HANDLERS; ++i) { if ( mlme_priv->im_event_handler[i] == NULL ) { mlme_priv->im_event_handler[i] = evhandler; mlme_priv->im_event_handler_arg[i] = arg; IEEE80211_VAP_UNLOCK(vap); return EOK; } } IEEE80211_VAP_UNLOCK(vap); return ENOMEM; }
/* Set application defined IEs */ int wlan_mlme_set_appie(wlan_if_t vaphandle, ieee80211_frame_type ftype, u_int8_t *buf, u_int16_t buflen) { struct ieee80211vap *vap = vaphandle; struct ieee80211com *ic = vap->iv_ic; int error = 0; u_int8_t *iebuf = NULL; bool alloc_iebuf = FALSE; IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s\n", __func__); ASSERT(ftype < IEEE80211_FRAME_TYPE_MAX); if (ftype >= IEEE80211_FRAME_TYPE_MAX) { error = -EINVAL; goto exit; } #if ATH_SUPPORT_HS20 buflen = wlan_mlme_parse_appie(vap, ftype, buf, buflen); #endif if (buflen > vap->iv_app_ie_maxlen[ftype]) { /* Allocate ie buffer */ iebuf = OS_MALLOC(ic->ic_osdev, buflen, 0); if (iebuf == NULL) { error = -ENOMEM; goto exit; } alloc_iebuf = TRUE; vap->iv_app_ie_maxlen[ftype] = buflen; } else { iebuf = vap->iv_app_ie[ftype].ie; } IEEE80211_VAP_LOCK(vap); /* * Temp: reduce window of race with beacon update in Linux AP. * In Linux AP, ieee80211_beacon_update is called in ISR, so * iv_lock is not acquired. */ IEEE80211_VAP_APPIE_UPDATE_DISABLE(vap); /* Free existing buffer */ if (alloc_iebuf == TRUE && vap->iv_app_ie[ftype].ie) { OS_FREE(vap->iv_app_ie[ftype].ie); } vap->iv_app_ie[ftype].ie = iebuf; vap->iv_app_ie[ftype].length = buflen; if (buflen) { ASSERT(buf); if (buf == NULL) { IEEE80211_VAP_UNLOCK(vap); error = -EINVAL; goto exit; } /* Copy app ie contents and save pointer/length */ OS_MEMCPY(iebuf, buf, buflen); } /* Set appropriate flag so that the IE gets updated in the next beacon */ IEEE80211_VAP_APPIE_UPDATE_ENABLE(vap); IEEE80211_VAP_UNLOCK(vap); exit: return error; }
/* * Craft a temporary node suitable for sending a management frame * to the specified station. We craft only as much state as we * need to do the work since the node will be immediately reclaimed * once the send completes, and the temporary node will NOT be put * into node table. */ struct ieee80211_node * ieee80211_tmp_node(struct ieee80211vap *vap, const u_int8_t *macaddr) { struct ieee80211com *ic = vap->iv_ic; struct ieee80211_node *ni; int i; /* * if vap is being deleted, do not allow new allocations. */ if (ieee80211_vap_deleted_is_set(vap)) { return NULL; } ni = ic->ic_node_alloc(&ic->ic_sta, vap, TRUE /* temp node */); if (ni == NULL) { vap->iv_stats.is_rx_nodealloc++; return NULL; } #ifdef IEEE80211_DEBUG_NODELEAK do { rwlock_state_t lock_state; OS_RWLOCK_WRITE_LOCK(&ic->ic_nodelock,&lock_state); TAILQ_INSERT_TAIL(&ic->ic_nodes, ni, ni_alloc_list); OS_RWLOCK_WRITE_UNLOCK(&ic->ic_nodelock,&lock_state); } while(0); #endif ni->ni_flags |= IEEE80211_NODE_TEMP; /* useful for debugging */ ieee80211_ref_node(ni); /* mark referenced */ IEEE80211_VAP_LOCK(vap); vap->iv_node_count++; IEEE80211_VAP_UNLOCK(vap); ni->ni_bss_node = ieee80211_ref_bss_node(vap); ni->ni_vap = vap; ni->ni_ic = ic; ni->ni_table = NULL; /* copy some default variables from parent */ IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr); ni->ni_intval = ic->ic_intval; /* default beacon interval */ /* set default rate and channel */ ieee80211_node_set_chan(ni); ni->ni_txpower = ic->ic_txpowlimit; /* max power */ /* init our unicast / receive key state */ ieee80211_crypto_resetkey(vap, &ni->ni_ucastkey, IEEE80211_KEYIX_NONE); ieee80211_crypto_resetkey(vap, &ni->ni_persta.nips_hwkey, IEEE80211_KEYIX_NONE); for (i = 0; i < IEEE80211_WEP_NKID; i++) { ieee80211_crypto_resetkey(vap, &ni->ni_persta.nips_swkey[i], IEEE80211_KEYIX_NONE); } ni->ni_ath_defkeyindex = IEEE80211_INVAL_DEFKEY; /* IBSS-only: mark as unassociated by default. */ ni->ni_assoc_state = IEEE80211_NODE_ADHOC_STATE_UNAUTH_UNASSOC; /* 11n */ ni->ni_chwidth = ic->ic_cwm_get_width(ic); IEEE80211_ADDR_COPY(ni->ni_bssid, vap->iv_bss->ni_bssid); return ni; }
bool _ieee80211_node_leave(struct ieee80211_node *ni) #endif { struct ieee80211com *ic = ni->ni_ic; struct ieee80211vap *vap = ni->ni_vap; bool retval = false; #ifdef IEEE80211_DEBUG_REFCNT TRACENODE(ni, func, line); #endif IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC | IEEE80211_MSG_DEBUG, ni, "station with aid %d leaves (refcnt %u) \n", IEEE80211_NODE_AID(ni), ieee80211_node_refcnt(ni)); #ifdef ATH_SWRETRY if (ic->ic_reset_pause_tid) ic->ic_reset_pause_tid(ni->ni_ic, ni); #endif if (!IEEE80211_IS_TDLS_NODE(ni)) KASSERT(vap->iv_opmode == IEEE80211_M_HOSTAP || vap->iv_opmode == IEEE80211_M_WDS || vap->iv_opmode == IEEE80211_M_BTAMP || vap->iv_opmode == IEEE80211_M_IBSS, ("unexpected operating mode %u", vap->iv_opmode)); /* Multicast enhancement: If the entry with the node's address exists in * the snoop table, it should be removed. */ if (vap->iv_ique_ops.me_clean) { vap->iv_ique_ops.me_clean(ni); } /* * HBR / headline block removal: delete the node entity from the table * for HBR purpose */ if (vap->iv_ique_ops.hbr_nodeleave) { vap->iv_ique_ops.hbr_nodeleave(vap, ni); } /* * If node wasn't previously associated all * we need to do is reclaim the reference. */ /* XXX ibss mode bypasses 11g and notification */ IEEE80211_NODE_STATE_LOCK(ni); if (ni->ni_associd && (0 == ni->ni_leaving)) { ni->ni_leaving = 1; IEEE80211_VAP_LOCK(vap); vap->iv_sta_assoc--; IEEE80211_VAP_UNLOCK(vap); IEEE80211_COMM_LOCK(ic); ic->ic_sta_assoc--; /* Update bss load element in beacon */ ieee80211_vap_bssload_update_set(vap); if (IEEE80211_NODE_USE_HT(ni)) { ic->ic_ht_sta_assoc--; if (ni->ni_htcap & IEEE80211_HTCAP_C_GREENFIELD) { ASSERT(ic->ic_ht_gf_sta_assoc > 0); ic->ic_ht_gf_sta_assoc--; } #if ATH_TxBF_DYNAMIC_LOF_ON_N_CHAIN_MASK iee80211_txbf_loforce_check(ni,0); #endif if ((ni->ni_chwidth == IEEE80211_CWM_WIDTH40) || (ni->ni_chwidth == IEEE80211_CWM_WIDTH80)) ic->ic_ht40_sta_assoc--; } if ((IEEE80211_IS_CHAN_ANYG(vap->iv_bsschan) || IEEE80211_IS_CHAN_11NG(vap->iv_bsschan)) && !IEEE80211_IS_TDLS_NODE(ni)) ieee80211_node_leave_11g(ni); ieee80211_admctl_node_leave(vap, ni); /* * Cleanup station state. In particular clear various state that * might otherwise be reused if the node is reused before the * reference count goes to zero (and memory is reclaimed). * * If ni is not in node table, it has been reclaimed in another thread. */ retval = ieee80211_sta_leave(ni); IEEE80211_COMM_UNLOCK(ic); IEEE80211_NODE_STATE_UNLOCK(ni); IEEE80211_DELETE_NODE_TARGET(ni, ic, vap, 0); } else { ieee80211_admctl_node_leave(vap, ni); retval = ieee80211_sta_leave(ni); IEEE80211_NODE_STATE_UNLOCK(ni); } if ((ni->ni_flags & IEEE80211_NODE_HT) && (ni->ni_flags & IEEE80211_NODE_40_INTOLERANT)) { ieee80211_change_cw(ic); } return retval; }
/* * 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; }
/* * Send a probe response frame. * NB: for probe response, the node may not represent the peer STA. * We could use BSS node to reduce the memory usage from temporary node. */ int ieee80211_send_proberesp(struct ieee80211_node *ni, u_int8_t *macaddr, const void *optie, const size_t optielen) { struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; struct ieee80211_rsnparms *rsn = &vap->iv_rsn; wbuf_t wbuf; struct ieee80211_frame *wh; u_int8_t *frm; u_int16_t capinfo; int enable_htrates; bool add_wpa_ie = true; ASSERT(vap->iv_opmode == IEEE80211_M_HOSTAP || vap->iv_opmode == IEEE80211_M_IBSS || vap->iv_opmode == IEEE80211_M_BTAMP); wbuf = wbuf_alloc(ic->ic_osdev, WBUF_TX_MGMT, MAX_TX_RX_PACKET_SIZE); if (wbuf == NULL) return -ENOMEM; #ifdef IEEE80211_DEBUG_REFCNT printk("%s ,line %u: increase node %p <%s> refcnt to %d\n", __func__, __LINE__, ni, ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)); #endif /* setup the wireless header */ wh = (struct ieee80211_frame *)wbuf_header(wbuf); ieee80211_send_setup(vap, ni, wh, IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP, vap->iv_myaddr, macaddr, ieee80211_node_get_bssid(ni)); frm = (u_int8_t *)&wh[1]; /* * probe response frame format * [8] time stamp * [2] beacon interval * [2] cabability information * [tlv] ssid * [tlv] supported rates * [tlv] parameter set (FH/DS) * [tlv] parameter set (IBSS) * [tlv] extended rate phy (ERP) * [tlv] extended supported rates * [tlv] country (if present) * [3] power constraint * [tlv] WPA * [tlv] WME * [tlv] HT Capabilities * [tlv] HT Information * [tlv] Atheros Advanced Capabilities */ OS_MEMZERO(frm, 8); /* timestamp should be filled later */ frm += 8; *(u_int16_t *)frm = htole16(vap->iv_bss->ni_intval); frm += 2; 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(ic->ic_curchan)) 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; *(u_int16_t *)frm = htole16(capinfo); frm += 2; frm = ieee80211_add_ssid(frm, vap->iv_bss->ni_essid, vap->iv_bss->ni_esslen); frm = ieee80211_add_rates(frm, &vap->iv_bss->ni_rates, ic); if (!IEEE80211_IS_CHAN_FHSS(vap->iv_bsschan)) { *frm++ = IEEE80211_ELEMID_DSPARMS; *frm++ = 1; *frm++ = ieee80211_chan2ieee(ic, ic->ic_curchan); } if (vap->iv_opmode == IEEE80211_M_IBSS) { *frm++ = IEEE80211_ELEMID_IBSSPARMS; *frm++ = 2; *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ } if (IEEE80211_IS_COUNTRYIE_ENABLED(ic)) { frm = ieee80211_add_country(frm, vap); } if (ieee80211_ic_doth_is_set(ic) && ieee80211_vap_doth_is_set(vap)) { *frm++ = IEEE80211_ELEMID_PWRCNSTR; *frm++ = 1; *frm++ = IEEE80211_PWRCONSTRAINT_VAL(vap); } #if ATH_SUPPORT_IBSS_DFS if (vap->iv_opmode == IEEE80211_M_IBSS) { frm = ieee80211_add_ibss_dfs(frm,vap); } #endif if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan) || IEEE80211_IS_CHAN_11NG(ic->ic_curchan)) { frm = ieee80211_add_erp(frm, ic); } /* * check if os shim has setup RSN IE it self. */ IEEE80211_VAP_LOCK(vap); if (vap->iv_app_ie[IEEE80211_FRAME_TYPE_PROBERESP].length) { add_wpa_ie = ieee80211_check_wpaie(vap, vap->iv_app_ie[IEEE80211_FRAME_TYPE_PROBERESP].ie, vap->iv_app_ie[IEEE80211_FRAME_TYPE_PROBERESP].length); } if (vap->iv_opt_ie.length) { add_wpa_ie = ieee80211_check_wpaie(vap, vap->iv_opt_ie.ie, vap->iv_opt_ie.length); } IEEE80211_VAP_UNLOCK(vap); if (add_wpa_ie) { if (RSN_AUTH_IS_RSNA(rsn)) frm = ieee80211_setup_rsn_ie(vap, frm); } #if ATH_SUPPORT_WAPI if (RSN_AUTH_IS_WAI(rsn)) frm = ieee80211_setup_wapi_ie(vap, frm); #endif frm = ieee80211_add_xrates(frm, &vap->iv_bss->ni_rates, ic); enable_htrates = ieee80211vap_htallowed(vap); if (IEEE80211_IS_CHAN_11N(ic->ic_curchan) && enable_htrates) { frm = ieee80211_add_htcap(frm, ni, IEEE80211_FC0_SUBTYPE_PROBE_RESP); if (!IEEE80211_IS_HTVIE_ENABLED(ic)) frm = ieee80211_add_htcap_pre_ana(frm, ni, IEEE80211_FC0_SUBTYPE_PROBE_RESP); frm = ieee80211_add_htinfo(frm, ni); if (!IEEE80211_IS_HTVIE_ENABLED(ic)) frm = ieee80211_add_htinfo_pre_ana(frm, ni); if (!(ic->ic_flags & IEEE80211_F_COEXT_DISABLE)) { frm = ieee80211_add_obss_scan(frm, ni); frm = ieee80211_add_extcap(frm, ni); } } if (add_wpa_ie) { if (RSN_AUTH_IS_WPA(rsn)) frm = ieee80211_setup_wpa_ie(vap, frm); } if (ieee80211_vap_wme_is_set(vap) && (vap->iv_opmode == IEEE80211_M_HOSTAP || vap->iv_opmode == IEEE80211_M_BTAMP)) /* don't support WMM in ad-hoc for now */ frm = ieee80211_add_wme_param(frm, &ic->ic_wme, IEEE80211_VAP_IS_UAPSD_ENABLED(vap)); if ((IEEE80211_IS_CHAN_11N(ic->ic_curchan)) && (IEEE80211_IS_HTVIE_ENABLED(ic)) && enable_htrates) { frm = ieee80211_add_htcap_vendor_specific(frm, ni, IEEE80211_FC0_SUBTYPE_PROBE_RESP); frm = ieee80211_add_htinfo_vendor_specific(frm, ni); } if (vap->iv_bss->ni_ath_flags) { frm = ieee80211_add_athAdvCap(frm, vap->iv_bss->ni_ath_flags, vap->iv_bss->ni_ath_defkeyindex); } else { frm = ieee80211_add_athAdvCap(frm, 0, IEEE80211_INVAL_DEFKEY); } /* Insert ieee80211_ie_ath_extcap IE to beacon */ if (ic->ic_ath_extcap) frm = ieee80211_add_athextcap(frm, ic->ic_ath_extcap, ic->ic_weptkipaggr_rxdelim); #ifdef notyet if (ni->ni_ath_ie != NULL) /* XXX */ frm = ieee80211_add_ath(frm, ni); #endif IEEE80211_VAP_LOCK(vap); if (vap->iv_opt_ie.length) { OS_MEMCPY(frm, vap->iv_opt_ie.ie, vap->iv_opt_ie.length); frm += vap->iv_opt_ie.length; } if (vap->iv_app_ie[IEEE80211_FRAME_TYPE_PROBERESP].length) { OS_MEMCPY(frm, vap->iv_app_ie[IEEE80211_FRAME_TYPE_PROBERESP].ie, vap->iv_app_ie[IEEE80211_FRAME_TYPE_PROBERESP].length); frm += vap->iv_app_ie[IEEE80211_FRAME_TYPE_PROBERESP].length; } /* Add the Application IE's */ frm = ieee80211_mlme_app_ie_append(vap, IEEE80211_FRAME_TYPE_PROBERESP, frm); IEEE80211_VAP_UNLOCK(vap); if (optie != NULL && optielen != 0) { OS_MEMCPY(frm, optie, optielen); frm += optielen; } wbuf_set_pktlen(wbuf, (frm - (u_int8_t *)wbuf_header(wbuf))); return ieee80211_send_mgmt(vap,ni, wbuf,true); }
static u_int8_t * ieee80211_beacon_init(struct ieee80211_node *ni, struct ieee80211_beacon_offsets *bo, u_int8_t *frm) { struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; u_int16_t capinfo; struct ieee80211_rateset *rs = &ni->ni_rates; struct ieee80211_rsnparms *rsn = &vap->iv_rsn; int enable_htrates; bool add_wpa_ie = true; /*Begin: Added by zhanghu for increasing rate*/ ic->ic_rate_mask_bak = ic->ic_rate_mask; ic->ic_mcs_mask_bak = ic->ic_mcs_mask; /*End: Added by zhanghu for increasing rate*/ KASSERT(vap->iv_bsschan != IEEE80211_CHAN_ANYC, ("no bss chan")); OS_MEMZERO(frm, 8); /* XXX timestamp is set by hardware/driver */ frm += 8; *(u_int16_t *)frm = htole16(ieee80211_node_get_beacon_interval(ni)); frm += 2; 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; rs = &ic->ic_sup_rates[IEEE80211_MODE_11B]; } else if (IEEE80211_VAP_IS_PUREG_ENABLED(vap)) { ieee80211_setpuregbasicrates(rs); } bo->bo_caps = (u_int16_t *)frm; *(u_int16_t *)frm = htole16(capinfo); frm += 2; *frm++ = IEEE80211_ELEMID_SSID; if (IEEE80211_VAP_IS_HIDESSID_ENABLED(vap)) { *frm++ = 0; } else { /* AUTELAN-Added-Begin : &tuqiang for openessid */ #if 0 *frm++ = ni->ni_esslen; OS_MEMCPY(frm, ni->ni_essid, ni->ni_esslen); frm += ni->ni_esslen; #endif if(!(openessid_param & OPENESSID_ENABLE_MASK)){ /* openessid disable */ *frm++ = ni->ni_esslen; OS_MEMCPY(frm, ni->ni_essid, ni->ni_esslen); frm += ni->ni_esslen; } else { /* openessid enable */ int index; while(vap->iv_essid_be_cnt < 4) { index = vap->iv_essid_index[vap->iv_essid_be_cnt]; vap->iv_essid_be_cnt++; if(index < 0) continue; *frm++ = g_essid_table[index].len; OS_MEMCPY(frm, g_essid_table[index].essid, g_essid_table[index].len); frm += g_essid_table[index].len; break; /* break while */ } /* end while */ if(vap->iv_essid_be_cnt == 4){ vap->iv_essid_be_cnt = 0; } } /* AUTELAN-Added-End : [email protected] */ } frm = ieee80211_add_rates(frm, rs, ic); /* XXX better way to check this? */ if (!IEEE80211_IS_CHAN_FHSS(vap->iv_bsschan)) { *frm++ = IEEE80211_ELEMID_DSPARMS; *frm++ = 1; *frm++ = ieee80211_chan2ieee(ic, vap->iv_bsschan); } bo->bo_tim = frm; if (vap->iv_opmode == IEEE80211_M_IBSS) { *frm++ = IEEE80211_ELEMID_IBSSPARMS; *frm++ = 2; *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ bo->bo_tim_len = 0; } else { struct ieee80211_tim_ie *tie = (struct ieee80211_tim_ie *) frm; tie->tim_ie = IEEE80211_ELEMID_TIM; tie->tim_len = 4; /* length */ tie->tim_count = 0; /* DTIM count */ tie->tim_period = vap->iv_dtim_period; /* DTIM period */ tie->tim_bitctl = 0; /* bitmap control */ tie->tim_bitmap[0] = 0; /* Partial Virtual Bitmap */ frm += sizeof(struct ieee80211_tim_ie); bo->bo_tim_len = 1; } bo->bo_tim_trailer = frm; if (IEEE80211_IS_COUNTRYIE_ENABLED(ic)) { frm = ieee80211_add_country(frm, vap); } if (ieee80211_ic_doth_is_set(ic) && ieee80211_vap_doth_is_set(vap)) { *frm++ = IEEE80211_ELEMID_PWRCNSTR; *frm++ = 1; *frm++ = IEEE80211_PWRCONSTRAINT_VAL(vap); } bo->bo_chanswitch = frm; #if ATH_SUPPORT_IBSS_DFS if (vap->iv_opmode == IEEE80211_M_IBSS) { if (ieee80211_ibss_dfs_element_enable(vap, ic)) { ieee80211_build_ibss_dfs_ie(vap); bo->bo_ibssdfs = frm; frm = ieee80211_add_ibss_dfs(frm,vap); } else { bo->bo_ibssdfs = NULL; OS_MEMZERO(&vap->iv_ibssdfs_ie_data, sizeof(struct ieee80211_ibssdfs_ie)); } } #endif /* ATH_SUPPORT_IBSS_DFS */ enable_htrates = ieee80211vap_htallowed(vap); if (IEEE80211_IS_CHAN_ANYG(vap->iv_bsschan) || IEEE80211_IS_CHAN_11NG(vap->iv_bsschan)) { bo->bo_erp = frm; frm = ieee80211_add_erp(frm, ic); } /* * check if os shim has setup RSN IE it self. */ IEEE80211_VAP_LOCK(vap); if (vap->iv_app_ie[IEEE80211_FRAME_TYPE_BEACON].length) { add_wpa_ie = ieee80211_check_wpaie(vap, vap->iv_app_ie[IEEE80211_FRAME_TYPE_BEACON].ie, vap->iv_app_ie[IEEE80211_FRAME_TYPE_BEACON].length); } if (vap->iv_opt_ie.length) { add_wpa_ie = ieee80211_check_wpaie(vap, vap->iv_opt_ie.ie, vap->iv_opt_ie.length); } IEEE80211_VAP_UNLOCK(vap); /* XXX: put IEs in the order of element IDs. */ if (add_wpa_ie) { if (RSN_AUTH_IS_RSNA(rsn)) frm = ieee80211_setup_rsn_ie(vap, frm); } #if ATH_SUPPORT_WAPI if (RSN_AUTH_IS_WAI(rsn)) frm = ieee80211_setup_wapi_ie(vap, frm); #endif frm = ieee80211_add_xrates(frm, rs, ic); #ifdef E_CSA bo->bo_extchanswitch = frm; #endif /* E_CSA */ /* * 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) { bo->bo_htcap = frm; frm = ieee80211_add_htcap(frm, ni, IEEE80211_FC0_SUBTYPE_BEACON); bo->bo_htinfo = frm; frm = ieee80211_add_htinfo(frm, ni); if (!(ic->ic_flags & IEEE80211_F_COEXT_DISABLE)) { bo->bo_obss_scan = frm; frm = ieee80211_add_obss_scan(frm, ni); bo->bo_extcap = frm; frm = ieee80211_add_extcap(frm, ni); } } if (add_wpa_ie) { if (RSN_AUTH_IS_WPA(rsn)) frm = ieee80211_setup_wpa_ie(vap, frm); } if (ieee80211_vap_wme_is_set(vap) && (vap->iv_opmode == IEEE80211_M_HOSTAP || #if ATH_SUPPORT_IBSS_WMM vap->iv_opmode == IEEE80211_M_IBSS || #endif vap->iv_opmode == IEEE80211_M_BTAMP)) { bo->bo_wme = frm; frm = ieee80211_add_wme_param(frm, &ic->ic_wme, IEEE80211_VAP_IS_UAPSD_ENABLED(vap)); vap->iv_flags &= ~IEEE80211_F_WMEUPDATE; } if ((IEEE80211_IS_CHAN_11N(vap->iv_bsschan)) && IEEE80211_IS_HTVIE_ENABLED(ic) && enable_htrates) { frm = ieee80211_add_htcap_vendor_specific(frm, ni,IEEE80211_FC0_SUBTYPE_BEACON); bo->bo_htinfo_vendor_specific = frm; frm = ieee80211_add_htinfo_vendor_specific(frm, ni); } bo->bo_ath_caps = frm; if (vap->iv_bss && vap->iv_bss->ni_ath_flags) { frm = ieee80211_add_athAdvCap(frm, vap->iv_bss->ni_ath_flags, vap->iv_bss->ni_ath_defkeyindex); } else { frm = ieee80211_add_athAdvCap(frm, 0, IEEE80211_INVAL_DEFKEY); } /* Insert ieee80211_ie_ath_extcap IE to beacon */ if (ic->ic_ath_extcap) frm = ieee80211_add_athextcap(frm, ic->ic_ath_extcap, ic->ic_weptkipaggr_rxdelim); bo->bo_xr = frm; bo->bo_appie_buf = frm; bo->bo_appie_buf_len = 0; IEEE80211_VAP_LOCK(vap); if (vap->iv_opt_ie.length) { OS_MEMCPY(frm, vap->iv_opt_ie.ie, vap->iv_opt_ie.length); frm += vap->iv_opt_ie.length; } if (vap->iv_app_ie[IEEE80211_FRAME_TYPE_BEACON].length > 0) { OS_MEMCPY(frm,vap->iv_app_ie[IEEE80211_FRAME_TYPE_BEACON].ie, vap->iv_app_ie[IEEE80211_FRAME_TYPE_BEACON].length); frm += vap->iv_app_ie[IEEE80211_FRAME_TYPE_BEACON].length; bo->bo_appie_buf_len = vap->iv_app_ie[IEEE80211_FRAME_TYPE_BEACON].length; } /* Add the Application IE's */ frm = ieee80211_mlme_app_ie_append(vap, IEEE80211_FRAME_TYPE_BEACON, frm); bo->bo_appie_buf_len += vap->iv_app_ie_list[IEEE80211_FRAME_TYPE_BEACON].total_ie_len; IEEE80211_VAP_UNLOCK(vap); bo->bo_tim_trailerlen = frm - bo->bo_tim_trailer; bo->bo_chanswitch_trailerlen = frm - bo->bo_chanswitch; #ifdef E_CSA bo->bo_extchanswitch_trailerlen = frm - bo->bo_extchanswitch; #endif /* E_CSA */ #if ATH_SUPPORT_IBSS_DFS if (vap->iv_opmode == IEEE80211_M_IBSS && (bo->bo_ibssdfs != NULL)) { struct ieee80211_ibssdfs_ie * ibss_dfs_ie = (struct ieee80211_ibssdfs_ie *)bo->bo_ibssdfs; bo->bo_ibssdfs_trailerlen = frm - (bo->bo_ibssdfs + 2 + ibss_dfs_ie->len); } #endif /* ATH_SUPPORT_IBSS_DFS */ return frm; }
/* * function to handle station joining infrastructure network. * used for AP mode vap only. */ int ieee80211_node_join(struct ieee80211_node *ni) { struct ieee80211com *ic = ni->ni_ic; struct ieee80211vap *vap = ni->ni_vap; IEEE80211_NODE_STATE_LOCK(ni); if (ni->ni_associd == 0) { u_int16_t aid; if(vap->iv_sta_assoc >= vap->iv_max_aid - 1) { IEEE80211_NODE_STATE_UNLOCK(ni); return -1; /* soft client limit reached */ } if (vap->iv_aid_bitmap == NULL || IEEE80211_IS_TDLS_NODE(ni)) { IEEE80211_NODE_STATE_UNLOCK(ni); return -1; /* vap is being deleted */ } /* * It would be good to search the bitmap * more efficiently, but this will do for now. */ if (!IEEE80211_IS_TDLS_NODE(ni)) { for (aid = 1; aid < vap->iv_max_aid; aid++) { if (!IEEE80211_AID_ISSET(vap, aid)) break; } if (aid >= vap->iv_max_aid) { /* * Keep stats on this situation. */ IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC, "aid (%d)" " greater than max aid (%d)\n", aid, vap->iv_max_aid); IEEE80211_NODE_STATE_UNLOCK(ni); IEEE80211_NODE_LEAVE(ni); return -1; } ni->ni_associd = aid | 0xc000; IEEE80211_AID_SET(vap, ni->ni_associd); } else { /* To keep the other parts of code happy. Otherwise the code assumes * node disconnected and tries to delete it.There are no associd for * TDLS nodes. */ ni->ni_associd = vap->iv_bss->ni_associd; } IEEE80211_VAP_LOCK(vap); vap->iv_sta_assoc++; IEEE80211_VAP_UNLOCK(vap); ni->ni_leaving = 0; IEEE80211_COMM_LOCK(ic); ic->ic_sta_assoc++; /* Update bss load element in beacon */ ieee80211_vap_bssload_update_set(vap); if ((ni->ni_flags & IEEE80211_NODE_HT) && (ni->ni_flags & IEEE80211_NODE_40_INTOLERANT)) { ieee80211_change_cw(ic); } if (IEEE80211_IS_AMPDU_ENABLED(ic)) { ieee80211node_clear_flag(ni, IEEE80211_NODE_NOAMPDU); } else { ieee80211node_set_flag(ni, IEEE80211_NODE_NOAMPDU); } if (IEEE80211_NODE_USE_HT(ni)) { ic->ic_ht_sta_assoc++; if (ni->ni_htcap & IEEE80211_HTCAP_C_GREENFIELD) ic->ic_ht_gf_sta_assoc++; #if ATH_TxBF_DYNAMIC_LOF_ON_N_CHAIN_MASK iee80211_txbf_loforce_check(ni,1); #endif if ((ni->ni_chwidth == IEEE80211_CWM_WIDTH40 ) || (ni->ni_chwidth == IEEE80211_CWM_WIDTH80)) { ic->ic_ht40_sta_assoc++; } } if ((IEEE80211_IS_CHAN_ANYG(vap->iv_bsschan) || IEEE80211_IS_CHAN_11NG(vap->iv_bsschan)) && !IEEE80211_IS_TDLS_NODE(ni)) ieee80211_node_join_11g(ni); IEEE80211_COMM_UNLOCK(ic); } #if ATH_SUPPORT_WIFIPOS // Time stamp to send in status response ni->last_rx_desc_tsf = ic->ic_get_TSF32(ic); #endif ni->ni_inact_reload = ni->ni_vap->iv_inact_auth; ni->ni_inact = ni->ni_inact_reload; /* Multicast enhancement: If the entry with the node's address exists in * the snoop table, it should be removed. */ if (vap->iv_ique_ops.me_clean) { vap->iv_ique_ops.me_clean(ni); } /* * HBR / headline block removal: add the node entity to the table * for HBR purpose */ if (vap->iv_ique_ops.hbr_nodejoin) { vap->iv_ique_ops.hbr_nodejoin(vap, ni); } IEEE80211_NODE_STATE_UNLOCK(ni); IEEE80211_ADD_NODE_TARGET(ni, ni->ni_vap, 0); return 0; }