Пример #1
0
void
wep_dump(struct ieee80211_key *k, wbuf_t wbuf, int hdrlen)
{
	struct ieee80211_frame *wh;
    	struct wep_ctx *ctx = k->wk_private;
    	struct ieee80211vap *vap = ctx->wc_vap;
	unsigned int iv,idx,icv;
	unsigned char *ptr;
	unsigned char kbuf[64];


	wh = (struct ieee80211_frame *)wbuf_header(wbuf);
	ptr = (unsigned char*)wh;       

	idx = iv = 0;
	memcpy(&iv, ptr+hdrlen, 3);
	idx = ptr[hdrlen+3];
	memcpy(&icv, ptr+wbuf_get_pktlen(wbuf)-4, 4);

	memcpy(kbuf, k->wk_key, k->wk_keylen);
 
	IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr1,
            "%s and seq=%02x-%02x\n", "addr1", wh->i_seq[0], wh->i_seq[1]);
	IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr3,
            "%s", "addr3");
	IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
            "IV=%08x idx=%d ICV=%08x, hdrlen=%d",iv, idx&0xff, icv, hdrlen);

	printk("key dump:len=%d\n", k->wk_keylen);
	dump_hex_buf(kbuf, (int)k->wk_keylen);
	printk("packet dump:pktlen=%d,len=%d\n", wbuf_get_pktlen(wbuf), wbuf_get_len(wbuf));
	dump_hex_buf((uint8_t*)ptr/*wbuf_raw_data(wbuf)*/, (int)wbuf_get_pktlen(wbuf));
}
Пример #2
0
/*
 * Temporarily added to support older WMI events. We should move all events to unified
 * when the target is ready to support it.
 */
void
wmi_control_rx(void *ctx, HTC_PACKET *htc_packet)
{
    u_int16_t id;
    u_int8_t *data;
    u_int32_t len;
    int status = EOK;
    wmi_buf_t evt_buf;
    struct wmi_unified *wmi_handle = (struct wmi_unified *) ctx;
 
    evt_buf =  (wmi_buf_t)  htc_packet->pPktContext;

    /** 
     * This is  a HACK due to a Hack/WAR in HTC !!.
     * the head of the wbuf still contains the HTC header
     * but the length excludes htc header.  
     */
    wbuf_set_pktlen(evt_buf, htc_packet->ActualLength +  HTC_HEADER_LEN);
    wbuf_pull(evt_buf, HTC_HEADER_LEN);

    id = WMI_GET_FIELD(wbuf_header(evt_buf), WMI_CMD_HDR, COMMANDID);

    if ((id >= WMI_START_EVENTID) && (id <= WMI_END_EVENTID)) {
        status = wmi_unified_event_rx(wmi_handle, evt_buf);
        return ;
    }

    if (wbuf_pull(evt_buf, sizeof(WMI_CMD_HDR)) == NULL) {
        status = -1;
        goto end;
    }

    data = wbuf_header(evt_buf);
    len = wbuf_get_pktlen(evt_buf);

    switch(id)
    {
        default:
            printk("%s: Unhandled WMI command %d\n", __func__, id);
            break;
        case WMI_SERVICE_READY_EVENTID:
            status = wmi_service_ready_event_rx(wmi_handle, data, len);
            break;
        case WMI_READY_EVENTID:
            status = wmi_ready_event_rx(wmi_handle, data, len);
            break;
        case WMI_WLAN_VERSION_EVENTID:
            printk("%s: Handle WMI_VERSION_EVENTID\n", __func__);
            break;
        case WMI_REGDOMAIN_EVENTID:
            printk("%s: Handle WMI_REGDOMAIN_EVENTID\n", __func__);
            break;
        case WMI_DEBUG_MESG_EVENTID:
            dbglog_message_handler(wmi_handle->scn_handle, evt_buf);
            return;
    }

end:
    wbuf_free(evt_buf);
}
Пример #3
0
/*
 * Searches for the presence of a protocol header and returns protocol type.
 * proto_len and proto_log are modified to return length (in bytes) and
 * contents of header (in host byte order), if one is found.
 */ 
