wext-spy.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. /*
  2. * This file implement the Wireless Extensions spy API.
  3. *
  4. * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
  5. * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved.
  6. *
  7. * (As all part of the Linux kernel, this file is GPL)
  8. */
  9. #include <linux/wireless.h>
  10. #include <linux/netdevice.h>
  11. #include <linux/etherdevice.h>
  12. #include <linux/export.h>
  13. #include <net/iw_handler.h>
  14. #include <net/arp.h>
  15. #include <net/wext.h>
  16. static inline struct iw_spy_data *get_spydata(struct net_device *dev)
  17. {
  18. /* This is the new way */
  19. if (dev->wireless_data)
  20. return dev->wireless_data->spy_data;
  21. return NULL;
  22. }
  23. int iw_handler_set_spy(struct net_device * dev,
  24. struct iw_request_info * info,
  25. union iwreq_data * wrqu,
  26. char * extra)
  27. {
  28. struct iw_spy_data * spydata = get_spydata(dev);
  29. struct sockaddr * address = (struct sockaddr *) extra;
  30. /* Make sure driver is not buggy or using the old API */
  31. if (!spydata)
  32. return -EOPNOTSUPP;
  33. /* Disable spy collection while we copy the addresses.
  34. * While we copy addresses, any call to wireless_spy_update()
  35. * will NOP. This is OK, as anyway the addresses are changing. */
  36. spydata->spy_number = 0;
  37. /* We want to operate without locking, because wireless_spy_update()
  38. * most likely will happen in the interrupt handler, and therefore
  39. * have its own locking constraints and needs performance.
  40. * The rtnl_lock() make sure we don't race with the other iw_handlers.
  41. * This make sure wireless_spy_update() "see" that the spy list
  42. * is temporarily disabled. */
  43. smp_wmb();
  44. /* Are there are addresses to copy? */
  45. if (wrqu->data.length > 0) {
  46. int i;
  47. /* Copy addresses */
  48. for (i = 0; i < wrqu->data.length; i++)
  49. memcpy(spydata->spy_address[i], address[i].sa_data,
  50. ETH_ALEN);
  51. /* Reset stats */
  52. memset(spydata->spy_stat, 0,
  53. sizeof(struct iw_quality) * IW_MAX_SPY);
  54. }
  55. /* Make sure above is updated before re-enabling */
  56. smp_wmb();
  57. /* Enable addresses */
  58. spydata->spy_number = wrqu->data.length;
  59. return 0;
  60. }
  61. EXPORT_SYMBOL(iw_handler_set_spy);
  62. int iw_handler_get_spy(struct net_device * dev,
  63. struct iw_request_info * info,
  64. union iwreq_data * wrqu,
  65. char * extra)
  66. {
  67. struct iw_spy_data * spydata = get_spydata(dev);
  68. struct sockaddr * address = (struct sockaddr *) extra;
  69. int i;
  70. /* Make sure driver is not buggy or using the old API */
  71. if (!spydata)
  72. return -EOPNOTSUPP;
  73. wrqu->data.length = spydata->spy_number;
  74. /* Copy addresses. */
  75. for (i = 0; i < spydata->spy_number; i++) {
  76. memcpy(address[i].sa_data, spydata->spy_address[i], ETH_ALEN);
  77. address[i].sa_family = AF_UNIX;
  78. }
  79. /* Copy stats to the user buffer (just after). */
  80. if (spydata->spy_number > 0)
  81. memcpy(extra + (sizeof(struct sockaddr) *spydata->spy_number),
  82. spydata->spy_stat,
  83. sizeof(struct iw_quality) * spydata->spy_number);
  84. /* Reset updated flags. */
  85. for (i = 0; i < spydata->spy_number; i++)
  86. spydata->spy_stat[i].updated &= ~IW_QUAL_ALL_UPDATED;
  87. return 0;
  88. }
  89. EXPORT_SYMBOL(iw_handler_get_spy);
  90. /*------------------------------------------------------------------*/
  91. /*
  92. * Standard Wireless Handler : set spy threshold
  93. */
  94. int iw_handler_set_thrspy(struct net_device * dev,
  95. struct iw_request_info *info,
  96. union iwreq_data * wrqu,
  97. char * extra)
  98. {
  99. struct iw_spy_data * spydata = get_spydata(dev);
  100. struct iw_thrspy * threshold = (struct iw_thrspy *) extra;
  101. /* Make sure driver is not buggy or using the old API */
  102. if (!spydata)
  103. return -EOPNOTSUPP;
  104. /* Just do it */
  105. memcpy(&(spydata->spy_thr_low), &(threshold->low),
  106. 2 * sizeof(struct iw_quality));
  107. /* Clear flag */
  108. memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under));
  109. return 0;
  110. }
  111. EXPORT_SYMBOL(iw_handler_set_thrspy);
  112. /*------------------------------------------------------------------*/
  113. /*
  114. * Standard Wireless Handler : get spy threshold
  115. */
  116. int iw_handler_get_thrspy(struct net_device * dev,
  117. struct iw_request_info *info,
  118. union iwreq_data * wrqu,
  119. char * extra)
  120. {
  121. struct iw_spy_data * spydata = get_spydata(dev);
  122. struct iw_thrspy * threshold = (struct iw_thrspy *) extra;
  123. /* Make sure driver is not buggy or using the old API */
  124. if (!spydata)
  125. return -EOPNOTSUPP;
  126. /* Just do it */
  127. memcpy(&(threshold->low), &(spydata->spy_thr_low),
  128. 2 * sizeof(struct iw_quality));
  129. return 0;
  130. }
  131. EXPORT_SYMBOL(iw_handler_get_thrspy);
  132. /*------------------------------------------------------------------*/
  133. /*
  134. * Prepare and send a Spy Threshold event
  135. */
  136. static void iw_send_thrspy_event(struct net_device * dev,
  137. struct iw_spy_data * spydata,
  138. unsigned char * address,
  139. struct iw_quality * wstats)
  140. {
  141. union iwreq_data wrqu;
  142. struct iw_thrspy threshold;
  143. /* Init */
  144. wrqu.data.length = 1;
  145. wrqu.data.flags = 0;
  146. /* Copy address */
  147. memcpy(threshold.addr.sa_data, address, ETH_ALEN);
  148. threshold.addr.sa_family = ARPHRD_ETHER;
  149. /* Copy stats */
  150. memcpy(&(threshold.qual), wstats, sizeof(struct iw_quality));
  151. /* Copy also thresholds */
  152. memcpy(&(threshold.low), &(spydata->spy_thr_low),
  153. 2 * sizeof(struct iw_quality));
  154. /* Send event to user space */
  155. wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold);
  156. }
  157. /* ---------------------------------------------------------------- */
  158. /*
  159. * Call for the driver to update the spy data.
  160. * For now, the spy data is a simple array. As the size of the array is
  161. * small, this is good enough. If we wanted to support larger number of
  162. * spy addresses, we should use something more efficient...
  163. */
  164. void wireless_spy_update(struct net_device * dev,
  165. unsigned char * address,
  166. struct iw_quality * wstats)
  167. {
  168. struct iw_spy_data * spydata = get_spydata(dev);
  169. int i;
  170. int match = -1;
  171. /* Make sure driver is not buggy or using the old API */
  172. if (!spydata)
  173. return;
  174. /* Update all records that match */
  175. for (i = 0; i < spydata->spy_number; i++)
  176. if (ether_addr_equal(address, spydata->spy_address[i])) {
  177. memcpy(&(spydata->spy_stat[i]), wstats,
  178. sizeof(struct iw_quality));
  179. match = i;
  180. }
  181. /* Generate an event if we cross the spy threshold.
  182. * To avoid event storms, we have a simple hysteresis : we generate
  183. * event only when we go under the low threshold or above the
  184. * high threshold. */
  185. if (match >= 0) {
  186. if (spydata->spy_thr_under[match]) {
  187. if (wstats->level > spydata->spy_thr_high.level) {
  188. spydata->spy_thr_under[match] = 0;
  189. iw_send_thrspy_event(dev, spydata,
  190. address, wstats);
  191. }
  192. } else {
  193. if (wstats->level < spydata->spy_thr_low.level) {
  194. spydata->spy_thr_under[match] = 1;
  195. iw_send_thrspy_event(dev, spydata,
  196. address, wstats);
  197. }
  198. }
  199. }
  200. }
  201. EXPORT_SYMBOL(wireless_spy_update);