1
2
3
4
5
6
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
21
22
23
24const int ieee802_1d_to_ac[8] = { 2, 3, 3, 2, 1, 1, 0, 0 };
25
26static int wme_downgrade_ac(struct sk_buff *skb)
27{
28 switch (skb->priority) {
29 case 6:
30 case 7:
31 skb->priority = 5;
32 return 0;
33 case 4:
34 case 5:
35 skb->priority = 3;
36 return 0;
37 case 0:
38 case 3:
39 skb->priority = 2;
40 return 0;
41 default:
42 return -1;
43 }
44}
45
46
47
48static u16 classify80211(struct ieee80211_local *local, struct sk_buff *skb)
49{
50 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
51
52 if (!ieee80211_is_data(hdr->frame_control)) {
53
54
55 return 0;
56 }
57
58 if (0 ) {
59
60 }
61
62 if (!ieee80211_is_data_qos(hdr->frame_control)) {
63 skb->priority = 0;
64 return ieee802_1d_to_ac[skb->priority];
65 }
66
67
68
69 skb->priority = cfg80211_classify8021d(skb);
70
71
72 while (unlikely(local->wmm_acm & BIT(skb->priority))) {
73 if (wme_downgrade_ac(skb)) {
74
75
76
77
78
79
80 break;
81 }
82 }
83
84
85 return ieee802_1d_to_ac[skb->priority];
86}
87
88void ieee80211_select_queue(struct ieee80211_local *local, struct sk_buff *skb)
89{
90 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
91 u16 queue;
92 u8 tid;
93
94 queue = classify80211(local, skb);
95 if (unlikely(queue >= local->hw.queues))
96 queue = local->hw.queues - 1;
97
98
99
100
101
102 if (ieee80211_is_data_qos(hdr->frame_control)) {
103 u8 *p = ieee80211_get_qos_ctl(hdr);
104 u8 ack_policy = 0;
105 tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
106 if (unlikely(local->wifi_wme_noack_test))
107 ack_policy |= QOS_CONTROL_ACK_POLICY_NOACK <<
108 QOS_CONTROL_ACK_POLICY_SHIFT;
109
110 *p++ = ack_policy | tid;
111 *p = 0;
112 }
113
114 skb_set_queue_mapping(skb, queue);
115}
116