diff options
Diffstat (limited to 'net/mac80211/rate.c')
-rw-r--r-- | net/mac80211/rate.c | 249 |
1 files changed, 249 insertions, 0 deletions
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c new file mode 100644 index 000000000000..841df93807fc --- /dev/null +++ b/net/mac80211/rate.c | |||
@@ -0,0 +1,249 @@ | |||
1 | /* | ||
2 | * Copyright 2002-2005, Instant802 Networks, Inc. | ||
3 | * Copyright 2005-2006, Devicescape Software, Inc. | ||
4 | * Copyright (c) 2006 Jiri Benc <jbenc@suse.cz> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/rtnetlink.h> | ||
13 | #include "rate.h" | ||
14 | #include "ieee80211_i.h" | ||
15 | |||
16 | struct rate_control_alg { | ||
17 | struct list_head list; | ||
18 | struct rate_control_ops *ops; | ||
19 | }; | ||
20 | |||
21 | static LIST_HEAD(rate_ctrl_algs); | ||
22 | static DEFINE_MUTEX(rate_ctrl_mutex); | ||
23 | |||
24 | static char *ieee80211_default_rc_algo = CONFIG_MAC80211_RC_DEFAULT; | ||
25 | module_param(ieee80211_default_rc_algo, charp, 0644); | ||
26 | MODULE_PARM_DESC(ieee80211_default_rc_algo, | ||
27 | "Default rate control algorithm for mac80211 to use"); | ||
28 | |||
29 | int ieee80211_rate_control_register(struct rate_control_ops *ops) | ||
30 | { | ||
31 | struct rate_control_alg *alg; | ||
32 | |||
33 | if (!ops->name) | ||
34 | return -EINVAL; | ||
35 | |||
36 | mutex_lock(&rate_ctrl_mutex); | ||
37 | list_for_each_entry(alg, &rate_ctrl_algs, list) { | ||
38 | if (!strcmp(alg->ops->name, ops->name)) { | ||
39 | /* don't register an algorithm twice */ | ||
40 | WARN_ON(1); | ||
41 | mutex_unlock(&rate_ctrl_mutex); | ||
42 | return -EALREADY; | ||
43 | } | ||
44 | } | ||
45 | |||
46 | alg = kzalloc(sizeof(*alg), GFP_KERNEL); | ||
47 | if (alg == NULL) { | ||
48 | mutex_unlock(&rate_ctrl_mutex); | ||
49 | return -ENOMEM; | ||
50 | } | ||
51 | alg->ops = ops; | ||
52 | |||
53 | list_add_tail(&alg->list, &rate_ctrl_algs); | ||
54 | mutex_unlock(&rate_ctrl_mutex); | ||
55 | |||
56 | return 0; | ||
57 | } | ||
58 | EXPORT_SYMBOL(ieee80211_rate_control_register); | ||
59 | |||
60 | void ieee80211_rate_control_unregister(struct rate_control_ops *ops) | ||
61 | { | ||
62 | struct rate_control_alg *alg; | ||
63 | |||
64 | mutex_lock(&rate_ctrl_mutex); | ||
65 | list_for_each_entry(alg, &rate_ctrl_algs, list) { | ||
66 | if (alg->ops == ops) { | ||
67 | list_del(&alg->list); | ||
68 | kfree(alg); | ||
69 | break; | ||
70 | } | ||
71 | } | ||
72 | mutex_unlock(&rate_ctrl_mutex); | ||
73 | } | ||
74 | EXPORT_SYMBOL(ieee80211_rate_control_unregister); | ||
75 | |||
76 | static struct rate_control_ops * | ||
77 | ieee80211_try_rate_control_ops_get(const char *name) | ||
78 | { | ||
79 | struct rate_control_alg *alg; | ||
80 | struct rate_control_ops *ops = NULL; | ||
81 | |||
82 | if (!name) | ||
83 | return NULL; | ||
84 | |||
85 | mutex_lock(&rate_ctrl_mutex); | ||
86 | list_for_each_entry(alg, &rate_ctrl_algs, list) { | ||
87 | if (!strcmp(alg->ops->name, name)) | ||
88 | if (try_module_get(alg->ops->module)) { | ||
89 | ops = alg->ops; | ||
90 | break; | ||
91 | } | ||
92 | } | ||
93 | mutex_unlock(&rate_ctrl_mutex); | ||
94 | return ops; | ||
95 | } | ||
96 | |||
97 | /* Get the rate control algorithm. */ | ||
98 | static struct rate_control_ops * | ||
99 | ieee80211_rate_control_ops_get(const char *name) | ||
100 | { | ||
101 | struct rate_control_ops *ops; | ||
102 | const char *alg_name; | ||
103 | |||
104 | if (!name) | ||
105 | alg_name = ieee80211_default_rc_algo; | ||
106 | else | ||
107 | alg_name = name; | ||
108 | |||
109 | ops = ieee80211_try_rate_control_ops_get(alg_name); | ||
110 | if (!ops) { | ||
111 | request_module("rc80211_%s", alg_name); | ||
112 | ops = ieee80211_try_rate_control_ops_get(alg_name); | ||
113 | } | ||
114 | if (!ops && name) | ||
115 | /* try default if specific alg requested but not found */ | ||
116 | ops = ieee80211_try_rate_control_ops_get(ieee80211_default_rc_algo); | ||
117 | |||
118 | /* try built-in one if specific alg requested but not found */ | ||
119 | if (!ops && strlen(CONFIG_MAC80211_RC_DEFAULT)) | ||
120 | ops = ieee80211_try_rate_control_ops_get(CONFIG_MAC80211_RC_DEFAULT); | ||
121 | |||
122 | return ops; | ||
123 | } | ||
124 | |||
125 | static void ieee80211_rate_control_ops_put(struct rate_control_ops *ops) | ||
126 | { | ||
127 | module_put(ops->module); | ||
128 | } | ||
129 | |||
130 | struct rate_control_ref *rate_control_alloc(const char *name, | ||
131 | struct ieee80211_local *local) | ||
132 | { | ||
133 | struct rate_control_ref *ref; | ||
134 | |||
135 | ref = kmalloc(sizeof(struct rate_control_ref), GFP_KERNEL); | ||
136 | if (!ref) | ||
137 | goto fail_ref; | ||
138 | kref_init(&ref->kref); | ||
139 | ref->ops = ieee80211_rate_control_ops_get(name); | ||
140 | if (!ref->ops) | ||
141 | goto fail_ops; | ||
142 | ref->priv = ref->ops->alloc(local); | ||
143 | if (!ref->priv) | ||
144 | goto fail_priv; | ||
145 | return ref; | ||
146 | |||
147 | fail_priv: | ||
148 | ieee80211_rate_control_ops_put(ref->ops); | ||
149 | fail_ops: | ||
150 | kfree(ref); | ||
151 | fail_ref: | ||
152 | return NULL; | ||
153 | } | ||
154 | |||
155 | static void rate_control_release(struct kref *kref) | ||
156 | { | ||
157 | struct rate_control_ref *ctrl_ref; | ||
158 | |||
159 | ctrl_ref = container_of(kref, struct rate_control_ref, kref); | ||
160 | ctrl_ref->ops->free(ctrl_ref->priv); | ||
161 | ieee80211_rate_control_ops_put(ctrl_ref->ops); | ||
162 | kfree(ctrl_ref); | ||
163 | } | ||
164 | |||
165 | void rate_control_get_rate(struct net_device *dev, | ||
166 | struct ieee80211_supported_band *sband, | ||
167 | struct sk_buff *skb, | ||
168 | struct rate_selection *sel) | ||
169 | { | ||
170 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
171 | struct rate_control_ref *ref = local->rate_ctrl; | ||
172 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | ||
173 | struct sta_info *sta; | ||
174 | int i; | ||
175 | |||
176 | rcu_read_lock(); | ||
177 | sta = sta_info_get(local, hdr->addr1); | ||
178 | |||
179 | memset(sel, 0, sizeof(struct rate_selection)); | ||
180 | |||
181 | ref->ops->get_rate(ref->priv, dev, sband, skb, sel); | ||
182 | |||
183 | /* Select a non-ERP backup rate. */ | ||
184 | if (!sel->nonerp) { | ||
185 | for (i = 0; i < sband->n_bitrates; i++) { | ||
186 | struct ieee80211_rate *rate = &sband->bitrates[i]; | ||
187 | if (sel->rate->bitrate < rate->bitrate) | ||
188 | break; | ||
189 | |||
190 | if (rate_supported(sta, sband->band, i) && | ||
191 | !(rate->flags & IEEE80211_RATE_ERP_G)) | ||
192 | sel->nonerp = rate; | ||
193 | } | ||
194 | } | ||
195 | |||
196 | rcu_read_unlock(); | ||
197 | } | ||
198 | |||
199 | struct rate_control_ref *rate_control_get(struct rate_control_ref *ref) | ||
200 | { | ||
201 | kref_get(&ref->kref); | ||
202 | return ref; | ||
203 | } | ||
204 | |||
205 | void rate_control_put(struct rate_control_ref *ref) | ||
206 | { | ||
207 | kref_put(&ref->kref, rate_control_release); | ||
208 | } | ||
209 | |||
210 | int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, | ||
211 | const char *name) | ||
212 | { | ||
213 | struct rate_control_ref *ref, *old; | ||
214 | |||
215 | ASSERT_RTNL(); | ||
216 | if (local->open_count || netif_running(local->mdev)) | ||
217 | return -EBUSY; | ||
218 | |||
219 | ref = rate_control_alloc(name, local); | ||
220 | if (!ref) { | ||
221 | printk(KERN_WARNING "%s: Failed to select rate control " | ||
222 | "algorithm\n", wiphy_name(local->hw.wiphy)); | ||
223 | return -ENOENT; | ||
224 | } | ||
225 | |||
226 | old = local->rate_ctrl; | ||
227 | local->rate_ctrl = ref; | ||
228 | if (old) { | ||
229 | rate_control_put(old); | ||
230 | sta_info_flush(local, NULL); | ||
231 | } | ||
232 | |||
233 | printk(KERN_DEBUG "%s: Selected rate control " | ||
234 | "algorithm '%s'\n", wiphy_name(local->hw.wiphy), | ||
235 | ref->ops->name); | ||
236 | |||
237 | |||
238 | return 0; | ||
239 | } | ||
240 | |||
241 | void rate_control_deinitialize(struct ieee80211_local *local) | ||
242 | { | ||
243 | struct rate_control_ref *ref; | ||
244 | |||
245 | ref = local->rate_ctrl; | ||
246 | local->rate_ctrl = NULL; | ||
247 | rate_control_put(ref); | ||
248 | } | ||
249 | |||