| 
									
										
										
										
											2009-09-29 23:27:28 +02:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * This file implement the Wireless Extensions spy API. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com> | 
					
						
							|  |  |  |  * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * (As all part of the Linux kernel, this file is GPL) | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <linux/wireless.h>
 | 
					
						
							|  |  |  | #include <linux/netdevice.h>
 | 
					
						
							|  |  |  | #include <linux/etherdevice.h>
 | 
					
						
							| 
									
										
										
										
											2011-07-15 11:47:34 -04:00
										 |  |  | #include <linux/export.h>
 | 
					
						
							| 
									
										
										
										
											2009-09-29 23:27:28 +02:00
										 |  |  | #include <net/iw_handler.h>
 | 
					
						
							|  |  |  | #include <net/arp.h>
 | 
					
						
							|  |  |  | #include <net/wext.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline struct iw_spy_data *get_spydata(struct net_device *dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/* This is the new way */ | 
					
						
							|  |  |  | 	if (dev->wireless_data) | 
					
						
							|  |  |  | 		return dev->wireless_data->spy_data; | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int iw_handler_set_spy(struct net_device *	dev, | 
					
						
							|  |  |  | 		       struct iw_request_info *	info, | 
					
						
							|  |  |  | 		       union iwreq_data *	wrqu, | 
					
						
							|  |  |  | 		       char *			extra) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct iw_spy_data *	spydata = get_spydata(dev); | 
					
						
							|  |  |  | 	struct sockaddr *	address = (struct sockaddr *) extra; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Make sure driver is not buggy or using the old API */ | 
					
						
							|  |  |  | 	if (!spydata) | 
					
						
							|  |  |  | 		return -EOPNOTSUPP; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Disable spy collection while we copy the addresses.
 | 
					
						
							|  |  |  | 	 * While we copy addresses, any call to wireless_spy_update() | 
					
						
							|  |  |  | 	 * will NOP. This is OK, as anyway the addresses are changing. */ | 
					
						
							|  |  |  | 	spydata->spy_number = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* We want to operate without locking, because wireless_spy_update()
 | 
					
						
							|  |  |  | 	 * most likely will happen in the interrupt handler, and therefore | 
					
						
							|  |  |  | 	 * have its own locking constraints and needs performance. | 
					
						
							|  |  |  | 	 * The rtnl_lock() make sure we don't race with the other iw_handlers. | 
					
						
							|  |  |  | 	 * This make sure wireless_spy_update() "see" that the spy list | 
					
						
							|  |  |  | 	 * is temporarily disabled. */ | 
					
						
							|  |  |  | 	smp_wmb(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Are there are addresses to copy? */ | 
					
						
							|  |  |  | 	if (wrqu->data.length > 0) { | 
					
						
							|  |  |  | 		int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* Copy addresses */ | 
					
						
							|  |  |  | 		for (i = 0; i < wrqu->data.length; i++) | 
					
						
							|  |  |  | 			memcpy(spydata->spy_address[i], address[i].sa_data, | 
					
						
							|  |  |  | 			       ETH_ALEN); | 
					
						
							|  |  |  | 		/* Reset stats */ | 
					
						
							|  |  |  | 		memset(spydata->spy_stat, 0, | 
					
						
							|  |  |  | 		       sizeof(struct iw_quality) * IW_MAX_SPY); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Make sure above is updated before re-enabling */ | 
					
						
							|  |  |  | 	smp_wmb(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Enable addresses */ | 
					
						
							|  |  |  | 	spydata->spy_number = wrqu->data.length; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | EXPORT_SYMBOL(iw_handler_set_spy); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int iw_handler_get_spy(struct net_device *	dev, | 
					
						
							|  |  |  | 		       struct iw_request_info *	info, | 
					
						
							|  |  |  | 		       union iwreq_data *	wrqu, | 
					
						
							|  |  |  | 		       char *			extra) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct iw_spy_data *	spydata = get_spydata(dev); | 
					
						
							|  |  |  | 	struct sockaddr *	address = (struct sockaddr *) extra; | 
					
						
							|  |  |  | 	int			i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Make sure driver is not buggy or using the old API */ | 
					
						
							|  |  |  | 	if (!spydata) | 
					
						
							|  |  |  | 		return -EOPNOTSUPP; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	wrqu->data.length = spydata->spy_number; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Copy addresses. */ | 
					
						
							|  |  |  | 	for (i = 0; i < spydata->spy_number; i++) 	{ | 
					
						
							|  |  |  | 		memcpy(address[i].sa_data, spydata->spy_address[i], ETH_ALEN); | 
					
						
							|  |  |  | 		address[i].sa_family = AF_UNIX; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	/* Copy stats to the user buffer (just after). */ | 
					
						
							|  |  |  | 	if (spydata->spy_number > 0) | 
					
						
							|  |  |  | 		memcpy(extra  + (sizeof(struct sockaddr) *spydata->spy_number), | 
					
						
							|  |  |  | 		       spydata->spy_stat, | 
					
						
							|  |  |  | 		       sizeof(struct iw_quality) * spydata->spy_number); | 
					
						
							|  |  |  | 	/* Reset updated flags. */ | 
					
						
							|  |  |  | 	for (i = 0; i < spydata->spy_number; i++) | 
					
						
							|  |  |  | 		spydata->spy_stat[i].updated &= ~IW_QUAL_ALL_UPDATED; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | EXPORT_SYMBOL(iw_handler_get_spy); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*------------------------------------------------------------------*/ | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Standard Wireless Handler : set spy threshold | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | int iw_handler_set_thrspy(struct net_device *	dev, | 
					
						
							|  |  |  | 			  struct iw_request_info *info, | 
					
						
							|  |  |  | 			  union iwreq_data *	wrqu, | 
					
						
							|  |  |  | 			  char *		extra) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct iw_spy_data *	spydata = get_spydata(dev); | 
					
						
							|  |  |  | 	struct iw_thrspy *	threshold = (struct iw_thrspy *) extra; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Make sure driver is not buggy or using the old API */ | 
					
						
							|  |  |  | 	if (!spydata) | 
					
						
							|  |  |  | 		return -EOPNOTSUPP; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Just do it */ | 
					
						
							|  |  |  | 	memcpy(&(spydata->spy_thr_low), &(threshold->low), | 
					
						
							|  |  |  | 	       2 * sizeof(struct iw_quality)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Clear flag */ | 
					
						
							|  |  |  | 	memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | EXPORT_SYMBOL(iw_handler_set_thrspy); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*------------------------------------------------------------------*/ | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Standard Wireless Handler : get spy threshold | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | int iw_handler_get_thrspy(struct net_device *	dev, | 
					
						
							|  |  |  | 			  struct iw_request_info *info, | 
					
						
							|  |  |  | 			  union iwreq_data *	wrqu, | 
					
						
							|  |  |  | 			  char *		extra) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct iw_spy_data *	spydata = get_spydata(dev); | 
					
						
							|  |  |  | 	struct iw_thrspy *	threshold = (struct iw_thrspy *) extra; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Make sure driver is not buggy or using the old API */ | 
					
						
							|  |  |  | 	if (!spydata) | 
					
						
							|  |  |  | 		return -EOPNOTSUPP; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Just do it */ | 
					
						
							|  |  |  | 	memcpy(&(threshold->low), &(spydata->spy_thr_low), | 
					
						
							|  |  |  | 	       2 * sizeof(struct iw_quality)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | EXPORT_SYMBOL(iw_handler_get_thrspy); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*------------------------------------------------------------------*/ | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Prepare and send a Spy Threshold event | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void iw_send_thrspy_event(struct net_device *	dev, | 
					
						
							|  |  |  | 				 struct iw_spy_data *	spydata, | 
					
						
							|  |  |  | 				 unsigned char *	address, | 
					
						
							|  |  |  | 				 struct iw_quality *	wstats) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	union iwreq_data	wrqu; | 
					
						
							|  |  |  | 	struct iw_thrspy	threshold; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Init */ | 
					
						
							|  |  |  | 	wrqu.data.length = 1; | 
					
						
							|  |  |  | 	wrqu.data.flags = 0; | 
					
						
							|  |  |  | 	/* Copy address */ | 
					
						
							|  |  |  | 	memcpy(threshold.addr.sa_data, address, ETH_ALEN); | 
					
						
							|  |  |  | 	threshold.addr.sa_family = ARPHRD_ETHER; | 
					
						
							|  |  |  | 	/* Copy stats */ | 
					
						
							|  |  |  | 	memcpy(&(threshold.qual), wstats, sizeof(struct iw_quality)); | 
					
						
							|  |  |  | 	/* Copy also thresholds */ | 
					
						
							|  |  |  | 	memcpy(&(threshold.low), &(spydata->spy_thr_low), | 
					
						
							|  |  |  | 	       2 * sizeof(struct iw_quality)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Send event to user space */ | 
					
						
							|  |  |  | 	wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* ---------------------------------------------------------------- */ | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Call for the driver to update the spy data. | 
					
						
							|  |  |  |  * For now, the spy data is a simple array. As the size of the array is | 
					
						
							|  |  |  |  * small, this is good enough. If we wanted to support larger number of | 
					
						
							|  |  |  |  * spy addresses, we should use something more efficient... | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | void wireless_spy_update(struct net_device *	dev, | 
					
						
							|  |  |  | 			 unsigned char *	address, | 
					
						
							|  |  |  | 			 struct iw_quality *	wstats) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct iw_spy_data *	spydata = get_spydata(dev); | 
					
						
							|  |  |  | 	int			i; | 
					
						
							|  |  |  | 	int			match = -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Make sure driver is not buggy or using the old API */ | 
					
						
							|  |  |  | 	if (!spydata) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Update all records that match */ | 
					
						
							|  |  |  | 	for (i = 0; i < spydata->spy_number; i++) | 
					
						
							| 
									
										
										
											
												wireless: Convert compare_ether_addr to ether_addr_equal
Use the new bool function ether_addr_equal to add
some clarity and reduce the likelihood for misuse
of compare_ether_addr for sorting.
I removed a conversion from scan.c/cmp_bss_core
that appears to be a sorting function.
Done via cocci script:
$ cat compare_ether_addr.cocci
@@
expression a,b;
@@
-	!compare_ether_addr(a, b)
+	ether_addr_equal(a, b)
@@
expression a,b;
@@
-	compare_ether_addr(a, b)
+	!ether_addr_equal(a, b)
@@
expression a,b;
@@
-	!ether_addr_equal(a, b) == 0
+	ether_addr_equal(a, b)
@@
expression a,b;
@@
-	!ether_addr_equal(a, b) != 0
+	!ether_addr_equal(a, b)
@@
expression a,b;
@@
-	ether_addr_equal(a, b) == 0
+	!ether_addr_equal(a, b)
@@
expression a,b;
@@
-	ether_addr_equal(a, b) != 0
+	ether_addr_equal(a, b)
@@
expression a,b;
@@
-	!!ether_addr_equal(a, b)
+	ether_addr_equal(a, b)
Signed-off-by: Joe Perches <joe@perches.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
											
										 
											2012-05-08 18:56:55 +00:00
										 |  |  | 		if (ether_addr_equal(address, spydata->spy_address[i])) { | 
					
						
							| 
									
										
										
										
											2009-09-29 23:27:28 +02:00
										 |  |  | 			memcpy(&(spydata->spy_stat[i]), wstats, | 
					
						
							|  |  |  | 			       sizeof(struct iw_quality)); | 
					
						
							|  |  |  | 			match = i; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Generate an event if we cross the spy threshold.
 | 
					
						
							|  |  |  | 	 * To avoid event storms, we have a simple hysteresis : we generate | 
					
						
							|  |  |  | 	 * event only when we go under the low threshold or above the | 
					
						
							|  |  |  | 	 * high threshold. */ | 
					
						
							|  |  |  | 	if (match >= 0) { | 
					
						
							|  |  |  | 		if (spydata->spy_thr_under[match]) { | 
					
						
							|  |  |  | 			if (wstats->level > spydata->spy_thr_high.level) { | 
					
						
							|  |  |  | 				spydata->spy_thr_under[match] = 0; | 
					
						
							|  |  |  | 				iw_send_thrspy_event(dev, spydata, | 
					
						
							|  |  |  | 						     address, wstats); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			if (wstats->level < spydata->spy_thr_low.level) { | 
					
						
							|  |  |  | 				spydata->spy_thr_under[match] = 1; | 
					
						
							|  |  |  | 				iw_send_thrspy_event(dev, spydata, | 
					
						
							|  |  |  | 						     address, wstats); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | EXPORT_SYMBOL(wireless_spy_update); |