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