Merge /spare/repo/netdev-2.6/ branch 'ieee80211'
[powerpc.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 entries, entry, i, len, total = 0, hostscan;
306         struct hfa384x_scan_result *scanres;
307         struct hfa384x_hostscan_result *hscanres;
308         u8 *pos;
309
310         p += sprintf(p, "CHID ANL SL BcnInt Capab Rate BSSID ATIM SupRates "
311                      "SSID\n");
312
313         spin_lock_bh(&local->lock);
314         hostscan = local->last_scan_type == PRISM2_HOSTSCAN;
315         entries = hostscan ? local->last_hostscan_results_count :
316                 local->last_scan_results_count;
317         for (entry = 0; entry < entries; entry++) {
318                 hscanres = &local->last_hostscan_results[entry];
319                 scanres = &local->last_scan_results[entry];
320
321                 if (total + (p - page) <= off) {
322                         total += p - page;
323                         p = page;
324                 }
325                 if (total + (p - page) > off + count)
326                         break;
327                 if ((p - page) > (PAGE_SIZE - 200))
328                         break;
329
330                 if (hostscan) {
331                         p += sprintf(p, "%d %d %d %d 0x%02x %d " MACSTR " %d ",
332                                      le16_to_cpu(hscanres->chid),
333                                      (s16) le16_to_cpu(hscanres->anl),
334                                      (s16) le16_to_cpu(hscanres->sl),
335                                      le16_to_cpu(hscanres->beacon_interval),
336                                      le16_to_cpu(hscanres->capability),
337                                      le16_to_cpu(hscanres->rate),
338                                      MAC2STR(hscanres->bssid),
339                                      le16_to_cpu(hscanres->atim));
340                 } else {
341                         p += sprintf(p, "%d %d %d %d 0x%02x %d " MACSTR
342                                      " N/A ",
343                                      le16_to_cpu(scanres->chid),
344                                      (s16) le16_to_cpu(scanres->anl),
345                                      (s16) le16_to_cpu(scanres->sl),
346                                      le16_to_cpu(scanres->beacon_interval),
347                                      le16_to_cpu(scanres->capability),
348                                      le16_to_cpu(scanres->rate),
349                                      MAC2STR(scanres->bssid));
350                 }
351
352                 pos = hostscan ? hscanres->sup_rates : scanres->sup_rates;
353                 for (i = 0; i < sizeof(hscanres->sup_rates); i++) {
354                         if (pos[i] == 0)
355                                 break;
356                         p += sprintf(p, "<%02x>", pos[i]);
357                 }
358                 p += sprintf(p, " ");
359
360                 pos = hostscan ? hscanres->ssid : scanres->ssid;
361                 len = le16_to_cpu(hostscan ? hscanres->ssid_len :
362                                   scanres->ssid_len);
363                 if (len > 32)
364                         len = 32;
365                 for (i = 0; i < len; i++) {
366                         unsigned char c = pos[i];
367                         if (c >= 32 && c < 127)
368                                 p += sprintf(p, "%c", c);
369                         else
370                                 p += sprintf(p, "<%02x>", c);
371                 }
372                 p += sprintf(p, "\n");
373         }
374         spin_unlock_bh(&local->lock);
375
376         total += (p - page);
377         if (total >= off + count)
378                 *eof = 1;
379
380         if (total < off) {
381                 *eof = 1;
382                 return 0;
383         }
384
385         len = total - off;
386         if (len > (p - page))
387                 len = p - page;
388         *start = p - len;
389         if (len > count)
390                 len = count;
391
392         return len;
393 }
394 #endif /* PRISM2_NO_STATION_MODES */
395
396
397 void hostap_init_proc(local_info_t *local)
398 {
399         local->proc = NULL;
400
401         if (hostap_proc == NULL) {
402                 printk(KERN_WARNING "%s: hostap proc directory not created\n",
403                        local->dev->name);
404                 return;
405         }
406
407         local->proc = proc_mkdir(local->ddev->name, hostap_proc);
408         if (local->proc == NULL) {
409                 printk(KERN_INFO "/proc/net/hostap/%s creation failed\n",
410                        local->ddev->name);
411                 return;
412         }
413
414 #ifndef PRISM2_NO_PROCFS_DEBUG
415         create_proc_read_entry("debug", 0, local->proc,
416                                prism2_debug_proc_read, local);
417 #endif /* PRISM2_NO_PROCFS_DEBUG */
418         create_proc_read_entry("stats", 0, local->proc,
419                                prism2_stats_proc_read, local);
420         create_proc_read_entry("wds", 0, local->proc,
421                                prism2_wds_proc_read, local);
422         create_proc_read_entry("pda", 0, local->proc,
423                                prism2_pda_proc_read, local);
424         create_proc_read_entry("aux_dump", 0, local->proc,
425                                prism2_aux_dump_proc_read, local);
426         create_proc_read_entry("bss_list", 0, local->proc,
427                                prism2_bss_list_proc_read, local);
428         create_proc_read_entry("crypt", 0, local->proc,
429                                prism2_crypt_proc_read, local);
430 #ifdef PRISM2_IO_DEBUG
431         create_proc_read_entry("io_debug", 0, local->proc,
432                                prism2_io_debug_proc_read, local);
433 #endif /* PRISM2_IO_DEBUG */
434 #ifndef PRISM2_NO_STATION_MODES
435         create_proc_read_entry("scan_results", 0, local->proc,
436                                prism2_scan_results_proc_read, local);
437 #endif /* PRISM2_NO_STATION_MODES */
438 }
439
440
441 void hostap_remove_proc(local_info_t *local)
442 {
443         if (local->proc != NULL) {
444 #ifndef PRISM2_NO_STATION_MODES
445                 remove_proc_entry("scan_results", local->proc);
446 #endif /* PRISM2_NO_STATION_MODES */
447 #ifdef PRISM2_IO_DEBUG
448                 remove_proc_entry("io_debug", local->proc);
449 #endif /* PRISM2_IO_DEBUG */
450                 remove_proc_entry("pda", local->proc);
451                 remove_proc_entry("aux_dump", local->proc);
452                 remove_proc_entry("wds", local->proc);
453                 remove_proc_entry("stats", local->proc);
454                 remove_proc_entry("bss_list", local->proc);
455                 remove_proc_entry("crypt", local->proc);
456 #ifndef PRISM2_NO_PROCFS_DEBUG
457                 remove_proc_entry("debug", local->proc);
458 #endif /* PRISM2_NO_PROCFS_DEBUG */
459                 if (hostap_proc != NULL)
460                         remove_proc_entry(local->proc->name, hostap_proc);
461         }
462 }
463
464
465 EXPORT_SYMBOL(hostap_init_proc);
466 EXPORT_SYMBOL(hostap_remove_proc);