123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- /*
- * Copyright 2002-2005, Instant802 Networks, Inc.
- * Copyright 2005-2006, Devicescape Software, Inc.
- * Copyright (c) 2006 Jiri Benc <jbenc@suse.cz>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
- #include <linux/kernel.h>
- #include <linux/rtnetlink.h>
- #include "ieee80211_rate.h"
- #include "ieee80211_i.h"
- struct rate_control_alg {
- struct list_head list;
- struct rate_control_ops *ops;
- };
- static LIST_HEAD(rate_ctrl_algs);
- static DEFINE_MUTEX(rate_ctrl_mutex);
- int ieee80211_rate_control_register(struct rate_control_ops *ops)
- {
- struct rate_control_alg *alg;
- alg = kzalloc(sizeof(*alg), GFP_KERNEL);
- if (alg == NULL) {
- return -ENOMEM;
- }
- alg->ops = ops;
- mutex_lock(&rate_ctrl_mutex);
- list_add_tail(&alg->list, &rate_ctrl_algs);
- mutex_unlock(&rate_ctrl_mutex);
- return 0;
- }
- EXPORT_SYMBOL(ieee80211_rate_control_register);
- void ieee80211_rate_control_unregister(struct rate_control_ops *ops)
- {
- struct rate_control_alg *alg;
- mutex_lock(&rate_ctrl_mutex);
- list_for_each_entry(alg, &rate_ctrl_algs, list) {
- if (alg->ops == ops) {
- list_del(&alg->list);
- break;
- }
- }
- mutex_unlock(&rate_ctrl_mutex);
- kfree(alg);
- }
- EXPORT_SYMBOL(ieee80211_rate_control_unregister);
- static struct rate_control_ops *
- ieee80211_try_rate_control_ops_get(const char *name)
- {
- struct rate_control_alg *alg;
- struct rate_control_ops *ops = NULL;
- mutex_lock(&rate_ctrl_mutex);
- list_for_each_entry(alg, &rate_ctrl_algs, list) {
- if (!name || !strcmp(alg->ops->name, name))
- if (try_module_get(alg->ops->module)) {
- ops = alg->ops;
- break;
- }
- }
- mutex_unlock(&rate_ctrl_mutex);
- return ops;
- }
- /* Get the rate control algorithm. If `name' is NULL, get the first
- * available algorithm. */
- static struct rate_control_ops *
- ieee80211_rate_control_ops_get(const char *name)
- {
- struct rate_control_ops *ops;
- ops = ieee80211_try_rate_control_ops_get(name);
- if (!ops) {
- request_module("rc80211_%s", name ? name : "default");
- ops = ieee80211_try_rate_control_ops_get(name);
- }
- return ops;
- }
- static void ieee80211_rate_control_ops_put(struct rate_control_ops *ops)
- {
- module_put(ops->module);
- }
- struct rate_control_ref *rate_control_alloc(const char *name,
- struct ieee80211_local *local)
- {
- struct rate_control_ref *ref;
- ref = kmalloc(sizeof(struct rate_control_ref), GFP_KERNEL);
- if (!ref)
- goto fail_ref;
- kref_init(&ref->kref);
- ref->ops = ieee80211_rate_control_ops_get(name);
- if (!ref->ops)
- goto fail_ops;
- ref->priv = ref->ops->alloc(local);
- if (!ref->priv)
- goto fail_priv;
- return ref;
- fail_priv:
- ieee80211_rate_control_ops_put(ref->ops);
- fail_ops:
- kfree(ref);
- fail_ref:
- return NULL;
- }
- static void rate_control_release(struct kref *kref)
- {
- struct rate_control_ref *ctrl_ref;
- ctrl_ref = container_of(kref, struct rate_control_ref, kref);
- ctrl_ref->ops->free(ctrl_ref->priv);
- ieee80211_rate_control_ops_put(ctrl_ref->ops);
- kfree(ctrl_ref);
- }
- struct rate_control_ref *rate_control_get(struct rate_control_ref *ref)
- {
- kref_get(&ref->kref);
- return ref;
- }
- void rate_control_put(struct rate_control_ref *ref)
- {
- kref_put(&ref->kref, rate_control_release);
- }
- int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
- const char *name)
- {
- struct rate_control_ref *ref, *old;
- ASSERT_RTNL();
- if (local->open_count || netif_running(local->mdev))
- return -EBUSY;
- ref = rate_control_alloc(name, local);
- if (!ref) {
- printk(KERN_WARNING "%s: Failed to select rate control "
- "algorithm\n", wiphy_name(local->hw.wiphy));
- return -ENOENT;
- }
- old = local->rate_ctrl;
- local->rate_ctrl = ref;
- if (old) {
- rate_control_put(old);
- sta_info_flush(local, NULL);
- }
- printk(KERN_DEBUG "%s: Selected rate control "
- "algorithm '%s'\n", wiphy_name(local->hw.wiphy),
- ref->ops->name);
- return 0;
- }
- void rate_control_deinitialize(struct ieee80211_local *local)
- {
- struct rate_control_ref *ref;
- ref = local->rate_ctrl;
- local->rate_ctrl = NULL;
- rate_control_put(ref);
- }
|