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

📄 iw_ndis.c

📁 ndis在linux下的无线网卡驱动源码
💻 C
📖 第 1 页 / 共 5 页
字号:
 /* *  Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; either version 2 of the License, or *  (at your option) any later version. * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *  GNU General Public License for more details. * */#include <linux/version.h>#include <linux/wireless.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/ethtool.h>#include <linux/if_arp.h>#include <linux/usb.h>#include <linux/random.h>#include <net/iw_handler.h>#include <linux/rtnetlink.h>#include <asm/uaccess.h>#include "iw_ndis.h"#include "wrapndis.h"static int freq_chan[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442,			   2447, 2452, 2457, 2462, 2467, 2472, 2484 };static const char *network_names[] = {"IEEE 802.11FH", "IEEE 802.11b",				      "IEEE 802.11a", "IEEE 802.11g", "Auto"};int set_essid(struct wrap_ndis_device *wnd, const char *ssid, int ssid_len){	NDIS_STATUS res;	struct ndis_essid req;	if (ssid_len > NDIS_ESSID_MAX_SIZE)		return -EINVAL;	memset(&req, 0, sizeof(req));	req.length = ssid_len;	if (ssid_len)		memcpy(&req.essid, ssid, ssid_len);	DBG_BLOCK(2) {		char buf[NDIS_ESSID_MAX_SIZE+1];		memcpy(buf, ssid, ssid_len);		buf[ssid_len] = 0;		TRACE2("ssid = '%s'", buf);	}	res = miniport_set_info(wnd, OID_802_11_SSID, &req, sizeof(req));	if (res) {		WARNING("setting essid failed (%08X)", res);		EXIT2(return -EINVAL);	}	memcpy(&wnd->essid, &req, sizeof(req));	EXIT2(return 0);}static int set_assoc_params(struct wrap_ndis_device *wnd){#if WIRELESS_EXT > 17	int auth_mode, encr_mode, priv_mode;	priv_mode = Ndis802_11PrivFilterAcceptAll;	TRACE2("wpa_version=0x%x auth_alg=0x%x key_mgmt=0x%x "	       "cipher_pairwise=0x%x cipher_group=0x%x",	       wnd->iw_auth_wpa_version, wnd->iw_auth_80211_auth_alg,	       wnd->iw_auth_key_mgmt, wnd->iw_auth_cipher_pairwise,	       wnd->iw_auth_cipher_group);	if (wnd->iw_auth_wpa_version & IW_AUTH_WPA_VERSION_WPA2) {		priv_mode = Ndis802_11PrivFilter8021xWEP;		if (wnd->iw_auth_key_mgmt & IW_AUTH_KEY_MGMT_802_1X)			auth_mode = Ndis802_11AuthModeWPA2;		else			auth_mode = Ndis802_11AuthModeWPA2PSK;	} else if (wnd->iw_auth_wpa_version & IW_AUTH_WPA_VERSION_WPA) {		priv_mode = Ndis802_11PrivFilter8021xWEP;		if (wnd->iw_auth_key_mgmt & IW_AUTH_KEY_MGMT_802_1X)			auth_mode = Ndis802_11AuthModeWPA;		else if (wnd->iw_auth_key_mgmt & IW_AUTH_KEY_MGMT_PSK)			auth_mode = Ndis802_11AuthModeWPAPSK;		else			auth_mode = Ndis802_11AuthModeWPANone;	} else if (wnd->iw_auth_80211_auth_alg & IW_AUTH_ALG_SHARED_KEY) {		if (wnd->iw_auth_80211_auth_alg & IW_AUTH_ALG_OPEN_SYSTEM)			auth_mode = Ndis802_11AuthModeAutoSwitch;		else			auth_mode = Ndis802_11AuthModeShared;	} else		auth_mode = Ndis802_11AuthModeOpen;	if (wnd->iw_auth_cipher_pairwise & IW_AUTH_CIPHER_CCMP)		encr_mode = Ndis802_11Encryption3Enabled;	else if (wnd->iw_auth_cipher_pairwise & IW_AUTH_CIPHER_TKIP)		encr_mode = Ndis802_11Encryption2Enabled;	else if (wnd->iw_auth_cipher_pairwise &		 (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104))		encr_mode = Ndis802_11Encryption1Enabled;	else if (wnd->iw_auth_cipher_group & IW_AUTH_CIPHER_CCMP)		encr_mode = Ndis802_11Encryption3Enabled;	else if (wnd->iw_auth_cipher_group & IW_AUTH_CIPHER_TKIP)		encr_mode = Ndis802_11Encryption2Enabled;	else		encr_mode = Ndis802_11EncryptionDisabled;	TRACE2("priv_mode=%d auth_mode=%d encr_mode=%d",	       priv_mode, auth_mode, encr_mode);	set_priv_filter(wnd, priv_mode);	set_auth_mode(wnd, auth_mode);	set_encr_mode(wnd, encr_mode);#endif	return 0;}static int iw_set_essid(struct net_device *dev, struct iw_request_info *info,			union iwreq_data *wrqu, char *extra){	struct wrap_ndis_device *wnd = netdev_priv(dev);	char ssid[NDIS_ESSID_MAX_SIZE];	int length;	ENTER2("");	memset(ssid, 0, sizeof(ssid));	/* there is no way to turn off essid other than to set to	 * random bytes; instead, we use off to mean any */	if (wrqu->essid.flags) {		/* wireless-tools prior to version 20 add extra 1, and		 * later than 20 don't! Deal with that mess */		length = wrqu->essid.length - 1;		if (length > 0)			length--;		while (length < wrqu->essid.length && extra[length])			length++;		TRACE2("%d", length);		if (length <= 0 || length > NDIS_ESSID_MAX_SIZE)			EXIT2(return -EINVAL);	} else		length = 0;	if (wnd->iw_auth_set) {		int ret = set_assoc_params(wnd);		wnd->iw_auth_set = 0;		if (ret < 0)			EXIT2(return ret);	}	memcpy(ssid, extra, length);	if (set_essid(wnd, ssid, length))		EXIT2(return -EINVAL);	EXIT2(return 0);}static int iw_get_essid(struct net_device *dev, struct iw_request_info *info,			union iwreq_data *wrqu, char *extra){	struct wrap_ndis_device *wnd = netdev_priv(dev);	NDIS_STATUS res;	struct ndis_essid req;	ENTER2("");	memset(&req, 0, sizeof(req));	res = miniport_query_info(wnd, OID_802_11_SSID, &req, sizeof(req));	if (res) {		WARNING("getting essid failed (%08X)", res);		EXIT2(return -EOPNOTSUPP);	}	memcpy(extra, req.essid, req.length);	extra[req.length] = 0;	if (req.length > 0)		wrqu->essid.flags  = 1;	else		wrqu->essid.flags = 0;	wrqu->essid.length = req.length;	EXIT2(return 0);}int set_infra_mode(struct wrap_ndis_device *wnd,		   enum network_infrastructure mode){	NDIS_STATUS res;	unsigned int i;	ENTER2("%d", mode);	res = miniport_query_int(wnd, OID_802_11_INFRASTRUCTURE_MODE,				 &wnd->infrastructure_mode);	if (res != NDIS_STATUS_SUCCESS) {		WARNING("getting operating mode to failed (%08X)", res);		EXIT2(return -EINVAL);	}	if (wnd->infrastructure_mode == mode)		EXIT2(return 0);	res = miniport_set_int(wnd, OID_802_11_INFRASTRUCTURE_MODE, mode);	if (res) {		WARNING("setting operating mode to %d failed (%08X)",			mode, res);		EXIT2(return -EINVAL);	}	/* NDIS drivers clear keys when infrastructure mode is	 * changed. But Linux tools assume otherwise. So set the	 * keys */	for (i = 0; i < MAX_ENCR_KEYS; i++) {		if (wnd->encr_info.keys[i].length > 0)			add_wep_key(wnd, wnd->encr_info.keys[i].key,				    wnd->encr_info.keys[i].length, i);	}	wnd->infrastructure_mode = mode;	EXIT2(return 0);}static int iw_set_infra_mode(struct net_device *dev,			     struct iw_request_info *info,			     union iwreq_data *wrqu, char *extra){	struct wrap_ndis_device *wnd = netdev_priv(dev);	enum network_infrastructure ndis_mode;	ENTER2("");	switch (wrqu->mode) {	case IW_MODE_ADHOC:		ndis_mode = Ndis802_11IBSS;		break;	case IW_MODE_INFRA:		ndis_mode = Ndis802_11Infrastructure;		break;	case IW_MODE_AUTO:		ndis_mode = Ndis802_11AutoUnknown;		break;	default:		EXIT2(return -EINVAL);	}	if (set_infra_mode(wnd, ndis_mode))		EXIT2(return -EINVAL);	EXIT2(return 0);}static int iw_get_infra_mode(struct net_device *dev,			     struct iw_request_info *info,			     union iwreq_data *wrqu, char *extra){	struct wrap_ndis_device *wnd = netdev_priv(dev);	int ndis_mode, iw_mode;	NDIS_STATUS res;	ENTER2("");	res = miniport_query_int(wnd, OID_802_11_INFRASTRUCTURE_MODE,				 &ndis_mode);	if (res) {		WARNING("getting operating mode failed (%08X)", res);		EXIT2(return -EOPNOTSUPP);	}	switch(ndis_mode) {	case Ndis802_11IBSS:		iw_mode = IW_MODE_ADHOC;		break;	case Ndis802_11Infrastructure:		iw_mode = IW_MODE_INFRA;		break;	case Ndis802_11AutoUnknown:		iw_mode = IW_MODE_AUTO;		break;	default:		ERROR("invalid operating mode (%u)", ndis_mode);		EXIT2(return -EINVAL);	}	wrqu->mode = iw_mode;	EXIT2(return 0);}static const char *network_type_to_name(int net_type){	if (net_type >= 0 &&	    net_type < (sizeof(network_names)/sizeof(network_names[0])))		return network_names[net_type];	else		return network_names[sizeof(network_names) /				     sizeof(network_names[0]) - 1];}static int iw_get_network_type(struct net_device *dev,			       struct iw_request_info *info,			       union iwreq_data *wrqu, char *extra){	struct wrap_ndis_device *wnd = netdev_priv(dev);	unsigned int network_type;	NDIS_STATUS res;	ENTER2("");	res = miniport_query_int(wnd, OID_802_11_NETWORK_TYPE_IN_USE,				 &network_type);	if (res) {		WARNING("getting network type failed: %08X", res);		network_type = -1;	}	strncpy(wrqu->name, network_type_to_name(network_type),	        sizeof(wrqu->name) - 1);	wrqu->name[sizeof(wrqu->name)-1] = 0;	return 0;}static int iw_get_freq(struct net_device *dev, struct iw_request_info *info,		       union iwreq_data *wrqu, char *extra){	struct wrap_ndis_device *wnd = netdev_priv(dev);	NDIS_STATUS res;	struct ndis_configuration req;	ENTER2("");	memset(&req, 0, sizeof(req));	res = miniport_query_info(wnd, OID_802_11_CONFIGURATION,				  &req, sizeof(req));	if (res) {		WARNING("getting configuration failed (%08X)", res);		EXIT2(return -EOPNOTSUPP);	}	memset(&(wrqu->freq), 0, sizeof(struct iw_freq));	/* see comment in wireless.h above the "struct iw_freq"	   definition for an explanation of this if	   NOTE: 1000000 is due to the kHz	*/	if (req.ds_config > 1000000) {		wrqu->freq.m = req.ds_config / 10;		wrqu->freq.e = 1;	}	else		wrqu->freq.m = req.ds_config;	/* convert from kHz to Hz */	wrqu->freq.e += 3;	return 0;}static int iw_set_freq(struct net_device *dev, struct iw_request_info *info,		       union iwreq_data *wrqu, char *extra){	struct wrap_ndis_device *wnd = netdev_priv(dev);	NDIS_STATUS res;	struct ndis_configuration req;	ENTER2("");	/* this OID is valid only when not associated */	if (netif_carrier_ok(wnd->net_dev))		EXIT2(return 0);	memset(&req, 0, sizeof(req));	res = miniport_query_info(wnd, OID_802_11_CONFIGURATION,				  &req, sizeof(req));	if (res) {		WARNING("getting configuration failed (%08X)", res);		EXIT2(return 0);	}	if (wrqu->freq.m < 1000 && wrqu->freq.e == 0) {		if (wrqu->freq.m >= 1 &&		    wrqu->freq.m <= (sizeof(freq_chan) / sizeof(freq_chan[0])))			req.ds_config = freq_chan[wrqu->freq.m - 1] * 1000;		else			return -EINVAL;	} else {		int i;		req.ds_config = wrqu->freq.m;		for (i = wrqu->freq.e; i > 0; i--)			req.ds_config *= 10;		req.ds_config /= 1000;	}	res = miniport_set_info(wnd, OID_802_11_CONFIGURATION,				&req, sizeof(req));	if (res)		WARNING("setting configuration failed (%08X)", res);	return 0;}static int iw_get_tx_power(struct net_device *dev, struct iw_request_info *info,			   union iwreq_data *wrqu, char *extra){	struct wrap_ndis_device *wnd = netdev_priv(dev);	ndis_tx_power_level ndis_power;	NDIS_STATUS res;	ENTER2("");	res = miniport_query_info(wnd, OID_802_11_TX_POWER_LEVEL,				  &ndis_power, sizeof(ndis_power));	if (res)		return -EOPNOTSUPP;	wrqu->txpower.flags = IW_TXPOW_MWATT;	wrqu->txpower.disabled = 0;	wrqu->txpower.fixed = 0;	wrqu->txpower.value = ndis_power;	return 0;}static int iw_set_tx_power(struct net_device *dev, struct iw_request_info *info,			   union iwreq_data *wrqu, char *extra){	struct wrap_ndis_device *wnd = netdev_priv(dev);	ndis_tx_power_level ndis_power;	NDIS_STATUS res;	ENTER2("");	if (wrqu->txpower.disabled) {		ndis_power = 0;		res = miniport_set_info(wnd, OID_802_11_TX_POWER_LEVEL,					&ndis_power, sizeof(ndis_power));		if (res)			return -EOPNOTSUPP;		res = disassociate(wnd, 1);		if (res)			return -EOPNOTSUPP;		return 0;	} else {		if (wrqu->txpower.flags == IW_TXPOW_MWATT)			ndis_power = wrqu->txpower.value;		else { // wrqu->txpower.flags == IW_TXPOW_DBM			if (wrqu->txpower.value > 20)				ndis_power = 128;			else if (wrqu->txpower.value < -43)				ndis_power = 127;			else {				signed char tmp;				tmp = wrqu->txpower.value;				tmp = -12 - tmp;				tmp <<= 2;				ndis_power = (unsigned char)tmp;			}		}	}	res = miniport_set_info(wnd, OID_802_11_TX_POWER_LEVEL,				&ndis_power, sizeof(ndis_power));	if (res)		return -EOPNOTSUPP;	return 0;}static int iw_get_bitrate(struct net_device *dev, struct iw_request_info *info,			  union iwreq_data *wrqu, char *extra){	struct wrap_ndis_device *wnd = netdev_priv(dev);	ULONG ndis_rate;	int res;	ENTER2("");	res = miniport_query_info(wnd, OID_GEN_LINK_SPEED,				  &ndis_rate, sizeof(ndis_rate));	if (res) {		WARNING("getting bitrate failed (%08X)", res);		ndis_rate = 0;	}	wrqu->bitrate.value = ndis_rate * 100;	return 0;}static int iw_set_bitrate(struct net_device *dev, struct iw_request_info *info,			  union iwreq_data *wrqu, char *extra){

⌨️ 快捷键说明

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