hostap_proc.c 13.5 KB
Newer Older
Jouni Malinen's avatar
Jouni Malinen committed
1
2
/* /proc routines for Host AP driver */

3
4
#include <linux/types.h>
#include <linux/proc_fs.h>
5
#include <linux/export.h>
6
#include <net/lib80211.h>
7
8
9
10

#include "hostap_wlan.h"
#include "hostap.h"

Jouni Malinen's avatar
Jouni Malinen committed
11
12
13
14
#define PROC_LIMIT (PAGE_SIZE - 80)


#ifndef PRISM2_NO_PROCFS_DEBUG
15
static int prism2_debug_proc_show(struct seq_file *m, void *v)
Jouni Malinen's avatar
Jouni Malinen committed
16
{
17
	local_info_t *local = m->private;
Jouni Malinen's avatar
Jouni Malinen committed
18
19
	int i;

20
21
	seq_printf(m, "next_txfid=%d next_alloc=%d\n",
		   local->next_txfid, local->next_alloc);
Jouni Malinen's avatar
Jouni Malinen committed
22
	for (i = 0; i < PRISM2_TXFID_COUNT; i++)
23
24
25
26
27
28
29
30
		seq_printf(m, "FID: tx=%04X intransmit=%04X\n",
			   local->txfid[i], local->intransmitfid[i]);
	seq_printf(m, "FW TX rate control: %d\n", local->fw_tx_rate_control);
	seq_printf(m, "beacon_int=%d\n", local->beacon_int);
	seq_printf(m, "dtim_period=%d\n", local->dtim_period);
	seq_printf(m, "wds_max_connections=%d\n", local->wds_max_connections);
	seq_printf(m, "dev_enabled=%d\n", local->dev_enabled);
	seq_printf(m, "sw_tick_stuck=%d\n", local->sw_tick_stuck);
Jouni Malinen's avatar
Jouni Malinen committed
31
	for (i = 0; i < WEP_KEYS; i++) {
32
33
		if (local->crypt_info.crypt[i] &&
		    local->crypt_info.crypt[i]->ops) {
34
35
			seq_printf(m, "crypt[%d]=%s\n", i,
				   local->crypt_info.crypt[i]->ops->name);
Jouni Malinen's avatar
Jouni Malinen committed
36
37
		}
	}
38
39
40
41
42
43
44
	seq_printf(m, "pri_only=%d\n", local->pri_only);
	seq_printf(m, "pci=%d\n", local->func->hw_type == HOSTAP_HW_PCI);
	seq_printf(m, "sram_type=%d\n", local->sram_type);
	seq_printf(m, "no_pri=%d\n", local->no_pri);

	return 0;
}
Jouni Malinen's avatar
Jouni Malinen committed
45

46
47
48
static int prism2_debug_proc_open(struct inode *inode, struct file *file)
{
	return single_open(file, prism2_debug_proc_show, PDE_DATA(inode));
Jouni Malinen's avatar
Jouni Malinen committed
49
}
50
51
52
53
54
55
56

static const struct file_operations prism2_debug_proc_fops = {
	.open		= prism2_debug_proc_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};
Jouni Malinen's avatar
Jouni Malinen committed
57
58
59
#endif /* PRISM2_NO_PROCFS_DEBUG */


