📄 iw_ndis.c
字号:
/* * 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 "wrapper.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 ndis_handle *handle, const char *ssid, int ssid_len){ NDIS_STATUS res; struct ndis_essid req; memset(&req, 0, sizeof(req)); if (ssid_len == 0) req.length = 1; else { if (ssid_len > NDIS_ESSID_MAX_SIZE) return -EINVAL; req.length = ssid_len; memcpy(&req.essid, ssid, req.length); DBGTRACE1("ssid = '%s'", req.essid); } res = miniport_set_info(handle, OID_802_11_SSID, &req, sizeof(req)); if (res) WARNING("setting essid failed (%08X)", res); memcpy(&handle->essid, &req, sizeof(req)); TRACEEXIT1(return 0);}static int iw_set_essid(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra){ struct ndis_handle *handle = dev->priv; char ssid[IW_ESSID_MAX_SIZE]; memset(ssid, 0, sizeof(ssid)); /* iwconfig adds 1 to the actual length */ /* 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) wrqu->essid.length--; else wrqu->essid.length = 0; if (wrqu->essid.length > IW_ESSID_MAX_SIZE) TRACEEXIT1(return -EINVAL); memcpy(ssid, extra, wrqu->essid.length); if (set_essid(handle, ssid, wrqu->essid.length)) TRACEEXIT1(return -EINVAL); TRACEEXIT1(return 0);}static int iw_get_essid(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra){ struct ndis_handle *handle = dev->priv; NDIS_STATUS res; struct ndis_essid req; TRACEENTER1("%s", ""); memset(&req, 0, sizeof(req)); res = miniport_query_info(handle, OID_802_11_SSID, &req, sizeof(req)); if (res) WARNING("getting essid failed (%08X)", res); 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; TRACEEXIT1(return 0);}int set_infra_mode(struct ndis_handle *handle, enum network_infrastructure mode){ NDIS_STATUS res; unsigned int i; TRACEENTER1("%s", ""); res = miniport_set_int(handle, OID_802_11_INFRASTRUCTURE_MODE, mode); if (res == NDIS_STATUS_INVALID_DATA) { WARNING("setting operating mode failed (%08X)", res); TRACEEXIT1(return -EINVAL); } for (i = 0; i < MAX_ENCR_KEYS; i++) handle->encr_info.keys[i].length = 0; handle->infrastructure_mode = mode; TRACEEXIT1(return 0);}static int iw_set_infra_mode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra){ struct ndis_handle *handle = dev->priv; enum network_infrastructure ndis_mode; TRACEENTER1("%s", ""); 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: TRACEEXIT1(return -EINVAL); } if (set_infra_mode(handle, ndis_mode)) TRACEEXIT1(return -EINVAL); TRACEEXIT1(return 0);}static int iw_get_infra_mode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra){ struct ndis_handle *handle = dev->priv; int ndis_mode, iw_mode; NDIS_STATUS res; TRACEENTER1("%s", ""); res = miniport_query_int(handle, OID_802_11_INFRASTRUCTURE_MODE, &ndis_mode); if (res) { WARNING("getting operating mode failed (%08X)", res); TRACEEXIT1(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); TRACEEXIT1(return -EINVAL); } wrqu->mode = iw_mode; TRACEEXIT1(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 ndis_handle *handle = dev->priv; unsigned int network_type; NDIS_STATUS res; res = miniport_query_int(handle, OID_802_11_NETWORK_TYPE_IN_USE, &network_type); if (res == NDIS_STATUS_INVALID_DATA) 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 ndis_handle *handle = dev->priv; NDIS_STATUS res; struct ndis_configuration req; memset(&req, 0, sizeof(req)); res = miniport_query_info(handle, OID_802_11_CONFIGURATION, &req, sizeof(req)); if (res == NDIS_STATUS_INVALID_DATA) { WARNING("getting configuration failed (%08X)", res); TRACEEXIT2(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 ndis_handle *handle = dev->priv; NDIS_STATUS res; struct ndis_configuration req; memset(&req, 0, sizeof(req)); res = miniport_query_info(handle, OID_802_11_CONFIGURATION, &req, sizeof(req)); if (res == NDIS_STATUS_INVALID_DATA) { WARNING("getting configuration failed (%08X)", res); TRACEEXIT2(return -EOPNOTSUPP); } 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; for (req.ds_config = wrqu->freq.m, i = wrqu->freq.e ; i > 0 ; i--) req.ds_config *= 10; req.ds_config /= 1000; } res = miniport_set_info(handle, OID_802_11_CONFIGURATION, &req, sizeof(req)); if (res == NDIS_STATUS_INVALID_DATA) { WARNING("setting configuration failed (%08X)", res); return -EINVAL; } return 0;}static int iw_get_tx_power(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra){ struct ndis_handle *handle = dev->priv; ndis_tx_power_level ndis_power; NDIS_STATUS res; res = miniport_query_info(handle, OID_802_11_TX_POWER_LEVEL, &ndis_power, sizeof(ndis_power)); /* Centrino driver returns NDIS_STATUS_INVALID_OID (why?) */ if (res == NDIS_STATUS_NOT_SUPPORTED || res == NDIS_STATUS_INVALID_OID) 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 ndis_handle *handle = dev->priv; ndis_tx_power_level ndis_power; NDIS_STATUS res; if (wrqu->txpower.disabled) { ndis_power = 0; res = miniport_set_info(handle, OID_802_11_TX_POWER_LEVEL, &ndis_power, sizeof(ndis_power)); if (res == NDIS_STATUS_INVALID_DATA) return -EINVAL; res = miniport_set_int(handle, OID_802_11_DISASSOCIATE, 0); if (res) return -EINVAL; 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(handle, OID_802_11_TX_POWER_LEVEL, &ndis_power, sizeof(ndis_power)); if (res) WARNING("setting tx_power failed (%08X)", res); if (res == NDIS_STATUS_NOT_SUPPORTED) return -EOPNOTSUPP; if (res == NDIS_STATUS_INVALID_DATA) return -EINVAL; return 0;}static int iw_get_bitrate(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra){ struct ndis_handle *handle = dev->priv; ULONG ndis_rate; int res = miniport_query_info(handle, 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){ struct ndis_handle *handle = dev->priv; int i; NDIS_STATUS res; ndis_rates rates; if (wrqu->bitrate.fixed == 0) TRACEEXIT1(return 0); res = miniport_query_info(handle, OID_802_11_SUPPORTED_RATES, &rates, sizeof(rates)); if (res == NDIS_STATUS_NOT_SUPPORTED || res == NDIS_STATUS_INVALID_DATA) { WARNING("getting bit rate failed (%08X)", res); TRACEEXIT1(return 0); } for (i = 0 ; i < NDIS_MAX_RATES_EX ; i++) { if (rates[i] & 0x80) continue; if ((rates[i] & 0x7f) * 500000 > wrqu->bitrate.value) { DBGTRACE1("setting rate %d to 0", (rates[i] & 0x7f) * 500000); rates[i] = 0; } } res = miniport_query_info(handle, OID_802_11_DESIRED_RATES, &rates, sizeof(rates)); if (res == NDIS_STATUS_NOT_SUPPORTED || res == NDIS_STATUS_INVALID_DATA) { WARNING("setting bit rate failed (%08X)", res); TRACEEXIT1(return 0); } return 0;}static int iw_set_dummy(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra){ /* Do nothing. Used for ioctls that are not implemented. */ return 0;}static int iw_get_rts_threshold(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra){ struct ndis_handle *handle = dev->priv; ndis_rts_threshold rts_threshold; NDIS_STATUS res;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -