linux/net/mac80211/wme.c
<<
>>
Prefs
   1/*
   2 * Copyright 2004, Instant802 Networks, Inc.
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License version 2 as
   6 * published by the Free Software Foundation.
   7 */
   8
   9#include <linux/netdevice.h>
  10#include <linux/skbuff.h>
  11#include <linux/module.h>
  12#include <linux/if_arp.h>
  13#include <linux/types.h>
  14#include <net/ip.h>
  15#include <net/pkt_sched.h>
  16
  17#include <net/mac80211.h>
  18#include "ieee80211_i.h"
  19#include "wme.h"
  20
  21/* Default mapping in classifier to work with default
  22 * queue setup.
  23 */
  24const int ieee802_1d_to_ac[8] = { 2, 3, 3, 2, 1, 1, 0, 0 };
  25
  26static int wme_downgrade_ac(struct sk_buff *skb)
  27{
  28        switch (skb->priority) {
  29        case 6:
  30        case 7:
  31                skb->priority = 5; /* VO -> VI */
  32                return 0;
  33        case 4:
  34        case 5:
  35                skb->priority = 3; /* VI -> BE */
  36                return 0;
  37        case 0:
  38        case 3:
  39                skb->priority = 2; /* BE -> BK */
  40                return 0;
  41        default:
  42                return -1;
  43        }
  44}
  45
  46
  47/* Indicate which queue to use. */
  48u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
  49                           struct sk_buff *skb)
  50{
  51        struct ieee80211_local *local = sdata->local;
  52        struct sta_info *sta = NULL;
  53        u32 sta_flags = 0;
  54        const u8 *ra = NULL;
  55        bool qos = false;
  56
  57        if (local->hw.queues < 4 || skb->len < 6) {
  58                skb->priority = 0; /* required for correct WPA/11i MIC */
  59                return min_t(u16, local->hw.queues - 1,
  60                             ieee802_1d_to_ac[skb->priority]);
  61        }
  62
  63        rcu_read_lock();
  64        switch (sdata->vif.type) {
  65        case NL80211_IFTYPE_AP_VLAN:
  66                rcu_read_lock();
  67                sta = rcu_dereference(sdata->u.vlan.sta);
  68                if (sta)
  69                        sta_flags = get_sta_flags(sta);
  70                rcu_read_unlock();
  71                if (sta)
  72                        break;
  73        case NL80211_IFTYPE_AP:
  74                ra = skb->data;
  75                break;
  76        case NL80211_IFTYPE_WDS:
  77                ra = sdata->u.wds.remote_addr;
  78                break;
  79#ifdef CONFIG_MAC80211_MESH
  80        case NL80211_IFTYPE_MESH_POINT:
  81                /*
  82                 * XXX: This is clearly broken ... but already was before,
  83                 * because ieee80211_fill_mesh_addresses() would clear A1
  84                 * except for multicast addresses.
  85                 */
  86                break;
  87#endif
  88        case NL80211_IFTYPE_STATION:
  89                ra = sdata->u.mgd.bssid;
  90                break;
  91        case NL80211_IFTYPE_ADHOC:
  92                ra = skb->data;
  93                break;
  94        default:
  95                break;
  96        }
  97
  98        if (!sta && ra && !is_multicast_ether_addr(ra)) {
  99                sta = sta_info_get(sdata, ra);
 100                if (sta)
 101                        sta_flags = get_sta_flags(sta);
 102        }
 103
 104        if (sta_flags & WLAN_STA_WME)
 105                qos = true;
 106
 107        rcu_read_unlock();
 108
 109        if (!qos) {
 110                skb->priority = 0; /* required for correct WPA/11i MIC */
 111                return ieee802_1d_to_ac[skb->priority];
 112        }
 113
 114        /* use the data classifier to determine what 802.1d tag the
 115         * data frame has */
 116        skb->priority = cfg80211_classify8021d(skb);
 117
 118        return ieee80211_downgrade_queue(local, skb);
 119}
 120
 121u16 ieee80211_downgrade_queue(struct ieee80211_local *local,
 122                              struct sk_buff *skb)
 123{
 124        /* in case we are a client verify acm is not set for this ac */
 125        while (unlikely(local->wmm_acm & BIT(skb->priority))) {
 126                if (wme_downgrade_ac(skb)) {
 127                        /*
 128                         * This should not really happen. The AP has marked all
 129                         * lower ACs to require admission control which is not
 130                         * a reasonable configuration. Allow the frame to be
 131                         * transmitted using AC_BK as a workaround.
 132                         */
 133                        break;
 134                }
 135        }
 136
 137        /* look up which queue to use for frames with this 1d tag */
 138        return ieee802_1d_to_ac[skb->priority];
 139}
 140
 141void ieee80211_set_qos_hdr(struct ieee80211_local *local, struct sk_buff *skb)
 142{
 143        struct ieee80211_hdr *hdr = (void *)skb->data;
 144
 145        /* Fill in the QoS header if there is one. */
 146        if (ieee80211_is_data_qos(hdr->frame_control)) {
 147                u8 *p = ieee80211_get_qos_ctl(hdr);
 148                u8 ack_policy = 0, tid;
 149
 150                tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
 151
 152                if (unlikely(local->wifi_wme_noack_test))
 153                        ack_policy |= QOS_CONTROL_ACK_POLICY_NOACK <<
 154                                        QOS_CONTROL_ACK_POLICY_SHIFT;
 155                /* qos header is 2 bytes, second reserved */
 156                *p++ = ack_policy | tid;
 157                *p = 0;
 158        }
 159}
 160