iwevent.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804
  1. /*
  2. * Wireless Tools
  3. *
  4. * Jean II - HPL 99->04
  5. *
  6. * Main code for "iwevent". This listent for wireless events on rtnetlink.
  7. * You need to link this code against "iwcommon.c" and "-lm".
  8. *
  9. * Part of this code is from Alexey Kuznetsov, part is from Casey Carter,
  10. * I've just put the pieces together...
  11. * By the way, if you know a way to remove the root restrictions, tell me
  12. * about it...
  13. *
  14. * This file is released under the GPL license.
  15. * Copyright (c) 1997-2004 Jean Tourrilhes <jt@hpl.hp.com>
  16. */
  17. /***************************** INCLUDES *****************************/
  18. #include "iwlib.h" /* Header */
  19. #include <linux/netlink.h>
  20. #include <linux/rtnetlink.h>
  21. #include <getopt.h>
  22. #include <time.h>
  23. #include <sys/time.h>
  24. /* Ugly backward compatibility :-( */
  25. #ifndef IFLA_WIRELESS
  26. #define IFLA_WIRELESS (IFLA_MASTER + 1)
  27. #endif /* IFLA_WIRELESS */
  28. /****************************** TYPES ******************************/
  29. /*
  30. * Static information about wireless interface.
  31. * We cache this info for performance reason.
  32. */
  33. typedef struct wireless_iface
  34. {
  35. /* Linked list */
  36. struct wireless_iface * next;
  37. /* Interface identification */
  38. int ifindex; /* Interface index == black magic */
  39. /* Interface data */
  40. char ifname[IFNAMSIZ + 1]; /* Interface name */
  41. struct iw_range range; /* Wireless static data */
  42. int has_range;
  43. } wireless_iface;
  44. /**************************** VARIABLES ****************************/
  45. /* Cache of wireless interfaces */
  46. struct wireless_iface * interface_cache = NULL;
  47. /************************ RTNETLINK HELPERS ************************/
  48. /*
  49. * The following code is extracted from :
  50. * ----------------------------------------------
  51. * libnetlink.c RTnetlink service routines.
  52. *
  53. * This program is free software; you can redistribute it and/or
  54. * modify it under the terms of the GNU General Public License
  55. * as published by the Free Software Foundation; either version
  56. * 2 of the License, or (at your option) any later version.
  57. *
  58. * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  59. * -----------------------------------------------
  60. */
  61. struct rtnl_handle
  62. {
  63. int fd;
  64. struct sockaddr_nl local;
  65. struct sockaddr_nl peer;
  66. __u32 seq;
  67. __u32 dump;
  68. };
  69. static inline void rtnl_close(struct rtnl_handle *rth)
  70. {
  71. close(rth->fd);
  72. }
  73. static inline int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions)
  74. {
  75. int addr_len;
  76. memset(rth, 0, sizeof(rth));
  77. rth->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
  78. if (rth->fd < 0) {
  79. perror("Cannot open netlink socket");
  80. return -1;
  81. }
  82. memset(&rth->local, 0, sizeof(rth->local));
  83. rth->local.nl_family = AF_NETLINK;
  84. rth->local.nl_groups = subscriptions;
  85. if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) {
  86. perror("Cannot bind netlink socket");
  87. return -1;
  88. }
  89. addr_len = sizeof(rth->local);
  90. if (getsockname(rth->fd, (struct sockaddr*)&rth->local,
  91. (socklen_t *) &addr_len) < 0) {
  92. perror("Cannot getsockname");
  93. return -1;
  94. }
  95. if (addr_len != sizeof(rth->local)) {
  96. fprintf(stderr, "Wrong address length %d\n", addr_len);
  97. return -1;
  98. }
  99. if (rth->local.nl_family != AF_NETLINK) {
  100. fprintf(stderr, "Wrong address family %d\n", rth->local.nl_family);
  101. return -1;
  102. }
  103. rth->seq = time(NULL);
  104. return 0;
  105. }
  106. /******************* WIRELESS INTERFACE DATABASE *******************/
  107. /*
  108. * We keep a few information about each wireless interface on the
  109. * system. This avoid to query this info at each event, therefore
  110. * reducing overhead.
  111. *
  112. * Each interface is indexed by the 'ifindex'. As opposed to interface
  113. * names, 'ifindex' are never reused (even if you reactivate the same
  114. * hardware), so the data we cache will never apply to the wrong
  115. * interface.
  116. * Because of that, we are pretty lazy when it come to purging the
  117. * cache...
  118. */
  119. /*------------------------------------------------------------------*/
  120. /*
  121. * Get name of interface based on interface index...
  122. */
  123. static inline int
  124. index2name(int skfd,
  125. int ifindex,
  126. char * name)
  127. {
  128. struct ifreq irq;
  129. int ret = 0;
  130. memset(name, 0, IFNAMSIZ + 1);
  131. /* Get interface name */
  132. irq.ifr_ifindex = ifindex;
  133. if(ioctl(skfd, SIOCGIFNAME, &irq) < 0)
  134. ret = -1;
  135. else
  136. strncpy(name, irq.ifr_name, IFNAMSIZ);
  137. return(ret);
  138. }
  139. /*------------------------------------------------------------------*/
  140. /*
  141. * Get interface data from cache or live interface
  142. */
  143. static struct wireless_iface *
  144. iw_get_interface_data(int ifindex)
  145. {
  146. struct wireless_iface * curr;
  147. int skfd = -1; /* ioctl socket */
  148. /* Search for it in the database */
  149. curr = interface_cache;
  150. while(curr != NULL)
  151. {
  152. /* Match ? */
  153. if(curr->ifindex == ifindex)
  154. {
  155. //printf("Cache : found %d-%s\n", curr->ifindex, curr->ifname);
  156. /* Return */
  157. return(curr);
  158. }
  159. /* Next entry */
  160. curr = curr->next;
  161. }
  162. /* Create a channel to the NET kernel. Doesn't happen too often, so
  163. * socket creation overhead is minimal... */
  164. if((skfd = iw_sockets_open()) < 0)
  165. {
  166. perror("iw_sockets_open");
  167. return(NULL);
  168. }
  169. /* Create new entry, zero, init */
  170. curr = calloc(1, sizeof(struct wireless_iface));
  171. if(!curr)
  172. {
  173. fprintf(stderr, "Malloc failed\n");
  174. return(NULL);
  175. }
  176. curr->ifindex = ifindex;
  177. /* Extract static data */
  178. if(index2name(skfd, ifindex, curr->ifname) < 0)
  179. {
  180. perror("index2name");
  181. free(curr);
  182. return(NULL);
  183. }
  184. curr->has_range = (iw_get_range_info(skfd, curr->ifname, &curr->range) >= 0);
  185. //printf("Cache : create %d-%s\n", curr->ifindex, curr->ifname);
  186. /* Done */
  187. iw_sockets_close(skfd);
  188. /* Link it */
  189. curr->next = interface_cache;
  190. interface_cache = curr;
  191. return(curr);
  192. }
  193. /*------------------------------------------------------------------*/
  194. /*
  195. * Remove interface data from cache (if it exist)
  196. */
  197. static void
  198. iw_del_interface_data(int ifindex)
  199. {
  200. struct wireless_iface * curr;
  201. struct wireless_iface * prev = NULL;
  202. struct wireless_iface * next;
  203. /* Go through the list, find the interface, kills it */
  204. curr = interface_cache;
  205. while(curr)
  206. {
  207. next = curr->next;
  208. /* Got a match ? */
  209. if(curr->ifindex == ifindex)
  210. {
  211. /* Unlink. Root ? */
  212. if(!prev)
  213. interface_cache = next;
  214. else
  215. prev->next = next;
  216. //printf("Cache : purge %d-%s\n", curr->ifindex, curr->ifname);
  217. /* Destroy */
  218. free(curr);
  219. }
  220. else
  221. {
  222. /* Keep as previous */
  223. prev = curr;
  224. }
  225. /* Next entry */
  226. curr = next;
  227. }
  228. }
  229. /********************* WIRELESS EVENT DECODING *********************/
  230. /*
  231. * Parse the Wireless Event and print it out
  232. */
  233. /*------------------------------------------------------------------*/
  234. /*
  235. * Dump a buffer as a serie of hex
  236. * Maybe should go in iwlib...
  237. * Maybe we should have better formatting like iw_print_key...
  238. */
  239. static char *
  240. iw_hexdump(char * buf,
  241. size_t buflen,
  242. const unsigned char *data,
  243. size_t datalen)
  244. {
  245. size_t i;
  246. char * pos = buf;
  247. for(i = 0; i < datalen; i++)
  248. pos += snprintf(pos, buf + buflen - pos, "%02X", data[i]);
  249. return buf;
  250. }
  251. /*------------------------------------------------------------------*/
  252. /*
  253. * Print one element from the scanning results
  254. */
  255. static inline int
  256. print_event_token(struct iw_event * event, /* Extracted token */
  257. struct iw_range * iw_range, /* Range info */
  258. int has_range)
  259. {
  260. char buffer[128]; /* Temporary buffer */
  261. char buffer2[30]; /* Temporary buffer */
  262. char * prefix = (IW_IS_GET(event->cmd) ? "New" : "Set");
  263. /* Now, let's decode the event */
  264. switch(event->cmd)
  265. {
  266. /* ----- set events ----- */
  267. /* Events that result from a "SET XXX" operation by the user */
  268. case SIOCSIWNWID:
  269. if(event->u.nwid.disabled)
  270. printf("Set NWID:off/any\n");
  271. else
  272. printf("Set NWID:%X\n", event->u.nwid.value);
  273. break;
  274. case SIOCSIWFREQ:
  275. case SIOCGIWFREQ:
  276. {
  277. double freq; /* Frequency/channel */
  278. int channel = -1; /* Converted to channel */
  279. freq = iw_freq2float(&(event->u.freq));
  280. if(has_range)
  281. {
  282. if(freq < KILO)
  283. /* Convert channel to frequency if possible */
  284. channel = iw_channel_to_freq((int) freq, &freq, iw_range);
  285. else
  286. /* Convert frequency to channel if possible */
  287. channel = iw_freq_to_channel(freq, iw_range);
  288. }
  289. iw_print_freq(buffer, sizeof(buffer),
  290. freq, channel, event->u.freq.flags);
  291. printf("%s %s\n", prefix, buffer);
  292. }
  293. break;
  294. case SIOCSIWMODE:
  295. printf("Set Mode:%s\n",
  296. iw_operation_mode[event->u.mode]);
  297. break;
  298. case SIOCSIWESSID:
  299. case SIOCGIWESSID:
  300. {
  301. char essid[IW_ESSID_MAX_SIZE+1];
  302. memset(essid, '\0', sizeof(essid));
  303. if((event->u.essid.pointer) && (event->u.essid.length))
  304. memcpy(essid, event->u.essid.pointer, event->u.essid.length);
  305. if(event->u.essid.flags)
  306. {
  307. /* Does it have an ESSID index ? */
  308. if((event->u.essid.flags & IW_ENCODE_INDEX) > 1)
  309. printf("%s ESSID:\"%s\" [%d]\n", prefix, essid,
  310. (event->u.essid.flags & IW_ENCODE_INDEX));
  311. else
  312. printf("%s ESSID:\"%s\"\n", prefix, essid);
  313. }
  314. else
  315. printf("%s ESSID:off/any\n", prefix);
  316. }
  317. break;
  318. case SIOCSIWENCODE:
  319. {
  320. unsigned char key[IW_ENCODING_TOKEN_MAX];
  321. if(event->u.data.pointer)
  322. memcpy(key, event->u.data.pointer, event->u.data.length);
  323. else
  324. event->u.data.flags |= IW_ENCODE_NOKEY;
  325. printf("Set Encryption key:");
  326. if(event->u.data.flags & IW_ENCODE_DISABLED)
  327. printf("off\n");
  328. else
  329. {
  330. /* Display the key */
  331. iw_print_key(buffer, sizeof(buffer), key, event->u.data.length,
  332. event->u.data.flags);
  333. printf("%s", buffer);
  334. /* Other info... */
  335. if((event->u.data.flags & IW_ENCODE_INDEX) > 1)
  336. printf(" [%d]", event->u.data.flags & IW_ENCODE_INDEX);
  337. if(event->u.data.flags & IW_ENCODE_RESTRICTED)
  338. printf(" Security mode:restricted");
  339. if(event->u.data.flags & IW_ENCODE_OPEN)
  340. printf(" Security mode:open");
  341. printf("\n");
  342. }
  343. }
  344. break;
  345. /* ----- driver events ----- */
  346. /* Events generated by the driver when something important happens */
  347. case SIOCGIWAP:
  348. printf("New Access Point/Cell address:%s\n",
  349. iw_sawap_ntop(&event->u.ap_addr, buffer));
  350. break;
  351. case SIOCGIWSCAN:
  352. printf("Scan request completed\n");
  353. break;
  354. case IWEVTXDROP:
  355. printf("Tx packet dropped:%s\n",
  356. iw_saether_ntop(&event->u.addr, buffer));
  357. break;
  358. case IWEVCUSTOM:
  359. {
  360. char custom[IW_CUSTOM_MAX+1];
  361. memset(custom, '\0', sizeof(custom));
  362. if((event->u.data.pointer) && (event->u.data.length))
  363. memcpy(custom, event->u.data.pointer, event->u.data.length);
  364. printf("Custom driver event:%s\n", custom);
  365. }
  366. break;
  367. case IWEVREGISTERED:
  368. printf("Registered node:%s\n",
  369. iw_saether_ntop(&event->u.addr, buffer));
  370. break;
  371. case IWEVEXPIRED:
  372. printf("Expired node:%s\n",
  373. iw_saether_ntop(&event->u.addr, buffer));
  374. break;
  375. case SIOCGIWTHRSPY:
  376. {
  377. struct iw_thrspy threshold;
  378. if((event->u.data.pointer) && (event->u.data.length))
  379. {
  380. memcpy(&threshold, event->u.data.pointer,
  381. sizeof(struct iw_thrspy));
  382. printf("Spy threshold crossed on address:%s\n",
  383. iw_saether_ntop(&threshold.addr, buffer));
  384. iw_print_stats(buffer, sizeof(buffer),
  385. &threshold.qual, iw_range, has_range);
  386. printf(" Link %s\n", buffer);
  387. }
  388. else
  389. printf("Invalid Spy Threshold event\n");
  390. }
  391. break;
  392. /* ----- driver WPA events ----- */
  393. /* Events generated by the driver, used for WPA operation */
  394. case IWEVMICHAELMICFAILURE:
  395. if(event->u.data.length >= sizeof(struct iw_michaelmicfailure))
  396. {
  397. struct iw_michaelmicfailure mf;
  398. memcpy(&mf, event->u.data.pointer, sizeof(mf));
  399. printf("Michael MIC failure flags:0x%X src_addr:%s tsc:%s\n",
  400. mf.flags,
  401. iw_saether_ntop(&mf.src_addr, buffer2),
  402. iw_hexdump(buffer, sizeof(buffer),
  403. mf.tsc, IW_ENCODE_SEQ_MAX_SIZE));
  404. }
  405. break;
  406. case IWEVASSOCREQIE:
  407. printf("Association Request IEs:%s\n",
  408. iw_hexdump(buffer, sizeof(buffer),
  409. event->u.data.pointer, event->u.data.length));
  410. break;
  411. case IWEVASSOCRESPIE:
  412. printf("Association Response IEs:%s\n",
  413. iw_hexdump(buffer, sizeof(buffer),
  414. event->u.data.pointer, event->u.data.length));
  415. break;
  416. case IWEVPMKIDCAND:
  417. if(event->u.data.length >= sizeof(struct iw_pmkid_cand))
  418. {
  419. struct iw_pmkid_cand cand;
  420. memcpy(&cand, event->u.data.pointer, sizeof(cand));
  421. printf("PMKID candidate flags:0x%X index:%d bssid:%s\n",
  422. cand.flags, cand.index,
  423. iw_saether_ntop(&cand.bssid, buffer));
  424. }
  425. break;
  426. /* ----- junk ----- */
  427. /* other junk not currently in use */
  428. case SIOCGIWRATE:
  429. iw_print_bitrate(buffer, sizeof(buffer), event->u.bitrate.value);
  430. printf("New Bit Rate:%s\n", buffer);
  431. break;
  432. case SIOCGIWNAME:
  433. printf("Protocol:%-1.16s\n", event->u.name);
  434. break;
  435. case IWEVQUAL:
  436. {
  437. event->u.qual.updated = 0x0; /* Not that reliable, disable */
  438. iw_print_stats(buffer, sizeof(buffer),
  439. &event->u.qual, iw_range, has_range);
  440. printf("Link %s\n", buffer);
  441. break;
  442. }
  443. default:
  444. printf("(Unknown Wireless event 0x%04X)\n", event->cmd);
  445. } /* switch(event->cmd) */
  446. return(0);
  447. }
  448. /*------------------------------------------------------------------*/
  449. /*
  450. * Print out all Wireless Events part of the RTNetlink message
  451. * Most often, there will be only one event per message, but
  452. * just make sure we read everything...
  453. */
  454. static inline int
  455. print_event_stream(int ifindex,
  456. char * data,
  457. int len)
  458. {
  459. struct iw_event iwe;
  460. struct stream_descr stream;
  461. int i = 0;
  462. int ret;
  463. char buffer[64];
  464. struct timeval recv_time;
  465. struct timezone tz;
  466. struct wireless_iface * wireless_data;
  467. /* Get data from cache */
  468. wireless_data = iw_get_interface_data(ifindex);
  469. if(wireless_data == NULL)
  470. return(-1);
  471. /* Print received time in readable form */
  472. gettimeofday(&recv_time, &tz);
  473. iw_print_timeval(buffer, sizeof(buffer), &recv_time, &tz);
  474. iw_init_event_stream(&stream, data, len);
  475. do
  476. {
  477. /* Extract an event and print it */
  478. ret = iw_extract_event_stream(&stream, &iwe,
  479. wireless_data->range.we_version_compiled);
  480. if(ret != 0)
  481. {
  482. if(i++ == 0)
  483. printf("%s %-8.16s ", buffer, wireless_data->ifname);
  484. else
  485. printf(" ");
  486. if(ret > 0)
  487. print_event_token(&iwe,
  488. &wireless_data->range, wireless_data->has_range);
  489. else
  490. printf("(Invalid event)\n");
  491. /* Push data out *now*, in case we are redirected to a pipe */
  492. fflush(stdout);
  493. }
  494. }
  495. while(ret > 0);
  496. return(0);
  497. }
  498. /*********************** RTNETLINK EVENT DUMP***********************/
  499. /*
  500. * Dump the events we receive from rtnetlink
  501. * This code is mostly from Casey
  502. */
  503. /*------------------------------------------------------------------*/
  504. /*
  505. * Respond to a single RTM_NEWLINK event from the rtnetlink socket.
  506. */
  507. static int
  508. LinkCatcher(struct nlmsghdr *nlh)
  509. {
  510. struct ifinfomsg* ifi;
  511. #if 0
  512. fprintf(stderr, "nlmsg_type = %d.\n", nlh->nlmsg_type);
  513. #endif
  514. ifi = NLMSG_DATA(nlh);
  515. /* Code is ugly, but sort of works - Jean II */
  516. /* If interface is getting destoyed */
  517. if(nlh->nlmsg_type == RTM_DELLINK)
  518. {
  519. /* Remove from cache (if in cache) */
  520. iw_del_interface_data(ifi->ifi_index);
  521. return 0;
  522. }
  523. /* Only keep add/change events */
  524. if(nlh->nlmsg_type != RTM_NEWLINK)
  525. return 0;
  526. /* Check for attributes */
  527. if (nlh->nlmsg_len > NLMSG_ALIGN(sizeof(struct ifinfomsg)))
  528. {
  529. int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(sizeof(struct ifinfomsg));
  530. struct rtattr *attr = (void *) ((char *) ifi +
  531. NLMSG_ALIGN(sizeof(struct ifinfomsg)));
  532. while (RTA_OK(attr, attrlen))
  533. {
  534. /* Check if the Wireless kind */
  535. if(attr->rta_type == IFLA_WIRELESS)
  536. {
  537. /* Go to display it */
  538. print_event_stream(ifi->ifi_index,
  539. (char *) attr + RTA_ALIGN(sizeof(struct rtattr)),
  540. attr->rta_len - RTA_ALIGN(sizeof(struct rtattr)));
  541. }
  542. attr = RTA_NEXT(attr, attrlen);
  543. }
  544. }
  545. return 0;
  546. }
  547. /* ---------------------------------------------------------------- */
  548. /*
  549. * We must watch the rtnelink socket for events.
  550. * This routine handles those events (i.e., call this when rth.fd
  551. * is ready to read).
  552. */
  553. static inline void
  554. handle_netlink_events(struct rtnl_handle * rth)
  555. {
  556. while(1)
  557. {
  558. struct sockaddr_nl sanl;
  559. socklen_t sanllen = sizeof(struct sockaddr_nl);
  560. struct nlmsghdr *h;
  561. int amt;
  562. char buf[8192];
  563. amt = recvfrom(rth->fd, buf, sizeof(buf), MSG_DONTWAIT, (struct sockaddr*)&sanl, &sanllen);
  564. if(amt < 0)
  565. {
  566. if(errno != EINTR && errno != EAGAIN)
  567. {
  568. fprintf(stderr, "%s: error reading netlink: %s.\n",
  569. __PRETTY_FUNCTION__, strerror(errno));
  570. }
  571. return;
  572. }
  573. if(amt == 0)
  574. {
  575. fprintf(stderr, "%s: EOF on netlink??\n", __PRETTY_FUNCTION__);
  576. return;
  577. }
  578. h = (struct nlmsghdr*)buf;
  579. while(amt >= (int)sizeof(*h))
  580. {
  581. int len = h->nlmsg_len;
  582. int l = len - sizeof(*h);
  583. if(l < 0 || len > amt)
  584. {
  585. fprintf(stderr, "%s: malformed netlink message: len=%d\n", __PRETTY_FUNCTION__, len);
  586. break;
  587. }
  588. switch(h->nlmsg_type)
  589. {
  590. case RTM_NEWLINK:
  591. case RTM_DELLINK:
  592. LinkCatcher(h);
  593. break;
  594. default:
  595. #if 0
  596. fprintf(stderr, "%s: got nlmsg of type %#x.\n", __PRETTY_FUNCTION__, h->nlmsg_type);
  597. #endif
  598. break;
  599. }
  600. len = NLMSG_ALIGN(len);
  601. amt -= len;
  602. h = (struct nlmsghdr*)((char*)h + len);
  603. }
  604. if(amt > 0)
  605. fprintf(stderr, "%s: remnant of size %d on netlink\n", __PRETTY_FUNCTION__, amt);
  606. }
  607. }
  608. /**************************** MAIN LOOP ****************************/
  609. /* ---------------------------------------------------------------- */
  610. /*
  611. * Wait until we get an event
  612. */
  613. static inline int
  614. wait_for_event(struct rtnl_handle * rth)
  615. {
  616. #if 0
  617. struct timeval tv; /* Select timeout */
  618. #endif
  619. /* Forever */
  620. while(1)
  621. {
  622. fd_set rfds; /* File descriptors for select */
  623. int last_fd; /* Last fd */
  624. int ret;
  625. /* Guess what ? We must re-generate rfds each time */
  626. FD_ZERO(&rfds);
  627. FD_SET(rth->fd, &rfds);
  628. last_fd = rth->fd;
  629. /* Wait until something happens */
  630. ret = select(last_fd + 1, &rfds, NULL, NULL, NULL);
  631. /* Check if there was an error */
  632. if(ret < 0)
  633. {
  634. if(errno == EAGAIN || errno == EINTR)
  635. continue;
  636. fprintf(stderr, "Unhandled signal - exiting...\n");
  637. break;
  638. }
  639. /* Check if there was a timeout */
  640. if(ret == 0)
  641. {
  642. continue;
  643. }
  644. /* Check for interface discovery events. */
  645. if(FD_ISSET(rth->fd, &rfds))
  646. handle_netlink_events(rth);
  647. }
  648. return(0);
  649. }
  650. /******************************* MAIN *******************************/
  651. /* ---------------------------------------------------------------- */
  652. /*
  653. * helper ;-)
  654. */
  655. static void
  656. iw_usage(int status)
  657. {
  658. fputs("Usage: iwevent [OPTIONS]\n"
  659. " Monitors and displays Wireless Events.\n"
  660. " Options are:\n"
  661. " -h,--help Print this message.\n"
  662. " -v,--version Show version of this program.\n",
  663. status ? stderr : stdout);
  664. exit(status);
  665. }
  666. /* Command line options */
  667. static const struct option long_opts[] = {
  668. { "help", no_argument, NULL, 'h' },
  669. { "version", no_argument, NULL, 'v' },
  670. { NULL, 0, NULL, 0 }
  671. };
  672. /* ---------------------------------------------------------------- */
  673. /*
  674. * main body of the program
  675. */
  676. int
  677. main(int argc,
  678. char * argv[])
  679. {
  680. struct rtnl_handle rth;
  681. int opt;
  682. /* Check command line options */
  683. while((opt = getopt_long(argc, argv, "hv", long_opts, NULL)) > 0)
  684. {
  685. switch(opt)
  686. {
  687. case 'h':
  688. iw_usage(0);
  689. break;
  690. case 'v':
  691. return(iw_print_version_info("iwevent"));
  692. break;
  693. default:
  694. iw_usage(1);
  695. break;
  696. }
  697. }
  698. if(optind < argc)
  699. {
  700. fputs("Too many arguments.\n", stderr);
  701. iw_usage(1);
  702. }
  703. /* Open netlink channel */
  704. if(rtnl_open(&rth, RTMGRP_LINK) < 0)
  705. {
  706. perror("Can't initialize rtnetlink socket");
  707. return(1);
  708. }
  709. fprintf(stderr, "Waiting for Wireless Events from interfaces...\n");
  710. /* Do what we have to do */
  711. wait_for_event(&rth);
  712. /* Cleanup - only if you are pedantic */
  713. rtnl_close(&rth);
  714. return(0);
  715. }