static int 
pktlog_proto(struct ath_softc *sc, u_int32_t proto_log[PKTLOG_MAX_PROTO_WORDS],
             void *log_data, pktlog_proto_desc_t ds_type, int *proto_len, HAL_BOOL *isSack)
{
#define IPHDRLEN     20
    struct llc *llc = NULL;
    struct log_tx *tx_log;
    struct log_rx *rx_log;
    wbuf_t wbuf = NULL;
    static const int pktlog_proto_min_hlen = sizeof(struct ieee80211_frame) + 
                                             sizeof(struct llc) + IPHDRLEN;

    switch (ds_type) {
        case PKTLOG_PROTO_TX_DESC:
            tx_log = (struct log_tx *)log_data;
            wbuf = (wbuf_t)(tx_log->bf->bf_mpdu);
            if (wbuf_get_pktlen((wbuf_t)(tx_log->bf->bf_mpdu)) < pktlog_proto_min_hlen) {
                return PKTLOG_PROTO_NONE;
            }
            
            llc = (struct llc *)sc->sc_ieee_ops->parse_frm(sc->sc_ieee,
                                                           wbuf,
                                                           wbuf_get_node((wbuf_t)(tx_log->bf->bf_mpdu)),
                                                           tx_log->bf->bf_vdata,
                                                           0);
            break;
            
        case PKTLOG_PROTO_RX_DESC:
            rx_log = (struct log_rx *)log_data;
            if (rx_log->status->rs_datalen < pktlog_proto_min_hlen) {
                return PKTLOG_PROTO_NONE;
            }

            llc = (struct llc *)sc->sc_ieee_ops->parse_frm(sc->sc_ieee,
                                                           NULL, NULL,
                                                           rx_log->bf->bf_vdata,
                                                           rx_log->status->rs_keyix);
            break;
            
        default:
            return PKTLOG_PROTO_NONE;
    }

    if(!llc) {
        return PKTLOG_PROTO_NONE;
    }
    
    return pktlog_tcpip(sc, wbuf, llc, proto_log, proto_len, isSack);
#undef IPHDRLEN
}
Пример #4
0
int
wlan_frm_haswscie(const wbuf_t wbuf)
{
    const u_int8_t *frm = ((u_int8_t *)wbuf_header(wbuf) + sizeof(struct ieee80211_frame));
    const u_int8_t *efrm = ((u_int8_t *)wbuf_header(wbuf) + wbuf_get_pktlen(wbuf));
    while (frm < efrm) {
        switch (*frm) {
            case IEEE80211_ELEMID_VENDOR:
                if (iswpsoui((u_int8_t *)frm))
                    return 1;
                break;
                default:
                        break;
        }
        frm += frm[1] + 2;
    }
    return 0;
}
Пример #5
0
static int wmi_unified_event_rx(struct wmi_unified *wmi_handle, wmi_buf_t evt_buf)
{
    u_int16_t id;
    u_int8_t *event;
    u_int16_t len;
    int status = -1;
    u_int16_t handler_id;

    ASSERT(evt_buf != NULL);

    id = WMI_GET_FIELD(wbuf_header(evt_buf), WMI_CMD_HDR, COMMANDID);
    handler_id = (id - WMI_START_EVENTID);

    if (wbuf_pull(evt_buf, sizeof(WMI_CMD_HDR)) == NULL) {
        //A_DPRINTF(DBG_WMI, (DBGFMT "bad packet 1\n", DBGARG));
        //wmip->wmi_stats.cmd_len_err++;
        goto end;
    }
    if (handler_id >= WMI_UNIFIED_MAX_EVENT) {
        printk("%s : unkown event id : 0x%x  event handler id 0x%x \n", 
                __func__, id, handler_id);
        goto end;
    }
   
    event = wbuf_header(evt_buf);
    len = wbuf_get_pktlen(evt_buf);


    if (!wmi_handle->event_handler[handler_id]) {
        printk("%s : no registered event handler : event id 0x%x \n", 
                __func__, id);
        goto end;
    }


    /* Call the WMI registered event handler */
    status = wmi_handle->event_handler[handler_id](wmi_handle->scn_handle, event, len,
                                           wmi_handle->event_handler_cookie[handler_id]);

end:
    wbuf_free(evt_buf);
    return status;
}
Пример #6
0
void
host_htc_eptx_comp(void *context, wbuf_t skb, HTC_ENDPOINT_ID epid)
{

	/* for HTC, since we don't have the "real" tx-status, we do them here. */
    struct ath_softc_net80211 	*scn = (struct ath_softc_net80211 *)context;
	ath_dev_t  				 	sc_dev = scn->sc_dev;
	struct ath_softc 			*sc = ATH_DEV_TO_SC(sc_dev);
	u_int16_t 					min_len_req_by_stats = sizeof(ath_data_hdr_t)+sizeof(struct ieee80211_frame);

	if( wbuf_get_pktlen(skb)> min_len_req_by_stats &&
		wbuf_get_tid(skb) < ATH_HTC_WME_NUM_TID &&(
		epid == sc->sc_data_BE_ep ||
		epid == sc->sc_data_BK_ep ||
		epid == sc->sc_data_VI_ep ||
		epid == sc->sc_data_VO_ep	)){
		
		struct ieee80211_node 		*ni = wbuf_get_node(skb);
		struct ieee80211vap 		*vap = ni->ni_vap;
		struct ieee80211_frame 		*wh;
		struct ieee80211_tx_status 	ts;
		struct ieee80211_mac_stats 	*mac_stats;
		u_int8_t 					type, subtype;
		u_int8_t 					is_mcast;
				
		wh = (struct ieee80211_frame *)(wbuf_header(skb)+sizeof(ath_data_hdr_t));
		type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
		subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
		/* we fake ts becuase we don't have ts in HTC tx */
		ts.ts_flags = 0;                                    
    	ts.ts_retries = 0;  

		ieee80211_update_stats(vap, skb, wh, type, subtype, &ts);
		
		/* patch: HTC tx only ath_data_hdr length */
		is_mcast = IEEE80211_IS_MULTICAST(wh->i_addr1) ? 1 : 0;
		mac_stats = is_mcast ? &vap->iv_multicast_stats : &vap->iv_unicast_stats;
		mac_stats->ims_tx_bytes -= sizeof(ath_data_hdr_t);

 	}
	
    ieee80211_free_node(wbuf_get_node(skb));
}
Пример #7
0
 /*
  * processes data frames.
  * ieee80211_wow_magic_parser parses the wbuf to check if match magic packet.
  */