60
static int prism2_stats_proc_show(struct seq_file *m, void *v)
Jouni Malinen's avatar
Jouni Malinen committed
61
{
62
	local_info_t *local = m->private;
63
	struct comm_tallies_sums *sums = &local->comm_tallies;
Jouni Malinen's avatar
Jouni Malinen committed
64

65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
	seq_printf(m, "TxUnicastFrames=%u\n", sums->tx_unicast_frames);
	seq_printf(m, "TxMulticastframes=%u\n", sums->tx_multicast_frames);
	seq_printf(m, "TxFragments=%u\n", sums->tx_fragments);
	seq_printf(m, "TxUnicastOctets=%u\n", sums->tx_unicast_octets);
	seq_printf(m, "TxMulticastOctets=%u\n", sums->tx_multicast_octets);
	seq_printf(m, "TxDeferredTransmissions=%u\n",
		   sums->tx_deferred_transmissions);
	seq_printf(m, "TxSingleRetryFrames=%u\n", sums->tx_single_retry_frames);
	seq_printf(m, "TxMultipleRetryFrames=%u\n",
		   sums->tx_multiple_retry_frames);
	seq_printf(m, "TxRetryLimitExceeded=%u\n",
		   sums->tx_retry_limit_exceeded);
	seq_printf(m, "TxDiscards=%u\n", sums->tx_discards);
	seq_printf(m, "RxUnicastFrames=%u\n", sums->rx_unicast_frames);
	seq_printf(m, "RxMulticastFrames=%u\n", sums->rx_multicast_frames);
	seq_printf(m, "RxFragments=%u\n", sums->rx_fragments);
	seq_printf(m, "RxUnicastOctets=%u\n", sums->rx_unicast_octets);
	seq_printf(m, "RxMulticastOctets=%u\n", sums->rx_multicast_octets);
	seq_printf(m, "RxFCSErrors=%u\n", sums->rx_fcs_errors);
	seq_printf(m, "RxDiscardsNoBuffer=%u\n", sums->rx_discards_no_buffer);
	seq_printf(m, "TxDiscardsWrongSA=%u\n", sums->tx_discards_wrong_sa);
	seq_printf(m, "RxDiscardsWEPUndecryptable=%u\n",
		   sums->rx_discards_wep_undecryptable);
	seq_printf(m, "RxMessageInMsgFragments=%u\n",
		   sums->rx_message_in_msg_fragments);
	seq_printf(m, "RxMessageInBadMsgFragments=%u\n",
		   sums->rx_message_in_bad_msg_fragments);
Jouni Malinen's avatar
Jouni Malinen committed
92
93
	/* FIX: this may grow too long for one page(?) */

94
95
96
97
98
99
	return 0;
}

static int prism2_stats_proc_open(struct inode *inode, struct file *file)
{
	return single_open(file, prism2_stats_proc_show, PDE_DATA(inode));
Jouni Malinen's avatar
Jouni Malinen committed
100
101
}

102
103
104
105
106
107
108
static const struct file_operations prism2_stats_proc_fops = {
	.open		= prism2_stats_proc_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};

Jouni Malinen's avatar
Jouni Malinen committed
109

110
static int prism2_wds_proc_show(struct seq_file *m, void *v)
Jouni Malinen's avatar
Jouni Malinen committed
111
{
112
	struct list_head *ptr = v;
Jouni Malinen's avatar
Jouni Malinen committed
113
114
	struct hostap_interface *iface;

115
116
117
118
119
120
	iface = list_entry(ptr, struct hostap_interface, list);
	if (iface->type == HOSTAP_INTERFACE_WDS)
		seq_printf(m, "%s\t%pM\n",
			   iface->dev->name, iface->u.wds.remote_addr);
	return 0;
}
Jouni Malinen's avatar
Jouni Malinen committed
121

122
123
124
static void *prism2_wds_proc_start(struct seq_file *m, loff_t *_pos)
{
	local_info_t *local = m->private;
Jouni Malinen's avatar
Jouni Malinen committed
125
	read_lock_bh(&local->iface_lock);
126
127
	return seq_list_start(&local->hostap_interfaces, *_pos);
}
Jouni Malinen's avatar
Jouni Malinen committed
128

129
130
131
132
133
134
135
136
137
138
139
static void *prism2_wds_proc_next(struct seq_file *m, void *v, loff_t *_pos)
{
	local_info_t *local = m->private;
	return seq_list_next(v, &local->hostap_interfaces, _pos);
}

