/* Reset Connection */ int wlan_mlme_connection_reset(wlan_if_t vaphandle) { struct ieee80211vap *vap = vaphandle; struct ieee80211_mlme_priv *mlme_priv = vap->iv_mlme_priv; #if (UMAC_SUPPORT_TDLS == 1) && (ATH_TDLS_AUTO_CONNECT == 1) struct ieee80211com *ic = vap->iv_ic; ic->ic_tdls_clean(vap); #endif IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s\n", __func__); /* There should be no mlme requests pending */ ASSERT(vap->iv_mlme_priv->im_request_type == MLME_REQ_NONE); /* Reset state variables */ mlme_priv->im_connection_up = 0; /* Association failed, put underlying H/W back to init state. */ ieee80211_vap_stop(vap, FALSE); /* Leave the BSS */ ieee80211_sta_leave(vap->iv_bss); switch(vap->iv_opmode) { case IEEE80211_M_STA: mlme_sta_connection_reset(vap); default: break; } return 0; }
int wlan_vap_delete(wlan_if_t vaphandle) { struct ieee80211vap *vap = vaphandle; struct ieee80211com *ic = vap->iv_ic; IEEE80211_DPRINTF_IC(ic, IEEE80211_VERBOSE_LOUD,IEEE80211_MSG_DEBUG, "%s : enter. vaphandle=0x%x\n", __func__, vaphandle ); ieee80211_vap_pause_vdetach(ic,vap); IEEE80211_COMM_LOCK(ic); #ifdef MAGPIE_HIF_GMAC if (ic->ic_chanchange_cnt) ic->ic_chanchange_cnt -= ic->ic_chanchange_tbtt; #endif if (ieee80211_vap_deleted_is_clear(vap)) /* if not deleted then it is on the list */ { TAILQ_REMOVE(&ic->ic_vaps, vap, iv_next); if (TAILQ_EMPTY(&ic->ic_vaps)) /* reset to supported mode */ ic->ic_opmode = IEEE80211_M_STA; ieee80211_vap_deleted_set(vap); /* mark it as deleted */ IEEE80211_COMM_UNLOCK(ic); /* * In case iv_bss was not stopped or is in scanning. * TBD: BSS should have been stopped now. We can save the time for stop bss again. */ wlan_mlme_stop_bss(vap, WLAN_MLME_STOP_BSS_F_SEND_DEAUTH | WLAN_MLME_STOP_BSS_F_CLEAR_ASSOC_STATE | WLAN_MLME_STOP_BSS_F_WAIT_RX_DONE | WLAN_MLME_STOP_BSS_F_NO_RESET); ieee80211_sta_leave(vap->iv_bss); ieee80211_node_vdetach(vap); } else { IEEE80211_COMM_UNLOCK(ic); } IEEE80211_DPRINTF_IC(ic, IEEE80211_VERBOSE_LOUD,IEEE80211_MSG_DEBUG, "%s : exit. vaphandle=0x%x\n", __func__, vaphandle ); return 0; }
int wlan_mlme_deauth_request(wlan_if_t vaphandle, u_int8_t *macaddr, IEEE80211_REASON_CODE reason) { struct ieee80211vap *vap = vaphandle; struct ieee80211_node *ni; int error = 0; IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s\n", __func__); /* * if a node exist with the given address already , use it. * if not use bss node. */ ni = ieee80211_vap_find_node(vap, macaddr); if (ni == NULL) { if (IEEE80211_ADDR_EQ(macaddr, IEEE80211_GET_BCAST_ADDR(vap->iv_ic))) ni = ieee80211_ref_node(vap->iv_bss); else{ error = -EIO; goto exit; } } /* Send deauth frame */ error = ieee80211_send_deauth(ni, reason); /* Node needs to be removed from table as well, do it only for AP/IBSS now */ #if ATH_SUPPORT_IBSS if ((vap->iv_opmode == IEEE80211_M_HOSTAP || vap->iv_opmode == IEEE80211_M_IBSS) && ni != vap->iv_bss) { #else if (vap->iv_opmode == IEEE80211_M_HOSTAP && ni != vap->iv_bss) { #if ATH_SUPPORT_AOW ieee80211_aow_join_indicate(ni->ni_ic, AOW_STA_DISCONNECTED, ni); #endif /* ATH_SUPPORT_AOW */ #endif /* ATH_SUPPORT_IBSS */ IEEE80211_NODE_LEAVE(ni); } /* claim node immediately */ ieee80211_free_node(ni); if (error) { goto exit; } /* * Call MLME confirmation handler => mlme_deauth_complete * This should reflect the tx completion status of the deauth frame, * but since we don't have per frame completion, we'll always indicate success here. */ IEEE80211_DELIVER_EVENT_MLME_DEAUTH_COMPLETE(vap,macaddr, IEEE80211_STATUS_SUCCESS); exit: return error; } int wlan_mlme_disassoc_request(wlan_if_t vaphandle, u_int8_t *macaddr, IEEE80211_REASON_CODE reason) { struct ieee80211vap *vap = vaphandle; struct ieee80211_node *ni; int error = 0; IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s\n", __func__); /* Broadcast Addr - disassociate all stations */ if (IEEE80211_ADDR_EQ(macaddr, IEEE80211_GET_BCAST_ADDR(vap->iv_ic))) { if (vap->iv_opmode == IEEE80211_M_STA) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s: unexpected station vap with all 0xff mac address", __func__); ASSERT(0); goto exit; } else { /* Iterate station list only when PMF is not enabled */ if (!wlan_vap_is_pmf_enabled(vap)) { wlan_iterate_station_list(vap, sta_disassoc, NULL); goto exit; } } } /* * if a node exist with the given address already , use it. * if not use bss node. */ ni = ieee80211_vap_find_node(vap, macaddr); if (ni == NULL) { if (IEEE80211_ADDR_EQ(macaddr, IEEE80211_GET_BCAST_ADDR(vap->iv_ic))) ni = ieee80211_ref_node(vap->iv_bss); else{ error = -EIO; goto exit; } } /* Send disassoc frame */ error = ieee80211_send_disassoc(ni, reason); /* Node needs to be removed from table as well, do it only for AP now */ if (vap->iv_opmode == IEEE80211_M_HOSTAP && ni != vap->iv_bss) { #if ATH_SUPPORT_AOW ieee80211_aow_join_indicate(ni->ni_ic, AOW_STA_DISCONNECTED, ni); #endif /* ATH_SUPPORT_AOW */ IEEE80211_NODE_LEAVE(ni); } /* claim node immediately */ ieee80211_free_node(ni); if (error) { goto exit; } /* * Call MLME confirmation handler => mlme_disassoc_complete * This should reflect the tx completion status of the disassoc frame, * but since we don't have per frame completion, we'll always indicate success here. */ IEEE80211_DELIVER_EVENT_MLME_DISASSOC_COMPLETE(vap, macaddr, reason, IEEE80211_STATUS_SUCCESS); exit: return error; } int wlan_mlme_start_bss(wlan_if_t vaphandle) { struct ieee80211vap *vap = vaphandle; struct ieee80211_mlme_priv *mlme_priv = vap->iv_mlme_priv; int error = 0; IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s\n", __func__); switch(vap->iv_opmode) { case IEEE80211_M_IBSS: IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s: Create adhoc bss\n", __func__); /* Reset state */ mlme_priv->im_connection_up = 0; error = mlme_create_adhoc_bss(vap); break; case IEEE80211_M_MONITOR: case IEEE80211_M_HOSTAP: case IEEE80211_M_BTAMP: /* * start the AP . the channel/ssid should have been setup already. */ IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s: Create infrastructure(AP) bss\n", __func__); error = mlme_create_infra_bss(vap); break; default: ASSERT(0); } return error; } bool wlan_coext_enabled(wlan_if_t vaphandle) { struct ieee80211com *ic = vaphandle->iv_ic; return (ic->ic_flags & IEEE80211_F_COEXT_DISABLE) ? FALSE : TRUE; } void wlan_determine_cw(wlan_if_t vaphandle, wlan_chan_t channel) { struct ieee80211com *ic = vaphandle->iv_ic; int is_chan_ht40 = channel->ic_flags & (IEEE80211_CHAN_11NG_HT40PLUS | IEEE80211_CHAN_11NG_HT40MINUS); if (is_chan_ht40 && (channel->ic_flags & IEEE80211_CHAN_HT40INTOL)) { ic->ic_bss_to20(ic); } } static void sta_deauth(void *arg, struct ieee80211_node *ni) { struct ieee80211vap *vap = ni->ni_vap; u_int8_t macaddr[6]; IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s: deauth station %s \n", __func__,ether_sprintf(ni->ni_macaddr)); IEEE80211_ADDR_COPY(macaddr, ni->ni_macaddr); if (ni->ni_associd) { /* * if it is associated, then send disassoc. */ ieee80211_send_deauth(ni, IEEE80211_REASON_AUTH_LEAVE); } IEEE80211_NODE_LEAVE(ni); IEEE80211_DELIVER_EVENT_MLME_DEAUTH_INDICATION(vap, macaddr, IEEE80211_REASON_AUTH_LEAVE); } static void sta_disassoc(void *arg, struct ieee80211_node *ni) { struct ieee80211vap *vap = ni->ni_vap; u_int8_t macaddr[6]; IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s: disassoc station %s \n", __func__,ether_sprintf(ni->ni_macaddr)); IEEE80211_ADDR_COPY(macaddr, ni->ni_macaddr); if (ni->ni_associd) { /* * if it is associated, then send disassoc. */ ieee80211_send_disassoc(ni, IEEE80211_REASON_ASSOC_LEAVE); #if ATH_SUPPORT_AOW ieee80211_aow_join_indicate(ni->ni_ic, AOW_STA_DISCONNECTED, ni); #endif /* ATH_SUPPORT_AOW */ } IEEE80211_NODE_LEAVE(ni); IEEE80211_DELIVER_EVENT_MLME_DISASSOC_COMPLETE(vap, macaddr, IEEE80211_REASON_ASSOC_LEAVE, IEEE80211_STATUS_SUCCESS); } int wlan_mlme_stop_bss(wlan_if_t vaphandle, int flags) { #define WAIT_RX_INTERVAL 10000 u_int32_t elapsed_time = 0; struct ieee80211vap *vap = vaphandle; struct ieee80211_mlme_priv *mlme_priv = vap->iv_mlme_priv; int error = 0; IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s flags = 0x%x\n", __func__, flags); /* * Wait for current rx path to finish. Assume only one rx thread. */ if (flags & WLAN_MLME_STOP_BSS_F_WAIT_RX_DONE) { do { if (OS_ATOMIC_CMPXCHG(&vap->iv_rx_gate, 0, 1) == 0) { break; } OS_SLEEP(WAIT_RX_INTERVAL); elapsed_time += WAIT_RX_INTERVAL; if (elapsed_time > (100 * WAIT_RX_INTERVAL)) ieee80211_note (vap,"%s: Rx pending count stuck. Investigate!!!\n", __func__); } while (1); } switch(vap->iv_opmode) { #if UMAC_SUPPORT_IBSS case IEEE80211_M_IBSS: mlme_stop_adhoc_bss(vap, flags); break; #endif case IEEE80211_M_HOSTAP: case IEEE80211_M_BTAMP: /* disassoc/deauth all stations */ IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s: dsassocing/deauth all stations \n", __func__); if(vap->iv_send_deauth) wlan_iterate_station_list(vap, sta_deauth, NULL); else wlan_iterate_station_list(vap, sta_disassoc, NULL); break; case IEEE80211_M_STA: /* There should be no mlme requests pending */ ASSERT(vap->iv_mlme_priv->im_request_type == MLME_REQ_NONE); /* Reset state variables */ mlme_priv->im_connection_up = 0; mlme_sta_swbmiss_timer_stop(vap); ieee80211_sta_leave(vap->iv_bss); break; default: break; } if (flags & WLAN_MLME_STOP_BSS_F_FORCE_STOP_RESET) { /* put vap in init state */ ieee80211_vap_stop(vap, TRUE); } else { /* put vap in stopping state */ if (flags & WLAN_MLME_STOP_BSS_F_STANDBY) ieee80211_vap_standby(vap); else ieee80211_vap_stop(vap, FALSE); } if (!(flags & WLAN_MLME_STOP_BSS_F_NO_RESET)) error = ieee80211_reset_bss(vap); /* * Release the rx mutex. */ if (flags & WLAN_MLME_STOP_BSS_F_WAIT_RX_DONE) { (void) OS_ATOMIC_CMPXCHG(&vap->iv_rx_gate, 1, 0); } return error; #undef WAIT_RX_INTERVAL }
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 (ni->ni_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, ("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) { vap->iv_sta_assoc--; ic->ic_sta_assoc--; /* Update bss load element in beacon */ ieee80211_vap_bssload_update_set(vap); if (IEEE80211_NODE_USEAMPDU(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 (ni->ni_chwidth == IEEE80211_CWM_WIDTH40) 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_NODE_STATE_UNLOCK(ni); IEEE80211_DELETE_NODE_TARGET(ni, ic, vap, 0); } else { IEEE80211_NODE_STATE_UNLOCK(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); if ((ni->ni_flags & IEEE80211_NODE_HT) && (ni->ni_flags & IEEE80211_NODE_40_INTOLERANT)) { ieee80211_change_cw(ic); } return retval; }
/* * Join an infrastructure network */ int ieee80211_sta_join(struct ieee80211vap *vap, ieee80211_scan_entry_t scan_entry) { struct ieee80211com *ic = vap->iv_ic; struct ieee80211_node_table *nt = &ic->ic_sta; struct ieee80211_node *ni = NULL; const u_int8_t *macaddr = ieee80211_scan_entry_macaddr(scan_entry); int error = 0; ASSERT(vap->iv_opmode == IEEE80211_M_STA); ni = ieee80211_find_node(nt, macaddr); if (ni) { /* * reusing old node has a potential for several bugs . The old node may have some state info from previous association. * get rid of the old bss node and create a new bss node. */ ieee80211_sta_leave(ni); ieee80211_free_node(ni); } /* * Create a BSS node. */ ni = ieee80211_alloc_node(nt, vap, macaddr); if (ni == NULL) return -ENOMEM; /* set the maximum number frmaes to be queued when the vap is in fake sleep */ ieee80211_node_saveq_set_param(ni,IEEE80211_NODE_SAVEQ_DATA_Q_LEN,IEE80211_STA_MAX_NODE_SAVEQ_LEN); /* To become a bss node, a node need an extra reference count, which alloc node already gives */ #ifdef IEEE80211_DEBUG_REFCNT ieee80211_note(ni->ni_vap,"%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 bss node for association */ error = ieee80211_setup_node(ni, scan_entry); if (error != 0) { ieee80211_free_node(ni); return error; } /* copy the beacon timestamp */ OS_MEMCPY(ni->ni_tstamp.data, ieee80211_scan_entry_tsf(scan_entry), sizeof(ni->ni_tstamp)); /* * Join the BSS represented by this new node. * This function will free up the old BSS node * and use this one as the new BSS node. */ ieee80211_sta_join_bss(ni); IEEE80211_ADD_NODE_TARGET(ni, ni->ni_vap, 0); /* Save our home channel */ vap->iv_bsschan = ni->ni_chan; vap->iv_cur_mode = ieee80211_chan2mode(ni->ni_chan); /* Update the DotH falg */ ieee80211_update_spectrumrequirement(vap); /* * The OS will control our security keys. * If clear, keys will be cleared. * If static WEP, keys will be plumbed before JoinInfra. * If WPA/WPA2, ciphers will be setup, but no keys will be plumbed until * after they are negotiated. * XXX We should ASSERT that all of the foregoing is true. */ return 0; }
/* End: gengzj added end */ int wlan_vap_delete(wlan_if_t vaphandle) { struct ieee80211vap *vap = vaphandle; struct ieee80211com *ic = vap->iv_ic; IEEE80211_DPRINTF_IC(ic, IEEE80211_VERBOSE_LOUD,IEEE80211_MSG_DEBUG, "%s : enter. vaphandle=0x%x\n", __func__, vaphandle ); ieee80211_vap_pause_vdetach(ic,vap); IEEE80211_COMM_LOCK(ic); /* Begin: gengzj added for wifipos 2013-11-26 */ /*AUTELAN-Added-begin:Added by pengdecai for wifi scan locate function*/ #if 0 if((NULL != vap->iv_scan_locate) && \ (NULL != vap->iv_scan_locate->sl_sock)) { // printk("driver:fun %s vap->iv_scan_locate->sl_sock= %p\n",__func__, vap->iv_scan_locate->sl_sock); vap->iv_locate = 0; if(NULL != vap->iv_scan_locate->sl_sock) { OS_SOCKET_RELEASE(vap->iv_scan_locate->sl_sock); } //free scan locate struct OS_FREE(vap->iv_scan_locate); vap->iv_scan_locate = NULL; } #endif /*AUTELAN-Added-end:Added by pengdecai for wifi scan locate function*/ /* End: gengzj added end */ #ifdef MAGPIE_HIF_GMAC if (ic->ic_chanchange_cnt) ic->ic_chanchange_cnt -= ic->ic_chanchange_tbtt; #endif if (ieee80211_vap_deleted_is_clear(vap)) /* if not deleted then it is on the list */ { TAILQ_REMOVE(&ic->ic_vaps, vap, iv_next); if (TAILQ_EMPTY(&ic->ic_vaps)) /* reset to supported mode */ ic->ic_opmode = IEEE80211_M_STA; ieee80211_vap_deleted_set(vap); /* mark it as deleted */ IEEE80211_COMM_UNLOCK(ic); /* * In case iv_bss was not stopped or is in scanning. * TBD: BSS should have been stopped now. We can save the time for stop bss again. */ wlan_mlme_stop_bss(vap, WLAN_MLME_STOP_BSS_F_SEND_DEAUTH | WLAN_MLME_STOP_BSS_F_CLEAR_ASSOC_STATE | WLAN_MLME_STOP_BSS_F_WAIT_RX_DONE | WLAN_MLME_STOP_BSS_F_NO_RESET); /*zhaoyang1 transplant from 717*/ /*suzhaoyu add for customer online-traffic limit*/ OS_FREE_TIMER(&vap->online_traffic_timer); /*suzhaoyu addend*/ /*zhaoyang1 transplant end*/ ieee80211_sta_leave(vap->iv_bss); ieee80211_node_vdetach(vap); } else { IEEE80211_COMM_UNLOCK(ic); } IEEE80211_DPRINTF_IC(ic, IEEE80211_VERBOSE_LOUD,IEEE80211_MSG_DEBUG, "%s : exit. vaphandle=0x%x\n", __func__, vaphandle ); return 0; }