Linux Audio

Check our new training course

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