improve dependency handling, fix some package makefile bugs
[openwrt.git] / target / linux / package / ieee80211-dscape / src / ieee80211_proc.c
1 /*
2  * Copyright 2003-2005, Devicescape Software, Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  */
8
9 #include <linux/config.h>
10 #include <linux/version.h>
11 #include <linux/module.h>
12 #include <linux/netdevice.h>
13 #include <linux/proc_fs.h>
14 #include <linux/delay.h>
15
16 #ifdef CONFIG_PROC_FS
17
18 #include <net/ieee80211.h>
19 #include <net/ieee80211_common.h>
20 #include <net/ieee80211_mgmt.h>
21 #include "ieee80211_i.h"
22 #include "sta_info.h"
23 #include "ieee80211_proc.h"
24 #include "rate_control.h"
25
26
27 static struct proc_dir_entry *ieee80211_proc;
28
29 #define PROC_LIMIT (PAGE_SIZE - 80)
30
31
32 static char * ieee80211_proc_key(char *p, struct ieee80211_key *key,
33                                  int idx, int def_key)
34 {
35         int i;
36         u8 *tpn, *rpn;
37
38         if (!key)
39                 return p;
40
41         p += sprintf(p, "key[%d]%s len=%d sw_encrypt=%d idx=%d hwidx=%d "
42                      "tx_rx_count=%d",
43                      idx, def_key ? "*" : "", key->keylen,
44                      key->force_sw_encrypt, key->keyidx, key->hw_key_idx,
45                      key->tx_rx_count);
46         switch (key->alg) {
47         case ALG_WEP:
48                 p += sprintf(p, " alg=WEP");
49                 break;
50         case ALG_TKIP:
51                 p += sprintf(p, " alg=TKIP iv(tx)=%08x %04x",
52                              key->u.tkip.iv32, key->u.tkip.iv16);
53                 for (i = 0; i < NUM_RX_DATA_QUEUES; i++) {
54                         if (key->u.tkip.iv32_rx[i] == 0 &&
55                             key->u.tkip.iv16_rx[i] == 0)
56                                 continue;
57                         p += sprintf(p, " iv(rx %d)=%08x %04x", i,
58                                      key->u.tkip.iv32_rx[i],
59                                      key->u.tkip.iv16_rx[i]);
60                 }
61                 break;
62         case ALG_CCMP:
63                 tpn = key->u.ccmp.tx_pn;
64                 p += sprintf(p, " alg=CCMP PN(tx)=%02x%02x%02x%02x%02x%02x",
65                              tpn[0], tpn[1], tpn[2], tpn[3], tpn[4], tpn[5]);
66                 for (i = 0; i < NUM_RX_DATA_QUEUES; i++) {
67                         rpn = key->u.ccmp.rx_pn[i];
68                         if (memcmp(rpn, "\x00\x00\x00\x00\x00\x00", 6) == 0)
69                                 continue;
70                         p += sprintf(p, " PN(rx %d)=%02x%02x%02x%02x%02x%02x",
71                                      i, rpn[0], rpn[1], rpn[2], rpn[3], rpn[4],
72                                      rpn[5]);
73                 }
74                 p += sprintf(p, " replays=%u", key->u.ccmp.replays);
75                 break;
76         default:
77                 break;
78         }
79
80         p += sprintf(p, " key=");
81         for (i = 0; i < key->keylen; i++)
82                 p += sprintf(p, "%02x", key->key[i]);
83         p += sprintf(p, "\n");
84         return p;
85 }
86
87
88 static char * ieee80211_proc_sub_if_norm(char *p,
89                                          struct ieee80211_if_norm *norm)
90 {
91         p += sprintf(p, "type=norm\n");
92         if (norm->beacon_head)
93                 p += sprintf(p, "beacon_head_len=%d\n", norm->beacon_head_len);
94         if (norm->beacon_tail)
95                 p += sprintf(p, "beacon_tail_len=%d\n", norm->beacon_tail_len);
96         p += sprintf(p,
97                      "max_aid=%d\n"
98                      "num_sta_ps=%d\n"
99                      "num_buffered_multicast=%u\n"
100                      "dtim_period=%d\n"
101                      "dtim_count=%d\n"
102                      "num_beacons=%d\n"
103                      "force_unicast_rateidx=%d\n"
104                      "max_ratectrl_rateidx=%d\n",
105                      norm->max_aid, atomic_read(&norm->num_sta_ps),
106                      skb_queue_len(&norm->ps_bc_buf),
107                      norm->dtim_period, norm->dtim_count, norm->num_beacons,
108                      norm->force_unicast_rateidx, norm->max_ratectrl_rateidx);
109         return p;
110 }
111
112
113 static char * ieee80211_proc_sub_if_sta(char *p,
114                                         struct ieee80211_if_sta *ifsta)
115 {
116         p += sprintf(p, "type=sta\n");
117         p += sprintf(p,
118                      "state=%d\n"
119                      "bssid=" MACSTR "\n"
120                      "prev_bssid=" MACSTR "\n"
121                      "ssid_len=%zd\n"
122                      "aid=%d\n"
123                      "ap_capab=0x%x\n"
124                      "capab=0x%x\n"
125                      "extra_ie_len=%zd\n"
126                      "auth_tries=%d\n"
127                      "assoc_tries=%d\n"
128                      "flags=%s%s%s%s%s%s%s\n"
129                      "auth_algs=0x%x\n"
130                      "auth_alg=%d\n"
131                      "auth_transaction=%d\n",
132                      ifsta->state,
133                      MAC2STR(ifsta->bssid),
134                      MAC2STR(ifsta->prev_bssid),
135                      ifsta->ssid_len,
136                      ifsta->aid,
137                      ifsta->ap_capab,
138                      ifsta->capab,
139                      ifsta->extra_ie_len,
140                      ifsta->auth_tries,
141                      ifsta->assoc_tries,
142                      ifsta->ssid_set ? "[SSID]" : "",
143                      ifsta->bssid_set ? "[BSSID]" : "",
144                      ifsta->prev_bssid_set ? "[prev BSSID" : "",
145                      ifsta->authenticated ? "[AUTH]" : "",
146                      ifsta->associated ? "[ASSOC]" : "",
147                      ifsta->probereq_poll ? "[PROBEREQ POLL]" : "",
148                      ifsta->use_protection ? "[CTS prot]" : "",
149                      ifsta->auth_algs,
150                      ifsta->auth_alg,
151                      ifsta->auth_transaction);
152         return p;
153 }
154
155
156 static char * ieee80211_proc_sub_if(char *p,
157                                     struct ieee80211_sub_if_data *sdata)
158 {
159         if (sdata == NULL)
160                 return p;
161
162         if (sdata->bss)
163                 p += sprintf(p, "bss=%p\n", sdata->bss);
164
165         switch (sdata->type) {
166         case IEEE80211_SUB_IF_TYPE_NORM:
167                 p = ieee80211_proc_sub_if_norm(p, &sdata->u.norm);
168                 break;
169         case IEEE80211_SUB_IF_TYPE_WDS:
170                 p += sprintf(p, "type=wds\n");
171                 p += sprintf(p, "wds.peer=" MACSTR "\n",
172                              MAC2STR(sdata->u.wds.remote_addr));
173                 break;
174         case IEEE80211_SUB_IF_TYPE_VLAN:
175                 p += sprintf(p, "type=vlan\n");
176                 p += sprintf(p, "vlan.id=%d\n", sdata->u.vlan.id);
177                 break;
178         case IEEE80211_SUB_IF_TYPE_STA:
179                 p = ieee80211_proc_sub_if_sta(p, &sdata->u.sta);
180                 break;
181         }
182         p += sprintf(p, "channel_use=%d\n", sdata->channel_use);
183         p += sprintf(p, "drop_unencrypted=%d\n", sdata->drop_unencrypted);
184         p += sprintf(p, "eapol=%d\n", sdata->eapol);
185         p += sprintf(p, "ieee802_1x=%d\n", sdata->ieee802_1x);
186
187         return p;
188 }
189
190
191 static int ieee80211_proc_iface_read(char *page, char **start, off_t off,
192                                      int count, int *eof, void *data)
193 {
194         char *p = page;
195         struct net_device *dev = (struct net_device *) data;
196         struct ieee80211_sub_if_data *sdata;
197         int i;
198
199         if (off != 0) {
200                 *eof = 1;
201                 return 0;
202         }
203
204         sdata = IEEE80211_DEV_TO_SUB_IF(dev);
205         if (!sdata)
206                 return -1;
207
208         p = ieee80211_proc_sub_if(p, sdata);
209
210         for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
211                 if (sdata->keys[i] == NULL)
212                         continue;
213
214                 p = ieee80211_proc_key(p, sdata->keys[i], i,
215                                        sdata->keys[i] == sdata->default_key);
216         }
217
218         return (p - page);
219 }
220
221
222 static int ieee80211_proc_sta_read(char *page, char **start, off_t off,
223                                    int count, int *eof, void *data)
224 {
225         char *p = page;
226         struct sta_info *sta = (struct sta_info *) data;
227         struct ieee80211_local *local;
228         int inactive, i;
229
230         if (off != 0) {
231                 *eof = 1;
232                 return 0;
233         }
234
235         if (!sta || !sta->dev)
236                 return -1;
237
238         p += sprintf(p, "users=%d\n", atomic_read(&sta->users));
239         p += sprintf(p, "aid=%d\n", sta->aid);
240         p += sprintf(p, "flags=0x%x %s%s%s%s%s%s%s%s%s%s\n", sta->flags,
241                      sta->flags & WLAN_STA_AUTH ? "[AUTH]" : "",
242                      sta->flags & WLAN_STA_ASSOC ? "[ASSOC]" : "",
243                      sta->flags & WLAN_STA_PS ? "[PS]" : "",
244                      sta->flags & WLAN_STA_TIM ? "[TIM]" : "",
245                      sta->flags & WLAN_STA_PERM ? "[PERM]" : "",
246                      sta->flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" : "",
247                      sta->flags & WLAN_STA_SHORT_PREAMBLE ?
248                      "[SHORT PREAMBLE]" : "",
249                      sta->flags & WLAN_STA_WME ? "[WME]" : "",
250                      sta->flags & WLAN_STA_WDS ? "[WDS]" : "",
251                      sta->flags & WLAN_STA_XR ? "[XR]" : "");
252         p += sprintf(p, "key_idx_compression=%d\n",
253                      sta->key_idx_compression);
254         p += sprintf(p, "dev=%s\n", sta->dev->name);
255         if (sta->vlan_id > 0)
256                 p += sprintf(p, "vlan_id=%d\n", sta->vlan_id);
257         p += sprintf(p, "rx_packets=%lu\ntx_packets=%lu\nrx_bytes=%lu\n"
258                      "tx_bytes=%lu\nrx_duplicates=%lu\nrx_fragments=%lu\n"
259                      "rx_dropped=%lu\ntx_fragments=%lu\ntx_filtered=%lu\n",
260                      sta->rx_packets, sta->tx_packets,
261                      sta->rx_bytes, sta->tx_bytes,
262                      sta->num_duplicates, sta->rx_fragments, sta->rx_dropped,
263                      sta->tx_fragments, sta->tx_filtered_count);
264         p = ieee80211_proc_key(p, sta->key, 0, 1);
265
266         local = (struct ieee80211_local *) sta->dev->priv;
267         if (sta->txrate >= 0 && sta->txrate < local->num_curr_rates) {
268                 p += sprintf(p, "txrate=%d\n",
269                              local->curr_rates[sta->txrate].rate);
270         }
271         if (sta->last_txrate >= 0 &&
272             sta->last_txrate < local->num_curr_rates) {
273                 p += sprintf(p, "last_txrate=%d\n",
274                              local->curr_rates[sta->last_txrate].rate);
275         }
276         p += sprintf(p, "num_ps_buf_frames=%u\n",
277                      skb_queue_len(&sta->ps_tx_buf));
278         p += sprintf(p, "tx_retry_failed=%lu\n", sta->tx_retry_failed);
279         p += sprintf(p, "tx_retry_count=%lu\n", sta->tx_retry_count);
280         p += sprintf(p, "last_rssi=%d\n", sta->last_rssi);
281         p += sprintf(p, "last_ack_rssi=%d %d %d\n",
282                      sta->last_ack_rssi[0], sta->last_ack_rssi[1],
283                      sta->last_ack_rssi[2]);
284         if (sta->last_ack)
285                 p += sprintf(p, "last_ack_ms=%d\n",
286                              jiffies_to_msecs(jiffies - sta->last_ack));
287         inactive = jiffies - sta->last_rx;
288         p += sprintf(p, "inactive_msec=%d\n", jiffies_to_msecs(inactive));
289         p += sprintf(p, "channel_use=%d\n", sta->channel_use);
290         p += sprintf(p, "wep_weak_iv_count=%d\n", sta->wep_weak_iv_count);
291 #ifdef CONFIG_IEEE80211_DEBUG_COUNTERS
292         p += sprintf(p, "wme_rx_queue=");
293         for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
294                 p += sprintf(p, "%u ", sta->wme_rx_queue[i]);
295         p += sprintf(p, "\n");
296
297         p += sprintf(p, "wme_tx_queue=");
298         for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
299                 p += sprintf(p, "%u ", sta->wme_tx_queue[i]);
300         p += sprintf(p, "\n");
301 #endif /* CONFIG_IEEE80211_DEBUG_COUNTERS */
302         p += sprintf(p, "last_seq_ctrl=");
303         for (i = 0; i < NUM_RX_DATA_QUEUES; i++) {
304                         p += sprintf(p, "%x ", sta->last_seq_ctrl[i]);
305         }
306         p += sprintf(p, "\n");
307
308         p += rate_control_status_sta(local, sta, p);
309
310         return (p - page);
311 }
312
313
314 static int ieee80211_proc_counters_read(char *page, char **start, off_t off,
315                                         int count, int *eof, void *data)
316 {
317         char *p = page;
318         struct ieee80211_local *local = (struct ieee80211_local *) data;
319         struct ieee80211_low_level_stats stats;
320
321         if (off != 0) {
322                 *eof = 1;
323                 return 0;
324         }
325
326         p += sprintf(p,
327                      "TransmittedFragmentCount=%u\n"
328                      "MulticastTransmittedFrameCount=%u\n"
329                      "FailedCount=%u\n"
330                      "RetryCount=%u\n"
331                      "MultipleRetryCount=%d\n"
332                      "FrameDuplicateCount=%d\n"
333                      "ReceivedFragmentCount=%u\n"
334                      "MulticastReceivedFrameCount=%u\n"
335                      "TransmittedFrameCount=%u\n"
336                      "WEPUndecryptableCount=%u\n",
337                      local->dot11TransmittedFragmentCount,
338                      local->dot11MulticastTransmittedFrameCount,
339                      local->dot11FailedCount,
340                      local->dot11RetryCount,
341                      local->dot11MultipleRetryCount,
342                      local->dot11FrameDuplicateCount,
343                      local->dot11ReceivedFragmentCount,
344                      local->dot11MulticastReceivedFrameCount,
345                      local->dot11TransmittedFrameCount,
346                      local->dot11WEPUndecryptableCount);
347
348         memset(&stats, 0, sizeof(stats));
349         if (local->hw->get_stats &&
350             local->hw->get_stats(local->mdev, &stats) == 0) {
351                 p += sprintf(p,
352                              "ACKFailureCount=%u\n"
353                              "RTSFailureCount=%u\n"
354                              "FCSErrorCount=%u\n"
355                              "RTSSuccessCount=%u\n",
356                              stats.dot11ACKFailureCount,
357                              stats.dot11RTSFailureCount,
358                              stats.dot11FCSErrorCount,
359                              stats.dot11RTSSuccessCount);
360         }
361
362         return (p - page);
363 }
364
365
366 static int ieee80211_proc_debug_read(char *page, char **start, off_t off,
367                                      int count, int *eof, void *data)
368 {
369         char *p = page;
370         struct ieee80211_local *local = (struct ieee80211_local *) data;
371         int i;
372
373         if (off != 0) {
374                 *eof = 1;
375                 return 0;
376         }
377
378 #ifdef CONFIG_IEEE80211_DEBUG_COUNTERS
379         p += sprintf(p,
380                      "tx_handlers_drop=%u\n"
381                      "tx_handlers_queued=%u\n"
382                      "tx_handlers_drop_unencrypted=%u\n"
383                      "tx_handlers_drop_fragment=%u\n"
384                      "tx_handlers_drop_wep=%u\n"
385                      "tx_handlers_drop_rate_limit=%u\n"
386                      "tx_handlers_drop_not_assoc=%u\n"
387                      "tx_handlers_drop_unauth_port=%u\n"
388                      "rx_handlers_drop=%u\n"
389                      "rx_handlers_queued=%u\n"
390                      "rx_handlers_drop_nullfunc=%u\n"
391                      "rx_handlers_drop_defrag=%u\n"
392                      "rx_handlers_drop_short=%u\n"
393                      "rx_handlers_drop_passive_scan=%u\n"
394                      "tx_expand_skb_head=%u\n"
395                      "tx_expand_skb_head_cloned=%u\n"
396                      "rx_expand_skb_head=%u\n"
397                      "rx_expand_skb_head2=%u\n"
398                      "rx_handlers_fragments=%u\n"
399                      "tx_status_drop=%u\n",
400                      local->tx_handlers_drop,
401                      local->tx_handlers_queued,
402                      local->tx_handlers_drop_unencrypted,
403                      local->tx_handlers_drop_fragment,
404                      local->tx_handlers_drop_wep,
405                      local->tx_handlers_drop_rate_limit,
406                      local->tx_handlers_drop_not_assoc,
407                      local->tx_handlers_drop_unauth_port,
408                      local->rx_handlers_drop,
409                      local->rx_handlers_queued,
410                      local->rx_handlers_drop_nullfunc,
411                      local->rx_handlers_drop_defrag,
412                      local->rx_handlers_drop_short,
413                      local->rx_handlers_drop_passive_scan,
414                      local->tx_expand_skb_head,
415                      local->tx_expand_skb_head_cloned,
416                      local->rx_expand_skb_head,
417                      local->rx_expand_skb_head2,
418                      local->rx_handlers_fragments,
419                      local->tx_status_drop);
420         {
421                 int i;
422                 p += sprintf(p, "wme_rx_queue=");
423                 for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
424                         p += sprintf(p, " %u", local->wme_rx_queue[i]);
425                 p += sprintf(p, "\n");
426
427                 p += sprintf(p, "wme_tx_queue=");
428                 for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
429                         p += sprintf(p, " %u", local->wme_tx_queue[i]);
430                 p += sprintf(p, "\n");
431         }
432 #endif /* CONFIG_IEEE80211_DEBUG_COUNTERS */
433
434         p += sprintf(p, "num_scans=%u\n", local->scan.num_scans);
435
436         p += sprintf(p,
437                      "conf.bss_count=%d\n"
438                      "bss_dev_count=%u\n",
439                      local->conf.bss_count, local->bss_dev_count);
440         for (i = 0; i < local->conf.bss_count; i++) {
441                 p += sprintf(p, "bss_dev[%d]=%p (%s)\n",
442                              i, local->bss_devs[i],
443                              (i < local->bss_dev_count && local->bss_devs[i]) ?
444                              local->bss_devs[i]->name : "N/A");
445         }
446
447         return (p - page);
448 }
449
450
451 static const char * ieee80211_mode_str_short(int mode)
452 {
453         switch (mode) {
454         case MODE_IEEE80211A:
455                 return "802.11a";
456         case MODE_IEEE80211B:
457                 return "802.11b";
458         case MODE_IEEE80211G:
459                 return "802.11g";
460         case MODE_ATHEROS_TURBO:
461                 return "AtherosTurbo";
462         default:
463                 return "UNKNOWN";
464         }
465 }
466
467
468 static const char * ieee80211_mode_str(int mode)
469 {
470         switch (mode) {
471         case MODE_IEEE80211A:
472                 return "IEEE 802.11a";
473         case MODE_IEEE80211B:
474                 return "IEEE 802.11b";
475         case MODE_IEEE80211G:
476                 return "IEEE 802.11g";
477         case MODE_ATHEROS_TURBO:
478                 return "Atheros Turbo (5 GHz)";
479         default:
480                 return "UNKNOWN";
481         }
482 }
483
484
485 static int ieee80211_proc_info_read(char *page, char **start, off_t off,
486                                     int count, int *eof, void *data)
487 {
488         char *p = page;
489         struct ieee80211_local *local = (struct ieee80211_local *) data;
490         int m;
491         struct ieee80211_hw_modes *mode;
492
493         if (off != 0) {
494                 *eof = 1;
495                 return 0;
496         }
497
498         p += sprintf(p, "hw_name=%s\n", local->hw->name);
499         p += sprintf(p, "modes=");
500         for (m = 0; m < local->hw->num_modes; m++) {
501                 mode = &local->hw->modes[m];
502                 p += sprintf(p, "[%s]", ieee80211_mode_str_short(mode->mode));
503         }
504         p += sprintf(p, "\n");
505         if (local->rate_ctrl && local->rate_ctrl_priv)
506                 p+= sprintf(p, "rate_ctrl_alg=%s\n", local->rate_ctrl->name);
507         return (p - page);
508 }
509
510
511 static int ieee80211_proc_config_read(char *page, char **start, off_t off,
512                                       int count, int *eof, void *data)
513 {
514         char *p = page;
515         struct ieee80211_local *local = (struct ieee80211_local *) data;
516
517         if (off != 0) {
518                 *eof = 1;
519                 return 0;
520         }
521
522         p += sprintf(p,
523                      "low_level_driver=%s\n"
524                      "channel=%d\n"
525                      "freq=%d\n"
526                      "mode=%s\n"
527                          "802.11h=%d\n"
528                      "wep_iv=0x%06x\n"
529                      "antenna_sel=%d\n"
530                      "calib_int=%d\n"
531                      "tx_power_reduction=%d.%d dBm\n"
532                      "bridge_packets=%d\n"
533                      "key_tx_rx_threshold=%d\n"
534                      "rts_threshold=%d\n"
535                      "fragmentation_threshold=%d\n"
536                      "short_retry_limit=%d\n"
537                      "long_retry_limit=%d\n"
538                      "total_ps_buffered=%d\n",
539                      local->hw->name ? local->hw->name : "N/A",
540                      local->conf.channel,
541                      local->conf.freq,
542                      ieee80211_mode_str(local->conf.phymode),
543                          local->conf.radar_detect,
544                      local->wep_iv & 0xffffff,
545                      local->conf.antenna_sel,
546                      local->conf.calib_int,
547                      local->conf.tx_power_reduction / 10,
548                      local->conf.tx_power_reduction % 10,
549                      local->bridge_packets,
550                      local->key_tx_rx_threshold,
551                      local->rts_threshold,
552                      local->fragmentation_threshold,
553                      local->short_retry_limit,
554                      local->long_retry_limit,
555                      local->total_ps_buffered);
556
557         return (p - page);
558 }
559
560
561 static int ieee80211_proc_channels_read(char *page, char **start, off_t off,
562                                         int count, int *eof, void *data)
563 {
564         char *p = page;
565         struct ieee80211_local *local = (struct ieee80211_local *) data;
566         int m, c;
567         struct ieee80211_hw_modes *mode;
568         struct ieee80211_channel *chan;
569
570         if (off != 0) {
571                 *eof = 1;
572                 return 0;
573         }
574
575         p += sprintf(p, "MODE CHAN FREQ TXPOWER ANTMAX FLAGS\n");
576         for (m = 0; m < local->hw->num_modes; m++) {
577                 mode = &local->hw->modes[m];
578                 for (c = 0; c < mode->num_channels; c++) {
579                         chan = &mode->channels[c];
580                         p += sprintf(p, "%d %d %d %d %d %s%s%s\n",
581                                      mode->mode, chan->chan, chan->freq,
582                                      chan->power_level, chan->antenna_max,
583                                      chan->flag & IEEE80211_CHAN_W_SCAN ?
584                                      "[W_SCAN]" : "",
585                                      chan->flag & IEEE80211_CHAN_W_ACTIVE_SCAN
586                                      ? "[W_ACTIVE_SCAN]" : "",
587                                      chan->flag & IEEE80211_CHAN_W_IBSS ?
588                                      "[W_IBSS]" : "");
589                 }
590         }
591         return (p - page);
592 }
593
594
595 static int ieee80211_proc_rates_read(char *page, char **start, off_t off,
596                                      int count, int *eof, void *data)
597 {
598         char *p = page;
599         struct ieee80211_local *local = (struct ieee80211_local *) data;
600         int r;
601         struct ieee80211_rate *rate;
602
603         if (off != 0) {
604                 *eof = 1;
605                 return 0;
606         }
607
608         p += sprintf(p, "RATE VAL VAL2 MIN_RSSI_ACK MIN_RSSI_ACK_DELTA "
609                      "FLAGS\n");
610         for (r = 0; r < local->num_curr_rates; r++) {
611                 rate = &local->curr_rates[r];
612                 p += sprintf(p, "%d %d %d %d %d 0x%x %s%s%s%s%s%s%s%s\n",
613                              rate->rate, rate->val, rate->val2,
614                              rate->min_rssi_ack, rate->min_rssi_ack_delta,
615                              rate->flags,
616                              rate->flags & IEEE80211_RATE_ERP ? "[ERP]" : "",
617                              rate->flags & IEEE80211_RATE_BASIC ?
618                              "[BASIC]" : "",
619                              rate->flags & IEEE80211_RATE_PREAMBLE2 ?
620                              "[PREAMBLE2]" : "",
621                              rate->flags & IEEE80211_RATE_SUPPORTED ?
622                              "[SUPPORTED]" : "",
623                              rate->flags & IEEE80211_RATE_OFDM ? "[OFDM]" : "",
624                              rate->flags & IEEE80211_RATE_CCK ? "[CCK]" : "",
625                              rate->flags & IEEE80211_RATE_TURBO ?
626                              "[TURBO]" : "",
627                              rate->flags & IEEE80211_RATE_MANDATORY ?
628                              "[MANDATORY]" : "");
629         }
630         return (p - page);
631 }
632
633
634 static int ieee80211_proc_multicast_read(char *page, char **start, off_t off,
635                                          int count, int *eof, void *data)
636 {
637         char *p = page;
638         struct ieee80211_local *local = (struct ieee80211_local *) data;
639
640         if (off != 0) {
641                 *eof = 1;
642                 return 0;
643         }
644
645         return rate_control_status_global(local, p);
646
647 }
648
649
650 void ieee80211_proc_init_sta(struct ieee80211_local *local,
651                              struct sta_info *sta)
652 {
653         char buf[30];
654         struct proc_dir_entry *entry;
655
656         sprintf(buf, MACSTR, MAC2STR(sta->addr));
657
658         if (!local->proc_sta)
659                 return;
660
661         entry = create_proc_read_entry(buf, 0, local->proc_sta,
662                                        ieee80211_proc_sta_read, sta);
663         if (entry) {
664                 entry->mode &= ~(S_IRWXG | S_IRWXO);
665                 sta->proc_entry_added = 1;
666         }
667 }
668
669
670 void ieee80211_proc_deinit_sta(struct ieee80211_local *local,
671                                struct sta_info *sta)
672 {
673         char buf[30];
674         sprintf(buf, MACSTR, MAC2STR(sta->addr));
675         if (local->proc_sta) {
676                 remove_proc_entry(buf, local->proc_sta);
677                 sta->proc_entry_added = 0;
678         }
679 }
680
681
682 void ieee80211_proc_init_virtual(struct net_device *dev)
683 {
684         struct proc_dir_entry *entry;
685         struct ieee80211_local *local = (struct ieee80211_local *) dev->priv;
686
687         if (!local->proc_iface)
688                 return;
689
690         entry = create_proc_read_entry(dev->name, 0, local->proc_iface,
691                                        ieee80211_proc_iface_read, dev);
692         if (entry)
693                 entry->mode &= ~(S_IRWXG | S_IRWXO);
694 }
695
696
697 void ieee80211_proc_deinit_virtual(struct net_device *dev)
698 {
699         struct ieee80211_local *local = (struct ieee80211_local *) dev->priv;
700
701         if (local->proc_iface)
702                 remove_proc_entry(dev->name, local->proc_iface);
703 }
704
705
706 void ieee80211_proc_init_interface(struct ieee80211_local *local)
707 {
708         if (!ieee80211_proc)
709                 return;
710
711         local->proc = proc_mkdir(local->wdev->name, ieee80211_proc);
712         if (!local->proc)
713                 return;
714
715         local->proc_sta = proc_mkdir("sta", local->proc);
716         local->proc_iface = proc_mkdir("iface", local->proc);
717         create_proc_read_entry("counters", 0, local->proc,
718                                ieee80211_proc_counters_read, local);
719         create_proc_read_entry("config", 0, local->proc,
720                                ieee80211_proc_config_read, local);
721         create_proc_read_entry("channels", 0, local->proc,
722                                ieee80211_proc_channels_read, local);
723         create_proc_read_entry("rates", 0, local->proc,
724                                ieee80211_proc_rates_read, local);
725         create_proc_read_entry("multicast", 0, local->proc,
726                                ieee80211_proc_multicast_read, local);
727         create_proc_read_entry("debug", 0, local->proc,
728                                ieee80211_proc_debug_read, local);
729         create_proc_read_entry("info", 0, local->proc,
730                                ieee80211_proc_info_read, local);
731         ieee80211_proc_init_virtual(local->wdev);
732 }
733
734
735 void ieee80211_proc_deinit_interface(struct ieee80211_local *local)
736 {
737         if (!local->proc)
738                 return;
739
740         ieee80211_proc_deinit_virtual(local->wdev);
741         remove_proc_entry("iface", local->proc);
742         remove_proc_entry("sta", local->proc);
743         remove_proc_entry("counters", local->proc);
744         remove_proc_entry("debug", local->proc);
745         remove_proc_entry("config", local->proc);
746         remove_proc_entry("channels", local->proc);
747         remove_proc_entry("rates", local->proc);
748         remove_proc_entry("multicast", local->proc);
749         remove_proc_entry("info", local->proc);
750         local->proc = NULL;
751         remove_proc_entry(local->wdev->name, ieee80211_proc);
752 }
753
754
755 void ieee80211_proc_init(void)
756 {
757         if (proc_net == NULL) {
758                 ieee80211_proc = NULL;
759                 return;
760         }
761
762         ieee80211_proc = proc_mkdir("ieee80211", proc_net);
763         if (!ieee80211_proc)
764                 printk(KERN_WARNING "Failed to mkdir /proc/net/ieee80211\n");
765 }
766
767
768 void ieee80211_proc_deinit(void)
769 {
770         if (!ieee80211_proc)
771                 return;
772
773         ieee80211_proc = NULL;
774         remove_proc_entry("ieee80211", proc_net);
775 }
776
777 #endif /* CONFIG_PROC_FS */