示例#1
0
/*
 * Handler for add tspec request. 
 */
int ieee80211_admctl_addts(struct ieee80211_node *ni, struct ieee80211_wme_tspec* tspec)
{

    struct ieee80211vap *vap = ni->ni_vap;
    u_int8_t ac;
    struct ieee80211_admctl_tsentry *tsentry;
    struct ieee80211_admctl_priv *admctl_priv = ni->ni_admctl_priv;
    ieee80211_tspec_info ts;

    admctl_tspec_to_tsinfo(tspec, &ts);
    ac = TID_TO_WME_AC(ts.dot1Dtag);
    IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACTION, "ADDTS requested for AC %d \n", ac);
    /* check ACM set for this accesscategory */
    if (wlan_get_wmm_param(vap, WLAN_WME_ACM, 1, ac)) {
        IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACTION, "%s \n", "Processing ADDTS Req");
        /* admission control is required for this AC */
        tsentry = ieee80211_find_tsentry(admctl_priv, ts.tid);
        if (!tsentry) {
            /* create the traffic stream */
            tsentry = ieee80211_add_tsentry(admctl_priv, ac, ts.tid);
            /* copy the ts info */
            OS_MEMCPY(&tsentry->ts_info, &ts, sizeof(ieee80211_tspec_info));
        }
        else {
        }
        /* compute medium_time - in units of 32 us */
        tsentry->ts_info.medium_time = admctl_compute_medium_time(ni, vap, &ts);
        if ((ts.direction == ADMCTL_TSPEC_UPLINK) ||
           (ts.direction == ADMCTL_TSPEC_BIDI) ) {
           *((u_int16_t *) &tspec->ts_medium_time[0]) =
                   htole16((u_int16_t)(tsentry->ts_info.medium_time));

        }
        else {
            /* For downlink only TSPEC set the medium time to 0 */
            *((u_int16_t *) &tspec->ts_medium_time[0]) = 0;
        }
    }
    else {
        /* Addmission control is not required. Ignoring addts req */
        IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACTION, "%s \n", "Ignoring ADDTS : ACM is not set");
    }
    return IEEE80211_STATUS_SUCCESS;
}
示例#2
0
int ieee80211_admctl_send_delts(struct ieee80211vap *vap, u_int8_t *macaddr, u_int8_t tid)
{
    int error = 0;
    u_int8_t ac;
    struct ieee80211_admctl_tsentry *tsentry;
    struct ieee80211_admctl_priv *admctl_priv;
    struct ieee80211_node *ni;

    ni = ieee80211_find_txnode(vap, macaddr);
    if (ni == NULL) {
        error = -EINVAL;
        return error;
    }
    admctl_priv = ni->ni_admctl_priv;
    
    /* Get tspec */
    ac = TID_TO_WME_AC(tid);
    IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACTION, "%s : DELTS requested for AC %d \n", __func__, ac);

    /* admission control is required for this AC */
    tsentry = ieee80211_find_tsentry(admctl_priv, tid);
    if (!tsentry) {
        IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACTION, 
                          "%s : could not find TS entry for AC %d \n", __func__, ac);
        return -EINVAL;
    }
    error =  wlan_send_delts(vap, macaddr, &tsentry->ts_info);
    if (!error) {
        error = ieee80211_remove_tsentry(admctl_priv, tid);
        if (!error) {
            IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACTION, "%s : could not remove the tsentry \n", __func__);
            return -EINVAL;
        } 
    }
    else {
        IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACTION, "%s : wlan_send_delts is failed \n", __func__);
    }

    ieee80211_free_node(ni);
    return error;
}
示例#3
0
/**
 * rsi_core_xmit() - This function transmits the packets received from mac80211
 * @common: Pointer to the driver private structure.
 * @skb: Pointer to the socket buffer structure.
 *
 * Return: None.
 */
