2007-05-05 22:45:53 +04:00
/*
* 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>
2007-07-27 17:43:23 +04:00
# include <linux/rtnetlink.h>
2008-04-08 23:14:40 +04:00
# include "rate.h"
2007-05-05 22:45:53 +04:00
# 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 ) ;
2007-12-19 03:26:16 +03:00
static char * ieee80211_default_rc_algo = CONFIG_MAC80211_RC_DEFAULT ;
module_param ( ieee80211_default_rc_algo , charp , 0644 ) ;
MODULE_PARM_DESC ( ieee80211_default_rc_algo ,
" Default rate control algorithm for mac80211 to use " ) ;
2007-05-05 22:45:53 +04:00
int ieee80211_rate_control_register ( struct rate_control_ops * ops )
{
struct rate_control_alg * alg ;
2007-10-28 16:17:44 +03:00
if ( ! ops - > name )
return - EINVAL ;
2007-10-28 16:49:33 +03:00
mutex_lock ( & rate_ctrl_mutex ) ;
list_for_each_entry ( alg , & rate_ctrl_algs , list ) {
if ( ! strcmp ( alg - > ops - > name , ops - > name ) ) {
/* don't register an algorithm twice */
WARN_ON ( 1 ) ;
2007-12-14 02:52:11 +03:00
mutex_unlock ( & rate_ctrl_mutex ) ;
2007-10-28 16:49:33 +03:00
return - EALREADY ;
}
}
some kmalloc/memset ->kzalloc (tree wide)
Transform some calls to kmalloc/memset to a single kzalloc (or kcalloc).
Here is a short excerpt of the semantic patch performing
this transformation:
@@
type T2;
expression x;
identifier f,fld;
expression E;
expression E1,E2;
expression e1,e2,e3,y;
statement S;
@@
x =
- kmalloc
+ kzalloc
(E1,E2)
... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\)
- memset((T2)x,0,E1);
@@
expression E1,E2,E3;
@@
- kzalloc(E1 * E2,E3)
+ kcalloc(E1,E2,E3)
[akpm@linux-foundation.org: get kcalloc args the right way around]
Signed-off-by: Yoann Padioleau <padator@wanadoo.fr>
Cc: Richard Henderson <rth@twiddle.net>
Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
Acked-by: Russell King <rmk@arm.linux.org.uk>
Cc: Bryan Wu <bryan.wu@analog.com>
Acked-by: Jiri Slaby <jirislaby@gmail.com>
Cc: Dave Airlie <airlied@linux.ie>
Acked-by: Roland Dreier <rolandd@cisco.com>
Cc: Jiri Kosina <jkosina@suse.cz>
Acked-by: Dmitry Torokhov <dtor@mail.ru>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Acked-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Acked-by: Pierre Ossman <drzeus-list@drzeus.cx>
Cc: Jeff Garzik <jeff@garzik.org>
Cc: "David S. Miller" <davem@davemloft.net>
Acked-by: Greg KH <greg@kroah.com>
Cc: James Bottomley <James.Bottomley@steeleye.com>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-07-19 12:49:03 +04:00
alg = kzalloc ( sizeof ( * alg ) , GFP_KERNEL ) ;
2007-05-05 22:45:53 +04:00
if ( alg = = NULL ) {
2007-10-28 16:49:33 +03:00
mutex_unlock ( & rate_ctrl_mutex ) ;
2007-05-05 22:45:53 +04:00
return - ENOMEM ;
}
alg - > ops = ops ;
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 ) ;
2007-12-14 03:17:03 +03:00
kfree ( alg ) ;
2007-05-05 22:45:53 +04:00
break ;
}
}
mutex_unlock ( & rate_ctrl_mutex ) ;
}
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 ;
2007-10-28 16:17:44 +03:00
if ( ! name )
return NULL ;
2007-05-05 22:45:53 +04:00
mutex_lock ( & rate_ctrl_mutex ) ;
list_for_each_entry ( alg , & rate_ctrl_algs , list ) {
2007-10-28 16:17:44 +03:00
if ( ! strcmp ( alg - > ops - > name , name ) )
2007-05-05 22:45:53 +04:00
if ( try_module_get ( alg - > ops - > module ) ) {
ops = alg - > ops ;
break ;
}
}
mutex_unlock ( & rate_ctrl_mutex ) ;
return ops ;
}
2007-12-19 03:26:16 +03:00
/* Get the rate control algorithm. */
2007-05-05 22:45:53 +04:00
static struct rate_control_ops *
ieee80211_rate_control_ops_get ( const char * name )
{
struct rate_control_ops * ops ;
2007-12-19 03:26:16 +03:00
const char * alg_name ;
2007-05-05 22:45:53 +04:00
2007-10-28 16:17:44 +03:00
if ( ! name )
2007-12-19 03:26:16 +03:00
alg_name = ieee80211_default_rc_algo ;
else
alg_name = name ;
2007-10-28 16:17:44 +03:00
2007-12-19 03:26:16 +03:00
ops = ieee80211_try_rate_control_ops_get ( alg_name ) ;
2007-05-05 22:45:53 +04:00
if ( ! ops ) {
2007-12-19 03:26:16 +03:00
request_module ( " rc80211_%s " , alg_name ) ;
ops = ieee80211_try_rate_control_ops_get ( alg_name ) ;
2007-05-05 22:45:53 +04:00
}
2007-12-19 03:26:16 +03:00
if ( ! ops & & name )
/* try default if specific alg requested but not found */
ops = ieee80211_try_rate_control_ops_get ( ieee80211_default_rc_algo ) ;
2008-01-02 17:17:03 +03:00
/* try built-in one if specific alg requested but not found */
if ( ! ops & & strlen ( CONFIG_MAC80211_RC_DEFAULT ) )
ops = ieee80211_try_rate_control_ops_get ( CONFIG_MAC80211_RC_DEFAULT ) ;
2007-05-05 22:45:53 +04:00
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 ) ;
}
2007-12-20 15:50:07 +03:00
void rate_control_get_rate ( struct net_device * dev ,
2008-01-24 21:38:38 +03:00
struct ieee80211_supported_band * sband ,
struct sk_buff * skb ,
2007-12-20 15:50:07 +03:00
struct rate_selection * sel )
{
struct ieee80211_local * local = wdev_priv ( dev - > ieee80211_ptr ) ;
struct rate_control_ref * ref = local - > rate_ctrl ;
struct ieee80211_hdr * hdr = ( struct ieee80211_hdr * ) skb - > data ;
2008-02-25 18:27:46 +03:00
struct sta_info * sta ;
2007-12-20 15:50:07 +03:00
int i ;
2008-02-25 18:27:46 +03:00
rcu_read_lock ( ) ;
sta = sta_info_get ( local , hdr - > addr1 ) ;
2007-12-20 15:50:07 +03:00
memset ( sel , 0 , sizeof ( struct rate_selection ) ) ;
2008-01-24 21:38:38 +03:00
ref - > ops - > get_rate ( ref - > priv , dev , sband , skb , sel ) ;
2007-12-20 15:50:07 +03:00
/* Select a non-ERP backup rate. */
if ( ! sel - > nonerp ) {
2008-01-24 21:38:38 +03:00
for ( i = 0 ; i < sband - > n_bitrates ; i + + ) {
struct ieee80211_rate * rate = & sband - > bitrates [ i ] ;
if ( sel - > rate - > bitrate < rate - > bitrate )
2007-12-20 15:50:07 +03:00
break ;
2008-01-24 21:38:38 +03:00
if ( rate_supported ( sta , sband - > band , i ) & &
! ( rate - > flags & IEEE80211_RATE_ERP_G ) )
2007-12-20 15:50:07 +03:00
sel - > nonerp = rate ;
}
}
2008-02-25 18:27:46 +03:00
rcu_read_unlock ( ) ;
2007-12-20 15:50:07 +03:00
}
2007-05-05 22:45:53 +04:00
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 ) ;
}
2007-07-27 17:43:23 +04:00
int ieee80211_init_rate_ctrl_alg ( struct ieee80211_local * local ,
const char * name )
{
struct rate_control_ref * ref , * old ;
ASSERT_RTNL ( ) ;
2007-09-28 16:02:09 +04:00
if ( local - > open_count | | netif_running ( local - > mdev ) )
2007-07-27 17:43:23 +04:00
return - EBUSY ;
ref = rate_control_alloc ( name , local ) ;
if ( ! ref ) {
printk ( KERN_WARNING " %s: Failed to select rate control "
2007-09-19 01:29:20 +04:00
" algorithm \n " , wiphy_name ( local - > hw . wiphy ) ) ;
2007-07-27 17:43:23 +04:00
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 "
2007-09-19 01:29:20 +04:00
" algorithm '%s' \n " , wiphy_name ( local - > hw . wiphy ) ,
2007-07-27 17:43:23 +04:00
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 ) ;
}
2007-12-19 03:26:16 +03:00