static void prism2_wds_proc_stop(struct seq_file *m, void *v)
{
	local_info_t *local = m->private;
	read_unlock_bh(&local->iface_lock);
}
Jouni Malinen's avatar
Jouni Malinen committed
140

141
142
143
144
145
146
static const struct seq_operations prism2_wds_proc_seqops = {
	.start	= prism2_wds_proc_start,
	.next	= prism2_wds_proc_next,
	.stop	= prism2_wds_proc_stop,
	.show	= prism2_wds_proc_show,
};
Jouni Malinen's avatar
Jouni Malinen committed
147

148
149
150
151
152
153
154
155
static int prism2_wds_proc_open(struct inode *inode, struct file *file)
{
	int ret = seq_open(file, &prism2_wds_proc_seqops);
	if (ret == 0) {
		struct seq_file *m = file->private_data;
		m->private = PDE_DATA(inode);
	}
	return ret;
Jouni Malinen's avatar
Jouni Malinen committed
156
157
}

158
159
160
161
162
163
static const struct file_operations prism2_wds_proc_fops = {
	.open		= prism2_wds_proc_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};
Jouni Malinen's avatar
Jouni Malinen committed
164

165
166

static int prism2_bss_list_proc_show(struct seq_file *m, void *v)
Jouni Malinen's avatar
Jouni Malinen committed
167
{
168
169
	local_info_t *local = m->private;
	struct list_head *ptr = v;
Jouni Malinen's avatar
Jouni Malinen committed
170
171
172
	struct hostap_bss_info *bss;
	int i;

173
174
175
	if (ptr == &local->bss_list) {
		seq_printf(m, "#BSSID\tlast_update\tcount\tcapab_info\tSSID(txt)\t"
			   "SSID(hex)\tWPA IE\n");
Jouni Malinen's avatar
Jouni Malinen committed
176
177
178
		return 0;
	}

179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
	bss = list_entry(ptr, struct hostap_bss_info, list);
	seq_printf(m, "%pM\t%lu\t%u\t0x%x\t",
		   bss->bssid, bss->last_update,
		   bss->count, bss->capab_info);

	for (i = 0; i < bss->ssid_len; i++)
		seq_putc(m,bss->ssid[i] >= 32 && bss->ssid[i] < 127 ?
			   bss->ssid[i] : '_');

	seq_putc(m, '\t');
	for (i = 0; i < bss->ssid_len; i++)
		seq_printf(m, "%02x", bss->ssid[i]);
	seq_putc(m, '\t');
	for (i = 0; i < bss->wpa_ie_len; i++)
		seq_printf(m, "%02x", bss->wpa_ie[i]);
	seq_putc(m, '\n');
	return 0;
}

static void *prism2_bss_list_proc_start(struct seq_file *m, loff_t *_pos)
{
	local_info_t *local = m->private;
Jouni Malinen's avatar
Jouni Malinen committed
201
	spin_lock_bh(&local->lock);
202
203
	return seq_list_start_head(&local->bss_list, *_pos);
}
Jouni Malinen's avatar
Jouni Malinen committed
204

205
206
207
208
209
210
211
212
213
214
215
static void *prism2_bss_list_proc_next(struct seq_file *m, void *v, loff_t *_pos)
{
	local_info_t *local = m->private;
	return seq_list_next(v, &local->bss_list, _pos);
}

static void prism2_bss_list_proc_stop(struct seq_file *m, void *v)
{
	local_info_t *local = m->private;
	spin_unlock_bh(&local->lock);
}
Jouni Malinen's avatar
Jouni Malinen committed
216

217
218
219
220
221
222
static const struct seq_operations prism2_bss_list_proc_seqops = {
	.start	= prism2_bss_list_proc_start,
	.next	= prism2_bss_list_proc_next,
	.stop	= prism2_bss_list_proc_stop,
	.show	= prism2_bss_list_proc_show,
};
Jouni Malinen's avatar
Jouni Malinen committed
223

