wme.c
Go to the documentation of this file.
00001 /*
00002  * Copyright 2004, Instant802 Networks, Inc.
00003  *
00004  * This program is free software; you can redistribute it and/or modify
00005  * it under the terms of the GNU General Public License version 2 as
00006  * published by the Free Software Foundation.
00007  */
00008 
00009 #include <linux/netdevice.h>
00010 #include <linux/skbuff.h>
00011 #include <linux/module.h>
00012 #include <linux/if_arp.h>
00013 #include <linux/types.h>
00014 #include <net/ip.h>
00015 #include <net/pkt_sched.h>
00016 
00017 #include <net/mac80211.h>
00018 #include "ieee80211_i.h"
00019 #include "wme.h"
00020 
00021 /* Default mapping in classifier to work with default
00022  * queue setup.
00023  */
00024 const int ieee802_1d_to_ac[8] = {
00025         IEEE80211_AC_BE,
00026         IEEE80211_AC_BK,
00027         IEEE80211_AC_BK,
00028         IEEE80211_AC_BE,
00029         IEEE80211_AC_VI,
00030         IEEE80211_AC_VI,
00031         IEEE80211_AC_VO,
00032         IEEE80211_AC_VO
00033 };
00034 
00035 static int wme_downgrade_ac(struct sk_buff *skb)
00036 {
00037         switch (skb->priority) {
00038         case 6:
00039         case 7:
00040                 skb->priority = 5; /* VO -> VI */
00041                 return 0;
00042         case 4:
00043         case 5:
00044                 skb->priority = 3; /* VI -> BE */
00045                 return 0;
00046         case 0:
00047         case 3:
00048                 skb->priority = 2; /* BE -> BK */
00049                 return 0;
00050         default:
00051                 return -1;
00052         }
00053 }
00054 
00055 
00056 /* Indicate which queue to use. */
00057 u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
00058                            struct sk_buff *skb)
00059 {
00060         struct ieee80211_local *local = sdata->local;
00061         struct sta_info *sta = NULL;
00062         const u8 *ra = NULL;
00063         bool qos = false;
00064 
00065         if (local->hw.queues < 4 || skb->len < 6) {
00066                 skb->priority = 0; /* required for correct WPA/11i MIC */
00067                 return min_t(u16, local->hw.queues - 1, IEEE80211_AC_BE);
00068         }
00069 
00070         rcu_read_lock();
00071         switch (sdata->vif.type) {
00072         case NL80211_IFTYPE_AP_VLAN:
00073                 sta = rcu_dereference(sdata->u.vlan.sta);
00074                 if (sta) {
00075                         qos = test_sta_flag(sta, WLAN_STA_WME);
00076                         break;
00077                 }
00078         case NL80211_IFTYPE_AP:
00079                 ra = skb->data;
00080                 break;
00081         case NL80211_IFTYPE_WDS:
00082                 ra = sdata->u.wds.remote_addr;
00083                 break;
00084 #ifdef CONFIG_MAC80211_MESH
00085         case NL80211_IFTYPE_MESH_POINT:
00086                 ra = skb->data;
00087                 break;
00088 #endif
00089         case NL80211_IFTYPE_STATION:
00090                 ra = sdata->u.mgd.bssid;
00091                 break;
00092         case NL80211_IFTYPE_ADHOC:
00093                 ra = skb->data;
00094                 break;
00095         default:
00096                 break;
00097         }
00098 
00099         if (!sta && ra && !is_multicast_ether_addr(ra)) {
00100                 sta = sta_info_get(sdata, ra);
00101                 if (sta)
00102                         qos = test_sta_flag(sta, WLAN_STA_WME);
00103         }
00104         rcu_read_unlock();
00105 
00106         if (!qos) {
00107                 skb->priority = 0; /* required for correct WPA/11i MIC */
00108                 return IEEE80211_AC_BE;
00109         }
00110 
00111         /* use the data classifier to determine what 802.1d tag the
00112          * data frame has */
00113         skb->priority = cfg80211_classify8021d(skb);
00114 
00115         return ieee80211_downgrade_queue(local, skb);
00116 }
00117 
00118 u16 ieee80211_downgrade_queue(struct ieee80211_local *local,
00119                               struct sk_buff *skb)
00120 {
00121         /* in case we are a client verify acm is not set for this ac */
00122         while (unlikely(local->wmm_acm & BIT(skb->priority))) {
00123                 if (wme_downgrade_ac(skb)) {
00124                         /*
00125                          * This should not really happen. The AP has marked all
00126                          * lower ACs to require admission control which is not
00127                          * a reasonable configuration. Allow the frame to be
00128                          * transmitted using AC_BK as a workaround.
00129                          */
00130                         break;
00131                 }
00132         }
00133 
00134         /* look up which queue to use for frames with this 1d tag */
00135         return ieee802_1d_to_ac[skb->priority];
00136 }
00137 
00138 void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata,
00139                            struct sk_buff *skb)
00140 {
00141         struct ieee80211_hdr *hdr = (void *)skb->data;
00142 
00143         /* Fill in the QoS header if there is one. */
00144         if (ieee80211_is_data_qos(hdr->frame_control)) {
00145                 u8 *p = ieee80211_get_qos_ctl(hdr);
00146                 u8 ack_policy = 0, tid;
00147 
00148                 tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
00149 
00150                 if (unlikely(sdata->local->wifi_wme_noack_test))
00151                         ack_policy |= IEEE80211_QOS_CTL_ACK_POLICY_NOACK;
00152                 /* qos header is 2 bytes */
00153                 *p++ = ack_policy | tid;
00154                 *p = ieee80211_vif_is_mesh(&sdata->vif) ?
00155                         (IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT >> 8) : 0;
00156         }
00157 }


ros_rt_wmp
Author(s): Danilo Tardioli, dantard@unizar.es
autogenerated on Fri Jan 3 2014 12:07:56