void rsi_core_xmit(struct rsi_common *common, struct sk_buff *skb)
{
	struct rsi_hw *adapter = common->priv;
	struct ieee80211_tx_info *info;
	struct skb_info *tx_params;
	struct ieee80211_hdr *wh = NULL;
	struct ieee80211_vif *vif;
	u8 q_num, tid = 0;
	struct rsi_sta *rsta = NULL;

	if ((!skb) || (!skb->len)) {
		rsi_dbg(ERR_ZONE, "%s: Null skb/zero Length packet\n",
			__func__);
		goto xmit_fail;
	}
	if (common->fsm_state != FSM_MAC_INIT_DONE) {
		rsi_dbg(ERR_ZONE, "%s: FSM state not open\n", __func__);
		goto xmit_fail;
	}
	if (common->wow_flags & RSI_WOW_ENABLED) {
		rsi_dbg(ERR_ZONE,
			"%s: Blocking Tx_packets when WOWLAN is enabled\n",
			__func__);
		goto xmit_fail;
	}

	info = IEEE80211_SKB_CB(skb);
	tx_params = (struct skb_info *)info->driver_data;
	wh = (struct ieee80211_hdr *)&skb->data[0];
	tx_params->sta_id = 0;

	vif = rsi_get_vif(adapter, wh->addr2);
	if (!vif)
		goto xmit_fail;
	tx_params->vif = vif;
	tx_params->vap_id = ((struct vif_priv *)vif->drv_priv)->vap_id;
	if ((ieee80211_is_mgmt(wh->frame_control)) ||
	    (ieee80211_is_ctl(wh->frame_control)) ||
	    (ieee80211_is_qos_nullfunc(wh->frame_control))) {
		if (ieee80211_is_assoc_req(wh->frame_control) ||
		    ieee80211_is_reassoc_req(wh->frame_control)) {
			struct ieee80211_bss_conf *bss = &vif->bss_conf;

			common->eapol4_confirm = false;
			rsi_hal_send_sta_notify_frame(common,
						      RSI_IFTYPE_STATION,
						      STA_CONNECTED, bss->bssid,
						      bss->qos, bss->aid, 0,
						      vif);
		}

		q_num = MGMT_SOFT_Q;
		skb->priority = q_num;

		if (rsi_prepare_mgmt_desc(common, skb)) {
			rsi_dbg(ERR_ZONE, "Failed to prepare desc\n");
			goto xmit_fail;
		}
	} else {
		if (ieee80211_is_data_qos(wh->frame_control)) {
			u8 *qos = ieee80211_get_qos_ctl(wh);

			tid = *qos & IEEE80211_QOS_CTL_TID_MASK;
			skb->priority = TID_TO_WME_AC(tid);
		} else {
			tid = IEEE80211_NONQOS_TID;
			skb->priority = BE_Q;
		}

		q_num = skb->priority;
		tx_params->tid = tid;

		if (((vif->type == NL80211_IFTYPE_AP) ||
		     (vif->type == NL80211_IFTYPE_P2P_GO)) &&
		    (!is_broadcast_ether_addr(wh->addr1)) &&
		    (!is_multicast_ether_addr(wh->addr1))) {
			rsta = rsi_find_sta(common, wh->addr1);
			if (!rsta)
				goto xmit_fail;
			tx_params->sta_id = rsta->sta_id;
		} else {
			tx_params->sta_id = 0;
		}

		if (rsta) {
			/* Start aggregation if not done for this tid */
			if (!rsta->start_tx_aggr[tid]) {
				rsta->start_tx_aggr[tid] = true;
				ieee80211_start_tx_ba_session(rsta->sta,
							      tid, 0);
			}
		}
		if (skb->protocol == cpu_to_be16(ETH_P_PAE)) {
			q_num = MGMT_SOFT_Q;
			skb->priority = q_num;
		}
		if (rsi_prepare_data_desc(common, skb)) {
			rsi_dbg(ERR_ZONE, "Failed to prepare data desc\n");
			goto xmit_fail;
		}
	}

	if ((q_num < MGMT_SOFT_Q) &&
	    ((skb_queue_len(&common->tx_queue[q_num]) + 1) >=
	     DATA_QUEUE_WATER_MARK)) {
		rsi_dbg(ERR_ZONE, "%s: sw queue full\n", __func__);
		if (!ieee80211_queue_stopped(adapter->hw, WME_AC(q_num)))
			ieee80211_stop_queue(adapter->hw, WME_AC(q_num));
		rsi_set_event(&common->tx_thread.event);
		goto xmit_fail;
	}

	rsi_core_queue_pkt(common, skb);
	rsi_dbg(DATA_TX_ZONE, "%s: ===> Scheduling TX thread <===\n", __func__);
	rsi_set_event(&common->tx_thread.event);

	return;

xmit_fail:
	rsi_dbg(ERR_ZONE, "%s: Failed to queue packet\n", __func__);
	/* Dropping pkt here */
	ieee80211_free_txskb(common->priv->hw, skb);
}
示例#4
0
/*
 * process the tspec request and fill in the tspec response
 */