224
225
226
227
228
229
230
231
static int prism2_bss_list_proc_open(struct inode *inode, struct file *file)
{
	int ret = seq_open(file, &prism2_bss_list_proc_seqops);
	if (ret == 0) {
		struct seq_file *m = file->private_data;
		m->private = PDE_DATA(inode);
	}
	return ret;
Jouni Malinen's avatar
Jouni Malinen committed
232
233
}

234
235
236
237
238
239
static const struct file_operations prism2_bss_list_proc_fops = {
	.open		= prism2_bss_list_proc_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};
Jouni Malinen's avatar
Jouni Malinen committed
240

241
242

static int prism2_crypt_proc_show(struct seq_file *m, void *v)
Jouni Malinen's avatar
Jouni Malinen committed
243
{
244
	local_info_t *local = m->private;
Jouni Malinen's avatar
Jouni Malinen committed
245
246
	int i;

247
	seq_printf(m, "tx_keyidx=%d\n", local->crypt_info.tx_keyidx);
Jouni Malinen's avatar
Jouni Malinen committed
248
	for (i = 0; i < WEP_KEYS; i++) {
249
250
251
		if (local->crypt_info.crypt[i] &&
		    local->crypt_info.crypt[i]->ops &&
		    local->crypt_info.crypt[i]->ops->print_stats) {
252
253
			local->crypt_info.crypt[i]->ops->print_stats(
				m, local->crypt_info.crypt[i]->priv);
Jouni Malinen's avatar
Jouni Malinen committed
254
255
		}
	}
256
257
	return 0;
}
Jouni Malinen's avatar
Jouni Malinen committed
258

259
260
261
static int prism2_crypt_proc_open(struct inode *inode, struct file *file)
{
	return single_open(file, prism2_crypt_proc_show, PDE_DATA(inode));
Jouni Malinen's avatar
Jouni Malinen committed
262
263
}

264
265
266
267
268
269
270
static const struct file_operations prism2_crypt_proc_fops = {
	.open		= prism2_crypt_proc_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};

Jouni Malinen's avatar
Jouni Malinen committed
271

272
273
static ssize_t prism2_pda_proc_read(struct file *file, char __user *buf,
				    size_t count, loff_t *_pos)
Jouni Malinen's avatar
Jouni Malinen committed
274
{
275
276
	local_info_t *local = PDE_DATA(file_inode(file));
	size_t off;
Jouni Malinen's avatar
Jouni Malinen committed
277

278
	if (local->pda == NULL || *_pos >= PRISM2_PDA_SIZE)
Jouni Malinen's avatar
Jouni Malinen committed
279
280
		return 0;

281
282
	off = *_pos;
	if (count > PRISM2_PDA_SIZE - off)
Jouni Malinen's avatar
Jouni Malinen committed
283
		count = PRISM2_PDA_SIZE - off;
284
285
286
	if (copy_to_user(buf, local->pda + off, count) != 0)
		return -EFAULT;
	*_pos += count;
Jouni Malinen's avatar
Jouni Malinen committed
287
288
289
	return count;
}

290
291
292
293
static const struct file_operations prism2_pda_proc_fops = {
	.read		= prism2_pda_proc_read,
	.llseek		= generic_file_llseek,
};
Jouni Malinen's avatar
Jouni Malinen committed
294
295


296
297
298
299
static ssize_t prism2_aux_dump_proc_no_read(struct file *file, char __user *buf,
					    size_t bufsize, loff_t *_pos)
{
	return 0;
Jouni Malinen's avatar
Jouni Malinen committed
300
301
}

302
303
304
305
static const struct file_operations prism2_aux_dump_proc_fops = {
	.read		= prism2_aux_dump_proc_no_read,
};

Jouni Malinen's avatar
Jouni Malinen committed
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346

