~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/mac80211/wme.c

Version: ~ [ linux-5.4-rc7 ] ~ [ linux-5.3.11 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.84 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.154 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.201 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.201 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.77 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * Copyright 2004, Instant802 Networks, Inc.
  3  * Copyright 2013-2014  Intel Mobile Communications GmbH
  4  *
  5  * This program is free software; you can redistribute it and/or modify
  6  * it under the terms of the GNU General Public License version 2 as
  7  * published by the Free Software Foundation.
  8  */
  9 
 10 #include <linux/netdevice.h>
 11 #include <linux/skbuff.h>
 12 #include <linux/module.h>
 13 #include <linux/if_arp.h>
 14 #include <linux/types.h>
 15 #include <net/ip.h>
 16 #include <net/pkt_sched.h>
 17 
 18 #include <net/mac80211.h>
 19 #include "ieee80211_i.h"
 20 #include "wme.h"
 21 
 22 /* Default mapping in classifier to work with default
 23  * queue setup.
 24  */
 25 const int ieee802_1d_to_ac[8] = {
 26         IEEE80211_AC_BE,
 27         IEEE80211_AC_BK,
 28         IEEE80211_AC_BK,
 29         IEEE80211_AC_BE,
 30         IEEE80211_AC_VI,
 31         IEEE80211_AC_VI,
 32         IEEE80211_AC_VO,
 33         IEEE80211_AC_VO
 34 };
 35 
 36 static int wme_downgrade_ac(struct sk_buff *skb)
 37 {
 38         switch (skb->priority) {
 39         case 6:
 40         case 7:
 41                 skb->priority = 5; /* VO -> VI */
 42                 return 0;
 43         case 4:
 44         case 5:
 45                 skb->priority = 3; /* VI -> BE */
 46                 return 0;
 47         case 0:
 48         case 3:
 49                 skb->priority = 2; /* BE -> BK */
 50                 return 0;
 51         default:
 52                 return -1;
 53         }
 54 }
 55 
 56 /**
 57  * ieee80211_fix_reserved_tid - return the TID to use if this one is reserved
 58  * @tid: the assumed-reserved TID
 59  *
 60  * Returns: the alternative TID to use, or 0 on error
 61  */
 62 static inline u8 ieee80211_fix_reserved_tid(u8 tid)
 63 {
 64         switch (tid) {
 65         case 0:
 66                 return 3;
 67         case 1:
 68                 return 2;
 69         case 2:
 70                 return 1;
 71         case 3:
 72                 return 0;
 73         case 4:
 74                 return 5;
 75         case 5:
 76                 return 4;
 77         case 6:
 78                 return 7;
 79         case 7:
 80                 return 6;
 81         }
 82 
 83         return 0;
 84 }
 85 
 86 static u16 ieee80211_downgrade_queue(struct ieee80211_sub_if_data *sdata,
 87                                      struct sta_info *sta, struct sk_buff *skb)
 88 {
 89         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 90 
 91         /* in case we are a client verify acm is not set for this ac */
 92         while (sdata->wmm_acm & BIT(skb->priority)) {
 93                 int ac = ieee802_1d_to_ac[skb->priority];
 94 
 95                 if (ifmgd->tx_tspec[ac].admitted_time &&
 96                     skb->priority == ifmgd->tx_tspec[ac].up)
 97                         return ac;
 98 
 99                 if (wme_downgrade_ac(skb)) {
100                         /*
101                          * This should not really happen. The AP has marked all
102                          * lower ACs to require admission control which is not
103                          * a reasonable configuration. Allow the frame to be
104                          * transmitted using AC_BK as a workaround.
105                          */
106                         break;
107                 }
108         }
109 
110         /* Check to see if this is a reserved TID */
111         if (sta && sta->reserved_tid == skb->priority)
112                 skb->priority = ieee80211_fix_reserved_tid(skb->priority);
113 
114         /* look up which queue to use for frames with this 1d tag */
115         return ieee802_1d_to_ac[skb->priority];
116 }
117 
118 /* Indicate which queue to use for this fully formed 802.11 frame */
119 u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata,
120                                  struct sk_buff *skb,
121                                  struct ieee80211_hdr *hdr)
122 {
123         struct ieee80211_local *local = sdata->local;
124         u8 *p;
125 
126         if (local->hw.queues < IEEE80211_NUM_ACS)
127                 return 0;
128 
129         if (!ieee80211_is_data(hdr->frame_control)) {
130                 skb->priority = 7;
131                 return ieee802_1d_to_ac[skb->priority];
132         }
133         if (!ieee80211_is_data_qos(hdr->frame_control)) {
134                 skb->priority = 0;
135                 return ieee802_1d_to_ac[skb->priority];
136         }
137 
138         p = ieee80211_get_qos_ctl(hdr);
139         skb->priority = *p & IEEE80211_QOS_CTL_TAG1D_MASK;
140 
141         return ieee80211_downgrade_queue(sdata, NULL, skb);
142 }
143 
144 /* Indicate which queue to use. */
145 u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
146                            struct sk_buff *skb)
147 {
148         struct ieee80211_local *local = sdata->local;
149         struct sta_info *sta = NULL;
150         const u8 *ra = NULL;
151         bool qos = false;
152         struct mac80211_qos_map *qos_map;
153         u16 ret;
154 
155         if (local->hw.queues < IEEE80211_NUM_ACS || skb->len < 6) {
156                 skb->priority = 0; /* required for correct WPA/11i MIC */
157                 return 0;
158         }
159 
160         rcu_read_lock();
161         switch (sdata->vif.type) {
162         case NL80211_IFTYPE_AP_VLAN:
163                 sta = rcu_dereference(sdata->u.vlan.sta);
164                 if (sta) {
165                         qos = sta->sta.wme;
166                         break;
167                 }
168         case NL80211_IFTYPE_AP:
169                 ra = skb->data;
170                 break;
171         case NL80211_IFTYPE_WDS:
172                 ra = sdata->u.wds.remote_addr;
173                 break;
174 #ifdef CONFIG_MAC80211_MESH
175         case NL80211_IFTYPE_MESH_POINT:
176                 qos = true;
177                 break;
178 #endif
179         case NL80211_IFTYPE_STATION:
180                 /* might be a TDLS station */
181                 sta = sta_info_get(sdata, skb->data);
182                 if (sta)
183                         qos = sta->sta.wme;
184 
185                 ra = sdata->u.mgd.bssid;
186                 break;
187         case NL80211_IFTYPE_ADHOC:
188                 ra = skb->data;
189                 break;
190         case NL80211_IFTYPE_OCB:
191                 /* all stations are required to support WME */
192                 qos = true;
193                 break;
194         default:
195                 break;
196         }
197 
198         if (!sta && ra && !is_multicast_ether_addr(ra)) {
199                 sta = sta_info_get(sdata, ra);
200                 if (sta)
201                         qos = sta->sta.wme;
202         }
203 
204         if (!qos) {
205                 skb->priority = 0; /* required for correct WPA/11i MIC */
206                 ret = IEEE80211_AC_BE;
207                 goto out;
208         }
209 
210         if (skb->protocol == sdata->control_port_protocol) {
211                 skb->priority = 7;
212                 goto downgrade;
213         }
214 
215         /* use the data classifier to determine what 802.1d tag the
216          * data frame has */
217         qos_map = rcu_dereference(sdata->qos_map);
218         skb->priority = cfg80211_classify8021d(skb, qos_map ?
219                                                &qos_map->qos_map : NULL);
220 
221  downgrade:
222         ret = ieee80211_downgrade_queue(sdata, sta, skb);
223  out:
224         rcu_read_unlock();
225         return ret;
226 }
227 
228 /**
229  * ieee80211_set_qos_hdr - Fill in the QoS header if there is one.
230  *
231  * @sdata: local subif
232  * @skb: packet to be updated
233  */
234 void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata,
235                            struct sk_buff *skb)
236 {
237         struct ieee80211_hdr *hdr = (void *)skb->data;
238         struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
239         u8 tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
240         u8 flags;
241         u8 *p;
242 
243         if (!ieee80211_is_data_qos(hdr->frame_control))
244                 return;
245 
246         p = ieee80211_get_qos_ctl(hdr);
247 
248         /* set up the first byte */
249 
250         /*
251          * preserve everything but the TID and ACK policy
252          * (which we both write here)
253          */
254         flags = *p & ~(IEEE80211_QOS_CTL_TID_MASK |
255                        IEEE80211_QOS_CTL_ACK_POLICY_MASK);
256 
257         if (is_multicast_ether_addr(hdr->addr1) ||
258             sdata->noack_map & BIT(tid)) {
259                 flags |= IEEE80211_QOS_CTL_ACK_POLICY_NOACK;
260                 info->flags |= IEEE80211_TX_CTL_NO_ACK;
261         }
262 
263         *p = flags | tid;
264 
265         /* set up the second byte */
266         p++;
267 
268         if (ieee80211_vif_is_mesh(&sdata->vif)) {
269                 /* preserve RSPI and Mesh PS Level bit */
270                 *p &= ((IEEE80211_QOS_CTL_RSPI |
271                         IEEE80211_QOS_CTL_MESH_PS_LEVEL) >> 8);
272 
273                 /* Nulls don't have a mesh header (frame body) */
274                 if (!ieee80211_is_qos_nullfunc(hdr->frame_control))
275                         *p |= (IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT >> 8);
276         } else {
277                 *p = 0;
278         }
279 }
280 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp