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