at v3.14 504 lines 14 kB view raw
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 15static int prism2_debug_proc_show(struct seq_file *m, void *v) 16{ 17 local_info_t *local = m->private; 18 int i; 19 20 seq_printf(m, "next_txfid=%d next_alloc=%d\n", 21 local->next_txfid, local->next_alloc); 22 for (i = 0; i < PRISM2_TXFID_COUNT; i++) 23 seq_printf(m, "FID: tx=%04X intransmit=%04X\n", 24 local->txfid[i], local->intransmitfid[i]); 25 seq_printf(m, "FW TX rate control: %d\n", local->fw_tx_rate_control); 26 seq_printf(m, "beacon_int=%d\n", local->beacon_int); 27 seq_printf(m, "dtim_period=%d\n", local->dtim_period); 28 seq_printf(m, "wds_max_connections=%d\n", local->wds_max_connections); 29 seq_printf(m, "dev_enabled=%d\n", local->dev_enabled); 30 seq_printf(m, "sw_tick_stuck=%d\n", local->sw_tick_stuck); 31 for (i = 0; i < WEP_KEYS; i++) { 32 if (local->crypt_info.crypt[i] && 33 local->crypt_info.crypt[i]->ops) { 34 seq_printf(m, "crypt[%d]=%s\n", i, 35 local->crypt_info.crypt[i]->ops->name); 36 } 37 } 38 seq_printf(m, "pri_only=%d\n", local->pri_only); 39 seq_printf(m, "pci=%d\n", local->func->hw_type == HOSTAP_HW_PCI); 40 seq_printf(m, "sram_type=%d\n", local->sram_type); 41 seq_printf(m, "no_pri=%d\n", local->no_pri); 42 43 return 0; 44} 45 46static int prism2_debug_proc_open(struct inode *inode, struct file *file) 47{ 48 return single_open(file, prism2_debug_proc_show, PDE_DATA(inode)); 49} 50 51static const struct file_operations prism2_debug_proc_fops = { 52 .open = prism2_debug_proc_open, 53 .read = seq_read, 54 .llseek = seq_lseek, 55 .release = single_release, 56}; 57#endif /* PRISM2_NO_PROCFS_DEBUG */ 58 59 60static int prism2_stats_proc_show(struct seq_file *m, void *v) 61{ 62 local_info_t *local = m->private; 63 struct comm_tallies_sums *sums = &local->comm_tallies; 64 65 seq_printf(m, "TxUnicastFrames=%u\n", sums->tx_unicast_frames); 66 seq_printf(m, "TxMulticastframes=%u\n", sums->tx_multicast_frames); 67 seq_printf(m, "TxFragments=%u\n", sums->tx_fragments); 68 seq_printf(m, "TxUnicastOctets=%u\n", sums->tx_unicast_octets); 69 seq_printf(m, "TxMulticastOctets=%u\n", sums->tx_multicast_octets); 70 seq_printf(m, "TxDeferredTransmissions=%u\n", 71 sums->tx_deferred_transmissions); 72 seq_printf(m, "TxSingleRetryFrames=%u\n", sums->tx_single_retry_frames); 73 seq_printf(m, "TxMultipleRetryFrames=%u\n", 74 sums->tx_multiple_retry_frames); 75 seq_printf(m, "TxRetryLimitExceeded=%u\n", 76 sums->tx_retry_limit_exceeded); 77 seq_printf(m, "TxDiscards=%u\n", sums->tx_discards); 78 seq_printf(m, "RxUnicastFrames=%u\n", sums->rx_unicast_frames); 79 seq_printf(m, "RxMulticastFrames=%u\n", sums->rx_multicast_frames); 80 seq_printf(m, "RxFragments=%u\n", sums->rx_fragments); 81 seq_printf(m, "RxUnicastOctets=%u\n", sums->rx_unicast_octets); 82 seq_printf(m, "RxMulticastOctets=%u\n", sums->rx_multicast_octets); 83 seq_printf(m, "RxFCSErrors=%u\n", sums->rx_fcs_errors); 84 seq_printf(m, "RxDiscardsNoBuffer=%u\n", sums->rx_discards_no_buffer); 85 seq_printf(m, "TxDiscardsWrongSA=%u\n", sums->tx_discards_wrong_sa); 86 seq_printf(m, "RxDiscardsWEPUndecryptable=%u\n", 87 sums->rx_discards_wep_undecryptable); 88 seq_printf(m, "RxMessageInMsgFragments=%u\n", 89 sums->rx_message_in_msg_fragments); 90 seq_printf(m, "RxMessageInBadMsgFragments=%u\n", 91 sums->rx_message_in_bad_msg_fragments); 92 /* FIX: this may grow too long for one page(?) */ 93 94 return 0; 95} 96 97static int prism2_stats_proc_open(struct inode *inode, struct file *file) 98{ 99 return single_open(file, prism2_stats_proc_show, PDE_DATA(inode)); 100} 101 102static const struct file_operations prism2_stats_proc_fops = { 103 .open = prism2_stats_proc_open, 104 .read = seq_read, 105 .llseek = seq_lseek, 106 .release = single_release, 107}; 108 109 110static int prism2_wds_proc_show(struct seq_file *m, void *v) 111{ 112 struct list_head *ptr = v; 113 struct hostap_interface *iface; 114 115 iface = list_entry(ptr, struct hostap_interface, list); 116 if (iface->type == HOSTAP_INTERFACE_WDS) 117 seq_printf(m, "%s\t%pM\n", 118 iface->dev->name, iface->u.wds.remote_addr); 119 return 0; 120} 121 122static void *prism2_wds_proc_start(struct seq_file *m, loff_t *_pos) 123{ 124 local_info_t *local = m->private; 125 read_lock_bh(&local->iface_lock); 126 return seq_list_start(&local->hostap_interfaces, *_pos); 127} 128 129static void *prism2_wds_proc_next(struct seq_file *m, void *v, loff_t *_pos) 130{ 131 local_info_t *local = m->private; 132 return seq_list_next(v, &local->hostap_interfaces, _pos); 133} 134 135static void prism2_wds_proc_stop(struct seq_file *m, void *v) 136{ 137 local_info_t *local = m->private; 138 read_unlock_bh(&local->iface_lock); 139} 140 141static const struct seq_operations prism2_wds_proc_seqops = { 142 .start = prism2_wds_proc_start, 143 .next = prism2_wds_proc_next, 144 .stop = prism2_wds_proc_stop, 145 .show = prism2_wds_proc_show, 146}; 147 148static int prism2_wds_proc_open(struct inode *inode, struct file *file) 149{ 150 int ret = seq_open(file, &prism2_wds_proc_seqops); 151 if (ret == 0) { 152 struct seq_file *m = file->private_data; 153 m->private = PDE_DATA(inode); 154 } 155 return ret; 156} 157 158static const struct file_operations prism2_wds_proc_fops = { 159 .open = prism2_wds_proc_open, 160 .read = seq_read, 161 .llseek = seq_lseek, 162 .release = seq_release, 163}; 164 165 166static int prism2_bss_list_proc_show(struct seq_file *m, void *v) 167{ 168 local_info_t *local = m->private; 169 struct list_head *ptr = v; 170 struct hostap_bss_info *bss; 171 int i; 172 173 if (ptr == &local->bss_list) { 174 seq_printf(m, "#BSSID\tlast_update\tcount\tcapab_info\tSSID(txt)\t" 175 "SSID(hex)\tWPA IE\n"); 176 return 0; 177 } 178 179 bss = list_entry(ptr, struct hostap_bss_info, list); 180 seq_printf(m, "%pM\t%lu\t%u\t0x%x\t", 181 bss->bssid, bss->last_update, 182 bss->count, bss->capab_info); 183 184 for (i = 0; i < bss->ssid_len; i++) 185 seq_putc(m,bss->ssid[i] >= 32 && bss->ssid[i] < 127 ? 186 bss->ssid[i] : '_'); 187 188 seq_putc(m, '\t'); 189 for (i = 0; i < bss->ssid_len; i++) 190 seq_printf(m, "%02x", bss->ssid[i]); 191 seq_putc(m, '\t'); 192 for (i = 0; i < bss->wpa_ie_len; i++) 193 seq_printf(m, "%02x", bss->wpa_ie[i]); 194 seq_putc(m, '\n'); 195 return 0; 196} 197 198static void *prism2_bss_list_proc_start(struct seq_file *m, loff_t *_pos) 199{ 200 local_info_t *local = m->private; 201 spin_lock_bh(&local->lock); 202 return seq_list_start_head(&local->bss_list, *_pos); 203} 204 205static void *prism2_bss_list_proc_next(struct seq_file *m, void *v, loff_t *_pos) 206{ 207 local_info_t *local = m->private; 208 return seq_list_next(v, &local->bss_list, _pos); 209} 210 211static void prism2_bss_list_proc_stop(struct seq_file *m, void *v) 212{ 213 local_info_t *local = m->private; 214 spin_unlock_bh(&local->lock); 215} 216 217static const struct seq_operations prism2_bss_list_proc_seqops = { 218 .start = prism2_bss_list_proc_start, 219 .next = prism2_bss_list_proc_next, 220 .stop = prism2_bss_list_proc_stop, 221 .show = prism2_bss_list_proc_show, 222}; 223 224static int prism2_bss_list_proc_open(struct inode *inode, struct file *file) 225{ 226 int ret = seq_open(file, &prism2_bss_list_proc_seqops); 227 if (ret == 0) { 228 struct seq_file *m = file->private_data; 229 m->private = PDE_DATA(inode); 230 } 231 return ret; 232} 233 234static const struct file_operations prism2_bss_list_proc_fops = { 235 .open = prism2_bss_list_proc_open, 236 .read = seq_read, 237 .llseek = seq_lseek, 238 .release = seq_release, 239}; 240 241 242static int prism2_crypt_proc_show(struct seq_file *m, void *v) 243{ 244 local_info_t *local = m->private; 245 int i; 246 247 seq_printf(m, "tx_keyidx=%d\n", local->crypt_info.tx_keyidx); 248 for (i = 0; i < WEP_KEYS; i++) { 249 if (local->crypt_info.crypt[i] && 250 local->crypt_info.crypt[i]->ops && 251 local->crypt_info.crypt[i]->ops->print_stats) { 252 local->crypt_info.crypt[i]->ops->print_stats( 253 m, local->crypt_info.crypt[i]->priv); 254 } 255 } 256 return 0; 257} 258 259static int prism2_crypt_proc_open(struct inode *inode, struct file *file) 260{ 261 return single_open(file, prism2_crypt_proc_show, PDE_DATA(inode)); 262} 263 264static const struct file_operations prism2_crypt_proc_fops = { 265 .open = prism2_crypt_proc_open, 266 .read = seq_read, 267 .llseek = seq_lseek, 268 .release = single_release, 269}; 270 271 272static ssize_t prism2_pda_proc_read(struct file *file, char __user *buf, 273 size_t count, loff_t *_pos) 274{ 275 local_info_t *local = PDE_DATA(file_inode(file)); 276 size_t off; 277 278 if (local->pda == NULL || *_pos >= PRISM2_PDA_SIZE) 279 return 0; 280 281 off = *_pos; 282 if (count > PRISM2_PDA_SIZE - off) 283 count = PRISM2_PDA_SIZE - off; 284 if (copy_to_user(buf, local->pda + off, count) != 0) 285 return -EFAULT; 286 *_pos += count; 287 return count; 288} 289 290static const struct file_operations prism2_pda_proc_fops = { 291 .read = prism2_pda_proc_read, 292 .llseek = generic_file_llseek, 293}; 294 295 296static ssize_t prism2_aux_dump_proc_no_read(struct file *file, char __user *buf, 297 size_t bufsize, loff_t *_pos) 298{ 299 return 0; 300} 301 302static const struct file_operations prism2_aux_dump_proc_fops = { 303 .read = prism2_aux_dump_proc_no_read, 304}; 305 306 307#ifdef PRISM2_IO_DEBUG 308static int prism2_io_debug_proc_read(char *page, char **start, off_t off, 309 int count, int *eof, void *data) 310{ 311 local_info_t *local = (local_info_t *) data; 312 int head = local->io_debug_head; 313 int start_bytes, left, copy, copied; 314 315 if (off + count > PRISM2_IO_DEBUG_SIZE * 4) { 316 *eof = 1; 317 if (off >= PRISM2_IO_DEBUG_SIZE * 4) 318 return 0; 319 count = PRISM2_IO_DEBUG_SIZE * 4 - off; 320 } 321 322 copied = 0; 323 start_bytes = (PRISM2_IO_DEBUG_SIZE - head) * 4; 324 left = count; 325 326 if (off < start_bytes) { 327 copy = start_bytes - off; 328 if (copy > count) 329 copy = count; 330 memcpy(page, ((u8 *) &local->io_debug[head]) + off, copy); 331 left -= copy; 332 if (left > 0) 333 memcpy(&page[copy], local->io_debug, left); 334 } else { 335 memcpy(page, ((u8 *) local->io_debug) + (off - start_bytes), 336 left); 337 } 338 339 *start = page; 340 341 return count; 342} 343#endif /* PRISM2_IO_DEBUG */ 344 345 346#ifndef PRISM2_NO_STATION_MODES 347static int prism2_scan_results_proc_show(struct seq_file *m, void *v) 348{ 349 local_info_t *local = m->private; 350 unsigned long entry; 351 int i, len; 352 struct hfa384x_hostscan_result *scanres; 353 u8 *p; 354 355 if (v == SEQ_START_TOKEN) { 356 seq_printf(m, 357 "CHID ANL SL BcnInt Capab Rate BSSID ATIM SupRates SSID\n"); 358 return 0; 359 } 360 361 entry = (unsigned long)v - 2; 362 scanres = &local->last_scan_results[entry]; 363 364 seq_printf(m, "%d %d %d %d 0x%02x %d %pM %d ", 365 le16_to_cpu(scanres->chid), 366 (s16) le16_to_cpu(scanres->anl), 367 (s16) le16_to_cpu(scanres->sl), 368 le16_to_cpu(scanres->beacon_interval), 369 le16_to_cpu(scanres->capability), 370 le16_to_cpu(scanres->rate), 371 scanres->bssid, 372 le16_to_cpu(scanres->atim)); 373 374 p = scanres->sup_rates; 375 for (i = 0; i < sizeof(scanres->sup_rates); i++) { 376 if (p[i] == 0) 377 break; 378 seq_printf(m, "<%02x>", p[i]); 379 } 380 seq_putc(m, ' '); 381 382 p = scanres->ssid; 383 len = le16_to_cpu(scanres->ssid_len); 384 if (len > 32) 385 len = 32; 386 for (i = 0; i < len; i++) { 387 unsigned char c = p[i]; 388 if (c >= 32 && c < 127) 389 seq_putc(m, c); 390 else 391 seq_printf(m, "<%02x>", c); 392 } 393 seq_putc(m, '\n'); 394 return 0; 395} 396 397static void *prism2_scan_results_proc_start(struct seq_file *m, loff_t *_pos) 398{ 399 local_info_t *local = m->private; 400 spin_lock_bh(&local->lock); 401 402 /* We have a header (pos 0) + N results to show (pos 1...N) */ 403 if (*_pos > local->last_scan_results_count) 404 return NULL; 405 return (void *)(unsigned long)(*_pos + 1); /* 0 would be EOF */ 406} 407 408static void *prism2_scan_results_proc_next(struct seq_file *m, void *v, loff_t *_pos) 409{ 410 local_info_t *local = m->private; 411 412 ++*_pos; 413 if (*_pos > local->last_scan_results_count) 414 return NULL; 415 return (void *)(unsigned long)(*_pos + 1); /* 0 would be EOF */ 416} 417 418static void prism2_scan_results_proc_stop(struct seq_file *m, void *v) 419{ 420 local_info_t *local = m->private; 421 spin_unlock_bh(&local->lock); 422} 423 424static const struct seq_operations prism2_scan_results_proc_seqops = { 425 .start = prism2_scan_results_proc_start, 426 .next = prism2_scan_results_proc_next, 427 .stop = prism2_scan_results_proc_stop, 428 .show = prism2_scan_results_proc_show, 429}; 430 431static int prism2_scan_results_proc_open(struct inode *inode, struct file *file) 432{ 433 int ret = seq_open(file, &prism2_scan_results_proc_seqops); 434 if (ret == 0) { 435 struct seq_file *m = file->private_data; 436 m->private = PDE_DATA(inode); 437 } 438 return ret; 439} 440 441static const struct file_operations prism2_scan_results_proc_fops = { 442 .open = prism2_scan_results_proc_open, 443 .read = seq_read, 444 .llseek = seq_lseek, 445 .release = seq_release, 446}; 447 448 449#endif /* PRISM2_NO_STATION_MODES */ 450 451 452void hostap_init_proc(local_info_t *local) 453{ 454 local->proc = NULL; 455 456 if (hostap_proc == NULL) { 457 printk(KERN_WARNING "%s: hostap proc directory not created\n", 458 local->dev->name); 459 return; 460 } 461 462 local->proc = proc_mkdir(local->ddev->name, hostap_proc); 463 if (local->proc == NULL) { 464 printk(KERN_INFO "/proc/net/hostap/%s creation failed\n", 465 local->ddev->name); 466 return; 467 } 468 469#ifndef PRISM2_NO_PROCFS_DEBUG 470 proc_create_data("debug", 0, local->proc, 471 &prism2_debug_proc_fops, local); 472#endif /* PRISM2_NO_PROCFS_DEBUG */ 473 proc_create_data("stats", 0, local->proc, 474 &prism2_stats_proc_fops, local); 475 proc_create_data("wds", 0, local->proc, 476 &prism2_wds_proc_fops, local); 477 proc_create_data("pda", 0, local->proc, 478 &prism2_pda_proc_fops, local); 479 proc_create_data("aux_dump", 0, local->proc, 480 local->func->read_aux_fops ?: &prism2_aux_dump_proc_fops, 481 local); 482 proc_create_data("bss_list", 0, local->proc, 483 &prism2_bss_list_proc_fops, local); 484 proc_create_data("crypt", 0, local->proc, 485 &prism2_crypt_proc_fops, local); 486#ifdef PRISM2_IO_DEBUG 487 proc_create_data("io_debug", 0, local->proc, 488 &prism2_io_debug_proc_fops, local); 489#endif /* PRISM2_IO_DEBUG */ 490#ifndef PRISM2_NO_STATION_MODES 491 proc_create_data("scan_results", 0, local->proc, 492 &prism2_scan_results_proc_fops, local); 493#endif /* PRISM2_NO_STATION_MODES */ 494} 495 496 497void hostap_remove_proc(local_info_t *local) 498{ 499 proc_remove(local->proc); 500} 501 502 503EXPORT_SYMBOL(hostap_init_proc); 504EXPORT_SYMBOL(hostap_remove_proc);