void 
ieee80211_wow_magic_parser(struct ieee80211_node *ni, wbuf_t wbuf)
{
    struct ieee80211vap *vap = ni->ni_vap;
    a_uint8_t    i_addr[IEEE80211_ADDR_LEN];
    a_int32_t    left_len = wbuf_get_pktlen(wbuf);
    a_uint8_t    *cur_ptr;
    a_uint32_t   dup_cnt, is_match = FALSE, is_bcast = FALSE;

    //wow_dump_pkt(wbuf->data, wbuf->len);

    if (left_len < IEEE80211_WOW_MAGIC_PKTLEN)
        return;
        
    cur_ptr = wbuf_header(wbuf);
    IEEE80211_ADDR_COPY(i_addr, vap->iv_myaddr);

    /* parse whole pkt */
    while (cur_ptr && (left_len>0) && (!is_match)) {
        
        /* left len is less than magic pkt size, give up */
        if (left_len < IEEE80211_WOW_MAGIC_PKTLEN)
            break;

        /* to skip continuous 0xFF and to match last 6 bytes of 0xFF */
        while (IEEE80211_IS_BROADCAST(cur_ptr) && (left_len>=IEEE80211_WOW_MAGIC_PKTLEN)) {
            is_bcast = TRUE;
            cur_ptr += IEEE80211_ADDR_LEN;
            left_len -= IEEE80211_ADDR_LEN;
        }

        /* 6 bytes of 0xFF matched, to check if 16 duplications of the IEEE address */
        if (is_bcast) {
            
            dup_cnt = 0;
            
            /* if 0xFF exists at head, skip it */
            while ((cur_ptr[0]==0xFF) && (left_len>=IEEE80211_WOW_MAGIC_DUPLEN)) {
                cur_ptr++;
                left_len--;
            }

            /* left len is less than duplication size, give up */
            if (left_len < IEEE80211_WOW_MAGIC_DUPLEN)
                break;
            
            /* to check if 16 duplications of the IEEE address */
            while (cur_ptr && (left_len>=IEEE80211_ADDR_LEN) && IEEE80211_ADDR_EQ(cur_ptr, i_addr)) {
                cur_ptr += IEEE80211_ADDR_LEN;
                left_len -= IEEE80211_ADDR_LEN;
                dup_cnt++;
                
                if (dup_cnt >= IEEE80211_WOW_MAGIC_DUPCNT) {
                    is_match = TRUE;
                    break;
                }
            }

            /* not match magic pkt, keep parsing */
            is_bcast = FALSE;

        } else {
            cur_ptr++;
            left_len--;
        }        
    }
    
    if (is_match) {
        adf_os_print("Magic packet received...\n");
        ieee80211_wow_set_gpio(vap);
    }
}
Пример #8
0
int
ccmp_encrypt(struct ieee80211_key *key, wbuf_t wbuf0, int hdrlen, int mfp)
{
    struct ccmp_ctx *ctx = key->wk_private;
    struct ieee80211_frame *wh;
    wbuf_t wbuf = wbuf0;
    int data_len, i, space;
    uint8_t aad[2 * AES_BLOCK_LEN], b0[AES_BLOCK_LEN], b[AES_BLOCK_LEN],
        e[AES_BLOCK_LEN], s0[AES_BLOCK_LEN];
    uint8_t *pos;

    ctx->cc_vap->iv_stats.is_crypto_ccmp++;
    wh = (struct ieee80211_frame *)wbuf_header(wbuf);
    data_len = wbuf_get_pktlen(wbuf) - (hdrlen + ccmp.ic_header);
    ccmp_init_blocks(&ctx->cc_aes, wh, key->wk_keytsc,
                     data_len, b0, aad, b, s0, mfp);

    i = 1;
    pos = (u_int8_t *)wbuf_header(wbuf) + hdrlen + ccmp.ic_header;
    /* NB: assumes header is entirely in first mbuf */
    space = wbuf_get_pktlen(wbuf) - (hdrlen + ccmp.ic_header);
    for (;;) {
        if (space > data_len)
            space = data_len;
        /*
         * Do full blocks.
         */
        while (space >= AES_BLOCK_LEN) {
            CCMP_ENCRYPT(i, b, b0, pos, e, AES_BLOCK_LEN);
            pos += AES_BLOCK_LEN, space -= AES_BLOCK_LEN;
            data_len -= AES_BLOCK_LEN;
            i++;
        }
        if (data_len <= 0)		/* no more data */
            break;
        wbuf = wbuf_next(wbuf);
        if (wbuf == NULL) {		/* last buffer */
            if (space != 0) {
                /*
                 * Short last block.
                 */
                CCMP_ENCRYPT(i, b, b0, pos, e, space);
            }
            break;
        }
#if 1 /* assume only one chunk */
        break;
#else
        if (space != 0) {
            uint8_t *pos_next;
            int space_next;
            int len, dl, sp;
            wbuf_t wbufi_new;

            /*
             * Block straddles one or more mbufs, gather data
             * into the block buffer b, apply the cipher, then
             * scatter the results back into the mbuf chain.
             * The buffer will automatically get space bytes
             * of data at offset 0 copied in+out by the
             * CCMP_ENCRYPT request so we must take care of
             * the remaining data.
             */
            wbuf_new = wbuf;
            dl = data_len;
            sp = space;
            for (;;) {
                pos_next = (u_int8_t *)wbuf_header(wbuf_new);
                len = min(dl, AES_BLOCK_LEN);
                space_next = len > sp ? len - sp : 0;
                if (wbuf_get_len(wbuf_new) >= space_next) {
                    /*
                     * This mbuf has enough data; just grab
                     * what we need and stop.
                     */
                    xor_block(b+sp, pos_next, space_next);
                    break;
                }
                /*
                 * This mbuf's contents are insufficient,
                 * take 'em all and prepare to advance to
                 * the next mbuf.
                 */
                xor_block(b+sp, pos_next, n->m_len);
                sp += wbuf_get_len(wbuf_new), dl -= wbuf_get_len(wbuf_new);
                wbuf_next = m_next;
                if (n == NULL)
                    break;
            }

            CCMP_ENCRYPT(i, b, b0, pos, e, space);

            /* NB: just like above, but scatter data to mbufs */
            dl = data_len;
            sp = space;
            for (;;) {
                pos_next = mtod(m, uint8_t *);
                len = min(dl, AES_BLOCK_LEN);
                space_next = len > sp ? len - sp : 0;
                if (m->m_len >= space_next) {
                    xor_block(pos_next, e+sp, space_next);
                    break;
                }
                xor_block(pos_next, e+sp, m->m_len);
                sp += m->m_len, dl -= m->m_len;
                m = m->m_next;
                if (m == NULL)
                    goto done;
            }
            /*
             * Do bookkeeping.  m now points to the last mbuf
             * we grabbed data from.  We know we consumed a
             * full block of data as otherwise we'd have hit
             * the end of the mbuf chain, so deduct from data_len.
             * Otherwise advance the block number (i) and setup
             * pos+space to reflect contents of the new mbuf.
             */
            data_len -= AES_BLOCK_LEN;
            i++;
            pos = pos_next + space_next;
            space = m->m_len - space_next;
        } else {
Пример #9
0
int
ieee80211_recv_asreq(struct ieee80211_node *ni, wbuf_t wbuf, int subtype)
{
    struct ieee80211com *ic = ni->ni_ic;
    struct ieee80211vap *vap = ni->ni_vap;
    struct ieee80211_frame *wh;
    u_int8_t *frm, *efrm;
    u_int16_t capinfo, bintval;
    struct ieee80211_rsnparms rsn;
    u_int8_t reason;
    int reassoc, resp;
    u_int8_t *ssid, *rates, *xrates, *wpa, *wme, *ath, *htcap,*vendor_ie, *wps;
    u_int8_t *athextcap;

    if (vap->iv_opmode != IEEE80211_M_HOSTAP && vap->iv_opmode != IEEE80211_M_BTAMP) {
        vap->iv_stats.is_rx_mgtdiscard++;
        return -EINVAL;
    }

    wh = (struct ieee80211_frame *) wbuf_header(wbuf);
    frm = (u_int8_t *)&wh[1];
    efrm = wbuf_header(wbuf) + wbuf_get_pktlen(wbuf);

    if (subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) {
        reassoc = 1;
        resp = IEEE80211_FC0_SUBTYPE_REASSOC_RESP;
		/*zhaoyang1 transplant from 717*/
		/*pengruofeng add start for management frame stats 2011-5-9*/
		vap->iv_stats.is_rx_reassoc++;
		/*pengruofeng add end 2011-5-9*/	
		/*zhaoyang1 transplant end*/
    } else {
        reassoc = 0;
        resp = IEEE80211_FC0_SUBTYPE_ASSOC_RESP;
    }
    /*
     * asreq frame format
     *    [2] capability information
     *    [2] listen interval
     *    [6*] current AP address (reassoc only)
     *    [tlv] ssid
     *    [tlv] supported rates
     *    [tlv] extended supported rates
     *    [tlv] WPA or RSN
     *    [tlv] WME
     *    [tlv] HT Capabilities
     *    [tlv] Atheros capabilities
     */
    IEEE80211_VERIFY_LENGTH(efrm - frm, (reassoc ? 10 : 4));
    if (!IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_bss->ni_bssid)) {
        IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
                          wh, ieee80211_mgt_subtype_name[subtype >>
                                                         IEEE80211_FC0_SUBTYPE_SHIFT],
                          "%s\n", "wrong bssid");
		/*zhaoyang1 transplant from 717*/
		/*pengruofeng add start for management frame stats 2011-5-9*/
		if (reassoc) {
		
			vap->iv_stats.is_rx_reassoc_bss++;
		} else {
		
			vap->iv_stats.is_rx_assoc_bss++;
		}
		/*pengruofeng add end 2011-5-9*/
		/*zhaoyang1 transplant end*/
		
        return -EINVAL;
    }
Пример #10
0
int
ieee80211_recv_probereq(struct ieee80211_node *ni, wbuf_t wbuf, int subtype)
{
    struct ieee80211com *ic = ni->ni_ic;
    struct ieee80211vap *vap = ni->ni_vap;
    struct ieee80211_frame *wh;
    u_int8_t *frm, *efrm;
    u_int8_t *ssid, *rates, *ven;

#if ATH_SUPPORT_AP_WDS_COMBO
    if (vap->iv_opmode == IEEE80211_M_STA || !ieee80211_vap_ready_is_set(vap) || vap->iv_no_beacon) {
#else
    if (vap->iv_opmode == IEEE80211_M_STA || !ieee80211_vap_ready_is_set(vap)) {
#endif
        vap->iv_stats.is_rx_mgtdiscard++;   /* XXX stat */
        return -EINVAL;
    }

    wh = (struct ieee80211_frame *) wbuf_header(wbuf);
    frm = (u_int8_t *)&wh[1];
    efrm = wbuf_header(wbuf) + wbuf_get_pktlen(wbuf);

	/*zhaoyang1 add start for  probe request REQUIREMENTS-340*/
	if (vap->iv_probe_request) {
		switch (vap->iv_probe_request) {
			case IEEE80211_BROADCAST_PROBE:
				if (IEEE80211_IS_BROADCAST(wh->i_addr1)) {
					vap->iv_stats.is_rx_mgtdiscard++;   /* XXX stat */
			        return -EINVAL;
				}
				break;
			case IEEE80211_ALL_PROBE:
				vap->iv_stats.is_rx_mgtdiscard++;   /* XXX stat */
	    		return -EINVAL;
			default:
				printk("Probe_req value is wrong, iv_probe_request = %d\n", vap->iv_probe_request);
				break;
		}
	}
	/*zhaoyang1 add end*/
	if (IEEE80211_IS_MULTICAST(wh->i_addr2)) {
        /* frame must be directed */
        vap->iv_stats.is_rx_mgtdiscard++;   /* XXX stat */
        return -EINVAL;
    }

    /*
     * prreq frame format
     *  [tlv] ssid
     *  [tlv] supported rates
     *  [tlv] extended supported rates
     *  [tlv] Atheros Advanced Capabilities
     */
    ssid = rates = NULL;
    while (((frm+1) < efrm) && (frm + frm[1] + 1 < efrm)) {
        switch (*frm) {
        case IEEE80211_ELEMID_SSID:
            ssid = frm;
            break;
        case IEEE80211_ELEMID_RATES:
            rates = frm;
            break;
        case IEEE80211_ELEMID_VENDOR:
            if (vap->iv_venie && vap->iv_venie->ven_oui_set) {            
                ven = frm;
                if (ven[2] == vap->iv_venie->ven_oui[0] && 
                    ven[3] == vap->iv_venie->ven_oui[1] && 
                    ven[4] == vap->iv_venie->ven_oui[2]) {
                    vap->iv_venie->ven_ie_len = MIN(ven[1] + 2, IEEE80211_MAX_IE_LEN);
                    OS_MEMCPY(vap->iv_venie->ven_ie, ven, vap->iv_venie->ven_ie_len);
                }
            }
            break;
        }
        frm += frm[1] + 2;
    }

    if (frm > efrm) {
        return -EINVAL;
    }

    IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_MAXSIZE);
    IEEE80211_VERIFY_ELEMENT(ssid, IEEE80211_NWID_LEN);
    IEEE80211_VERIFY_SSID(vap->iv_bss, ssid);

    if (IEEE80211_VAP_IS_HIDESSID_ENABLED(vap) && (ssid[1] == 0)) {
        IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
                          wh, ieee80211_mgt_subtype_name[
                              subtype >> IEEE80211_FC0_SUBTYPE_SHIFT],
                          "%s", "no ssid with ssid suppression enabled");
        vap->iv_stats.is_rx_ssidmismatch++; /*XXX*/
        return -EINVAL;
    }

    /*
     * Skip Probe Requests received while the scan algorithm is setting a new 
     * channel, or while in a foreign channel.
     * Trying to transmit a frame (Probe Response) during a channel change 
     * (which includes a channel reset) can cause a NMI due to invalid HW 
     * addresses. 
     * Trying to transmit the Probe Response while in a foreign channel 
     * wouldn't do us any good either.
     */
    if (ieee80211_scan_can_transmit(ic->ic_scanner))
        ieee80211_send_proberesp(ni, wh->i_addr2, NULL,0);
    
    return 0;
}
Пример #11
0
int
ieee80211_recv_asreq(struct ieee80211_node *ni, wbuf_t wbuf, int subtype)
{
    struct ieee80211com *ic = ni->ni_ic;
    struct ieee80211vap *vap = ni->ni_vap;
    struct ieee80211_frame *wh;
    u_int8_t *frm, *efrm;
    u_int16_t capinfo, bintval;
    struct ieee80211_rsnparms rsn;
    u_int8_t reason;
    int reassoc, resp;
    u_int8_t *ssid, *rates, *xrates, *wpa, *wme, *ath, *htcap,*vendor_ie, *wps, *aow;
    u_int8_t *athextcap;

#if UMAC_SUPPORT_WNM

	u_int8_t *timbcast;
	timbcast = NULL;

#endif


    if (vap->iv_opmode != IEEE80211_M_HOSTAP && vap->iv_opmode != IEEE80211_M_BTAMP) {
        vap->iv_stats.is_rx_mgtdiscard++;
        return -EINVAL;
    }
    wh = (struct ieee80211_frame *) wbuf_header(wbuf);
    frm = (u_int8_t *)&wh[1];
    efrm = wbuf_header(wbuf) + wbuf_get_pktlen(wbuf);

    if (subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) {
        reassoc = 1;
        resp = IEEE80211_FC0_SUBTYPE_REASSOC_RESP;
        uranus_report_wireless_event(ni->ni_vap, ni, WEVENT_AUTH_STATUS_REASSOC_REQ);
    } else {
        reassoc = 0;
        resp = IEEE80211_FC0_SUBTYPE_ASSOC_RESP;
    }
    
    /*
     * asreq frame format
     *    [2] capability information
     *    [2] listen interval
     *    [6*] current AP address (reassoc only)
     *    [tlv] ssid
     *    [tlv] supported rates
     *    [tlv] extended supported rates
     *    [tlv] WPA or RSN
     *    [tlv] WME
     *    [tlv] HT Capabilities
     *    [tlv] Atheros capabilities
     */
    IEEE80211_VERIFY_LENGTH(efrm - frm, (reassoc ? 10 : 4));
    if (!IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_bss->ni_bssid)) {
        IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
                          wh, ieee80211_mgt_subtype_name[subtype >>
                                                         IEEE80211_FC0_SUBTYPE_SHIFT],
                          "%s\n", "wrong bssid");
        vap->iv_stats.is_rx_assoc_bss++;
        uranus_report_wireless_event(ni->ni_vap, ni, WEVENT_AUTH_STATUS_ASSOC_FAILED);
        return -EINVAL;
    }
