Пример #1
0
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;
}
Пример #2
0
/* 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;
}
Пример #3
0
/* 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;
}
Пример #4
0
/* 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;
}
Пример #5
0
/**
 * @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;

}
Пример #6
0
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;
}
Пример #7
0
/**
 * 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;
}
Пример #8
0
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;
}
Пример #9
0
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);
}
Пример #10
0
/**
 * @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;
}
Пример #11
0
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;
}
Пример #12
0
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);
}
Пример #13
0
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;
}
Пример #14
0
/**
 * 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;
}
Пример #15
0
/* 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;
}
Пример #16
0
/*
 * 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;
}
Пример #17
0
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;
}
Пример #18
0
/*
 * 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;
}
Пример #19
0
/*
 * 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);
}
Пример #20
0
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;
}
Пример #21
0
/*
 * 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;
}