#ifdef PRISM2_IO_DEBUG
static int prism2_io_debug_proc_read(char *page, char **start, off_t off,
				     int count, int *eof, void *data)
{
	local_info_t *local = (local_info_t *) data;
	int head = local->io_debug_head;
	int start_bytes, left, copy, copied;

	if (off + count > PRISM2_IO_DEBUG_SIZE * 4) {
		*eof = 1;
		if (off >= PRISM2_IO_DEBUG_SIZE * 4)
			return 0;
		count = PRISM2_IO_DEBUG_SIZE * 4 - off;
	}

	copied = 0;
	start_bytes = (PRISM2_IO_DEBUG_SIZE - head) * 4;
	left = count;

	if (off < start_bytes) {
		copy = start_bytes - off;
		if (copy > count)
			copy = count;
		memcpy(page, ((u8 *) &local->io_debug[head]) + off, copy);
		left -= copy;
		if (left > 0)
			memcpy(&page[copy], local->io_debug, left);
	} else {
		memcpy(page, ((u8 *) local->io_debug) + (off - start_bytes),
		       left);
	}

	*start = page;

	return count;
}
#endif /* PRISM2_IO_DEBUG */


#ifndef PRISM2_NO_STATION_MODES
347
static int prism2_scan_results_proc_show(struct seq_file *m, void *v)
Jouni Malinen's avatar
Jouni Malinen committed
348
{
349
350
351
	local_info_t *local = m->private;
	unsigned long entry;
	int i, len;
Jouni Malinen's avatar
Jouni Malinen committed
352
	struct hfa384x_hostscan_result *scanres;
353
	u8 *p;
Jouni Malinen's avatar
Jouni Malinen committed
354

355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
	if (v == SEQ_START_TOKEN) {
		seq_printf(m,
			   "CHID ANL SL BcnInt Capab Rate BSSID ATIM SupRates SSID\n");
		return 0;
	}

	entry = (unsigned long)v - 2;
	scanres = &local->last_scan_results[entry];

	seq_printf(m, "%d %d %d %d 0x%02x %d %pM %d ",
		   le16_to_cpu(scanres->chid),
		   (s16) le16_to_cpu(scanres->anl),
		   (s16) le16_to_cpu(scanres->sl),
		   le16_to_cpu(scanres->beacon_interval),
		   le16_to_cpu(scanres->capability),
		   le16_to_cpu(scanres->rate),
		   scanres->bssid,
		   le16_to_cpu(scanres->atim));

	p = scanres->sup_rates;
	for (i = 0; i < sizeof(scanres->sup_rates); i++) {
		if (p[i] == 0)
			break;
		seq_printf(m, "<%02x>", p[i]);
	}
	seq_putc(m, ' ');

	p = scanres->ssid;
	len = le16_to_cpu(scanres->ssid_len);
	if (len > 32)
		len = 32;
	for (i = 0; i < len; i++) {
		unsigned char c = p[i];
		if (c >= 32 && c < 127)
			seq_putc(m, c);
		else
			seq_printf(m, "<%02x>", c);
	}
	seq_putc(m, '\n');
	return 0;
}
Jouni Malinen's avatar
Jouni Malinen committed
396

397
398
399
static void *prism2_scan_results_proc_start(struct seq_file *m, loff_t *_pos)
{
	local_info_t *local = m->private;
Jouni Malinen's avatar
Jouni Malinen committed
400
401
	spin_lock_bh(&local->lock);

402
403
404
405
406
	/* We have a header (pos 0) + N results to show (pos 1...N) */
	if (*_pos > local->last_scan_results_count)
		return NULL;
	return (void *)(unsigned long)(*_pos + 1); /* 0 would be EOF */
}
Jouni Malinen's avatar
Jouni Malinen committed
407

408
409
410
411
412
413
414
415
416
417
418
419
420
static void *prism2_scan_results_proc_next(struct seq_file *m, void *v, loff_t *_pos)
{
	local_info_t *local = m->private;

	++*_pos;
	if (*_pos > local->last_scan_results_count)
		return NULL;
	return (void *)(unsigned long)(*_pos + 1); /* 0 would be EOF */
}