int ieee80211_admctl_process_addts_req(struct ieee80211_node *ni, ieee80211_tspec_info* tsinfo, int dialog_token)
{
    struct ieee80211vap *vap = ni->ni_vap;
    u_int8_t *macaddr = ni->ni_macaddr;
    u_int8_t ac;
    u_int16_t medium_time;
    struct ieee80211_admctl_tsentry *tsentry;
    struct ieee80211_admctl_priv *admctl_priv = ni->ni_admctl_priv;

    /* Get tspec */
    ac = TID_TO_WME_AC(tsinfo->dot1Dtag);
    IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACTION, "%s : ADDTS requested for AC %d \n", __func__, ac);
    /* check ACM set for this accesscategory */
    IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACTION, "%s \n", "Processing ADDTS Req");
        
    /* compute medium_time */
    medium_time = admctl_compute_medium_time(ni, vap, tsinfo);
    if (ieee80211_check_medium_time(vap, ni, medium_time)) {
        /* medium_time is not available */
        IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACTION, "%s \n", "ADDTS REFUSED - No available medium time ");
        wlan_send_addts_resp(vap, macaddr, tsinfo, ADMCTL_ADDTS_RESP_REFUSED, dialog_token);
        return 0;
    }

    /* admission control is required for this AC */
    tsentry = ieee80211_find_tsentry(admctl_priv, tsinfo->tid);
    if (!tsentry) {
        tsentry = ieee80211_add_replace_tsentry(ni, ac, tsinfo);
    }
    else {
        if (tsentry->ts_ac == ac) {
            if (tsinfo->direction == tsentry->ts_info.direction) {
                u_int16_t old_mediumtime;
                /* replace tspec, but restore previous medium time */
                old_mediumtime = tsentry->ts_info.medium_time;
                OS_MEMCPY(&tsentry->ts_info, tsinfo, sizeof(ieee80211_tspec_info));
                ieee80211_parse_psb(ni, tsinfo->direction, tsinfo->psb, ac);
                tsentry->ts_info.medium_time = old_mediumtime;
            } else {
                ieee80211_remove_ac_tsentries(admctl_priv, ac);
                tsentry = ieee80211_add_tsentry(admctl_priv, ac, tsinfo->tid);
                OS_MEMCPY(&tsentry->ts_info, tsinfo, sizeof(ieee80211_tspec_info));
                tsentry->ts_info.medium_time = 0;
                ieee80211_parse_psb(ni, tsinfo->direction, tsinfo->psb, ac);
            }
        }
        else {
             IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACTION, "%s \n", "ADDTS REFUSED for INVALID PARAM");
             wlan_send_addts_resp(vap, macaddr, tsinfo, ADMCTL_ADDTS_RESP_INVALID_PARAM, dialog_token);
             return 0;
        }
    }
    if (tsentry->ts_info.medium_time > medium_time)
        vap->iv_ic->ic_mediumtime_reserved -= tsentry->ts_info.medium_time - medium_time;
    else
        vap->iv_ic->ic_mediumtime_reserved += medium_time - tsentry->ts_info.medium_time;

    /* update medium_time */
    tsentry->ts_info.medium_time = medium_time;

    if ((tsinfo->direction == ADMCTL_TSPEC_UPLINK) ||
           (tsinfo->direction == ADMCTL_TSPEC_BIDI) ) {
        tsinfo->medium_time = tsentry->ts_info.medium_time;
    }
    else {
        /* For downlink only TSPEC set the medium time to 0 */
        tsinfo->medium_time = 0;
    }
    if (wlan_get_wmm_param(vap, WLAN_WME_ACM, 1, ac) == 0) {
        tsinfo->medium_time = 0;
    }

    /* send addts response */
    IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACTION, "%s \n", "ADDTS Accepted");
    wlan_send_addts_resp(vap, macaddr, tsinfo, 0, dialog_token);

    return 0;
}
示例#5
0
/*
 * This function determines whether the received frame is a valid UAPSD trigger.
 * Called from interrupt context or DPC context depending on parameter isr_context.
 */
