--- 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) {