Пример #1
0
static int
hwmp_send_action(struct ieee80211_node *ni,
    const uint8_t sa[IEEE80211_ADDR_LEN],
    const uint8_t da[IEEE80211_ADDR_LEN],
    uint8_t *ie, size_t len)
{
	struct ieee80211vap *vap = ni->ni_vap;
	struct ieee80211com *ic = ni->ni_ic;
	struct ieee80211_bpf_params params;
	struct mbuf *m;
	uint8_t *frm;
#ifdef IEEE80211_DEBUG_REFCNT
	char ethstr[ETHER_ADDRSTRLEN + 1];
#endif
	if (vap->iv_state == IEEE80211_S_CAC) {
		IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, ni,
		    "block %s frame in CAC state", "HWMP action");
		vap->iv_stats.is_tx_badstate++;
		return EIO;	/* XXX */
	}

	KASSERT(ni != NULL, ("null node"));
	/*
	 * Hold a reference on the node so it doesn't go away until after
	 * the xmit is complete all the way in the driver.  On error we
	 * will remove our reference.
	 */
#ifdef IEEE80211_DEBUG_REFCNT
	IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
	    "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n",
	    __func__, __LINE__,
	    ni, kether_ntoa(ni->ni_macaddr, ethstr),
	    ieee80211_node_refcnt(ni)+1);
#endif
	ieee80211_ref_node(ni);

	m = ieee80211_getmgtframe(&frm,
	    ic->ic_headroom + sizeof(struct ieee80211_frame),
	    sizeof(struct ieee80211_action) + len
	);
	if (m == NULL) {
		ieee80211_free_node(ni);
		vap->iv_stats.is_tx_nobuf++;
		return ENOMEM;
	}
	*frm++ = IEEE80211_ACTION_CAT_MESHPATH;
	*frm++ = IEEE80211_ACTION_MESHPATH_SEL;
	switch (*ie) {
	case IEEE80211_ELEMID_MESHPREQ:
		frm = hwmp_add_meshpreq(frm,
		    (struct ieee80211_meshpreq_ie *)ie);
		break;
	case IEEE80211_ELEMID_MESHPREP:
		frm = hwmp_add_meshprep(frm,
		    (struct ieee80211_meshprep_ie *)ie);
		break;
	case IEEE80211_ELEMID_MESHPERR:
		frm = hwmp_add_meshperr(frm,
		    (struct ieee80211_meshperr_ie *)ie);
		break;
	case IEEE80211_ELEMID_MESHRANN:
		frm = hwmp_add_meshrann(frm,
		    (struct ieee80211_meshrann_ie *)ie);
		break;
	}

	m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
	M_PREPEND(m, sizeof(struct ieee80211_frame), MB_DONTWAIT);
	if (m == NULL) {
		ieee80211_free_node(ni);
		vap->iv_stats.is_tx_nobuf++;
		return ENOMEM;
	}
	ieee80211_send_setup(ni, m,
	    IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_ACTION,
	    IEEE80211_NONQOS_TID, sa, da, sa);

	m->m_flags |= M_ENCAP;		/* mark encapsulated */
	IEEE80211_NODE_STAT(ni, tx_mgmt);

	memset(&params, 0, sizeof(params));
	params.ibp_pri = WME_AC_VO;
	params.ibp_rate0 = ni->ni_txparms->mgmtrate;
	if (IEEE80211_IS_MULTICAST(da))
		params.ibp_try0 = 1;
	else
		params.ibp_try0 = ni->ni_txparms->maxretry;
	params.ibp_power = ni->ni_txpower;
	return ic->ic_raw_xmit(ni, m, &params);
}
Пример #2
0
static void
tdma_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
	int subtype, int rssi, int nf)
{
	struct ieee80211com *ic = ni->ni_ic;
	struct ieee80211vap *vap = ni->ni_vap;
	struct ieee80211_tdma_state *ts = vap->iv_tdma;

	if (subtype == IEEE80211_FC0_SUBTYPE_BEACON &&
	    (ic->ic_flags & IEEE80211_F_SCAN) == 0) {
		struct ieee80211_frame *wh = mtod(m0, struct ieee80211_frame *);
		struct ieee80211_scanparams scan;

		if (ieee80211_parse_beacon(ni, m0, &scan) != 0)
			return;
		if (scan.tdma == NULL) {
			/*
			 * TDMA stations must beacon a TDMA ie; ignore
			 * any other station.
			 * XXX detect overlapping bss and change channel
			 */
			IEEE80211_DISCARD(vap,
			    IEEE80211_MSG_ELEMID | IEEE80211_MSG_INPUT,
			    wh, ieee80211_mgt_subtype_name[subtype >>
				IEEE80211_FC0_SUBTYPE_SHIFT],
			    "%s", "no TDMA ie");
			vap->iv_stats.is_rx_mgtdiscard++;
			return;
		}
		if (ni == vap->iv_bss &&
		    !IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_macaddr)) {
			/*
			 * Fake up a node for this newly
			 * discovered member of the IBSS.
			 */
			ni = ieee80211_add_neighbor(vap, wh, &scan);
			if (ni == NULL) {
				/* NB: stat kept for alloc failure */
				return;
			}
		}
		/*
		 * Check for state updates.
		 */
		if (IEEE80211_ADDR_EQ(wh->i_addr3, ni->ni_bssid)) {
			/*
			 * Count frame now that we know it's to be processed.
			 */
			vap->iv_stats.is_rx_beacon++;
			IEEE80211_NODE_STAT(ni, rx_beacons);
			/*
			 * Record tsf of last beacon.  NB: this must be
			 * done before calling tdma_process_params
			 * as deeper routines reference it.
			 */
			memcpy(&ni->ni_tstamp.data, scan.tstamp,
				sizeof(ni->ni_tstamp.data));
			/*
			 * Count beacon frame for s/w bmiss handling.
			 */
			vap->iv_swbmiss_count++;
			/*
			 * Process tdma ie.  The contents are used to sync
			 * the slot timing, reconfigure the bss, etc.
			 */
			(void) tdma_process_params(ni, scan.tdma, rssi, nf, wh);
			return;
		}
		/*
		 * NB: defer remaining work to the adhoc code; this causes
		 *     2x parsing of the frame but should happen infrequently
		 */
	}