bool
ath_net80211_check_uapsdtrigger(ieee80211_handle_t ieee, struct ieee80211_qosframe *qwh, u_int16_t keyix, bool isr_context)
{
    struct ieee80211com *ic = NET80211_HANDLE(ieee);
    struct ath_softc_net80211 *scn = ATH_SOFTC_NET80211(ic);
    struct ieee80211_node *ni;
    int tid, ac;
    u_int16_t frame_seq;
    int queue_depth;
    bool isapsd = false;

    /*
     * Locate the node for sender
     */
    IEEE80211_KEYMAP_LOCK(scn);
    ni = (keyix != HAL_RXKEYIX_INVALID) ? scn->sc_keyixmap[keyix] : NULL;
    if (ni == NULL) {
        IEEE80211_KEYMAP_UNLOCK(scn);
        /*
         * No key index or no entry, do a lookup
         */
        if (isr_context) {
            ni = ieee80211_find_rxnode_nolock(ic, (struct ieee80211_frame_min *)qwh);
        }
        else {
            ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)qwh);
        }
        if (ni == NULL) {
            return isapsd;
        }
    } else {
        ieee80211_ref_node(ni);
        IEEE80211_KEYMAP_UNLOCK(scn);
    }


    if (!(ni->ni_flags & IEEE80211_NODE_UAPSD))
        goto end;

    if (ni->ni_flags & IEEE80211_NODE_UAPSD_SP)
        goto end;    
    /*
     * Must deal with change of state here, since otherwise there would
     * be a race (on two quick frames from STA) between this code and the
     * tasklet where we would:
     *   - miss a trigger on entry to PS if we're already trigger hunting
     *   - generate spurious SP on exit (due to frame following exit frame)
     */
    if ((((qwh->i_fc[1] & IEEE80211_FC1_PWR_MGT) == IEEE80211_FC1_PWR_MGT) ^
        ((ni->ni_flags & IEEE80211_NODE_UAPSD_TRIG) == IEEE80211_NODE_UAPSD_TRIG)))
    {
        ni->ni_flags &= ~IEEE80211_NODE_UAPSD_SP;

        if (qwh->i_fc[1] & IEEE80211_FC1_PWR_MGT) {
            WME_UAPSD_NODE_TRIGSEQINIT(ni);
            ni->ni_stats.ns_uapsd_triggerenabled++;
            ni->ni_flags |= IEEE80211_NODE_UAPSD_TRIG;
        } else {
            /*
             * Node transitioned from UAPSD -> Active state. Flush out UAPSD frames
             */
            ni->ni_stats.ns_uapsd_active++;
            ni->ni_flags &= ~IEEE80211_NODE_UAPSD_TRIG;
            scn->sc_ops->process_uapsd_trigger(scn->sc_dev,
                                               ATH_NODE_NET80211(ni)->an_sta,
                                               WME_UAPSD_NODE_MAXQDEPTH, 0, 1, WME_UAPSD_NODE_MAXQDEPTH);
        }

        goto end;
    }


    /*
     * Check for a valid trigger frame i.e. QoS Data or QoS NULL
     */
      if ( ((qwh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) !=
              IEEE80211_FC0_TYPE_DATA ) ||
             !(qwh->i_fc[0] & IEEE80211_FC0_SUBTYPE_QOS) ) {
          goto end;
      }

    if (((qwh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) &&
       (((qwh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_QOS) ||
        ((qwh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_QOS_NULL)))
    {
        tid = qwh->i_qos[0] & IEEE80211_QOS_TID;
        ac = TID_TO_WME_AC(tid);

        isapsd = true;

        if (WME_UAPSD_AC_CAN_TRIGGER(ac, ni)) {
            /*
             * Detect duplicate triggers and drop if so.
             */
            frame_seq = le16toh(*(u_int16_t *)qwh->i_seq);
            if ((qwh->i_fc[1] & IEEE80211_FC1_RETRY) &&
                frame_seq == ni->ni_uapsd_trigseq[ac])
            {
                ni->ni_stats.ns_uapsd_duptriggers++;
                goto end;
            }

            /*
             * SP in progress for this node, discard trigger.
             */
            if (ni->ni_flags & IEEE80211_NODE_UAPSD_SP) {
                ni->ni_stats.ns_uapsd_ignoretriggers++;
                goto end;
            }

            /* start the SP */
            ni->ni_stats.ns_uapsd_triggers++;
            ni->ni_flags |= IEEE80211_NODE_UAPSD_SP;
            ni->ni_uapsd_trigseq[ac] = frame_seq;

            queue_depth = scn->sc_ops->process_uapsd_trigger(scn->sc_dev,
                                               ATH_NODE_NET80211(ni)->an_sta,
                                               ni->ni_uapsd_maxsp, ac, 0, WME_UAPSD_NODE_MAXQDEPTH);
            if (!queue_depth &&
                (ni->ni_vap->iv_set_tim != NULL) &&
                IEEE80211_NODE_UAPSD_USETIM(ni))
            {
                ni->ni_vap->iv_set_tim(ni, 0);
            }
        }
    }
end:
    ieee80211_free_node(ni);
    return isapsd;
}
示例#6
0
/*
 * Process a received frame.  The node associated with the sender
 * should be supplied.  If nothing was found in the node table then
 * the caller is assumed to supply a reference to ic_bss instead.
 * The RSSI and a timestamp are also supplied.  The RSSI data is used
 * during AP scanning to select a AP to associate with; it can have
 * any units so long as values have consistent units and higher values
 * mean ``better signal''.  The receive timestamp is currently not used
 * by the 802.11 layer.
 */
int
ieee80211_input(ieee80211com_t *ic, mblk_t *mp, struct ieee80211_node *in,
    int32_t rssi, uint32_t rstamp)
{
	struct ieee80211_frame *wh;
	struct ieee80211_key *key;
	uint8_t *bssid;
	int hdrspace;
	int len;
	uint16_t rxseq;
	uint8_t dir;
	uint8_t type;
	uint8_t subtype;
	uint8_t tid;
	uint8_t qos;

	if (mp->b_flag & M_AMPDU) {
		/*
		 * Fastpath for A-MPDU reorder q resubmission.  Frames
		 * w/ M_AMPDU marked have already passed through here
		 * but were received out of order and been held on the
		 * reorder queue.  When resubmitted they are marked
		 * with the M_AMPDU flag and we can bypass most of the
		 * normal processing.
		 */
		IEEE80211_LOCK(ic);
		wh = (struct ieee80211_frame *)mp->b_rptr;
		type = IEEE80211_FC0_TYPE_DATA;
		dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK;
		subtype = IEEE80211_FC0_SUBTYPE_QOS;
		hdrspace = ieee80211_hdrspace(ic, wh);	/* optimize */
		/* clear driver/net80211 flags before passing up */
		mp->b_flag &= ~M_AMPDU;
		goto resubmit_ampdu;
	}

	ASSERT(in != NULL);
	in->in_inact = in->in_inact_reload;
	type = (uint8_t)-1;		/* undefined */
	len = MBLKL(mp);
	if (len < sizeof (struct ieee80211_frame_min)) {
		ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_input: "
		    "too short (1): len %u", len);
		goto out;
	}
	/*
	 * Bit of a cheat here, we use a pointer for a 3-address
	 * frame format but don't reference fields past outside
	 * ieee80211_frame_min w/o first validating the data is
	 * present.
	 */
	wh = (struct ieee80211_frame *)mp->b_rptr;
	if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) !=
	    IEEE80211_FC0_VERSION_0) {
		ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_input: "
		    "discard pkt with wrong version %x", wh->i_fc[0]);
		goto out;
	}

	dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK;
	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
	subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;

	IEEE80211_LOCK(ic);
	if (!(ic->ic_flags & IEEE80211_F_SCAN)) {
		switch (ic->ic_opmode) {
		case IEEE80211_M_STA:
			bssid = wh->i_addr2;
			if (!IEEE80211_ADDR_EQ(bssid, in->in_bssid))
				goto out_exit_mutex;
			break;
		case IEEE80211_M_IBSS:
		case IEEE80211_M_AHDEMO:
			if (dir != IEEE80211_FC1_DIR_NODS) {
				bssid = wh->i_addr1;
			} else if (type == IEEE80211_FC0_TYPE_CTL) {
				bssid = wh->i_addr1;
			} else {
				if (len < sizeof (struct ieee80211_frame)) {
					ieee80211_dbg(IEEE80211_MSG_ANY,
					    "ieee80211_input: too short(2):"
					    "len %u\n", len);
					goto out_exit_mutex;
				}
				bssid = wh->i_addr3;
			}
			if (type != IEEE80211_FC0_TYPE_DATA)
				break;
			/*
			 * Data frame, validate the bssid.
			 */
			if (!IEEE80211_ADDR_EQ(bssid, ic->ic_bss->in_bssid) &&
			    !IEEE80211_ADDR_EQ(bssid, wifi_bcastaddr)) {
				/* not interested in */
				ieee80211_dbg(IEEE80211_MSG_INPUT,
				    "ieee80211_input: not to bss %s\n",
				    ieee80211_macaddr_sprintf(bssid));
				goto out_exit_mutex;
			}
			/*
			 * For adhoc mode we cons up a node when it doesn't
			 * exist. This should probably done after an ACL check.
			 */
			if (in == ic->ic_bss &&
			    ic->ic_opmode != IEEE80211_M_HOSTAP &&
			    !IEEE80211_ADDR_EQ(wh->i_addr2, in->in_macaddr)) {
				/*
				 * Fake up a node for this newly
				 * discovered member of the IBSS.
				 */
				in = ieee80211_fakeup_adhoc_node(&ic->ic_sta,
				    wh->i_addr2);
				if (in == NULL) {
					/* NB: stat kept for alloc failure */
					goto out_exit_mutex;
				}
			}
			break;
		default:
			goto out_exit_mutex;
		}
		in->in_rssi = (uint8_t)rssi;
		in->in_rstamp = rstamp;
		if (!(type & IEEE80211_FC0_TYPE_CTL)) {
			if (IEEE80211_QOS_HAS_SEQ(wh)) {
				tid = ((struct ieee80211_qosframe *)wh)->
				    i_qos[0] & IEEE80211_QOS_TID;
				if (TID_TO_WME_AC(tid) >= WME_AC_VI)
					ic->ic_wme.wme_hipri_traffic++;
				tid++;
			} else {
				tid = IEEE80211_NONQOS_TID;
			}
			rxseq = LE_16(*(uint16_t *)wh->i_seq);
			if ((in->in_flags & IEEE80211_NODE_HT) == 0 &&
			    (wh->i_fc[1] & IEEE80211_FC1_RETRY) &&
			    (rxseq - in->in_rxseqs[tid]) <= 0) {
				/* duplicate, discard */
				ieee80211_dbg(IEEE80211_MSG_INPUT,
				    "ieee80211_input: duplicate",
				    "seqno <%u,%u> fragno <%u,%u> tid %u",
				    rxseq >> IEEE80211_SEQ_SEQ_SHIFT,
				    in->in_rxseqs[tid] >>
				    IEEE80211_SEQ_SEQ_SHIFT,
				    rxseq & IEEE80211_SEQ_FRAG_MASK,
				    in->in_rxseqs[tid] &
				    IEEE80211_SEQ_FRAG_MASK,
				    tid);
				ic->ic_stats.is_rx_dups++;
				goto out_exit_mutex;
			}
			in->in_rxseqs[tid] = rxseq;
		}
	}
