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