static void prism2_scan_results_proc_stop(struct seq_file *m, void *v)
{
	local_info_t *local = m->private;
Jouni Malinen's avatar
Jouni Malinen committed
421
	spin_unlock_bh(&local->lock);
422
}
Jouni Malinen's avatar
Jouni Malinen committed
423

424
425
426
427
428
429
static const struct seq_operations prism2_scan_results_proc_seqops = {
	.start	= prism2_scan_results_proc_start,
	.next	= prism2_scan_results_proc_next,
	.stop	= prism2_scan_results_proc_stop,
	.show	= prism2_scan_results_proc_show,
};
Jouni Malinen's avatar
Jouni Malinen committed
430

431
432
433
434
435
436
static int prism2_scan_results_proc_open(struct inode *inode, struct file *file)
{
	int ret = seq_open(file, &prism2_scan_results_proc_seqops);
	if (ret == 0) {
		struct seq_file *m = file->private_data;
		m->private = PDE_DATA(inode);
Jouni Malinen's avatar
Jouni Malinen committed
437
	}
438
439
440
441
442
443
444
445
446
	return ret;
}

static const struct file_operations prism2_scan_results_proc_fops = {
	.open		= prism2_scan_results_proc_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};
Jouni Malinen's avatar
Jouni Malinen committed
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469


#endif /* PRISM2_NO_STATION_MODES */


void hostap_init_proc(local_info_t *local)
{
	local->proc = NULL;

	if (hostap_proc == NULL) {
		printk(KERN_WARNING "%s: hostap proc directory not created\n",
		       local->dev->name);
		return;
	}

	local->proc = proc_mkdir(local->ddev->name, hostap_proc);
	if (local->proc == NULL) {
		printk(KERN_INFO "/proc/net/hostap/%s creation failed\n",
		       local->ddev->name);
		return;
	}

#ifndef PRISM2_NO_PROCFS_DEBUG
470
471
	proc_create_data("debug", 0, local->proc,
			 &prism2_debug_proc_fops, local);
Jouni Malinen's avatar
Jouni Malinen committed
472
#endif /* PRISM2_NO_PROCFS_DEBUG */
473
474
475
476
477
478
479
480
481
482
483
484
485
	proc_create_data("stats", 0, local->proc,
			 &prism2_stats_proc_fops, local);
	proc_create_data("wds", 0, local->proc,
			 &prism2_wds_proc_fops, local);
	proc_create_data("pda", 0, local->proc,
			 &prism2_pda_proc_fops, local);
	proc_create_data("aux_dump", 0, local->proc,
			 local->func->read_aux_fops ?: &prism2_aux_dump_proc_fops,
			 local);
	proc_create_data("bss_list", 0, local->proc,
			 &prism2_bss_list_proc_fops, local);
	proc_create_data("crypt", 0, local->proc,
			 &prism2_crypt_proc_fops, local);
Jouni Malinen's avatar
Jouni Malinen committed
486
#ifdef PRISM2_IO_DEBUG
487
488
	proc_create_data("io_debug", 0, local->proc,
			 &prism2_io_debug_proc_fops, local);
Jouni Malinen's avatar
Jouni Malinen committed
489
490
#endif /* PRISM2_IO_DEBUG */
#ifndef PRISM2_NO_STATION_MODES
491
492
	proc_create_data("scan_results", 0, local->proc,
			 &prism2_scan_results_proc_fops, local);
Jouni Malinen's avatar
Jouni Malinen committed
493
494
495
496
497
498
#endif /* PRISM2_NO_STATION_MODES */
}


void hostap_remove_proc(local_info_t *local)
{
499
	remove_proc_subtree(local->ddev->name, hostap_proc);
Jouni Malinen's avatar
Jouni Malinen committed
500
501
502
503
504
}


EXPORT_SYMBOL(hostap_init_proc);
EXPORT_SYMBOL(hostap_remove_proc);