示例#7
0
/*
 * This function is called for each frame received on the high priority queue.
 * If the hardware has classified this frame as a UAPSD trigger, we locate the node
 * and deliver data.
 * For non-trigger frames, we check for PM transition.
 * Called from interrupt context.
 */
void
ath_net80211_uapsd_deliverdata(ieee80211_handle_t        ieee,
                               struct ieee80211_qosframe *qwh,
                               u_int16_t                 keyix,
                               u_int8_t                  is_trig,
                               bool                      isr_context)
{
    struct ieee80211com          *ic = NET80211_HANDLE(ieee);
    struct ath_softc_net80211    *scn = ATH_SOFTC_NET80211(ic);
    struct ieee80211_node        *ni;
    int                          tid, ac;
    u_int16_t                    frame_seq;
    int                          queue_depth;
    bool                         sent_eosp = false;

    UNREFERENCED_PARAMETER(isr_context);

    /*
     * Locate the node for sender
     */
    IEEE80211_KEYMAP_LOCK(scn);
    ni = (keyix != HAL_RXKEYIX_INVALID) ? scn->sc_keyixmap[keyix] : NULL;
    IEEE80211_KEYMAP_UNLOCK(scn);
    if (ni == NULL) {
        /*
         * No key index or no entry, do a lookup
         */
        ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)qwh);
        if (ni == NULL) {
            return;
        }
    } else {
        ieee80211_ref_node(ni);
    }

    if (!(ni->ni_flags & IEEE80211_NODE_UAPSD) || (ni->ni_flags & IEEE80211_NODE_ATH_PAUSED))
        goto end;

    /* We cannot have a PM state change if this is a trigger frame */
    if (!is_trig)
    {
        /*
         * Must deal with change of state here, since otherwise there would
         * be a race (on two quick frames from STA) between this code and the
         * tasklet where we would:
         *   - miss a trigger on entry to PS if we're already trigger hunting
         *   - generate spurious SP on exit (due to frame following exit frame)
         */
        if ((((qwh->i_fc[1] & IEEE80211_FC1_PWR_MGT) == IEEE80211_FC1_PWR_MGT) ^
            ((ni->ni_flags & IEEE80211_NODE_UAPSD_TRIG) == IEEE80211_NODE_UAPSD_TRIG)))
        {
            ni->ni_flags &= ~IEEE80211_NODE_UAPSD_SP;

            if (qwh->i_fc[1] & IEEE80211_FC1_PWR_MGT) {
                WME_UAPSD_NODE_TRIGSEQINIT(ni);
                ni->ni_stats.ns_uapsd_triggerenabled++;
                ni->ni_flags |= IEEE80211_NODE_UAPSD_TRIG;
            } else {
                /*
                 * Node transitioned from UAPSD -> Active state. Flush out UAPSD frames
                 */
                ni->ni_stats.ns_uapsd_active++;
                ni->ni_flags &= ~IEEE80211_NODE_UAPSD_TRIG;
                scn->sc_ops->process_uapsd_trigger(scn->sc_dev,
                                                   ATH_NODE_NET80211(ni)->an_sta,
                                                   WME_UAPSD_NODE_MAXQDEPTH, 0, 1, &sent_eosp, WME_UAPSD_NODE_MAXQDEPTH);
            }

            goto end;
        }
    } else {  /* Is UAPSD trigger */
        tid = qwh->i_qos[0] & IEEE80211_QOS_TID;
        ac = TID_TO_WME_AC(tid);

        if (WME_UAPSD_AC_CAN_TRIGGER(ac, ni)) {
            /*
             * Detect duplicate triggers and drop if so.
             */
            frame_seq = le16toh(*(u_int16_t *)qwh->i_seq);
            if ((qwh->i_fc[1] & IEEE80211_FC1_RETRY) &&
                frame_seq == ni->ni_uapsd_trigseq[ac])
            {
                ni->ni_stats.ns_uapsd_duptriggers++;
                DPRINTF(scn, ATH_DEBUG_UAPSD, "%s : Drop duplicate trigger\n", __func__);
                goto end;
            }

            if (IEEE80211_IS_TDLS_NODE(ni)) {
            /*
                 * TDLS defines any QoS frame with EOSP
                 * set to be a non-trigger frame. Therefore,
                 * ignore trigger.
                 */
                if(qwh->i_qos[0] & IEEE80211_QOS_EOSP) {
                    ni->ni_stats.ns_uapsd_ignoretriggers++;
                    DPRINTF(scn, ATH_DEBUG_UAPSD, "%s : TDLS QOS frame with EOSP; ignore trigger\n", __func__);
                    goto end;
                }
            }

            /*
             * SP in progress for this node, discard trigger.
             */
            if (ni->ni_flags & IEEE80211_NODE_UAPSD_SP) {
                ni->ni_stats.ns_uapsd_ignoretriggers++;
                DPRINTF(scn, ATH_DEBUG_UAPSD, "%s : SP in-progress; ignore trigger\n", __func__);
                goto end;
            }

            ni->ni_stats.ns_uapsd_triggers++;

            DPRINTF(scn, ATH_DEBUG_UAPSD, "%s : Start SP\n", __func__);

            queue_depth = scn->sc_ops->process_uapsd_trigger(scn->sc_dev,
                                               ATH_NODE_NET80211(ni)->an_sta,
                                               ni->ni_uapsd_maxsp, ac, 0, &sent_eosp, WME_UAPSD_NODE_MAXQDEPTH);
            if (queue_depth == -1)
                goto end;

            /* start the SP */
            ni->ni_flags |= IEEE80211_NODE_UAPSD_SP;
            ni->ni_uapsd_trigseq[ac] = frame_seq;

            if (IEEE80211_IS_TDLS_NODE(ni)) {
                if (sent_eosp) {
                    ni->ni_flags &= ~IEEE80211_NODE_UAPSD_SP;
                    DPRINTF(scn, ATH_DEBUG_UAPSD, "%s : TDLS; End SP\n", __func__);
                }
            }
            else {
            if (!queue_depth &&
                (ni->ni_vap->iv_set_tim != NULL) &&
                IEEE80211_NODE_UAPSD_USETIM(ni))
            {
                ni->ni_vap->iv_set_tim(ni, 0, isr_context);
            }
            }
        }
    }
