⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wext.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * This file implement the Wireless Extensions APIs. * * 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) *//************************** DOCUMENTATION **************************//* * API definition : * -------------- * See <linux/wireless.h> for details of the APIs and the rest. * * History : * ------- * * v1 - 5.12.01 - Jean II *	o Created this file. * * v2 - 13.12.01 - Jean II *	o Move /proc/net/wireless stuff from net/core/dev.c to here *	o Make Wireless Extension IOCTLs go through here *	o Added iw_handler handling ;-) *	o Added standard ioctl description *	o Initial dumb commit strategy based on orinoco.c * * v3 - 19.12.01 - Jean II *	o Make sure we don't go out of standard_ioctl[] in ioctl_standard_call *	o Add event dispatcher function *	o Add event description *	o Propagate events as rtnetlink IFLA_WIRELESS option *	o Generate event on selected SET requests * * v4 - 18.04.02 - Jean II *	o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1 * * v5 - 21.06.02 - Jean II *	o Add IW_PRIV_TYPE_ADDR in priv_type_size (+cleanup) *	o Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes *	o Add IWEVCUSTOM for driver specific event/scanning token *	o Turn on WE_STRICT_WRITE by default + kernel warning *	o Fix WE_STRICT_WRITE in ioctl_export_private() (32 => iw_num) *	o Fix off-by-one in test (extra_size <= IFNAMSIZ) * * v6 - 9.01.03 - Jean II *	o Add common spy support : iw_handler_set_spy(), wireless_spy_update() *	o Add enhanced spy support : iw_handler_set_thrspy() and event. *	o Add WIRELESS_EXT version display in /proc/net/wireless * * v6 - 18.06.04 - Jean II *	o Change get_spydata() method for added safety *	o Remove spy #ifdef, they are always on -> cleaner code *	o Allow any size GET request if user specifies length > max *		and if request has IW_DESCR_FLAG_NOMAX flag or is SIOCGIWPRIV *	o Start migrating get_wireless_stats to struct iw_handler_def *	o Add wmb() in iw_handler_set_spy() for non-coherent archs/cpus * Based on patch from Pavel Roskin <proski@gnu.org> : *	o Fix kernel data leak to user space in private handler handling * * v7 - 18.3.05 - Jean II *	o Remove (struct iw_point *)->pointer from events and streams *	o Remove spy_offset from struct iw_handler_def *	o Start deprecating dev->get_wireless_stats, output a warning *	o If IW_QUAL_DBM is set, show dBm values in /proc/net/wireless *	o Don't loose INVALID/DBM flags when clearing UPDATED flags (iwstats) * * v8 - 17.02.06 - Jean II *	o RtNetlink requests support (SET/GET) * * v8b - 03.08.06 - Herbert Xu *	o Fix Wireless Event locking issues. * * v9 - 14.3.06 - Jean II *	o Change length in ESSID and NICK to strlen() instead of strlen()+1 *	o Make standard_ioctl_num and standard_event_num unsigned *	o Remove (struct net_device *)->get_wireless_stats() * * v10 - 16.3.07 - Jean II *	o Prevent leaking of kernel space in stream on 64 bits. *//***************************** INCLUDES *****************************/#include <linux/module.h>#include <linux/types.h>		/* off_t */#include <linux/netdevice.h>		/* struct ifreq, dev_get_by_name() */#include <linux/proc_fs.h>#include <linux/rtnetlink.h>		/* rtnetlink stuff */#include <linux/seq_file.h>#include <linux/init.h>			/* for __init */#include <linux/if_arp.h>		/* ARPHRD_ETHER */#include <linux/etherdevice.h>		/* compare_ether_addr */#include <linux/interrupt.h>#include <net/net_namespace.h>#include <linux/wireless.h>		/* Pretty obvious */#include <net/iw_handler.h>		/* New driver API */#include <net/netlink.h>#include <net/wext.h>#include <asm/uaccess.h>		/* copy_to_user() *//************************* GLOBAL VARIABLES *************************//* * You should not use global variables, because of re-entrancy. * On our case, it's only const, so it's OK... *//* * Meta-data about all the standard Wireless Extension request we * know about. */static const struct iw_ioctl_description standard_ioctl[] = {	[SIOCSIWCOMMIT	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_NULL,	},	[SIOCGIWNAME	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_CHAR,		.flags		= IW_DESCR_FLAG_DUMP,	},	[SIOCSIWNWID	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_PARAM,		.flags		= IW_DESCR_FLAG_EVENT,	},	[SIOCGIWNWID	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_PARAM,		.flags		= IW_DESCR_FLAG_DUMP,	},	[SIOCSIWFREQ	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_FREQ,		.flags		= IW_DESCR_FLAG_EVENT,	},	[SIOCGIWFREQ	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_FREQ,		.flags		= IW_DESCR_FLAG_DUMP,	},	[SIOCSIWMODE	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_UINT,		.flags		= IW_DESCR_FLAG_EVENT,	},	[SIOCGIWMODE	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_UINT,		.flags		= IW_DESCR_FLAG_DUMP,	},	[SIOCSIWSENS	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_PARAM,	},	[SIOCGIWSENS	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_PARAM,	},	[SIOCSIWRANGE	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_NULL,	},	[SIOCGIWRANGE	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_POINT,		.token_size	= 1,		.max_tokens	= sizeof(struct iw_range),		.flags		= IW_DESCR_FLAG_DUMP,	},	[SIOCSIWPRIV	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_NULL,	},	[SIOCGIWPRIV	- SIOCIWFIRST] = { /* (handled directly by us) */		.header_type	= IW_HEADER_TYPE_POINT,		.token_size	= sizeof(struct iw_priv_args),		.max_tokens	= 16,		.flags		= IW_DESCR_FLAG_NOMAX,	},	[SIOCSIWSTATS	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_NULL,	},	[SIOCGIWSTATS	- SIOCIWFIRST] = { /* (handled directly by us) */		.header_type	= IW_HEADER_TYPE_POINT,		.token_size	= 1,		.max_tokens	= sizeof(struct iw_statistics),		.flags		= IW_DESCR_FLAG_DUMP,	},	[SIOCSIWSPY	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_POINT,		.token_size	= sizeof(struct sockaddr),		.max_tokens	= IW_MAX_SPY,	},	[SIOCGIWSPY	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_POINT,		.token_size	= sizeof(struct sockaddr) +				  sizeof(struct iw_quality),		.max_tokens	= IW_MAX_SPY,	},	[SIOCSIWTHRSPY	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_POINT,		.token_size	= sizeof(struct iw_thrspy),		.min_tokens	= 1,		.max_tokens	= 1,	},	[SIOCGIWTHRSPY	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_POINT,		.token_size	= sizeof(struct iw_thrspy),		.min_tokens	= 1,		.max_tokens	= 1,	},	[SIOCSIWAP	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_ADDR,	},	[SIOCGIWAP	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_ADDR,		.flags		= IW_DESCR_FLAG_DUMP,	},	[SIOCSIWMLME	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_POINT,		.token_size	= 1,		.min_tokens	= sizeof(struct iw_mlme),		.max_tokens	= sizeof(struct iw_mlme),	},	[SIOCGIWAPLIST	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_POINT,		.token_size	= sizeof(struct sockaddr) +				  sizeof(struct iw_quality),		.max_tokens	= IW_MAX_AP,		.flags		= IW_DESCR_FLAG_NOMAX,	},	[SIOCSIWSCAN	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_POINT,		.token_size	= 1,		.min_tokens	= 0,		.max_tokens	= sizeof(struct iw_scan_req),	},	[SIOCGIWSCAN	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_POINT,		.token_size	= 1,		.max_tokens	= IW_SCAN_MAX_DATA,		.flags		= IW_DESCR_FLAG_NOMAX,	},	[SIOCSIWESSID	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_POINT,		.token_size	= 1,		.max_tokens	= IW_ESSID_MAX_SIZE,		.flags		= IW_DESCR_FLAG_EVENT,	},	[SIOCGIWESSID	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_POINT,		.token_size	= 1,		.max_tokens	= IW_ESSID_MAX_SIZE,		.flags		= IW_DESCR_FLAG_DUMP,	},	[SIOCSIWNICKN	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_POINT,		.token_size	= 1,		.max_tokens	= IW_ESSID_MAX_SIZE,	},	[SIOCGIWNICKN	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_POINT,		.token_size	= 1,		.max_tokens	= IW_ESSID_MAX_SIZE,	},	[SIOCSIWRATE	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_PARAM,	},	[SIOCGIWRATE	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_PARAM,	},	[SIOCSIWRTS	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_PARAM,	},	[SIOCGIWRTS	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_PARAM,	},	[SIOCSIWFRAG	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_PARAM,	},	[SIOCGIWFRAG	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_PARAM,	},	[SIOCSIWTXPOW	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_PARAM,	},	[SIOCGIWTXPOW	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_PARAM,	},	[SIOCSIWRETRY	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_PARAM,	},	[SIOCGIWRETRY	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_PARAM,	},	[SIOCSIWENCODE	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_POINT,		.token_size	= 1,		.max_tokens	= IW_ENCODING_TOKEN_MAX,		.flags		= IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT,	},	[SIOCGIWENCODE	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_POINT,		.token_size	= 1,		.max_tokens	= IW_ENCODING_TOKEN_MAX,		.flags		= IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT,	},	[SIOCSIWPOWER	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_PARAM,	},	[SIOCGIWPOWER	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_PARAM,	},	[SIOCSIWGENIE	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_POINT,		.token_size	= 1,		.max_tokens	= IW_GENERIC_IE_MAX,	},	[SIOCGIWGENIE	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_POINT,		.token_size	= 1,		.max_tokens	= IW_GENERIC_IE_MAX,	},	[SIOCSIWAUTH	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_PARAM,	},	[SIOCGIWAUTH	- SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_PARAM,	},	[SIOCSIWENCODEEXT - SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_POINT,		.token_size	= 1,		.min_tokens	= sizeof(struct iw_encode_ext),		.max_tokens	= sizeof(struct iw_encode_ext) +				  IW_ENCODING_TOKEN_MAX,	},	[SIOCGIWENCODEEXT - SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_POINT,		.token_size	= 1,		.min_tokens	= sizeof(struct iw_encode_ext),		.max_tokens	= sizeof(struct iw_encode_ext) +				  IW_ENCODING_TOKEN_MAX,	},	[SIOCSIWPMKSA - SIOCIWFIRST] = {		.header_type	= IW_HEADER_TYPE_POINT,		.token_size	= 1,		.min_tokens	= sizeof(struct iw_pmksa),		.max_tokens	= sizeof(struct iw_pmksa),	},};static const unsigned standard_ioctl_num = ARRAY_SIZE(standard_ioctl);/* * Meta-data about all the additional standard Wireless Extension events * we know about. */static const struct iw_ioctl_description standard_event[] = {	[IWEVTXDROP	- IWEVFIRST] = {		.header_type	= IW_HEADER_TYPE_ADDR,	},	[IWEVQUAL	- IWEVFIRST] = {		.header_type	= IW_HEADER_TYPE_QUAL,	},	[IWEVCUSTOM	- IWEVFIRST] = {		.header_type	= IW_HEADER_TYPE_POINT,		.token_size	= 1,		.max_tokens	= IW_CUSTOM_MAX,	},	[IWEVREGISTERED	- IWEVFIRST] = {		.header_type	= IW_HEADER_TYPE_ADDR,	},	[IWEVEXPIRED	- IWEVFIRST] = {		.header_type	= IW_HEADER_TYPE_ADDR,	},	[IWEVGENIE	- IWEVFIRST] = {		.header_type	= IW_HEADER_TYPE_POINT,		.token_size	= 1,		.max_tokens	= IW_GENERIC_IE_MAX,	},	[IWEVMICHAELMICFAILURE	- IWEVFIRST] = {		.header_type	= IW_HEADER_TYPE_POINT,		.token_size	= 1,		.max_tokens	= sizeof(struct iw_michaelmicfailure),	},	[IWEVASSOCREQIE	- IWEVFIRST] = {		.header_type	= IW_HEADER_TYPE_POINT,		.token_size	= 1,		.max_tokens	= IW_GENERIC_IE_MAX,	},	[IWEVASSOCRESPIE	- IWEVFIRST] = {		.header_type	= IW_HEADER_TYPE_POINT,		.token_size	= 1,		.max_tokens	= IW_GENERIC_IE_MAX,	},	[IWEVPMKIDCAND	- IWEVFIRST] = {		.header_type	= IW_HEADER_TYPE_POINT,		.token_size	= 1,		.max_tokens	= sizeof(struct iw_pmkid_cand),	},};static const unsigned standard_event_num = ARRAY_SIZE(standard_event);/* Size (in bytes) of the various private data types */static const char iw_priv_type_size[] = {	0,				/* IW_PRIV_TYPE_NONE */	1,				/* IW_PRIV_TYPE_BYTE */	1,				/* IW_PRIV_TYPE_CHAR */	0,				/* Not defined */	sizeof(__u32),			/* IW_PRIV_TYPE_INT */	sizeof(struct iw_freq),		/* IW_PRIV_TYPE_FLOAT */	sizeof(struct sockaddr),	/* IW_PRIV_TYPE_ADDR */	0,				/* Not defined */};/* Size (in bytes) of various events */static const int event_type_size[] = {	IW_EV_LCP_LEN,			/* IW_HEADER_TYPE_NULL */	0,	IW_EV_CHAR_LEN,			/* IW_HEADER_TYPE_CHAR */	0,	IW_EV_UINT_LEN,			/* IW_HEADER_TYPE_UINT */	IW_EV_FREQ_LEN,			/* IW_HEADER_TYPE_FREQ */	IW_EV_ADDR_LEN,			/* IW_HEADER_TYPE_ADDR */	0,	IW_EV_POINT_LEN,		/* Without variable payload */	IW_EV_PARAM_LEN,		/* IW_HEADER_TYPE_PARAM */	IW_EV_QUAL_LEN,			/* IW_HEADER_TYPE_QUAL */};/* Size (in bytes) of various events, as packed */static const int event_type_pk_size[] = {	IW_EV_LCP_PK_LEN,		/* IW_HEADER_TYPE_NULL */	0,	IW_EV_CHAR_PK_LEN,		/* IW_HEADER_TYPE_CHAR */	0,	IW_EV_UINT_PK_LEN,		/* IW_HEADER_TYPE_UINT */	IW_EV_FREQ_PK_LEN,		/* IW_HEADER_TYPE_FREQ */	IW_EV_ADDR_PK_LEN,		/* IW_HEADER_TYPE_ADDR */	0,	IW_EV_POINT_PK_LEN,		/* Without variable payload */	IW_EV_PARAM_PK_LEN,		/* IW_HEADER_TYPE_PARAM */	IW_EV_QUAL_PK_LEN,		/* IW_HEADER_TYPE_QUAL */};/************************ COMMON SUBROUTINES ************************//* * Stuff that may be used in various place or doesn't fit in one * of the section below. *//* ---------------------------------------------------------------- *//* * Return the driver handler associated with a specific Wireless Extension. */static iw_handler get_handler(struct net_device *dev, unsigned int cmd){	/* Don't "optimise" the following variable, it will crash */	unsigned int	index;		/* *MUST* be unsigned */	/* Check if we have some wireless handlers defined */	if (dev->wireless_handlers == NULL)		return NULL;	/* Try as a standard command */	index = cmd - SIOCIWFIRST;	if (index < dev->wireless_handlers->num_standard)		return dev->wireless_handlers->standard[index];	/* Try as a private command */	index = cmd - SIOCIWFIRSTPRIV;	if (index < dev->wireless_handlers->num_private)		return dev->wireless_handlers->private[index];	/* Not found */	return NULL;}/* ---------------------------------------------------------------- *//* * Get statistics out of the driver */static struct iw_statistics *get_wireless_stats(struct net_device *dev){	/* New location */	if ((dev->wireless_handlers != NULL) &&	   (dev->wireless_handlers->get_wireless_stats != NULL))		return dev->wireless_handlers->get_wireless_stats(dev);	/* Not found */	return NULL;}/* ---------------------------------------------------------------- *//* * Call the commit handler in the driver * (if exist and if conditions are right) * * Note : our current commit strategy is currently pretty dumb, * but we will be able to improve on that... * The goal is to try to agreagate as many changes as possible * before doing the commit. Drivers that will define a commit handler * are usually those that need a reset after changing parameters, so * we want to minimise the number of reset. * A cool idea is to use a timer : at each "set" command, we re-set the * timer, when the timer eventually fires, we call the driver. * Hopefully, more on that later. * * Also, I'm waiting to see how many people will complain about the * netif_running(dev) test. I'm open on that one... * Hopefully, the driver will remember to do a commit in "open()" ;-) */static int call_commit_handler(struct net_device *dev){	if ((netif_running(dev)) &&	   (dev->wireless_handlers->standard[0] != NULL))		/* Call the commit handler on the driver */		return dev->wireless_handlers->standard[0](dev, NULL,							   NULL, NULL);	else		return 0;		/* Command completed successfully */}/* ---------------------------------------------------------------- */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -