File Index
Files and directories
Sign in
FILE

libipw_spy.c

File preview with syntax highlighting.

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