]>
Commit | Line | Data |
---|---|---|
f0706e82 JB |
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 | ||
51cb6db0 | 21 | /* Default mapping in classifier to work with default |
e100bb64 JB |
22 | * queue setup. |
23 | */ | |
9e723492 | 24 | const int ieee802_1d_to_ac[8] = { 2, 3, 3, 2, 1, 1, 0, 0 }; |
f0706e82 | 25 | |
51cb6db0 | 26 | static int wme_downgrade_ac(struct sk_buff *skb) |
f0706e82 JB |
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 | ||
51cb6db0 | 47 | /* Indicate which queue to use. */ |
b4a4bf5d | 48 | static u16 classify80211(struct ieee80211_local *local, struct sk_buff *skb) |
f0706e82 | 49 | { |
f0706e82 | 50 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
f0706e82 | 51 | |
002aaf4e | 52 | if (!ieee80211_is_data(hdr->frame_control)) { |
f0706e82 JB |
53 | /* management frames go on AC_VO queue, but are sent |
54 | * without QoS control fields */ | |
e100bb64 | 55 | return 0; |
f0706e82 JB |
56 | } |
57 | ||
f9d540ee JB |
58 | if (0 /* injected */) { |
59 | /* use AC from radiotap */ | |
f0706e82 JB |
60 | } |
61 | ||
002aaf4e | 62 | if (!ieee80211_is_data_qos(hdr->frame_control)) { |
f0706e82 JB |
63 | skb->priority = 0; /* required for correct WPA/11i MIC */ |
64 | return ieee802_1d_to_ac[skb->priority]; | |
65 | } | |
66 | ||
67 | /* use the data classifier to determine what 802.1d tag the | |
3c3b00ca | 68 | * data frame has */ |
e31a16d6 | 69 | skb->priority = cfg80211_classify8021d(skb); |
f0706e82 | 70 | |
3c3b00ca | 71 | /* in case we are a client verify acm is not set for this ac */ |
f0706e82 JB |
72 | while (unlikely(local->wmm_acm & BIT(skb->priority))) { |
73 | if (wme_downgrade_ac(skb)) { | |
0eeb59fe JM |
74 | /* |
75 | * This should not really happen. The AP has marked all | |
76 | * lower ACs to require admission control which is not | |
77 | * a reasonable configuration. Allow the frame to be | |
78 | * transmitted using AC_BK as a workaround. | |
51cb6db0 | 79 | */ |
0eeb59fe | 80 | break; |
f0706e82 JB |
81 | } |
82 | } | |
83 | ||
84 | /* look up which queue to use for frames with this 1d tag */ | |
85 | return ieee802_1d_to_ac[skb->priority]; | |
86 | } | |
87 | ||
3b8d81e0 | 88 | void ieee80211_select_queue(struct ieee80211_local *local, struct sk_buff *skb) |
f0706e82 | 89 | { |
f0706e82 | 90 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
51cb6db0 | 91 | u16 queue; |
9e723492 | 92 | u8 tid; |
f0706e82 | 93 | |
b4a4bf5d | 94 | queue = classify80211(local, skb); |
51cb6db0 DM |
95 | if (unlikely(queue >= local->hw.queues)) |
96 | queue = local->hw.queues - 1; | |
97 | ||
96f5e66e JB |
98 | /* |
99 | * Now we know the 1d priority, fill in the QoS header if | |
100 | * there is one (and we haven't done this before). | |
f0706e82 | 101 | */ |
8f77f384 | 102 | if (ieee80211_is_data_qos(hdr->frame_control)) { |
002aaf4e | 103 | u8 *p = ieee80211_get_qos_ctl(hdr); |
9e723492 | 104 | u8 ack_policy = 0; |
238f74a2 | 105 | tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; |
d3707d99 | 106 | if (unlikely(local->wifi_wme_noack_test)) |
9e723492 | 107 | ack_policy |= QOS_CONTROL_ACK_POLICY_NOACK << |
f0706e82 JB |
108 | QOS_CONTROL_ACK_POLICY_SHIFT; |
109 | /* qos header is 2 bytes, second reserved */ | |
002aaf4e | 110 | *p++ = ack_policy | tid; |
f0706e82 JB |
111 | *p = 0; |
112 | } | |
113 | ||
3b8d81e0 | 114 | skb_set_queue_mapping(skb, queue); |
f0706e82 | 115 | } |