cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

wext-spy.c (6649B)


      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	spydata->spy_thr_low = threshold->low;
    124	spydata->spy_thr_high = threshold->high;
    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	threshold->low = spydata->spy_thr_low;
    151	threshold->high = spydata->spy_thr_high;
    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	threshold.qual = *wstats;
    177	/* Copy also thresholds */
    178	threshold.low = spydata->spy_thr_low;
    179	threshold.high = spydata->spy_thr_high;
    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);