Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[linux-2.6] / drivers / net / wireless / hostap / hostap_proc.c
1 /* /proc routines for Host AP driver */
2
3 #include <linux/types.h>
4 #include <linux/proc_fs.h>
5 #include <net/ieee80211_crypt.h>
6
7 #include "hostap_wlan.h"
8 #include "hostap.h"
9
10 #define PROC_LIMIT (PAGE_SIZE - 80)
11
12
13 #ifndef PRISM2_NO_PROCFS_DEBUG
14 static int prism2_debug_proc_read(char *page, char **start, off_t off,
15                                   int count, int *eof, void *data)
16 {
17         char *p = page;
18         local_info_t *local = (local_info_t *) data;
19         int i;
20
21         if (off != 0) {
22                 *eof = 1;
23                 return 0;
24         }
25
26         p += sprintf(p, "next_txfid=%d next_alloc=%d\n",
27                      local->next_txfid, local->next_alloc);
28         for (i = 0; i < PRISM2_TXFID_COUNT; i++)
29                 p += sprintf(p, "FID: tx=%04X intransmit=%04X\n",
30                              local->txfid[i], local->intransmitfid[i]);
31         p += sprintf(p, "FW TX rate control: %d\n", local->fw_tx_rate_control);
32         p += sprintf(p, "beacon_int=%d\n", local->beacon_int);
33         p += sprintf(p, "dtim_period=%d\n", local->dtim_period);
34         p += sprintf(p, "wds_max_connections=%d\n",
35                      local->wds_max_connections);
36         p += sprintf(p, "dev_enabled=%d\n", local->dev_enabled);
37         p += sprintf(p, "sw_tick_stuck=%d\n", local->sw_tick_stuck);
38         for (i = 0; i < WEP_KEYS; i++) {
39                 if (local->crypt[i] && local->crypt[i]->ops) {
40                         p += sprintf(p, "crypt[%d]=%s\n",
41                                      i, local->crypt[i]->ops->name);
42                 }
43         }
44         p += sprintf(p, "pri_only=%d\n", local->pri_only);
45         p += sprintf(p, "pci=%d\n", local->func->hw_type == HOSTAP_HW_PCI);
46         p += sprintf(p, "sram_type=%d\n", local->sram_type);
47         p += sprintf(p, "no_pri=%d\n", local->no_pri);
48
49         return (p - page);
50 }
51 #endif /* PRISM2_NO_PROCFS_DEBUG */
52
53
54 static int prism2_stats_proc_read(char *page, char **start, off_t off,
55                                   int count, int *eof, void *data)
56 {
57         char *p = page;
58         local_info_t *local = (local_info_t *) data;
59         struct comm_tallies_sums *sums = (struct comm_tallies_sums *)
60                 &local->comm_tallies;
61
62         if (off != 0) {
63                 *eof = 1;
64                 return 0;
65         }
66
67         p += sprintf(p, "TxUnicastFrames=%u\n", sums->tx_unicast_frames);
68         p += sprintf(p, "TxMulticastframes=%u\n", sums->tx_multicast_frames);
69         p += sprintf(p, "TxFragments=%u\n", sums->tx_fragments);
70         p += sprintf(p, "TxUnicastOctets=%u\n", sums->tx_unicast_octets);
71         p += sprintf(p, "TxMulticastOctets=%u\n", sums->tx_multicast_octets);
72         p += sprintf(p, "TxDeferredTransmissions=%u\n",
73                      sums->tx_deferred_transmissions);
74         p += sprintf(p, "TxSingleRetryFrames=%u\n",
75                      sums->tx_single_retry_frames);
76         p += sprintf(p, "TxMultipleRetryFrames=%u\n",
77                      sums->tx_multiple_retry_frames);
78         p += sprintf(p, "TxRetryLimitExceeded=%u\n",
79                      sums->tx_retry_limit_exceeded);
80         p += sprintf(p, "TxDiscards=%u\n", sums->tx_discards);
81         p += sprintf(p, "RxUnicastFrames=%u\n", sums->rx_unicast_frames);
82         p += sprintf(p, "RxMulticastFrames=%u\n", sums->rx_multicast_frames);
83         p += sprintf(p, "RxFragments=%u\n", sums->rx_fragments);
84         p += sprintf(p, "RxUnicastOctets=%u\n", sums->rx_unicast_octets);
85         p += sprintf(p, "RxMulticastOctets=%u\n", sums->rx_multicast_octets);
86         p += sprintf(p, "RxFCSErrors=%u\n", sums->rx_fcs_errors);
87         p += sprintf(p, "RxDiscardsNoBuffer=%u\n",
88                      sums->rx_discards_no_buffer);
89         p += sprintf(p, "TxDiscardsWrongSA=%u\n", sums->tx_discards_wrong_sa);
90         p += sprintf(p, "RxDiscardsWEPUndecryptable=%u\n",
91                      sums->rx_discards_wep_undecryptable);
92         p += sprintf(p, "RxMessageInMsgFragments=%u\n",
93                      sums->rx_message_in_msg_fragments);
94         p += sprintf(p, "RxMessageInBadMsgFragments=%u\n",
95                      sums->rx_message_in_bad_msg_fragments);
96         /* FIX: this may grow too long for one page(?) */
97
98         return (p - page);
99 }
100
101
102 static int prism2_wds_proc_read(char *page, char **start, off_t off,
103                                 int count, int *eof, void *data)
104 {
105         char *p = page;
106         local_info_t *local = (local_info_t *) data;
107         struct list_head *ptr;
108         struct hostap_interface *iface;
109
110         if (off > PROC_LIMIT) {
111                 *eof = 1;
112                 return 0;
113         }
114
115         read_lock_bh(&local->iface_lock);
116         list_for_each(ptr, &local->hostap_interfaces) {
117                 iface = list_entry(ptr, struct hostap_interface, list);
118                 if (iface->type != HOSTAP_INTERFACE_WDS)
119                         continue;
120                 p += sprintf(p, "%s\t" MACSTR "\n",
121                              iface->dev->name,
122                              MAC2STR(iface->u.wds.remote_addr));
123                 if ((p - page) > PROC_LIMIT) {
124                         printk(KERN_DEBUG "%s: wds proc did not fit\n",
125                                local->dev->name);
126                         break;
127                 }
128         }
129         read_unlock_bh(&local->iface_lock);
130
131         if ((p - page) <= off) {
132                 *eof = 1;
133                 return 0;
134         }
135
136         *start = page + off;
137
138         return (p - page - off);
139 }
140
141
142 static int prism2_bss_list_proc_read(char *page, char **start, off_t off,
143                                      int count, int *eof, void *data)
144 {
145         char *p = page;
146         local_info_t *local = (local_info_t *) data;
147         struct list_head *ptr;
148         struct hostap_bss_info *bss;
149         int i;
150
151         if (off > PROC_LIMIT) {
152                 *eof = 1;
153                 return 0;
154         }
155
156         p += sprintf(p, "#BSSID\tlast_update\tcount\tcapab_info\tSSID(txt)\t"
157                      "SSID(hex)\tWPA IE\n");
158         spin_lock_bh(&local->lock);
159         list_for_each(ptr, &local->bss_list) {
160                 bss = list_entry(ptr, struct hostap_bss_info, list);
161                 p += sprintf(p, MACSTR "\t%lu\t%u\t0x%x\t",
162                              MAC2STR(bss->bssid), bss->last_update,
163                              bss->count, bss->capab_info);
164                 for (i = 0; i < bss->ssid_len; i++) {
165                         p += sprintf(p, "%c",
166                                      bss->ssid[i] >= 32 && bss->ssid[i] < 127 ?
167                                      bss->ssid[i] : '_');
168                 }
169                 p += sprintf(p, "\t");
170                 for (i = 0; i < bss->ssid_len; i++) {
171                         p += sprintf(p, "%02x", bss->ssid[i]);
172                 }
173                 p += sprintf(p, "\t");
174                 for (i = 0; i < bss->wpa_ie_len; i++) {
175                         p += sprintf(p, "%02x", bss->wpa_ie[i]);
176                 }
177                 p += sprintf(p, "\n");
178                 if ((p - page) > PROC_LIMIT) {
179                         printk(KERN_DEBUG "%s: BSS proc did not fit\n",
180                                local->dev->name);
181                         break;
182                 }
183         }
184         spin_unlock_bh(&local->lock);
185
186         if ((p - page) <= off) {
187                 *eof = 1;
188                 return 0;
189         }
190
191         *start = page + off;
192
193         return (p - page - off);
194 }
195
196
197 static int prism2_crypt_proc_read(char *page, char **start, off_t off,
198                                   int count, int *eof, void *data)
199 {
200         char *p = page;
201         local_info_t *local = (local_info_t *) data;
202         int i;
203
204         if (off > PROC_LIMIT) {
205                 *eof = 1;
206                 return 0;
207         }
208
209         p += sprintf(p, "tx_keyidx=%d\n", local->tx_keyidx);
210         for (i = 0; i < WEP_KEYS; i++) {
211                 if (local->crypt[i] && local->crypt[i]->ops &&
212                     local->crypt[i]->ops->print_stats) {
213                         p = local->crypt[i]->ops->print_stats(
214                                 p, local->crypt[i]->priv);
215                 }
216         }
217
218         if ((p - page) <= off) {
219                 *eof = 1;
220                 return 0;
221         }
222
223         *start = page + off;
224
225         return (p - page - off);
226 }
227
228
229 static int prism2_pda_proc_read(char *page, char **start, off_t off,
230                                 int count, int *eof, void *data)
231 {
232         local_info_t *local = (local_info_t *) data;
233
234         if (local->pda == NULL || off >= PRISM2_PDA_SIZE) {
235                 *eof = 1;
236                 return 0;
237         }
238
239         if (off + count > PRISM2_PDA_SIZE)
240                 count = PRISM2_PDA_SIZE - off;
241
242         memcpy(page, local->pda + off, count);
243         return count;
244 }
245
246
247 static int prism2_aux_dump_proc_read(char *page, char **start, off_t off,
248                                      int count, int *eof, void *data)
249 {
250         local_info_t *local = (local_info_t *) data;
251
252         if (local->func->read_aux == NULL) {
253                 *eof = 1;
254                 return 0;
255         }
256
257         if (local->func->read_aux(local->dev, off, count, page)) {
258                 *eof = 1;
259                 return 0;
260         }
261         *start = page;
262
263         return count;
264 }
265
266
267 #ifdef PRISM2_IO_DEBUG
268 static int prism2_io_debug_proc_read(char *page, char **start, off_t off,
269                                      int count, int *eof, void *data)
270 {
271         local_info_t *local = (local_info_t *) data;
272         int head = local->io_debug_head;
273         int start_bytes, left, copy, copied;
274
275         if (off + count > PRISM2_IO_DEBUG_SIZE * 4) {
276                 *eof = 1;
277                 if (off >= PRISM2_IO_DEBUG_SIZE * 4)
278                         return 0;
279                 count = PRISM2_IO_DEBUG_SIZE * 4 - off;
280         }
281
282         copied = 0;
283         start_bytes = (PRISM2_IO_DEBUG_SIZE - head) * 4;
284         left = count;
285
286         if (off < start_bytes) {
287                 copy = start_bytes - off;
288                 if (copy > count)
289                         copy = count;
290                 memcpy(page, ((u8 *) &local->io_debug[head]) + off, copy);
291                 left -= copy;
292                 if (left > 0)
293                         memcpy(&page[copy], local->io_debug, left);
294         } else {
295                 memcpy(page, ((u8 *) local->io_debug) + (off - start_bytes),
296                        left);
297         }
298
299         *start = page;
300
301         return count;
302 }
303 #endif /* PRISM2_IO_DEBUG */
304
305
306 #ifndef PRISM2_NO_STATION_MODES
307 static int prism2_scan_results_proc_read(char *page, char **start, off_t off,
308                                          int count, int *eof, void *data)
309 {
310         char *p = page;
311         local_info_t *local = (local_info_t *) data;
312         int entry, i, len, total = 0;
313         struct hfa384x_hostscan_result *scanres;
314         u8 *pos;
315
316         p += sprintf(p, "CHID ANL SL BcnInt Capab Rate BSSID ATIM SupRates "
317                      "SSID\n");
318
319         spin_lock_bh(&local->lock);
320         for (entry = 0; entry < local->last_scan_results_count; entry++) {
321                 scanres = &local->last_scan_results[entry];
322
323                 if (total + (p - page) <= off) {
324                         total += p - page;
325                         p = page;
326                 }
327                 if (total + (p - page) > off + count)
328                         break;
329                 if ((p - page) > (PAGE_SIZE - 200))
330                         break;
331
332                 p += sprintf(p, "%d %d %d %d 0x%02x %d " MACSTR " %d ",
333                              le16_to_cpu(scanres->chid),
334                              (s16) le16_to_cpu(scanres->anl),
335                              (s16) le16_to_cpu(scanres->sl),
336                              le16_to_cpu(scanres->beacon_interval),
337                              le16_to_cpu(scanres->capability),
338                              le16_to_cpu(scanres->rate),
339                              MAC2STR(scanres->bssid),
340                              le16_to_cpu(scanres->atim));
341
342                 pos = scanres->sup_rates;
343                 for (i = 0; i < sizeof(scanres->sup_rates); i++) {
344                         if (pos[i] == 0)
345                                 break;
346                         p += sprintf(p, "<%02x>", pos[i]);
347                 }
348                 p += sprintf(p, " ");
349
350                 pos = scanres->ssid;
351                 len = le16_to_cpu(scanres->ssid_len);
352                 if (len > 32)
353                         len = 32;
354                 for (i = 0; i < len; i++) {
355                         unsigned char c = pos[i];
356                         if (c >= 32 && c < 127)
357                                 p += sprintf(p, "%c", c);
358                         else
359                                 p += sprintf(p, "<%02x>", c);
360                 }
361                 p += sprintf(p, "\n");
362         }
363         spin_unlock_bh(&local->lock);
364
365         total += (p - page);
366         if (total >= off + count)
367                 *eof = 1;
368
369         if (total < off) {
370                 *eof = 1;
371                 return 0;
372         }
373
374         len = total - off;
375         if (len > (p - page))
376                 len = p - page;
377         *start = p - len;
378         if (len > count)
379                 len = count;
380
381         return len;
382 }
383 #endif /* PRISM2_NO_STATION_MODES */
384
385
386 void hostap_init_proc(local_info_t *local)
387 {
388         local->proc = NULL;
389
390         if (hostap_proc == NULL) {
391                 printk(KERN_WARNING "%s: hostap proc directory not created\n",
392                        local->dev->name);
393                 return;
394         }
395
396         local->proc = proc_mkdir(local->ddev->name, hostap_proc);
397         if (local->proc == NULL) {
398                 printk(KERN_INFO "/proc/net/hostap/%s creation failed\n",
399                        local->ddev->name);
400                 return;
401         }
402
403 #ifndef PRISM2_NO_PROCFS_DEBUG
404         create_proc_read_entry("debug", 0, local->proc,
405                                prism2_debug_proc_read, local);
406 #endif /* PRISM2_NO_PROCFS_DEBUG */
407         create_proc_read_entry("stats", 0, local->proc,
408                                prism2_stats_proc_read, local);
409         create_proc_read_entry("wds", 0, local->proc,
410                                prism2_wds_proc_read, local);
411         create_proc_read_entry("pda", 0, local->proc,
412                                prism2_pda_proc_read, local);
413         create_proc_read_entry("aux_dump", 0, local->proc,
414                                prism2_aux_dump_proc_read, local);
415         create_proc_read_entry("bss_list", 0, local->proc,
416                                prism2_bss_list_proc_read, local);
417         create_proc_read_entry("crypt", 0, local->proc,
418                                prism2_crypt_proc_read, local);
419 #ifdef PRISM2_IO_DEBUG
420         create_proc_read_entry("io_debug", 0, local->proc,
421                                prism2_io_debug_proc_read, local);
422 #endif /* PRISM2_IO_DEBUG */
423 #ifndef PRISM2_NO_STATION_MODES
424         create_proc_read_entry("scan_results", 0, local->proc,
425                                prism2_scan_results_proc_read, local);
426 #endif /* PRISM2_NO_STATION_MODES */
427 }
428
429
430 void hostap_remove_proc(local_info_t *local)
431 {
432         if (local->proc != NULL) {
433 #ifndef PRISM2_NO_STATION_MODES
434                 remove_proc_entry("scan_results", local->proc);
435 #endif /* PRISM2_NO_STATION_MODES */
436 #ifdef PRISM2_IO_DEBUG
437                 remove_proc_entry("io_debug", local->proc);
438 #endif /* PRISM2_IO_DEBUG */
439                 remove_proc_entry("pda", local->proc);
440                 remove_proc_entry("aux_dump", local->proc);
441                 remove_proc_entry("wds", local->proc);
442                 remove_proc_entry("stats", local->proc);
443                 remove_proc_entry("bss_list", local->proc);
444                 remove_proc_entry("crypt", local->proc);
445 #ifndef PRISM2_NO_PROCFS_DEBUG
446                 remove_proc_entry("debug", local->proc);
447 #endif /* PRISM2_NO_PROCFS_DEBUG */
448                 if (hostap_proc != NULL)
449                         remove_proc_entry(local->proc->name, hostap_proc);
450         }
451 }
452
453
454 EXPORT_SYMBOL(hostap_init_proc);
455 EXPORT_SYMBOL(hostap_remove_proc);