iwgetid.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581
  1. /*
  2. * Wireless Tools
  3. *
  4. * Jean II - HPL '01
  5. *
  6. * Just print the ESSID or NWID...
  7. *
  8. * This file is released under the GPL license.
  9. * Copyright (c) 1997-2004 Jean Tourrilhes <jt@hpl.hp.com>
  10. */
  11. #include "iwlib.h" /* Header */
  12. #include <getopt.h>
  13. /*
  14. * Note on Pcmcia Schemes :
  15. * ----------------------
  16. * The purpose of this tool is to use the ESSID discovery mechanism
  17. * to select the appropriate Pcmcia Scheme. The card tell us which
  18. * ESSID it has found, and we can then select the appropriate Pcmcia
  19. * Scheme for this ESSID (Wireless config (encrypt keys) and IP config).
  20. * The way to do it is as follows :
  21. * cardctl scheme "essidany"
  22. * delay 100
  23. * $scheme = iwgetid --scheme
  24. * cardctl scheme $scheme
  25. * Of course, you need to add a scheme called "essidany" with the
  26. * following setting :
  27. * essidany,*,*,*)
  28. * ESSID="any"
  29. * IPADDR="10.0.0.1"
  30. *
  31. * This can also be integrated int he Pcmcia scripts.
  32. * Some drivers don't activate the card up to "ifconfig up".
  33. * Therefore, they wont scan ESSID up to this point, so we can't
  34. * read it reliably in Pcmcia scripts.
  35. * I guess the proper way to write the network script is as follows :
  36. * if($scheme == "iwgetid") {
  37. * iwconfig $name essid any
  38. * iwconfig $name nwid any
  39. * ifconfig $name up
  40. * delay 100
  41. * $scheme = iwgetid $name --scheme
  42. * ifconfig $name down
  43. * }
  44. *
  45. * This is pseudo code, but you get an idea...
  46. * The "ifconfig up" activate the card.
  47. * The "delay" is necessary to let time for the card scan the
  48. * frequencies and associate with the AP.
  49. * The "ifconfig down" is necessary to allow the driver to optimise
  50. * the wireless parameters setting (minimise number of card resets).
  51. *
  52. * Another cute idea is to have a list of Pcmcia Schemes to try
  53. * and to keep the first one that associate (AP address != 0). This
  54. * would be necessary for closed networks and cards that can't
  55. * discover essid...
  56. *
  57. * Jean II - 29/3/01
  58. */
  59. /**************************** CONSTANTS ****************************/
  60. #define FORMAT_DEFAULT 0 /* Nice looking display for the user */
  61. #define FORMAT_SCHEME 1 /* To be used as a Pcmcia Scheme */
  62. #define FORMAT_RAW 2 /* Raw value, for shell scripts */
  63. #define WTYPE_ESSID 0 /* Display ESSID or NWID */
  64. #define WTYPE_AP 1 /* Display AP/Cell Address */
  65. #define WTYPE_FREQ 2 /* Display frequency/channel */
  66. #define WTYPE_CHANNEL 3 /* Display channel (converted from freq) */
  67. #define WTYPE_MODE 4 /* Display mode */
  68. #define WTYPE_PROTO 5 /* Display protocol name */
  69. /************************ DISPLAY ESSID/NWID ************************/
  70. /*------------------------------------------------------------------*/
  71. /*
  72. * Display the ESSID if possible
  73. */
  74. static int
  75. print_essid(int skfd,
  76. const char * ifname,
  77. int format)
  78. {
  79. struct iwreq wrq;
  80. char essid[IW_ESSID_MAX_SIZE + 1]; /* ESSID */
  81. char pessid[IW_ESSID_MAX_SIZE + 1]; /* Pcmcia format */
  82. unsigned int i;
  83. unsigned int j;
  84. /* Make sure ESSID is always NULL terminated */
  85. memset(essid, 0, sizeof(essid));
  86. /* Get ESSID */
  87. wrq.u.essid.pointer = (caddr_t) essid;
  88. wrq.u.essid.length = IW_ESSID_MAX_SIZE + 1;
  89. wrq.u.essid.flags = 0;
  90. if(iw_get_ext(skfd, ifname, SIOCGIWESSID, &wrq) < 0)
  91. return(-1);
  92. switch(format)
  93. {
  94. case FORMAT_SCHEME:
  95. /* Strip all white space and stuff */
  96. j = 0;
  97. for(i = 0; i < strlen(essid); i++)
  98. if(isalnum(essid[i]))
  99. pessid[j++] = essid[i];
  100. pessid[j] = '\0';
  101. if((j == 0) || (j > 32))
  102. return(-2);
  103. printf("%s\n", pessid);
  104. break;
  105. case FORMAT_RAW:
  106. printf("%s\n", essid);
  107. break;
  108. default:
  109. printf("%-8.16s ESSID:\"%s\"\n", ifname, essid);
  110. break;
  111. }
  112. return(0);
  113. }
  114. /*------------------------------------------------------------------*/
  115. /*
  116. * Display the NWID if possible
  117. */
  118. static int
  119. print_nwid(int skfd,
  120. const char * ifname,
  121. int format)
  122. {
  123. struct iwreq wrq;
  124. /* Get network ID */
  125. if(iw_get_ext(skfd, ifname, SIOCGIWNWID, &wrq) < 0)
  126. return(-1);
  127. switch(format)
  128. {
  129. case FORMAT_SCHEME:
  130. /* Prefix with nwid to avoid name space collisions */
  131. printf("nwid%X\n", wrq.u.nwid.value);
  132. break;
  133. case FORMAT_RAW:
  134. printf("%X\n", wrq.u.nwid.value);
  135. break;
  136. default:
  137. printf("%-8.16s NWID:%X\n", ifname, wrq.u.nwid.value);
  138. break;
  139. }
  140. return(0);
  141. }
  142. /**************************** AP ADDRESS ****************************/
  143. /*------------------------------------------------------------------*/
  144. /*
  145. * Display the AP Address if possible
  146. */
  147. static int
  148. print_ap(int skfd,
  149. const char * ifname,
  150. int format)
  151. {
  152. struct iwreq wrq;
  153. char buffer[64];
  154. /* Get AP Address */
  155. if(iw_get_ext(skfd, ifname, SIOCGIWAP, &wrq) < 0)
  156. return(-1);
  157. /* Print */
  158. iw_ether_ntop((const struct ether_addr *) wrq.u.ap_addr.sa_data, buffer);
  159. switch(format)
  160. {
  161. case FORMAT_SCHEME:
  162. /* I think ':' are not problematic, because Pcmcia scripts
  163. * seem to handle them properly... */
  164. case FORMAT_RAW:
  165. printf("%s\n", buffer);
  166. break;
  167. default:
  168. printf("%-8.16s Access Point/Cell: %s\n", ifname, buffer);
  169. break;
  170. }
  171. return(0);
  172. }
  173. /****************************** OTHER ******************************/
  174. /*------------------------------------------------------------------*/
  175. /*
  176. * Display the frequency (or channel) if possible
  177. */
  178. static int
  179. print_freq(int skfd,
  180. const char * ifname,
  181. int format)
  182. {
  183. struct iwreq wrq;
  184. double freq;
  185. char buffer[64];
  186. /* Get frequency / channel */
  187. if(iw_get_ext(skfd, ifname, SIOCGIWFREQ, &wrq) < 0)
  188. return(-1);
  189. /* Print */
  190. freq = iw_freq2float(&(wrq.u.freq));
  191. switch(format)
  192. {
  193. case FORMAT_SCHEME:
  194. /* Prefix with freq to avoid name space collisions */
  195. printf("freq%g\n", freq);
  196. break;
  197. case FORMAT_RAW:
  198. printf("%g\n", freq);
  199. break;
  200. default:
  201. iw_print_freq(buffer, sizeof(buffer), freq, -1, wrq.u.freq.flags);
  202. printf("%-8.16s %s\n", ifname, buffer);
  203. break;
  204. }
  205. return(0);
  206. }
  207. /*------------------------------------------------------------------*/
  208. /*
  209. * Display the channel (converted from frequency) if possible
  210. */
  211. static int
  212. print_channel(int skfd,
  213. const char * ifname,
  214. int format)
  215. {
  216. struct iwreq wrq;
  217. struct iw_range range;
  218. double freq;
  219. int channel;
  220. /* Get frequency / channel */
  221. if(iw_get_ext(skfd, ifname, SIOCGIWFREQ, &wrq) < 0)
  222. return(-1);
  223. /* Convert to channel */
  224. if(iw_get_range_info(skfd, ifname, &range) < 0)
  225. return(-2);
  226. freq = iw_freq2float(&(wrq.u.freq));
  227. if(freq < KILO)
  228. channel = (int) freq;
  229. else
  230. {
  231. channel = iw_freq_to_channel(freq, &range);
  232. if(channel < 0)
  233. return(-3);
  234. }
  235. /* Print */
  236. switch(format)
  237. {
  238. case FORMAT_SCHEME:
  239. /* Prefix with freq to avoid name space collisions */
  240. printf("channel%d\n", channel);
  241. break;
  242. case FORMAT_RAW:
  243. printf("%d\n", channel);
  244. break;
  245. default:
  246. printf("%-8.16s Channel:%d\n", ifname, channel);
  247. break;
  248. }
  249. return(0);
  250. }
  251. /*------------------------------------------------------------------*/
  252. /*
  253. * Display the mode if possible
  254. */
  255. static int
  256. print_mode(int skfd,
  257. const char * ifname,
  258. int format)
  259. {
  260. struct iwreq wrq;
  261. /* Get frequency / channel */
  262. if(iw_get_ext(skfd, ifname, SIOCGIWMODE, &wrq) < 0)
  263. return(-1);
  264. if(wrq.u.mode >= IW_NUM_OPER_MODE)
  265. return(-2);
  266. /* Print */
  267. switch(format)
  268. {
  269. case FORMAT_SCHEME:
  270. /* Strip all white space and stuff */
  271. if(wrq.u.mode == IW_MODE_ADHOC)
  272. printf("AdHoc\n");
  273. else
  274. printf("%s\n", iw_operation_mode[wrq.u.mode]);
  275. break;
  276. case FORMAT_RAW:
  277. printf("%d\n", wrq.u.mode);
  278. break;
  279. default:
  280. printf("%-8.16s Mode:%s\n", ifname, iw_operation_mode[wrq.u.mode]);
  281. break;
  282. }
  283. return(0);
  284. }
  285. /*------------------------------------------------------------------*/
  286. /*
  287. * Display the ESSID if possible
  288. */
  289. static int
  290. print_protocol(int skfd,
  291. const char * ifname,
  292. int format)
  293. {
  294. struct iwreq wrq;
  295. char proto[IFNAMSIZ + 1]; /* Protocol */
  296. char pproto[IFNAMSIZ + 1]; /* Pcmcia format */
  297. unsigned int i;
  298. unsigned int j;
  299. /* Get Protocol name */
  300. if(iw_get_ext(skfd, ifname, SIOCGIWNAME, &wrq) < 0)
  301. return(-1);
  302. strncpy(proto, wrq.u.name, IFNAMSIZ);
  303. proto[IFNAMSIZ] = '\0';
  304. switch(format)
  305. {
  306. case FORMAT_SCHEME:
  307. /* Strip all white space and stuff */
  308. j = 0;
  309. for(i = 0; i < strlen(proto); i++)
  310. if(isalnum(proto[i]))
  311. pproto[j++] = proto[i];
  312. pproto[j] = '\0';
  313. if((j == 0) || (j > 32))
  314. return(-2);
  315. printf("%s\n", pproto);
  316. break;
  317. case FORMAT_RAW:
  318. printf("%s\n", proto);
  319. break;
  320. default:
  321. printf("%-8.16s Protocol Name:\"%s\"\n", ifname, proto);
  322. break;
  323. }
  324. return(0);
  325. }
  326. /******************************* MAIN ********************************/
  327. /*------------------------------------------------------------------*/
  328. /*
  329. * Check options and call the proper handler
  330. */
  331. static int
  332. print_one_device(int skfd,
  333. int format,
  334. int wtype,
  335. const char* ifname)
  336. {
  337. int ret;
  338. /* Check wtype */
  339. switch(wtype)
  340. {
  341. case WTYPE_AP:
  342. /* Try to print an AP */
  343. ret = print_ap(skfd, ifname, format);
  344. break;
  345. case WTYPE_CHANNEL:
  346. /* Try to print channel */
  347. ret = print_channel(skfd, ifname, format);
  348. break;
  349. case WTYPE_FREQ:
  350. /* Try to print frequency */
  351. ret = print_freq(skfd, ifname, format);
  352. break;
  353. case WTYPE_MODE:
  354. /* Try to print the mode */
  355. ret = print_mode(skfd, ifname, format);
  356. break;
  357. case WTYPE_PROTO:
  358. /* Try to print the protocol */
  359. ret = print_protocol(skfd, ifname, format);
  360. break;
  361. default:
  362. /* Try to print an ESSID */
  363. ret = print_essid(skfd, ifname, format);
  364. if(ret < 0)
  365. {
  366. /* Try to print a nwid */
  367. ret = print_nwid(skfd, ifname, format);
  368. }
  369. }
  370. return(ret);
  371. }
  372. /*------------------------------------------------------------------*/
  373. /*
  374. * Try the various devices until one return something we can use
  375. *
  376. * Note : we can't use iw_enum_devices() because we want a different
  377. * behaviour :
  378. * 1) Stop at the first valid wireless device
  379. * 2) Only go through active devices
  380. */
  381. static int
  382. scan_devices(int skfd,
  383. int format,
  384. int wtype)
  385. {
  386. char buff[1024];
  387. struct ifconf ifc;
  388. struct ifreq *ifr;
  389. int i;
  390. /* Get list of active devices */
  391. ifc.ifc_len = sizeof(buff);
  392. ifc.ifc_buf = buff;
  393. if(ioctl(skfd, SIOCGIFCONF, &ifc) < 0)
  394. {
  395. perror("SIOCGIFCONF");
  396. return(-1);
  397. }
  398. ifr = ifc.ifc_req;
  399. /* Print the first match */
  400. for(i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++)
  401. {
  402. if(print_one_device(skfd, format, wtype, ifr->ifr_name) >= 0)
  403. return 0;
  404. }
  405. return(-1);
  406. }
  407. /*------------------------------------------------------------------*/
  408. /*
  409. * helper
  410. */
  411. static void
  412. iw_usage(int status)
  413. {
  414. fputs("Usage iwgetid [OPTIONS] [ifname]\n"
  415. " Options are:\n"
  416. " -a,--ap Print the access point address\n"
  417. " -c,--channel Print the current channel\n"
  418. " -f,--freq Print the current frequency\n"
  419. " -m,--mode Print the current mode\n"
  420. " -p,--protocol Print the protocol name\n"
  421. " -r,--raw Format the output as raw value for shell scripts\n"
  422. " -s,--scheme Format the output as a PCMCIA scheme identifier\n"
  423. " -h,--help Print this message\n",
  424. status ? stderr : stdout);
  425. exit(status);
  426. }
  427. static const struct option long_opts[] = {
  428. { "ap", no_argument, NULL, 'a' },
  429. { "channel", no_argument, NULL, 'c' },
  430. { "freq", no_argument, NULL, 'f' },
  431. { "mode", no_argument, NULL, 'm' },
  432. { "protocol", no_argument, NULL, 'p' },
  433. { "help", no_argument, NULL, 'h' },
  434. { "raw", no_argument, NULL, 'r' },
  435. { "scheme", no_argument, NULL, 's' },
  436. { NULL, 0, NULL, 0 }
  437. };
  438. /*------------------------------------------------------------------*/
  439. /*
  440. * The main !
  441. */
  442. int
  443. main(int argc,
  444. char ** argv)
  445. {
  446. int skfd; /* generic raw socket desc. */
  447. int format = FORMAT_DEFAULT;
  448. int wtype = WTYPE_ESSID;
  449. int opt;
  450. int ret = -1;
  451. /* Check command line arguments */
  452. while((opt = getopt_long(argc, argv, "acfhmprs", long_opts, NULL)) > 0)
  453. {
  454. switch(opt)
  455. {
  456. case 'a':
  457. /* User wants AP/Cell Address */
  458. wtype = WTYPE_AP;
  459. break;
  460. case 'c':
  461. /* User wants channel only */
  462. wtype = WTYPE_CHANNEL;
  463. break;
  464. case 'f':
  465. /* User wants frequency/channel */
  466. wtype = WTYPE_FREQ;
  467. break;
  468. case 'm':
  469. /* User wants the mode */
  470. wtype = WTYPE_MODE;
  471. break;
  472. case 'p':
  473. /* User wants the protocol */
  474. wtype = WTYPE_PROTO;
  475. break;
  476. case 'h':
  477. iw_usage(0);
  478. break;
  479. case 'r':
  480. /* User wants a Raw format */
  481. format = FORMAT_RAW;
  482. break;
  483. case 's':
  484. /* User wants a Scheme format */
  485. format = FORMAT_SCHEME;
  486. break;
  487. default:
  488. iw_usage(1);
  489. break;
  490. }
  491. }
  492. if(optind + 1 < argc) {
  493. fputs("Too many arguments.\n", stderr);
  494. iw_usage(1);
  495. }
  496. /* Create a channel to the NET kernel. */
  497. if((skfd = iw_sockets_open()) < 0)
  498. {
  499. perror("socket");
  500. return(-1);
  501. }
  502. /* Check if first argument is a device name */
  503. if(optind < argc)
  504. {
  505. /* Yes : query only this device */
  506. ret = print_one_device(skfd, format, wtype, argv[optind]);
  507. }
  508. else
  509. {
  510. /* No : query all devices and print first found */
  511. ret = scan_devices(skfd, format, wtype);
  512. }
  513. fflush(stdout);
  514. iw_sockets_close(skfd);
  515. return(ret);
  516. }