end:
    ieee80211_free_node(ni);
    return;
}
示例#8
0
	
	if (eh->ether_type == __constant_htons(ETHERTYPE_IP)) {
		const struct iphdr *ip = (struct iphdr *)
		(wbuf->data + sizeof (struct ether_header));
		ac = dscp_to_wmm(vap,(ip->tos >> 2));

	}
	else if(eh->ether_type == __constant_htons(ETHERTYPE_IPV6))
	{
		struct ipv6hdr * ipv6h = (struct ipv6hdr*)(wbuf->data + sizeof(struct ether_header));
		unsigned char tos = 0;		
		tos = ipv6h->priority;
		tos = tos << 4;
		tos |= (ipv6h->flow_lbl[0] >> 4);
		tid = dscp_to_wmm(vap,(tos >> 2));
		ac = TID_TO_WME_AC(tid);
	}
	
	return ac;
}

/*return ac */
u_int8_t 
ieee80211_vlan_priv_to_wmm(struct ieee80211vap *vap,u_int8_t v_priv)
{	
	u_int8_t ac = WME_AC_BE;

    if( v_priv > 7){
		vap->priv_wmm.vlan_to_wmm_error ++;
		return WME_AC_BE;
	}
示例#9
0
/**
 * rsi_core_xmit() - This function transmits the packets received from mac80211
 * @common: Pointer to the driver private structure.
 * @skb: Pointer to the socket buffer structure.
 *
 * Return: None.
 */
void rsi_core_xmit(struct rsi_common *common, struct sk_buff *skb)
{
	struct rsi_hw *adapter = common->priv;
	struct ieee80211_tx_info *info;
	struct skb_info *tx_params;
	struct ieee80211_hdr *tmp_hdr = NULL;
	u8 q_num, tid = 0;

	if ((!skb) || (!skb->len)) {
		rsi_dbg(ERR_ZONE, "%s: Null skb/zero Length packet\n",
			__func__);
		goto xmit_fail;
	}
	info = IEEE80211_SKB_CB(skb);
	tx_params = (struct skb_info *)info->driver_data;
	tmp_hdr = (struct ieee80211_hdr *)&skb->data[0];

	if (common->fsm_state != FSM_MAC_INIT_DONE) {
		rsi_dbg(ERR_ZONE, "%s: FSM state not open\n", __func__);
		goto xmit_fail;
	}

	if ((ieee80211_is_mgmt(tmp_hdr->frame_control)) ||
	    (ieee80211_is_ctl(tmp_hdr->frame_control)) ||
	    (ieee80211_is_qos_nullfunc(tmp_hdr->frame_control))) {
		q_num = MGMT_SOFT_Q;
		skb->priority = q_num;
	} else {
		if (ieee80211_is_data_qos(tmp_hdr->frame_control)) {
			tid = (skb->data[24] & IEEE80211_QOS_TID);
			skb->priority = TID_TO_WME_AC(tid);
		} else {
			tid = IEEE80211_NONQOS_TID;
			skb->priority = BE_Q;
		}
		q_num = skb->priority;
		tx_params->tid = tid;
		tx_params->sta_id = 0;
	}

	if ((q_num != MGMT_SOFT_Q) &&
	    ((skb_queue_len(&common->tx_queue[q_num]) + 1) >=
	     DATA_QUEUE_WATER_MARK)) {
		rsi_dbg(ERR_ZONE, "%s: sw queue full\n", __func__);
		if (!ieee80211_queue_stopped(adapter->hw, WME_AC(q_num)))
			ieee80211_stop_queue(adapter->hw, WME_AC(q_num));
		rsi_set_event(&common->tx_thread.event);
		goto xmit_fail;
	}

	rsi_core_queue_pkt(common, skb);
	rsi_dbg(DATA_TX_ZONE, "%s: ===> Scheduling TX thead <===\n", __func__);
	rsi_set_event(&common->tx_thread.event);

	return;

xmit_fail:
	rsi_dbg(ERR_ZONE, "%s: Failed to queue packet\n", __func__);
	/* Dropping pkt here */
	ieee80211_free_txskb(common->priv->hw, skb);
}