Пример #12
0
static int ath_rx_assemble_buf(struct ath_softc *sc, wbuf_t *wbuf, 
                        ieee80211_rx_status_t *status, 
                        u_int16_t keyix) 
{

    struct ath_buf *bf = NULL;
    struct sk_buff *kb = NULL; 

    wbuf_t nwbuf;

    if (wbuf_next(*wbuf)) { /* for linux multiple receive buffer */


          bf = ATH_GET_RX_CONTEXT_BUF(wbuf_next(*wbuf));
          bf->bf_mpdu = wbuf_next(*wbuf);
          /* unlink the top half buffer and bottom half buffer */
          wbuf_setnextpkt(*wbuf, NULL); 
          /* use skb_copy_expand for combining two buffer, nwbuf = wbuf##twbuf */
          nwbuf = skb_copy_expand((struct sk_buff *)*wbuf, 
                  0, wbuf_get_pktlen(*wbuf)+wbuf_get_pktlen(bf->bf_mpdu),
                  GFP_ATOMIC);

          if (nwbuf != NULL) {
              skb_copy_bits(bf->bf_mpdu, 0, 
                      wbuf_header(nwbuf) + wbuf_get_pktlen(*wbuf), 
                      wbuf_get_pktlen(bf->bf_mpdu));
              kb = (struct sk_buff *)nwbuf;
              ((struct ieee80211_cb *)kb->cb)->context =
                       &(((struct ieee80211_cb *)kb->cb)[1]);
              skb_put(nwbuf,wbuf_get_pktlen(bf->bf_mpdu));

              wbuf_free(bf->bf_mpdu); 
              bf->bf_mpdu = nwbuf;
              ATH_SET_RX_CONTEXT_BUF(nwbuf, bf);
         } else {

              ATH_GET_RX_CONTEXT_BUF(*wbuf)->bf_status |= ATH_BUFSTATUS_FREE; 

              if (sc->sc_enhanceddmasupport) {
                wbuf_push(*wbuf, sc->sc_rxstatuslen);
                wbuf_push(bf->bf_mpdu, sc->sc_rxstatuslen);
              }

              wbuf_trim(bf->bf_mpdu, wbuf_get_pktlen(bf->bf_mpdu));
              wbuf_trim(*wbuf, wbuf_get_pktlen(*wbuf));

              bf->bf_buf_addr[0] = wbuf_map_single(sc->sc_osdev, 
                                                   bf->bf_mpdu, 
                                                   BUS_DMA_FROMDEVICE, 
                                                   OS_GET_DMA_MEM_CONTEXT(bf, bf_dmacontext));

              /* relink unused wbuf to H/W */
              ath_rx_requeue(sc, *wbuf);
              ath_rx_requeue(sc, bf->bf_mpdu);
              return -1;
         }

           ATH_GET_RX_CONTEXT_BUF(*wbuf)->bf_status |= ATH_BUFSTATUS_FREE; 

           if (sc->sc_enhanceddmasupport) {
              wbuf_push(*wbuf, sc->sc_rxstatuslen);
           }

           wbuf_trim(*wbuf, wbuf_get_pktlen(*wbuf));
           /* relink unused wbuf to H/W */
           ath_rx_requeue(sc, *wbuf);
           *wbuf = bf->bf_mpdu;
    }
    return 0;

}
Пример #13
0
/* 
 * Log Tx data - logs into adapter's buffer if sc is not NULL; 
 *               logs into system-wide buffer if sc is NULL.
 */
