2
* Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation; either version 2 of the License, or
7
* (at your option) any later version.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
15
#include <linux/proc_fs.h>
16
#include <linux/module.h>
17
#include <asm/uaccess.h>
25
#define MAX_PROC_STR_LEN 32
27
static struct proc_dir_entry *wrap_procfs_entry;
29
static int procfs_read_ndis_stats(char *page, char **start, off_t off,
30
int count, int *eof, void *data)
33
struct ndis_device *wnd = (struct ndis_device *)data;
34
struct ndis_wireless_stats stats;
43
res = mp_query(wnd, OID_802_11_RSSI, &rssi, sizeof(rssi));
45
p += sprintf(p, "signal_level=%d dBm\n", (s32)rssi);
47
res = mp_query(wnd, OID_802_11_STATISTICS, &stats, sizeof(stats));
50
p += sprintf(p, "tx_frames=%llu\n", stats.tx_frag);
51
p += sprintf(p, "tx_multicast_frames=%llu\n",
53
p += sprintf(p, "tx_failed=%llu\n", stats.failed);
54
p += sprintf(p, "tx_retry=%llu\n", stats.retry);
55
p += sprintf(p, "tx_multi_retry=%llu\n", stats.multi_retry);
56
p += sprintf(p, "tx_rtss_success=%llu\n", stats.rtss_succ);
57
p += sprintf(p, "tx_rtss_fail=%llu\n", stats.rtss_fail);
58
p += sprintf(p, "ack_fail=%llu\n", stats.ack_fail);
59
p += sprintf(p, "frame_duplicates=%llu\n", stats.frame_dup);
60
p += sprintf(p, "rx_frames=%llu\n", stats.rx_frag);
61
p += sprintf(p, "rx_multicast_frames=%llu\n",
63
p += sprintf(p, "fcs_errors=%llu\n", stats.fcs_err);
66
if (p - page > count) {
67
ERROR("wrote %td bytes (limit is %u)\n",
75
static int procfs_read_ndis_encr(char *page, char **start, off_t off,
76
int count, int *eof, void *data)
79
struct ndis_device *wnd = (struct ndis_device *)data;
80
int i, encr_status, auth_mode, infra_mode;
82
struct ndis_essid essid;
83
mac_address ap_address;
90
res = mp_query(wnd, OID_802_11_BSSID,
91
&ap_address, sizeof(ap_address));
93
memset(ap_address, 0, ETH_ALEN);
94
p += sprintf(p, "ap_address=%2.2X", ap_address[0]);
95
for (i = 1; i < ETH_ALEN; i++)
96
p += sprintf(p, ":%2.2X", ap_address[i]);
97
p += sprintf(p, "\n");
99
res = mp_query(wnd, OID_802_11_SSID, &essid, sizeof(essid));
101
p += sprintf(p, "essid=%.*s\n", essid.length, essid.essid);
103
res = mp_query_int(wnd, OID_802_11_ENCRYPTION_STATUS, &encr_status);
105
typeof(&wnd->encr_info.keys[0]) tx_key;
106
p += sprintf(p, "tx_key=%u\n", wnd->encr_info.tx_key_index);
107
p += sprintf(p, "key=");
108
tx_key = &wnd->encr_info.keys[wnd->encr_info.tx_key_index];
109
if (tx_key->length > 0)
110
for (i = 0; i < tx_key->length; i++)
111
p += sprintf(p, "%2.2X", tx_key->key[i]);
113
p += sprintf(p, "off");
114
p += sprintf(p, "\n");
115
p += sprintf(p, "encr_mode=%d\n", encr_status);
117
res = mp_query_int(wnd, OID_802_11_AUTHENTICATION_MODE, &auth_mode);
119
p += sprintf(p, "auth_mode=%d\n", auth_mode);
120
res = mp_query_int(wnd, OID_802_11_INFRASTRUCTURE_MODE, &infra_mode);
121
p += sprintf(p, "mode=%s\n", (infra_mode == Ndis802_11IBSS) ?
122
"adhoc" : (infra_mode == Ndis802_11Infrastructure) ?
124
if (p - page > count) {
125
WARNING("wrote %td bytes (limit is %u)",
133
static int procfs_read_ndis_hw(char *page, char **start, off_t off,
134
int count, int *eof, void *data)
137
struct ndis_device *wnd = (struct ndis_device *)data;
138
struct ndis_configuration config;
139
enum ndis_power power_mode;
141
ndis_tx_power_level tx_power;
143
ndis_rts_threshold rts_threshold;
144
ndis_fragmentation_threshold frag_threshold;
145
ndis_antenna antenna;
149
char *hw_status[] = {"ready", "initializing", "resetting", "closing",
157
res = mp_query_int(wnd, OID_GEN_HARDWARE_STATUS, &n);
158
if (res == NDIS_STATUS_SUCCESS && n >= 0 && n < ARRAY_SIZE(hw_status))
159
p += sprintf(p, "status=%s\n", hw_status[n]);
161
res = mp_query(wnd, OID_802_3_CURRENT_ADDRESS, mac, sizeof(mac));
163
p += sprintf(p, "mac: " MACSTRSEP "\n", MAC2STR(mac));
164
res = mp_query(wnd, OID_802_11_CONFIGURATION, &config, sizeof(config));
166
p += sprintf(p, "beacon_period=%u msec\n",
167
config.beacon_period);
168
p += sprintf(p, "atim_window=%u msec\n", config.atim_window);
169
p += sprintf(p, "frequency=%u kHz\n", config.ds_config);
170
p += sprintf(p, "hop_pattern=%u\n",
171
config.fh_config.hop_pattern);
172
p += sprintf(p, "hop_set=%u\n",
173
config.fh_config.hop_set);
174
p += sprintf(p, "dwell_time=%u msec\n",
175
config.fh_config.dwell_time);
178
res = mp_query(wnd, OID_802_11_TX_POWER_LEVEL,
179
&tx_power, sizeof(tx_power));
181
p += sprintf(p, "tx_power=%u mW\n", tx_power);
183
res = mp_query(wnd, OID_GEN_LINK_SPEED, &bit_rate, sizeof(bit_rate));
185
p += sprintf(p, "bit_rate=%u kBps\n", (u32)bit_rate / 10);
187
res = mp_query(wnd, OID_802_11_RTS_THRESHOLD,
188
&rts_threshold, sizeof(rts_threshold));
190
p += sprintf(p, "rts_threshold=%u bytes\n", rts_threshold);
192
res = mp_query(wnd, OID_802_11_FRAGMENTATION_THRESHOLD,
193
&frag_threshold, sizeof(frag_threshold));
195
p += sprintf(p, "frag_threshold=%u bytes\n", frag_threshold);
197
res = mp_query_int(wnd, OID_802_11_POWER_MODE, &power_mode);
199
p += sprintf(p, "power_mode=%s\n",
200
(power_mode == NDIS_POWER_OFF) ? "always_on" :
201
(power_mode == NDIS_POWER_MAX) ?
202
"max_savings" : "min_savings");
204
res = mp_query(wnd, OID_802_11_NUMBER_OF_ANTENNAS,
205
&antenna, sizeof(antenna));
207
p += sprintf(p, "num_antennas=%u\n", antenna);
209
res = mp_query(wnd, OID_802_11_TX_ANTENNA_SELECTED,
210
&antenna, sizeof(antenna));
212
p += sprintf(p, "tx_antenna=%u\n", antenna);
214
res = mp_query(wnd, OID_802_11_RX_ANTENNA_SELECTED,
215
&antenna, sizeof(antenna));
217
p += sprintf(p, "rx_antenna=%u\n", antenna);
219
p += sprintf(p, "encryption_modes=%s%s%s%s%s%s%s\n",
220
test_bit(Ndis802_11Encryption1Enabled, &wnd->capa.encr) ?
223
test_bit(Ndis802_11Encryption2Enabled, &wnd->capa.encr) ?
224
"; TKIP with WPA" : "",
225
test_bit(Ndis802_11AuthModeWPA2, &wnd->capa.auth) ?
227
test_bit(Ndis802_11AuthModeWPA2PSK, &wnd->capa.auth) ?
230
test_bit(Ndis802_11Encryption3Enabled, &wnd->capa.encr) ?
231
"; AES/CCMP with WPA" : "",
232
test_bit(Ndis802_11AuthModeWPA2, &wnd->capa.auth) ?
234
test_bit(Ndis802_11AuthModeWPA2PSK, &wnd->capa.auth) ?
237
res = mp_query_int(wnd, OID_GEN_CURRENT_PACKET_FILTER, &packet_filter);
239
if (packet_filter != wnd->packet_filter)
240
WARNING("wrong packet_filter? 0x%08x, 0x%08x\n",
241
packet_filter, wnd->packet_filter);
242
p += sprintf(p, "packet_filter: 0x%08x\n", packet_filter);
244
if (p - page > count) {
245
WARNING("wrote %td bytes (limit is %u)",
253
static int procfs_read_ndis_settings(char *page, char **start, off_t off,
254
int count, int *eof, void *data)
257
struct ndis_device *wnd = (struct ndis_device *)data;
258
struct wrap_device_setting *setting;
265
p += sprintf(p, "hangcheck_interval=%d\n",
266
hangcheck_interval == 0 ?
267
(wnd->hangcheck_interval / HZ) : -1);
269
list_for_each_entry(setting, &wnd->wd->settings, list) {
270
p += sprintf(p, "%s=%s\n", setting->name, setting->value);
273
list_for_each_entry(setting, &wnd->wd->driver->settings, list) {
274
p += sprintf(p, "%s=%s\n", setting->name, setting->value);
280
static int procfs_write_ndis_settings(struct file *file, const char __user *buf,
281
unsigned long count, void *data)
283
struct ndis_device *wnd = (struct ndis_device *)data;
284
char setting[MAX_PROC_STR_LEN], *p;
288
if (count > MAX_PROC_STR_LEN)
291
memset(setting, 0, sizeof(setting));
292
if (copy_from_user(setting, buf, count))
295
if ((p = strchr(setting, '\n')))
298
if ((p = strchr(setting, '=')))
301
if (!strcmp(setting, "hangcheck_interval")) {
305
i = simple_strtol(p, NULL, 10);
308
wnd->hangcheck_interval = i * HZ;
311
} else if (!strcmp(setting, "suspend")) {
315
i = simple_strtol(p, NULL, 10);
319
if (wrap_is_pci_bus(wnd->wd->dev_bus))
320
i = wrap_pnp_suspend_pci_device(wnd->wd->pci.pdev,
322
else if (wrap_is_usb_bus(wnd->wd->dev_bus))
323
i = wrap_pnp_suspend_usb_device(wnd->wd->usb.intf,
327
} else if (!strcmp(setting, "resume")) {
329
if (wrap_is_pci_bus(wnd->wd->dev_bus))
330
i = wrap_pnp_resume_pci_device(wnd->wd->pci.pdev);
331
else if (wrap_is_usb_bus(wnd->wd->dev_bus))
332
i = wrap_pnp_resume_usb_device(wnd->wd->usb.intf);
335
} else if (!strcmp(setting, "stats_enabled")) {
339
i = simple_strtol(p, NULL, 10);
341
wnd->iw_stats_enabled = TRUE;
343
wnd->iw_stats_enabled = FALSE;
344
} else if (!strcmp(setting, "packet_filter")) {
348
i = simple_strtol(p, NULL, 10);
349
res = mp_set_int(wnd, OID_GEN_CURRENT_PACKET_FILTER, i);
351
WARNING("setting packet_filter failed: %08X", res);
352
} else if (!strcmp(setting, "reinit")) {
353
if (ndis_reinit(wnd) != NDIS_STATUS_SUCCESS)
356
struct ndis_configuration_parameter param;
357
struct unicode_string key;
358
struct ansi_string ansi;
363
RtlInitAnsiString(&ansi, p);
364
if (RtlAnsiStringToUnicodeString(¶m.data.string, &ansi,
365
TRUE) != STATUS_SUCCESS)
366
EXIT1(return -EFAULT);
367
param.type = NdisParameterString;
368
RtlInitAnsiString(&ansi, setting);
369
if (RtlAnsiStringToUnicodeString(&key, &ansi,
370
TRUE) != STATUS_SUCCESS) {
371
RtlFreeUnicodeString(¶m.data.string);
372
EXIT1(return -EINVAL);
374
NdisWriteConfiguration(&res, wnd->nmb, &key, ¶m);
375
RtlFreeUnicodeString(&key);
376
RtlFreeUnicodeString(¶m.data.string);
377
if (res != NDIS_STATUS_SUCCESS)
383
int wrap_procfs_add_ndis_device(struct ndis_device *wnd)
385
struct proc_dir_entry *procfs_entry;
387
if (wrap_procfs_entry == NULL)
390
if (wnd->procfs_iface) {
391
ERROR("%s already registered?", wnd->procfs_iface->name);
394
wnd->procfs_iface = proc_mkdir(wnd->net_dev->name, wrap_procfs_entry);
395
if (wnd->procfs_iface == NULL) {
396
ERROR("couldn't create proc directory");
399
wnd->procfs_iface->uid = proc_uid;
400
wnd->procfs_iface->gid = proc_gid;
402
procfs_entry = create_proc_entry("hw", S_IFREG | S_IRUSR | S_IRGRP,
404
if (procfs_entry == NULL) {
405
ERROR("couldn't create proc entry for 'hw'");
408
procfs_entry->uid = proc_uid;
409
procfs_entry->gid = proc_gid;
410
procfs_entry->data = wnd;
411
procfs_entry->read_proc = procfs_read_ndis_hw;
414
procfs_entry = create_proc_entry("stats", S_IFREG | S_IRUSR | S_IRGRP,
416
if (procfs_entry == NULL) {
417
ERROR("couldn't create proc entry for 'stats'");
420
procfs_entry->uid = proc_uid;
421
procfs_entry->gid = proc_gid;
422
procfs_entry->data = wnd;
423
procfs_entry->read_proc = procfs_read_ndis_stats;
426
procfs_entry = create_proc_entry("encr", S_IFREG | S_IRUSR | S_IRGRP,
428
if (procfs_entry == NULL) {
429
ERROR("couldn't create proc entry for 'encr'");
432
procfs_entry->uid = proc_uid;
433
procfs_entry->gid = proc_gid;
434
procfs_entry->data = wnd;
435
procfs_entry->read_proc = procfs_read_ndis_encr;
438
procfs_entry = create_proc_entry("settings", S_IFREG |
440
S_IWUSR | S_IWGRP, wnd->procfs_iface);
441
if (procfs_entry == NULL) {
442
ERROR("couldn't create proc entry for 'settings'");
445
procfs_entry->uid = proc_uid;
446
procfs_entry->gid = proc_gid;
447
procfs_entry->data = wnd;
448
procfs_entry->read_proc = procfs_read_ndis_settings;
449
procfs_entry->write_proc = procfs_write_ndis_settings;
454
remove_proc_entry("encr", wnd->procfs_iface);
456
remove_proc_entry("stats", wnd->procfs_iface);
458
remove_proc_entry("hw", wnd->procfs_iface);
460
remove_proc_entry(wnd->procfs_iface->name, wrap_procfs_entry);
461
wnd->procfs_iface = NULL;
465
void wrap_procfs_remove_ndis_device(struct ndis_device *wnd)
467
struct proc_dir_entry *procfs_iface = xchg(&wnd->procfs_iface, NULL);
469
if (procfs_iface == NULL)
471
remove_proc_entry("hw", procfs_iface);
472
remove_proc_entry("stats", procfs_iface);
473
remove_proc_entry("encr", procfs_iface);
474
remove_proc_entry("settings", procfs_iface);
475
if (wrap_procfs_entry)
476
remove_proc_entry(procfs_iface->name, wrap_procfs_entry);
479
static int procfs_read_debug(char *page, char **start, off_t off,
480
int count, int *eof, void *data)
484
enum alloc_type type;
491
p += sprintf(p, "%d\n", debug);
493
for (type = 0; type < ALLOC_TYPE_MAX; type++)
494
p += sprintf(p, "total size of allocations in %s: %d\n",
495
alloc_type_name[type], alloc_size(type));
500
static int procfs_write_debug(struct file *file, const char __user *buf,
501
unsigned long count, void *data)
504
char setting[MAX_PROC_STR_LEN], *p;
506
if (count > MAX_PROC_STR_LEN)
509
memset(setting, 0, sizeof(setting));
510
if (copy_from_user(setting, buf, count))
513
if ((p = strchr(setting, '\n')))
516
if ((p = strchr(setting, '=')))
519
i = simple_strtol(setting, NULL, 10);
520
if (i >= 0 && i < 10)
527
int wrap_procfs_init(void)
529
struct proc_dir_entry *procfs_entry;
531
wrap_procfs_entry = proc_mkdir(DRIVER_NAME, proc_net_root);
532
if (wrap_procfs_entry == NULL) {
533
ERROR("couldn't create procfs directory");
536
wrap_procfs_entry->uid = proc_uid;
537
wrap_procfs_entry->gid = proc_gid;
539
procfs_entry = create_proc_entry("debug", S_IFREG | S_IRUSR | S_IRGRP,
541
if (procfs_entry == NULL) {
542
ERROR("couldn't create proc entry for 'debug'");
545
procfs_entry->uid = proc_uid;
546
procfs_entry->gid = proc_gid;
547
procfs_entry->read_proc = procfs_read_debug;
548
procfs_entry->write_proc = procfs_write_debug;
553
void wrap_procfs_remove(void)
555
if (wrap_procfs_entry == NULL)
557
remove_proc_entry("debug", wrap_procfs_entry);
558
remove_proc_entry(DRIVER_NAME, proc_net_root);