hostap_proc.c 12 KB

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