Пример #3
0
/*
 * Save an outbound packet for a node in power-save sleep state.
 * The new packet is placed on the node's saved queue, and the TIM
 * is changed, if necessary.
 */
void
ieee80211_node_saveq_queue(struct ieee80211_node *ni, wbuf_t wbuf, u_int8_t frame_type)
{
    struct ieee80211vap *vap = ni->ni_vap;
    struct ieee80211com *ic = ni->ni_ic;
    int qlen, age;
    struct node_powersave_queue *dataq,*mgtq,*psq;
    struct ieee80211_tx_status ts;

#if LMAC_SUPPORT_POWERSAVE_QUEUE
    /* mark the frame and will give to ath layer */
    wbuf_set_legacy_ps(wbuf);
    if (ic->ic_get_lmac_pwrsaveq_len(ic, ni, 0) == 0 && vap->iv_set_tim != NULL) {
        vap->iv_set_tim(ni, 1, false);
    }

    return;
#endif

    dataq = IEEE80211_NODE_SAVEQ_DATAQ(ni);
    mgtq  = IEEE80211_NODE_SAVEQ_MGMTQ(ni);


    IEEE80211_NODE_SAVEQ_LOCK(dataq);
    IEEE80211_NODE_SAVEQ_LOCK(mgtq);

    if (frame_type == IEEE80211_FC0_TYPE_MGT) {
        psq = mgtq;
    } else {
        psq = dataq;
    }

    if (IEEE80211_NODE_SAVEQ_FULL(psq)) {
        IEEE80211_NODE_SAVEQ_UNLOCK(mgtq);
        IEEE80211_NODE_SAVEQ_UNLOCK(dataq);
        IEEE80211_NOTE(vap, IEEE80211_MSG_ANY, ni,
                       "%s pwr save q: overflow, drops (size %d) \n",
                       (psq == dataq) ? "data" : "mgt",
                       IEEE80211_PS_MAX_QUEUE);
        IEEE80211_NODE_STAT(ni,psq_drops);
#ifdef IEEE80211_DEBUG
        if (ieee80211_msg_dumppkts(vap))
            ieee80211_dump_pkt(ni->ni_ic, wtod(wbuf, caddr_t), wbuf_get_len(wbuf), -1, -1);
#endif
        ts.ts_flags = IEEE80211_TX_ERROR;
        ieee80211_release_wbuf(ni,wbuf, &ts);
        return;

    }
    /*
     * special handling of frames with PS = 1.
     */
    ieee80211_node_saveq_handle_ps_frames(ni,wbuf,frame_type);

    /*
     * Tag the frame with it's expiry time and insert
     * it in the queue.  The aging interval is 4 times
     * the listen interval specified by the station.
     * Frames that sit around too long are reclaimed
     * using this information.
     */
    age = ((ni->ni_intval * ic->ic_lintval) << 2) >> 10; /* TU -> secs */
    /*
     * Note: our aging algorithm is not working well. In fact, due to the long interval
     * when the aging algorithm is called (IEEE80211_INACT_WAIT is 15 secs), we depend on
     * the associated station node to be disassociated to clear its stale frames. However,
     * as a temporary fix, I will make sure that the age is at least greater than
     * IEEE80211_INACT_WAIT. Otherwise, we will discard all frames in ps queue even though
     * it is just queued.
    */
    if (age < IEEE80211_INACT_WAIT) {
        IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni,
                       "%s Note: increased age from %d to %d secs.\n",
                       __func__, age, IEEE80211_INACT_WAIT);
        age = IEEE80211_INACT_WAIT;
    }
    IEEE80211_NODE_SAVEQ_ENQUEUE(psq, wbuf, qlen, age);
    /*
     * calculate the combined queue length of management and data queues.
     */
    qlen = IEEE80211_NODE_SAVEQ_QLEN(dataq);
    qlen += IEEE80211_NODE_SAVEQ_QLEN(mgtq);

    IEEE80211_NODE_SAVEQ_UNLOCK(mgtq);
    IEEE80211_NODE_SAVEQ_UNLOCK(dataq);

    IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni,
                   "%s pwr queue:save frame, %u now queued \n", (psq == dataq) ? "data" : "mgt" ,qlen);
    if (qlen == 1 && vap->iv_set_tim != NULL)
        vap->iv_set_tim(ni, 1, false);
}