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