Commit 40aefedc8b494d6a7006ceb9d051fbc58268c86e
Committed by
Johannes Berg
1 parent
65821635d2
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
mac80211: refactor ieee80211_set_qos_hdr
Return early if not a QoS Data frame. Give proper documentation. Signed-off-by: Marco Porsch <marco.porsch@etit.tu-chemnitz.de> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Showing 1 changed file with 23 additions and 17 deletions Inline Diff
net/mac80211/wme.c
1 | /* | 1 | /* |
2 | * Copyright 2004, Instant802 Networks, Inc. | 2 | * Copyright 2004, Instant802 Networks, Inc. |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify | 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 | 5 | * it under the terms of the GNU General Public License version 2 as |
6 | * published by the Free Software Foundation. | 6 | * published by the Free Software Foundation. |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/netdevice.h> | 9 | #include <linux/netdevice.h> |
10 | #include <linux/skbuff.h> | 10 | #include <linux/skbuff.h> |
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/if_arp.h> | 12 | #include <linux/if_arp.h> |
13 | #include <linux/types.h> | 13 | #include <linux/types.h> |
14 | #include <net/ip.h> | 14 | #include <net/ip.h> |
15 | #include <net/pkt_sched.h> | 15 | #include <net/pkt_sched.h> |
16 | 16 | ||
17 | #include <net/mac80211.h> | 17 | #include <net/mac80211.h> |
18 | #include "ieee80211_i.h" | 18 | #include "ieee80211_i.h" |
19 | #include "wme.h" | 19 | #include "wme.h" |
20 | 20 | ||
21 | /* Default mapping in classifier to work with default | 21 | /* Default mapping in classifier to work with default |
22 | * queue setup. | 22 | * queue setup. |
23 | */ | 23 | */ |
24 | const int ieee802_1d_to_ac[8] = { | 24 | const int ieee802_1d_to_ac[8] = { |
25 | IEEE80211_AC_BE, | 25 | IEEE80211_AC_BE, |
26 | IEEE80211_AC_BK, | 26 | IEEE80211_AC_BK, |
27 | IEEE80211_AC_BK, | 27 | IEEE80211_AC_BK, |
28 | IEEE80211_AC_BE, | 28 | IEEE80211_AC_BE, |
29 | IEEE80211_AC_VI, | 29 | IEEE80211_AC_VI, |
30 | IEEE80211_AC_VI, | 30 | IEEE80211_AC_VI, |
31 | IEEE80211_AC_VO, | 31 | IEEE80211_AC_VO, |
32 | IEEE80211_AC_VO | 32 | IEEE80211_AC_VO |
33 | }; | 33 | }; |
34 | 34 | ||
35 | static int wme_downgrade_ac(struct sk_buff *skb) | 35 | static int wme_downgrade_ac(struct sk_buff *skb) |
36 | { | 36 | { |
37 | switch (skb->priority) { | 37 | switch (skb->priority) { |
38 | case 6: | 38 | case 6: |
39 | case 7: | 39 | case 7: |
40 | skb->priority = 5; /* VO -> VI */ | 40 | skb->priority = 5; /* VO -> VI */ |
41 | return 0; | 41 | return 0; |
42 | case 4: | 42 | case 4: |
43 | case 5: | 43 | case 5: |
44 | skb->priority = 3; /* VI -> BE */ | 44 | skb->priority = 3; /* VI -> BE */ |
45 | return 0; | 45 | return 0; |
46 | case 0: | 46 | case 0: |
47 | case 3: | 47 | case 3: |
48 | skb->priority = 2; /* BE -> BK */ | 48 | skb->priority = 2; /* BE -> BK */ |
49 | return 0; | 49 | return 0; |
50 | default: | 50 | default: |
51 | return -1; | 51 | return -1; |
52 | } | 52 | } |
53 | } | 53 | } |
54 | 54 | ||
55 | static u16 ieee80211_downgrade_queue(struct ieee80211_sub_if_data *sdata, | 55 | static u16 ieee80211_downgrade_queue(struct ieee80211_sub_if_data *sdata, |
56 | struct sk_buff *skb) | 56 | struct sk_buff *skb) |
57 | { | 57 | { |
58 | /* in case we are a client verify acm is not set for this ac */ | 58 | /* in case we are a client verify acm is not set for this ac */ |
59 | while (unlikely(sdata->wmm_acm & BIT(skb->priority))) { | 59 | while (unlikely(sdata->wmm_acm & BIT(skb->priority))) { |
60 | if (wme_downgrade_ac(skb)) { | 60 | if (wme_downgrade_ac(skb)) { |
61 | /* | 61 | /* |
62 | * This should not really happen. The AP has marked all | 62 | * This should not really happen. The AP has marked all |
63 | * lower ACs to require admission control which is not | 63 | * lower ACs to require admission control which is not |
64 | * a reasonable configuration. Allow the frame to be | 64 | * a reasonable configuration. Allow the frame to be |
65 | * transmitted using AC_BK as a workaround. | 65 | * transmitted using AC_BK as a workaround. |
66 | */ | 66 | */ |
67 | break; | 67 | break; |
68 | } | 68 | } |
69 | } | 69 | } |
70 | 70 | ||
71 | /* look up which queue to use for frames with this 1d tag */ | 71 | /* look up which queue to use for frames with this 1d tag */ |
72 | return ieee802_1d_to_ac[skb->priority]; | 72 | return ieee802_1d_to_ac[skb->priority]; |
73 | } | 73 | } |
74 | 74 | ||
75 | /* Indicate which queue to use for this fully formed 802.11 frame */ | 75 | /* Indicate which queue to use for this fully formed 802.11 frame */ |
76 | u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata, | 76 | u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata, |
77 | struct sk_buff *skb, | 77 | struct sk_buff *skb, |
78 | struct ieee80211_hdr *hdr) | 78 | struct ieee80211_hdr *hdr) |
79 | { | 79 | { |
80 | struct ieee80211_local *local = sdata->local; | 80 | struct ieee80211_local *local = sdata->local; |
81 | u8 *p; | 81 | u8 *p; |
82 | 82 | ||
83 | if (local->hw.queues < IEEE80211_NUM_ACS) | 83 | if (local->hw.queues < IEEE80211_NUM_ACS) |
84 | return 0; | 84 | return 0; |
85 | 85 | ||
86 | if (!ieee80211_is_data(hdr->frame_control)) { | 86 | if (!ieee80211_is_data(hdr->frame_control)) { |
87 | skb->priority = 7; | 87 | skb->priority = 7; |
88 | return ieee802_1d_to_ac[skb->priority]; | 88 | return ieee802_1d_to_ac[skb->priority]; |
89 | } | 89 | } |
90 | if (!ieee80211_is_data_qos(hdr->frame_control)) { | 90 | if (!ieee80211_is_data_qos(hdr->frame_control)) { |
91 | skb->priority = 0; | 91 | skb->priority = 0; |
92 | return ieee802_1d_to_ac[skb->priority]; | 92 | return ieee802_1d_to_ac[skb->priority]; |
93 | } | 93 | } |
94 | 94 | ||
95 | p = ieee80211_get_qos_ctl(hdr); | 95 | p = ieee80211_get_qos_ctl(hdr); |
96 | skb->priority = *p & IEEE80211_QOS_CTL_TAG1D_MASK; | 96 | skb->priority = *p & IEEE80211_QOS_CTL_TAG1D_MASK; |
97 | 97 | ||
98 | return ieee80211_downgrade_queue(sdata, skb); | 98 | return ieee80211_downgrade_queue(sdata, skb); |
99 | } | 99 | } |
100 | 100 | ||
101 | /* Indicate which queue to use. */ | 101 | /* Indicate which queue to use. */ |
102 | u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, | 102 | u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, |
103 | struct sk_buff *skb) | 103 | struct sk_buff *skb) |
104 | { | 104 | { |
105 | struct ieee80211_local *local = sdata->local; | 105 | struct ieee80211_local *local = sdata->local; |
106 | struct sta_info *sta = NULL; | 106 | struct sta_info *sta = NULL; |
107 | const u8 *ra = NULL; | 107 | const u8 *ra = NULL; |
108 | bool qos = false; | 108 | bool qos = false; |
109 | 109 | ||
110 | if (local->hw.queues < IEEE80211_NUM_ACS || skb->len < 6) { | 110 | if (local->hw.queues < IEEE80211_NUM_ACS || skb->len < 6) { |
111 | skb->priority = 0; /* required for correct WPA/11i MIC */ | 111 | skb->priority = 0; /* required for correct WPA/11i MIC */ |
112 | return 0; | 112 | return 0; |
113 | } | 113 | } |
114 | 114 | ||
115 | rcu_read_lock(); | 115 | rcu_read_lock(); |
116 | switch (sdata->vif.type) { | 116 | switch (sdata->vif.type) { |
117 | case NL80211_IFTYPE_AP_VLAN: | 117 | case NL80211_IFTYPE_AP_VLAN: |
118 | sta = rcu_dereference(sdata->u.vlan.sta); | 118 | sta = rcu_dereference(sdata->u.vlan.sta); |
119 | if (sta) { | 119 | if (sta) { |
120 | qos = test_sta_flag(sta, WLAN_STA_WME); | 120 | qos = test_sta_flag(sta, WLAN_STA_WME); |
121 | break; | 121 | break; |
122 | } | 122 | } |
123 | case NL80211_IFTYPE_AP: | 123 | case NL80211_IFTYPE_AP: |
124 | ra = skb->data; | 124 | ra = skb->data; |
125 | break; | 125 | break; |
126 | case NL80211_IFTYPE_WDS: | 126 | case NL80211_IFTYPE_WDS: |
127 | ra = sdata->u.wds.remote_addr; | 127 | ra = sdata->u.wds.remote_addr; |
128 | break; | 128 | break; |
129 | #ifdef CONFIG_MAC80211_MESH | 129 | #ifdef CONFIG_MAC80211_MESH |
130 | case NL80211_IFTYPE_MESH_POINT: | 130 | case NL80211_IFTYPE_MESH_POINT: |
131 | qos = true; | 131 | qos = true; |
132 | break; | 132 | break; |
133 | #endif | 133 | #endif |
134 | case NL80211_IFTYPE_STATION: | 134 | case NL80211_IFTYPE_STATION: |
135 | ra = sdata->u.mgd.bssid; | 135 | ra = sdata->u.mgd.bssid; |
136 | break; | 136 | break; |
137 | case NL80211_IFTYPE_ADHOC: | 137 | case NL80211_IFTYPE_ADHOC: |
138 | ra = skb->data; | 138 | ra = skb->data; |
139 | break; | 139 | break; |
140 | default: | 140 | default: |
141 | break; | 141 | break; |
142 | } | 142 | } |
143 | 143 | ||
144 | if (!sta && ra && !is_multicast_ether_addr(ra)) { | 144 | if (!sta && ra && !is_multicast_ether_addr(ra)) { |
145 | sta = sta_info_get(sdata, ra); | 145 | sta = sta_info_get(sdata, ra); |
146 | if (sta) | 146 | if (sta) |
147 | qos = test_sta_flag(sta, WLAN_STA_WME); | 147 | qos = test_sta_flag(sta, WLAN_STA_WME); |
148 | } | 148 | } |
149 | rcu_read_unlock(); | 149 | rcu_read_unlock(); |
150 | 150 | ||
151 | if (!qos) { | 151 | if (!qos) { |
152 | skb->priority = 0; /* required for correct WPA/11i MIC */ | 152 | skb->priority = 0; /* required for correct WPA/11i MIC */ |
153 | return IEEE80211_AC_BE; | 153 | return IEEE80211_AC_BE; |
154 | } | 154 | } |
155 | 155 | ||
156 | /* use the data classifier to determine what 802.1d tag the | 156 | /* use the data classifier to determine what 802.1d tag the |
157 | * data frame has */ | 157 | * data frame has */ |
158 | skb->priority = cfg80211_classify8021d(skb); | 158 | skb->priority = cfg80211_classify8021d(skb); |
159 | 159 | ||
160 | return ieee80211_downgrade_queue(sdata, skb); | 160 | return ieee80211_downgrade_queue(sdata, skb); |
161 | } | 161 | } |
162 | 162 | ||
163 | /** | ||
164 | * ieee80211_set_qos_hdr - Fill in the QoS header if there is one. | ||
165 | * | ||
166 | * @sdata: local subif | ||
167 | * @skb: packet to be updated | ||
168 | */ | ||
163 | void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata, | 169 | void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata, |
164 | struct sk_buff *skb) | 170 | struct sk_buff *skb) |
165 | { | 171 | { |
166 | struct ieee80211_hdr *hdr = (void *)skb->data; | 172 | struct ieee80211_hdr *hdr = (void *)skb->data; |
167 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 173 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
174 | u8 *p; | ||
175 | u8 ack_policy, tid; | ||
168 | 176 | ||
169 | /* Fill in the QoS header if there is one. */ | 177 | if (!ieee80211_is_data_qos(hdr->frame_control)) |
170 | if (ieee80211_is_data_qos(hdr->frame_control)) { | 178 | return; |
171 | u8 *p = ieee80211_get_qos_ctl(hdr); | ||
172 | u8 ack_policy, tid; | ||
173 | 179 | ||
174 | tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; | 180 | p = ieee80211_get_qos_ctl(hdr); |
181 | tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; | ||
175 | 182 | ||
176 | /* preserve EOSP bit */ | 183 | /* preserve EOSP bit */ |
177 | ack_policy = *p & IEEE80211_QOS_CTL_EOSP; | 184 | ack_policy = *p & IEEE80211_QOS_CTL_EOSP; |
178 | 185 | ||
179 | if (is_multicast_ether_addr(hdr->addr1) || | 186 | if (is_multicast_ether_addr(hdr->addr1) || |
180 | sdata->noack_map & BIT(tid)) { | 187 | sdata->noack_map & BIT(tid)) { |
181 | ack_policy |= IEEE80211_QOS_CTL_ACK_POLICY_NOACK; | 188 | ack_policy |= IEEE80211_QOS_CTL_ACK_POLICY_NOACK; |
182 | info->flags |= IEEE80211_TX_CTL_NO_ACK; | 189 | info->flags |= IEEE80211_TX_CTL_NO_ACK; |
183 | } | ||
184 | |||
185 | /* qos header is 2 bytes */ | ||
186 | *p++ = ack_policy | tid; | ||
187 | *p = ieee80211_vif_is_mesh(&sdata->vif) ? | ||
188 | (IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT >> 8) : 0; |