void
pktlog_txctl(struct ath_softc *sc, struct log_tx *log_data, u_int16_t iflags)
{
    struct ath_pktlog_txctl *tx_log;
    int i, proto = PKTLOG_PROTO_NONE, proto_len = 0;
    u_int8_t misc_cnt;
    struct ath_pktlog_info *pl_info;
    struct ieee80211_frame *wh;
    u_int8_t dir;
    u_int32_t *ds_words, proto_hdr[PKTLOG_MAX_PROTO_WORDS];
    HAL_DESC_INFO desc_info;
    u_int32_t    flags = iflags;
    HAL_BOOL isSack = FALSE;
	wbuf_t wbuf;
	int frmlen;
    u_int32_t    *proto_hdrp, *misc_p;

    if ((NULL == log_data->bf) || (NULL == log_data->bf->bf_mpdu)) {
        return;
    }

    if (g_pktlog_mode == PKTLOG_MODE_ADAPTER)
        pl_info = sc->pl_info;
    else
        pl_info = g_pktlog_info;

    if ((pl_info->log_state & ATH_PKTLOG_TX)== 0 || 
        log_data->bf->bf_vdata == 0) {
        return;
    }

    misc_cnt = flags & PHFLAGS_MISCCNT_MASK;
    flags |= (((sc->ah_mac_rev << PHFLAGS_MACREV_SFT) & PHFLAGS_MACREV_MASK) |
        ((sc->ah_mac_version << PHFLAGS_MACVERSION_SFT) & PHFLAGS_MACVERSION_MASK));


#ifndef REMOVE_PKTLOG_PROTO
    if (pl_info->options & ATH_PKTLOG_PROTO) {
        proto = pktlog_proto(sc, proto_hdr, log_data, PKTLOG_PROTO_TX_DESC,
                             &proto_len, &isSack);
        flags |= (proto << PHFLAGS_PROTO_SFT) & PHFLAGS_PROTO_MASK;
    }
#endif

    tx_log = (struct ath_pktlog_txctl *)pktlog_getbuf(sc, pl_info, 
              PKTLOG_TYPE_TXCTL, sizeof(*tx_log) + 
              misc_cnt * sizeof(tx_log->misc[0]) + proto_len, flags);
    proto_hdrp = (u_int32_t *)&tx_log->proto_hdr;
    misc_p = (u_int32_t *) ((char *) proto_hdrp + roundup(proto_len,sizeof(int)));


    wh = (struct ieee80211_frame *) (wbuf_header(log_data->bf->bf_mpdu));
    tx_log->framectrl = *(u_int16_t *)(wh->i_fc);
    tx_log->seqctrl   = *(u_int16_t *)(wh->i_seq);

    dir = (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK);
    if(dir == IEEE80211_FC1_DIR_TODS) {
        tx_log->bssid_tail = (wh->i_addr1[IEEE80211_ADDR_LEN-2] << 8) | 
                             (wh->i_addr1[IEEE80211_ADDR_LEN-1]);
        tx_log->sa_tail    = (wh->i_addr2[IEEE80211_ADDR_LEN-2] << 8) | 
                             (wh->i_addr2[IEEE80211_ADDR_LEN-1]);
        tx_log->da_tail    = (wh->i_addr3[IEEE80211_ADDR_LEN-2] << 8) | 
                             (wh->i_addr3[IEEE80211_ADDR_LEN-1]);
    }
    else if(dir == IEEE80211_FC1_DIR_FROMDS) {
        tx_log->bssid_tail = (wh->i_addr2[IEEE80211_ADDR_LEN-2] << 8) | 
                             (wh->i_addr2[IEEE80211_ADDR_LEN-1]);
        tx_log->sa_tail    = (wh->i_addr3[IEEE80211_ADDR_LEN-2] << 8) | 
                             (wh->i_addr3[IEEE80211_ADDR_LEN-1]);
        tx_log->da_tail    = (wh->i_addr1[IEEE80211_ADDR_LEN-2] << 8) | 
                             (wh->i_addr1[IEEE80211_ADDR_LEN-1]);
    }
    else {
        tx_log->bssid_tail = (wh->i_addr3[IEEE80211_ADDR_LEN-2] << 8) | 
                             (wh->i_addr3[IEEE80211_ADDR_LEN-1]);
        tx_log->sa_tail    = (wh->i_addr2[IEEE80211_ADDR_LEN-2] << 8) | 
                             (wh->i_addr2[IEEE80211_ADDR_LEN-1]);
        tx_log->da_tail    = (wh->i_addr1[IEEE80211_ADDR_LEN-2] << 8) | 
                             (wh->i_addr1[IEEE80211_ADDR_LEN-1]);
    }       

    ath_hal_getdescinfo(sc->sc_ah, &desc_info);

    ds_words = (u_int32_t *)(log_data->firstds) + desc_info.txctl_offset;
    for(i = 0; i < desc_info.txctl_numwords; i++)
        tx_log->txdesc_ctl[i] = ds_words[i];

    for (i = 0; i < misc_cnt; i++)
        misc_p[i] = log_data->misc[i];

	if ((pl_info->options & ATH_PKTLOG_TRIGGER_THRUPUT)) { 
        wbuf = (wbuf_t)(log_data->bf->bf_mpdu);
        frmlen = wbuf_get_pktlen((wbuf_t)(log_data->bf->bf_mpdu));
		pl_info->pktlen += frmlen;
	}

    if (proto != PKTLOG_PROTO_NONE) {
        OS_MEMCPY(proto_hdrp, proto_hdr, proto_len);
		if ((proto == PKTLOG_PROTO_TCP) && (pl_info->options & ATH_PKTLOG_TRIGGER_SACK)) { 
                    pktlog_trigger_sack(isSack, pl_info);
                }
    }
}
Пример #14
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;
}