2 * Copyright 2002-2005, Instant802 Networks, Inc.
3 * Copyright 2005, Devicescape Software, Inc.
4 * Copyright 2007, Mattias Nissler <mattias.nissler@gmx.de>
5 <<<<<<< HEAD:net/mac80211/rc80211_pid_algo.c
6 * Copyright 2007, Stefano Brivio <stefano.brivio@polimi.it>
8 * Copyright 2007-2008, Stefano Brivio <stefano.brivio@polimi.it>
9 >>>>>>> 264e3e889d86e552b4191d69bb60f4f3b383135a:net/mac80211/rc80211_pid_algo.c
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
16 #include <linux/netdevice.h>
17 #include <linux/types.h>
18 #include <linux/skbuff.h>
19 #include <linux/debugfs.h>
20 #include <net/mac80211.h>
21 #include "ieee80211_rate.h"
23 #include "rc80211_pid.h"
26 /* This is an implementation of a TX rate control algorithm that uses a PID
27 * controller. Given a target failed frames rate, the controller decides about
28 * TX rate changes to meet the target failed frames rate.
30 * The controller basically computes the following:
32 * adj = CP * err + CI * err_avg + CD * (err - last_err) * (1 + sharpening)
35 * adj adjustment value that is used to switch TX rate (see below)
36 * err current error: target vs. current failed frames percentage
38 * err_avg average (i.e. poor man's integral) of recent errors
39 * sharpening non-zero when fast response is needed (i.e. right after
40 * association or no frames sent for a long time), heading
42 * CP Proportional coefficient
43 * CI Integral coefficient
44 * CD Derivative coefficient
46 * CP, CI, CD are subject to careful tuning.
48 * The integral component uses a exponential moving average approach instead of
49 * an actual sliding window. The advantage is that we don't need to keep an
50 * array of the last N error values and computation is easier.
52 * Once we have the adj value, we map it to a rate by means of a learning
53 * algorithm. This algorithm keeps the state of the percentual failed frames
54 * difference between rates. The behaviour of the lowest available rate is kept
55 * as a reference value, and every time we switch between two rates, we compute
56 * the difference between the failed frames each rate exhibited. By doing so,
57 * we compare behaviours which different rates exhibited in adjacent timeslices,
58 * thus the comparison is minimally affected by external conditions. This
59 * difference gets propagated to the whole set of measurements, so that the
60 * reference is always the same. Periodically, we normalize this set so that
61 * recent events weigh the most. By comparing the adj value with this set, we
62 * avoid pejorative switches to lower rates and allow for switches to higher
63 * rates if they behaved well.
65 * Note that for the computations we use a fixed-point representation to avoid
66 * floating point arithmetic. Hence, all values are shifted left by
70 <<<<<<< HEAD
:net
/mac80211
/rc80211_pid_algo
.c
72 /* Shift the adjustment so that we won't switch to a lower rate if it exhibited
73 * a worse failed frames behaviour and we'll choose the highest rate whose
74 * failed frames behaviour is not worse than the one of the original rate
75 * target. While at it, check that the adjustment is within the ranges. Then,
76 * provide the new rate index. */
77 static int rate_control_pid_shift_adjust(struct rc_pid_rateinfo
*r
,
78 int adj
, int cur
, int l
)
88 return r
[l
- 1].index
;
93 for (k
= j
; k
>= i
; k
--)
94 if (r
[k
].diff
<= r
[j
].diff
)
97 for (k
= i
+ 1; k
+ i
< l
; k
++)
98 if (r
[k
].diff
<= r
[i
].diff
)
106 /* Adjust the rate while ensuring that we won't switch to a lower rate if it
107 * exhibited a worse failed frames behaviour and we'll choose the highest rate
108 * whose failed frames behaviour is not worse than the one of the original rate
109 * target. While at it, check that the new rate is valid. */
110 >>>>>>> 264e3e889d86e552b4191d69bb60f4f3b383135a
:net
/mac80211
/rc80211_pid_algo
.c
111 static void rate_control_pid_adjust_rate(struct ieee80211_local
*local
,
112 struct sta_info
*sta
, int adj
,
113 struct rc_pid_rateinfo
*rinfo
)
115 struct ieee80211_sub_if_data
*sdata
;
116 struct ieee80211_hw_mode
*mode
;
117 <<<<<<< HEAD
:net
/mac80211
/rc80211_pid_algo
.c
120 int back
= (adj
> 0) ? 1 : -1;
122 int cur_sorted
, new_sorted
, probe
, tmp
, n_bitrates
;
123 int cur
= sta
->txrate
;
124 >>>>>>> 264e3e889d86e552b4191d69bb60f4f3b383135a
:net
/mac80211
/rc80211_pid_algo
.c
126 sdata
= IEEE80211_DEV_TO_SUB_IF(sta
->dev
);
128 mode
= local
->oper_hw_mode
;
129 <<<<<<< HEAD
:net
/mac80211
/rc80211_pid_algo
.c
130 maxrate
= sdata
->bss
? sdata
->bss
->max_ratectrl_rateidx
: -1;
132 n_bitrates
= mode
->num_rates
;
133 >>>>>>> 264e3e889d86e552b4191d69bb60f4f3b383135a
:net
/mac80211
/rc80211_pid_algo
.c
135 <<<<<<< HEAD
:net
/mac80211
/rc80211_pid_algo
.c
136 newidx
= rate_control_pid_shift_adjust(rinfo
, adj
, sta
->txrate
,
139 /* Map passed arguments to sorted values. */
140 cur_sorted
= rinfo
[cur
].rev_index
;
141 new_sorted
= cur_sorted
+ adj
;
142 >>>>>>> 264e3e889d86e552b4191d69bb60f4f3b383135a
:net
/mac80211
/rc80211_pid_algo
.c
144 <<<<<<< HEAD
:net
/mac80211
/rc80211_pid_algo
.c
145 while (newidx
!= sta
->txrate
) {
146 if (rate_supported(sta
, mode
, newidx
) &&
147 (maxrate
< 0 || newidx
<= maxrate
)) {
148 sta
->txrate
= newidx
;
154 new_sorted
= rinfo
[0].rev_index
;
155 else if (new_sorted
>= n_bitrates
)
156 new_sorted
= rinfo
[n_bitrates
- 1].rev_index
;
157 >>>>>>> 264e3e889d86e552b4191d69bb60f4f3b383135a
:net
/mac80211
/rc80211_pid_algo
.c
159 <<<<<<< HEAD
:net
/mac80211
/rc80211_pid_algo
.c
165 /* Ensure that the rate decrease isn't disadvantageous. */
166 for (probe
= cur_sorted
; probe
>= new_sorted
; probe
--)
167 if (rinfo
[probe
].diff
<= rinfo
[cur_sorted
].diff
&&
168 rate_supported(sta
, mode
, rinfo
[probe
].index
))
171 /* Look for rate increase with zero (or below) cost. */
172 for (probe
= new_sorted
+ 1; probe
< n_bitrates
; probe
++)
173 if (rinfo
[probe
].diff
<= rinfo
[new_sorted
].diff
&&
174 rate_supported(sta
, mode
, rinfo
[probe
].index
))
176 >>>>>>> 264e3e889d86e552b4191d69bb60f4f3b383135a
:net
/mac80211
/rc80211_pid_algo
.c
179 <<<<<<< HEAD
:net
/mac80211
/rc80211_pid_algo
.c
181 /* Fit the rate found to the nearest supported rate. */
183 if (rate_supported(sta
, mode
, rinfo
[tmp
].index
)) {
184 sta
->txrate
= rinfo
[tmp
].index
;
191 } while (tmp
< n_bitrates
&& tmp
>= 0);
193 >>>>>>> 264e3e889d86e552b4191d69bb60f4f3b383135a
:net
/mac80211
/rc80211_pid_algo
.c
194 #ifdef CONFIG_MAC80211_DEBUGFS
195 rate_control_pid_event_rate_change(
196 &((struct rc_pid_sta_info
*)sta
->rate_ctrl_priv
)->events
,
197 <<<<<<< HEAD
:net
/mac80211
/rc80211_pid_algo
.c
198 newidx
, mode
->rates
[newidx
].rate
);
200 cur
, mode
->rates
[cur
].rate
);
201 >>>>>>> 264e3e889d86e552b4191d69bb60f4f3b383135a
:net
/mac80211
/rc80211_pid_algo
.c
205 /* Normalize the failed frames per-rate differences. */
206 static void rate_control_pid_normalize(struct rc_pid_info
*pinfo
, int l
)
208 int i
, norm_offset
= pinfo
->norm_offset
;
209 struct rc_pid_rateinfo
*r
= pinfo
->rinfo
;
211 if (r
[0].diff
> norm_offset
)
212 r
[0].diff
-= norm_offset
;
213 else if (r
[0].diff
< -norm_offset
)
214 r
[0].diff
+= norm_offset
;
215 for (i
= 0; i
< l
- 1; i
++)
216 if (r
[i
+ 1].diff
> r
[i
].diff
+ norm_offset
)
217 r
[i
+ 1].diff
-= norm_offset
;
218 else if (r
[i
+ 1].diff
<= r
[i
].diff
)
219 r
[i
+ 1].diff
+= norm_offset
;
222 static void rate_control_pid_sample(struct rc_pid_info
*pinfo
,
223 struct ieee80211_local
*local
,
224 struct sta_info
*sta
)
226 struct rc_pid_sta_info
*spinfo
= sta
->rate_ctrl_priv
;
227 struct rc_pid_rateinfo
*rinfo
= pinfo
->rinfo
;
228 struct ieee80211_hw_mode
*mode
;
235 unsigned long period
;
237 mode
= local
->oper_hw_mode
;
238 spinfo
= sta
->rate_ctrl_priv
;
240 /* In case nothing happened during the previous control interval, turn
241 * the sharpening factor on. */
242 period
= (HZ
* pinfo
->sampling_period
+ 500) / 1000;
245 if (jiffies
- spinfo
->last_sample
> 2 * period
)
246 spinfo
->sharp_cnt
= pinfo
->sharpen_duration
;
248 spinfo
->last_sample
= jiffies
;
250 /* This should never happen, but in case, we assume the old sample is
251 * still a good measurement and copy it. */
252 if (unlikely(spinfo
->tx_num_xmit
== 0))
253 pf
= spinfo
->last_pf
;
255 pf
= spinfo
->tx_num_failed
* 100 / spinfo
->tx_num_xmit
;
256 pf
<<= RC_PID_ARITH_SHIFT
;
259 spinfo
->tx_num_xmit
= 0;
260 spinfo
->tx_num_failed
= 0;
262 /* If we just switched rate, update the rate behaviour info. */
263 if (pinfo
->oldrate
!= sta
->txrate
) {
265 i
= rinfo
[pinfo
->oldrate
].rev_index
;
266 j
= rinfo
[sta
->txrate
].rev_index
;
268 tmp
= (pf
- spinfo
->last_pf
);
269 tmp
= RC_PID_DO_ARITH_RIGHT_SHIFT(tmp
, RC_PID_ARITH_SHIFT
);
271 rinfo
[j
].diff
= rinfo
[i
].diff
+ tmp
;
272 pinfo
->oldrate
= sta
->txrate
;
274 rate_control_pid_normalize(pinfo
, mode
->num_rates
);
276 /* Compute the proportional, integral and derivative errors. */
277 err_prop
= (pinfo
->target
<< RC_PID_ARITH_SHIFT
) - pf
;
279 err_avg
= spinfo
->err_avg_sc
>> pinfo
->smoothing_shift
;
280 spinfo
->err_avg_sc
= spinfo
->err_avg_sc
- err_avg
+ err_prop
;
281 err_int
= spinfo
->err_avg_sc
>> pinfo
->smoothing_shift
;
283 err_der
= (pf
- spinfo
->last_pf
) *
284 (1 + pinfo
->sharpen_factor
* spinfo
->sharp_cnt
);
285 spinfo
->last_pf
= pf
;
286 if (spinfo
->sharp_cnt
)
289 #ifdef CONFIG_MAC80211_DEBUGFS
290 rate_control_pid_event_pf_sample(&spinfo
->events
, pf
, err_prop
, err_int
,
294 /* Compute the controller output. */
295 adj
= (err_prop
* pinfo
->coeff_p
+ err_int
* pinfo
->coeff_i
296 + err_der
* pinfo
->coeff_d
);
297 adj
= RC_PID_DO_ARITH_RIGHT_SHIFT(adj
, 2 * RC_PID_ARITH_SHIFT
);
301 rate_control_pid_adjust_rate(local
, sta
, adj
, rinfo
);
304 static void rate_control_pid_tx_status(void *priv
, struct net_device
*dev
,
306 struct ieee80211_tx_status
*status
)
308 struct ieee80211_local
*local
= wdev_priv(dev
->ieee80211_ptr
);
309 struct ieee80211_hdr
*hdr
= (struct ieee80211_hdr
*) skb
->data
;
310 struct ieee80211_sub_if_data
*sdata
;
311 struct rc_pid_info
*pinfo
= priv
;
312 struct sta_info
*sta
;
313 struct rc_pid_sta_info
*spinfo
;
314 unsigned long period
;
316 sta
= sta_info_get(local
, hdr
->addr1
);
321 /* Don't update the state if we're not controlling the rate. */
322 sdata
= IEEE80211_DEV_TO_SUB_IF(sta
->dev
);
323 if (sdata
->bss
&& sdata
->bss
->force_unicast_rateidx
> -1) {
324 sta
->txrate
= sdata
->bss
->max_ratectrl_rateidx
;
328 /* Ignore all frames that were sent with a different rate than the rate
329 * we currently advise mac80211 to use. */
330 if (status
->control
.rate
!= &local
->oper_hw_mode
->rates
[sta
->txrate
])
333 spinfo
= sta
->rate_ctrl_priv
;
334 spinfo
->tx_num_xmit
++;
336 #ifdef CONFIG_MAC80211_DEBUGFS
337 rate_control_pid_event_tx_status(&spinfo
->events
, status
);
340 /* We count frames that totally failed to be transmitted as two bad
341 * frames, those that made it out but had some retries as one good and
343 if (status
->excessive_retries
) {
344 spinfo
->tx_num_failed
+= 2;
345 spinfo
->tx_num_xmit
++;
346 } else if (status
->retry_count
) {
347 spinfo
->tx_num_failed
++;
348 spinfo
->tx_num_xmit
++;
351 if (status
->excessive_retries
) {
352 sta
->tx_retry_failed
++;
353 sta
->tx_num_consecutive_failures
++;
354 sta
->tx_num_mpdu_fail
++;
356 sta
->last_ack_rssi
[0] = sta
->last_ack_rssi
[1];
357 sta
->last_ack_rssi
[1] = sta
->last_ack_rssi
[2];
358 sta
->last_ack_rssi
[2] = status
->ack_signal
;
359 sta
->tx_num_consecutive_failures
= 0;
360 sta
->tx_num_mpdu_ok
++;
362 sta
->tx_retry_count
+= status
->retry_count
;
363 sta
->tx_num_mpdu_fail
+= status
->retry_count
;
365 /* Update PID controller state. */
366 period
= (HZ
* pinfo
->sampling_period
+ 500) / 1000;
369 if (time_after(jiffies
, spinfo
->last_sample
+ period
))
370 rate_control_pid_sample(pinfo
, local
, sta
);
376 static void rate_control_pid_get_rate(void *priv
, struct net_device
*dev
,
377 struct ieee80211_hw_mode
*mode
,
379 struct rate_selection
*sel
)
381 struct ieee80211_local
*local
= wdev_priv(dev
->ieee80211_ptr
);
382 struct ieee80211_hdr
*hdr
= (struct ieee80211_hdr
*) skb
->data
;
383 struct ieee80211_sub_if_data
*sdata
;
384 struct sta_info
*sta
;
388 sta
= sta_info_get(local
, hdr
->addr1
);
390 /* Send management frames and broadcast/multicast data using lowest
392 fc
= le16_to_cpu(hdr
->frame_control
);
393 if ((fc
& IEEE80211_FCTL_FTYPE
) != IEEE80211_FTYPE_DATA
||
394 is_multicast_ether_addr(hdr
->addr1
) || !sta
) {
395 sel
->rate
= rate_lowest(local
, mode
, sta
);
401 /* If a forced rate is in effect, select it. */
402 sdata
= IEEE80211_DEV_TO_SUB_IF(dev
);
403 if (sdata
->bss
&& sdata
->bss
->force_unicast_rateidx
> -1)
404 sta
->txrate
= sdata
->bss
->force_unicast_rateidx
;
406 rateidx
= sta
->txrate
;
408 if (rateidx
>= mode
->num_rates
)
409 rateidx
= mode
->num_rates
- 1;
411 sta
->last_txrate
= rateidx
;
415 sel
->rate
= &mode
->rates
[rateidx
];
417 #ifdef CONFIG_MAC80211_DEBUGFS
418 rate_control_pid_event_tx_rate(
419 &((struct rc_pid_sta_info
*) sta
->rate_ctrl_priv
)->events
,
420 rateidx
, mode
->rates
[rateidx
].rate
);
424 static void rate_control_pid_rate_init(void *priv
, void *priv_sta
,
425 struct ieee80211_local
*local
,
426 struct sta_info
*sta
)
428 /* TODO: This routine should consider using RSSI from previous packets
429 * as we need to have IEEE 802.1X auth succeed immediately after assoc..
430 * Until that method is implemented, we will use the lowest supported
431 * rate as a workaround. */
432 sta
->txrate
= rate_lowest_index(local
, local
->oper_hw_mode
, sta
);
435 static void *rate_control_pid_alloc(struct ieee80211_local
*local
)
437 struct rc_pid_info
*pinfo
;
438 struct rc_pid_rateinfo
*rinfo
;
439 struct ieee80211_hw_mode
*mode
;
442 #ifdef CONFIG_MAC80211_DEBUGFS
443 struct rc_pid_debugfs_entries
*de
;
446 pinfo
= kmalloc(sizeof(*pinfo
), GFP_ATOMIC
);
450 /* We can safely assume that oper_hw_mode won't change unless we get
452 mode
= local
->oper_hw_mode
;
453 rinfo
= kmalloc(sizeof(*rinfo
) * mode
->num_rates
, GFP_ATOMIC
);
459 /* Sort the rates. This is optimized for the most common case (i.e.
460 * almost-sorted CCK+OFDM rates). Kind of bubble-sort with reversed
462 for (i
= 0; i
< mode
->num_rates
; i
++) {
464 rinfo
[i
].rev_index
= i
;
465 if (pinfo
->fast_start
)
468 rinfo
[i
].diff
= i
* pinfo
->norm_offset
;
470 for (i
= 1; i
< mode
->num_rates
; i
++) {
472 for (j
= 0; j
< mode
->num_rates
- i
; j
++)
473 if (unlikely(mode
->rates
[rinfo
[j
].index
].rate
>
474 mode
->rates
[rinfo
[j
+ 1].index
].rate
)) {
475 tmp
= rinfo
[j
].index
;
476 rinfo
[j
].index
= rinfo
[j
+ 1].index
;
477 rinfo
[j
+ 1].index
= tmp
;
478 rinfo
[rinfo
[j
].index
].rev_index
= j
;
479 rinfo
[rinfo
[j
+ 1].index
].rev_index
= j
+ 1;
486 pinfo
->target
= RC_PID_TARGET_PF
;
487 pinfo
->sampling_period
= RC_PID_INTERVAL
;
488 pinfo
->coeff_p
= RC_PID_COEFF_P
;
489 pinfo
->coeff_i
= RC_PID_COEFF_I
;
490 pinfo
->coeff_d
= RC_PID_COEFF_D
;
491 pinfo
->smoothing_shift
= RC_PID_SMOOTHING_SHIFT
;
492 pinfo
->sharpen_factor
= RC_PID_SHARPENING_FACTOR
;
493 pinfo
->sharpen_duration
= RC_PID_SHARPENING_DURATION
;
494 pinfo
->norm_offset
= RC_PID_NORM_OFFSET
;
495 pinfo
->fast_start
= RC_PID_FAST_START
;
496 pinfo
->rinfo
= rinfo
;
499 #ifdef CONFIG_MAC80211_DEBUGFS
500 de
= &pinfo
->dentries
;
501 de
->dir
= debugfs_create_dir("rc80211_pid",
502 local
->hw
.wiphy
->debugfsdir
);
503 de
->target
= debugfs_create_u32("target_pf", S_IRUSR
| S_IWUSR
,
504 de
->dir
, &pinfo
->target
);
505 de
->sampling_period
= debugfs_create_u32("sampling_period",
506 S_IRUSR
| S_IWUSR
, de
->dir
,
507 &pinfo
->sampling_period
);
508 de
->coeff_p
= debugfs_create_u32("coeff_p", S_IRUSR
| S_IWUSR
,
509 de
->dir
, &pinfo
->coeff_p
);
510 de
->coeff_i
= debugfs_create_u32("coeff_i", S_IRUSR
| S_IWUSR
,
511 de
->dir
, &pinfo
->coeff_i
);
512 de
->coeff_d
= debugfs_create_u32("coeff_d", S_IRUSR
| S_IWUSR
,
513 de
->dir
, &pinfo
->coeff_d
);
514 de
->smoothing_shift
= debugfs_create_u32("smoothing_shift",
515 S_IRUSR
| S_IWUSR
, de
->dir
,
516 &pinfo
->smoothing_shift
);
517 de
->sharpen_factor
= debugfs_create_u32("sharpen_factor",
518 S_IRUSR
| S_IWUSR
, de
->dir
,
519 &pinfo
->sharpen_factor
);
520 de
->sharpen_duration
= debugfs_create_u32("sharpen_duration",
521 S_IRUSR
| S_IWUSR
, de
->dir
,
522 &pinfo
->sharpen_duration
);
523 de
->norm_offset
= debugfs_create_u32("norm_offset",
524 S_IRUSR
| S_IWUSR
, de
->dir
,
525 &pinfo
->norm_offset
);
526 de
->fast_start
= debugfs_create_bool("fast_start",
527 S_IRUSR
| S_IWUSR
, de
->dir
,
534 static void rate_control_pid_free(void *priv
)
536 struct rc_pid_info
*pinfo
= priv
;
537 #ifdef CONFIG_MAC80211_DEBUGFS
538 struct rc_pid_debugfs_entries
*de
= &pinfo
->dentries
;
540 debugfs_remove(de
->fast_start
);
541 debugfs_remove(de
->norm_offset
);
542 debugfs_remove(de
->sharpen_duration
);
543 debugfs_remove(de
->sharpen_factor
);
544 debugfs_remove(de
->smoothing_shift
);
545 debugfs_remove(de
->coeff_d
);
546 debugfs_remove(de
->coeff_i
);
547 debugfs_remove(de
->coeff_p
);
548 debugfs_remove(de
->sampling_period
);
549 debugfs_remove(de
->target
);
550 debugfs_remove(de
->dir
);
557 static void rate_control_pid_clear(void *priv
)
561 static void *rate_control_pid_alloc_sta(void *priv
, gfp_t gfp
)
563 struct rc_pid_sta_info
*spinfo
;
565 spinfo
= kzalloc(sizeof(*spinfo
), gfp
);
569 spinfo
->last_sample
= jiffies
;
571 #ifdef CONFIG_MAC80211_DEBUGFS
572 spin_lock_init(&spinfo
->events
.lock
);
573 init_waitqueue_head(&spinfo
->events
.waitqueue
);
579 static void rate_control_pid_free_sta(void *priv
, void *priv_sta
)
581 struct rc_pid_sta_info
*spinfo
= priv_sta
;
585 static struct rate_control_ops mac80211_rcpid
= {
587 .tx_status
= rate_control_pid_tx_status
,
588 .get_rate
= rate_control_pid_get_rate
,
589 .rate_init
= rate_control_pid_rate_init
,
590 .clear
= rate_control_pid_clear
,
591 .alloc
= rate_control_pid_alloc
,
592 .free
= rate_control_pid_free
,
593 .alloc_sta
= rate_control_pid_alloc_sta
,
594 .free_sta
= rate_control_pid_free_sta
,
595 #ifdef CONFIG_MAC80211_DEBUGFS
596 .add_sta_debugfs
= rate_control_pid_add_sta_debugfs
,
597 .remove_sta_debugfs
= rate_control_pid_remove_sta_debugfs
,
601 MODULE_DESCRIPTION("PID controller based rate control algorithm");
602 MODULE_AUTHOR("Stefano Brivio");
603 MODULE_AUTHOR("Mattias Nissler");
604 MODULE_LICENSE("GPL");
606 int __init
rc80211_pid_init(void)
608 return ieee80211_rate_control_register(&mac80211_rcpid
);
611 void rc80211_pid_exit(void)
613 ieee80211_rate_control_unregister(&mac80211_rcpid
);
616 #ifdef CONFIG_MAC80211_RC_PID_MODULE
617 module_init(rc80211_pid_init
);
618 module_exit(rc80211_pid_exit
);