--- a/net80211/ieee80211_output.c
+++ b/net80211/ieee80211_output.c
@@ -73,6 +73,29 @@ doprint(struct ieee80211vap *vap, int su
 }
 #endif
 
+static const int ieee802_1d_to_ac[8] = {
+	WME_AC_BE, WME_AC_BK, WME_AC_BK, WME_AC_BE,
+	WME_AC_VI, WME_AC_VI, WME_AC_VO, WME_AC_VO
+};
+
+/* Given a data frame determine the 802.1p/1d tag to use. */
+static unsigned int ieee80211_classify_ip(struct sk_buff *skb)
+{
+	const struct ether_header *eh = (struct ether_header *) skb->data;
+	const struct iphdr *ip = (struct iphdr *)
+			(skb->data + sizeof (struct ether_header));
+	unsigned int dscp;
+
+	switch (skb->protocol) {
+	case __constant_htons(ETH_P_IP):
+		dscp = ip->tos & 0xfc;
+		break;
+	default:
+		return 0;
+	}
+
+	return dscp >> 5;
+}
 
 /*
  * Determine the priority based on VLAN and/or IP TOS. Priority is
@@ -83,90 +106,24 @@ static int
 ieee80211_classify(struct ieee80211_node *ni, struct sk_buff *skb)
 {
 	struct ieee80211vap *vap = ni->ni_vap;
-	struct ether_header *eh = (struct ether_header *) skb->data;
-	int v_wme_ac = 0, d_wme_ac = 0;
-
-	/* default priority */
-	skb->priority = WME_AC_BE;
-
-	if (!(ni->ni_flags & IEEE80211_NODE_QOS))
-		return 0;
 
-	/* 
-	 * If node has a vlan tag then all traffic
-	 * to it must have a matching vlan id.
+	/* skb->priority values from 256->263 are magic values to
+	 * directly indicate a specific 802.1d priority.  This is used
+	 * to allow 802.1d priority to be passed directly in from VLAN
+	 * tags, etc.
 	 */
-	if (ni->ni_vlan != 0 && vlan_tx_tag_present(skb)) {
-		u_int32_t tag=0;
-		int v_pri;
-
-		if (vap->iv_vlgrp == NULL) {
-			IEEE80211_NODE_STAT(ni, tx_novlantag);
-			ni->ni_stats.ns_tx_novlantag++;
-			return 1;
-		}
-		if (((tag = vlan_tx_tag_get(skb)) & VLAN_VID_MASK) !=
-		    (ni->ni_vlan & VLAN_VID_MASK)) {
-			IEEE80211_NODE_STAT(ni, tx_vlanmismatch);
-			ni->ni_stats.ns_tx_vlanmismatch++;
-			return 1;
-		}
-		if (ni->ni_flags & IEEE80211_NODE_QOS) {
-			v_pri = (tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK;
-			switch (v_pri) {
-			case 1:
-			case 2:		/* Background (BK) */
-				v_wme_ac = WME_AC_BK;
-				break;
-			case 0:
-			case 3:		/* Best Effort (BE) */
-				v_wme_ac = WME_AC_BE;
-				break;
-			case 4:
-			case 5:		/* Video (VI) */
-				v_wme_ac = WME_AC_VI;
-				break;
-			case 6:
-			case 7:		/* Voice (VO) */
-				v_wme_ac = WME_AC_VO;
-				break;
-			}
-		}
+	if (skb->priority >= 256 && skb->priority <= 263) {
+		skb->priority = ieee802_1d_to_ac[skb->priority - 256];
+		return 0;
 	}
 
-	if (eh->ether_type == __constant_htons(ETHERTYPE_IP)) {
-		const struct iphdr *ip = (struct iphdr *)
-			(skb->data + sizeof (struct ether_header));
-		/*
-		 * IP frame, map the TOS field.
-		 *
-		 * XXX: fill out these mappings???
-		 */
-		switch (ip->tos) {
-		case 0x08:				/* Background */
-		case 0x20:
-			d_wme_ac = WME_AC_BK;
-			break;
-		case 0x28:				/* Video */
-		case 0xa0:
-			d_wme_ac = WME_AC_VI;
-			break;
-		case 0x30:				/* Voice */
-		case 0xe0:
-		case 0x88:				/* XXX UPSD */
-		case 0xb8:
-			d_wme_ac = WME_AC_VO;
-			break;
-		default:				/* All others */
-			d_wme_ac = WME_AC_BE;
-			break;
-		}
-	} else {
-		d_wme_ac = WME_AC_BE;
+	if (!(ni->ni_flags & IEEE80211_NODE_QOS)) {
+		/* default priority */
+		skb->priority = WME_AC_BE;
+		return 0;
 	}
-	skb->priority = d_wme_ac;
-	if (v_wme_ac > d_wme_ac)
-		skb->priority = v_wme_ac;
+
+	skb->priority = ieee802_1d_to_ac[ieee80211_classify_ip(skb)];
 
 	/* Applying ACM policy */
 	if (vap->iv_opmode == IEEE80211_M_STA) {
