blob: 81b321ba189a1bd561ada1bbed543263f3c18de5 [file] [log] [blame]
Jouni Malinenff1d2762005-05-12 22:54:16 -04001/* /proc routines for Host AP driver */
2
3#define PROC_LIMIT (PAGE_SIZE - 80)
4
5
6#ifndef PRISM2_NO_PROCFS_DEBUG
7static 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
47static 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
95static 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
135static 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
190static 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
222static 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
240static 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
261static 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
300static 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
397void 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
441void 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
465EXPORT_SYMBOL(hostap_init_proc);
466EXPORT_SYMBOL(hostap_remove_proc);