📄 ieee80211_wireless.c.svn-base
字号:
/*- * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification. * 2. Redistributions in binary form must reproduce at minimum a disclaimer * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any * redistribution must be conditioned upon including a substantially * similar Disclaimer requirement for further binary redistribution. * 3. Neither the names of the above-listed copyright holders nor the names * of any contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * Alternatively, this software may be distributed under the terms of the * GNU General Public License ("GPL") version 2 as published by the Free * Software Foundation. * * NO WARRANTY * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * * $Id$ *//* * Wireless extensions support for 802.11 common code. */#ifndef AUTOCONF_INCLUDED#include <linux/config.h>#endif#include <linux/version.h>#include <linux/module.h>#include <linux/netdevice.h>#include <linux/utsname.h>#include <linux/if_arp.h> /* for ARPHRD_ETHER */#include <linux/delay.h>#include <linux/wireless.h>#include <net/iw_handler.h>#if WIRELESS_EXT < 15#error "Wireless extensions v15 or better is needed."#endif#include <asm/uaccess.h>#include <net80211/if_media.h>#include <net80211/if_athproto.h>#include <net80211/ieee80211_var.h>#include <net80211/ieee80211_linux.h>#include "ah.h"#define IS_UP(_dev) \ (((_dev)->flags & (IFF_RUNNING|IFF_UP)) == (IFF_RUNNING|IFF_UP))#define IS_UP_AUTO(_vap) \ (IS_UP((_vap)->iv_dev) && \ (_vap)->iv_ic->ic_roaming == IEEE80211_ROAMING_AUTO)#define RESCAN 1static voidpre_announced_chanswitch(struct net_device *dev, u_int32_t channel, u_int32_t tbtt);static intpreempt_scan(struct net_device *dev, int max_grace, int max_wait){ struct ieee80211vap *vap = netdev_priv(dev); struct ieee80211com *ic = vap->iv_ic; int total_delay = 0; int canceled = 0, ready = 0; while (!ready && total_delay < max_grace + max_wait) { if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) { ready = 1; } else { if (!canceled && (total_delay > max_grace)) { /* Cancel any existing active scan, so that any new parameters * in this scan ioctl (or the defaults) can be honored, then * wait around a while to see if the scan cancels properly. */ IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s: cancel pending scan request\n", __func__); (void) ieee80211_cancel_scan(vap); canceled = 1; } mdelay (1); total_delay += 1; } } if (!ready) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s: Timeout canceling current scan.\n", __func__); } return ready;}static struct iw_statistics *ieee80211_iw_getstats(struct net_device *dev){ struct ieee80211vap *vap = netdev_priv(dev); struct iw_statistics *is = &vap->iv_iwstats; struct ieee80211com *ic = vap->iv_ic; set_quality(&is->qual, ieee80211_getrssi(vap->iv_ic), ic->ic_channoise); is->status = vap->iv_state; is->discard.nwid = vap->iv_stats.is_rx_wrongbss + vap->iv_stats.is_rx_ssidmismatch; is->discard.code = vap->iv_stats.is_rx_wepfail + vap->iv_stats.is_rx_decryptcrc; is->discard.fragment = 0; is->discard.retries = 0; is->discard.misc = 0; is->miss.beacon = 0; return is;}static intieee80211_ioctl_giwname(struct net_device *dev, struct iw_request_info *info, char *name, char *extra){ struct ieee80211vap *vap = netdev_priv(dev); struct ieee80211_channel *c = vap->iv_ic->ic_curchan; if (IEEE80211_IS_CHAN_108G(c)) strncpy(name, "IEEE 802.11Tg", IFNAMSIZ); else if (IEEE80211_IS_CHAN_108A(c)) strncpy(name, "IEEE 802.11Ta", IFNAMSIZ); else if (IEEE80211_IS_CHAN_TURBO(c)) strncpy(name, "IEEE 802.11T", IFNAMSIZ); else if (IEEE80211_IS_CHAN_ANYG(c)) strncpy(name, "IEEE 802.11g", IFNAMSIZ); else if (IEEE80211_IS_CHAN_A(c)) strncpy(name, "IEEE 802.11a", IFNAMSIZ); else if (IEEE80211_IS_CHAN_B(c)) strncpy(name, "IEEE 802.11b", IFNAMSIZ); else strncpy(name, "IEEE 802.11", IFNAMSIZ); /* XXX FHSS */ return 0;}/* * Get a key index from a request. If nothing is * specified in the request we use the current xmit * key index. Otherwise we just convert the index * to be base zero. */static intgetiwkeyix(struct ieee80211vap *vap, const struct iw_point *erq, ieee80211_keyix_t *rkix){ ieee80211_keyix_t kix; kix = erq->flags & IW_ENCODE_INDEX; if ((erq->flags & IW_ENCODE_INDEX) == (u_int8_t)IEEE80211_KEYIX_NONE) kix = IEEE80211_KEYIX_NONE; if (kix < 1 || kix > IEEE80211_WEP_NKID) { kix = vap->iv_def_txkey; if (kix == IEEE80211_KEYIX_NONE) kix = 0; } else --kix; if (kix < IEEE80211_WEP_NKID) { *rkix = kix; return 0; } else return -EINVAL;}static intieee80211_ioctl_siwencode(struct net_device *dev, struct iw_request_info *info, struct iw_point *erq, char *keybuf){ struct ieee80211vap *vap = netdev_priv(dev); int error; int wepchange = 0; ieee80211_keyix_t kix; if ((erq->flags & IW_ENCODE_DISABLED) == 0) { /* Check WEP support, load WEP module if needed */ if (!ieee80211_crypto_available(vap, IEEE80211_CIPHER_WEP)) return -EOPNOTSUPP; /* * Enable crypto, set key contents, and * set the default transmit key. */ error = getiwkeyix(vap, erq, &kix); if (error < 0) return error; if (erq->length > IEEE80211_KEYBUF_SIZE) return -E2BIG; /* XXX no way to install 0-length key */ ieee80211_key_update_begin(vap); if (erq->length > 0) { struct ieee80211_key *k = &vap->iv_nw_keys[kix]; /* * Set key contents. This interface only supports WEP. * Indicate intended key index. */ k->wk_keyix = kix; if (ieee80211_crypto_newkey(vap, IEEE80211_CIPHER_WEP, IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV, k)) { k->wk_keylen = erq->length; memcpy(k->wk_key, keybuf, erq->length); memset(k->wk_key + erq->length, 0, IEEE80211_KEYBUF_SIZE - erq->length); if (!ieee80211_crypto_setkey(vap, k, vap->iv_myaddr, NULL)) error = -EINVAL; /* XXX */ } else error = -EINVAL; } else { /* * When the length is zero the request only changes * the default transmit key. Verify the new key has * a non-zero length. */ if (vap->iv_nw_keys[kix].wk_keylen == 0) error = -EINVAL; } if (error == 0) { /* * The default transmit key is only changed when: * 1. Privacy is enabled and no key matter is * specified. * 2. Privacy is currently disabled. * This is deduced from the iwconfig man page. */ if (erq->length == 0 || (vap->iv_flags & IEEE80211_F_PRIVACY) == 0) vap->iv_def_txkey = kix; wepchange = (vap->iv_flags & IEEE80211_F_PRIVACY) == 0; vap->iv_flags |= IEEE80211_F_PRIVACY; } ieee80211_key_update_end(vap); } else { if ((vap->iv_flags & IEEE80211_F_PRIVACY) == 0) return 0; vap->iv_flags &= ~IEEE80211_F_PRIVACY; wepchange = 1; error = 0; } if (error == 0) { /* Set policy for unencrypted frames */ if ((erq->flags & IW_ENCODE_OPEN) && (!(erq->flags & IW_ENCODE_RESTRICTED))) { vap->iv_flags &= ~IEEE80211_F_DROPUNENC; } else if (!(erq->flags & IW_ENCODE_OPEN) && (erq->flags & IW_ENCODE_RESTRICTED)) { vap->iv_flags |= IEEE80211_F_DROPUNENC; } else { /* Default policy */ if (vap->iv_flags & IEEE80211_F_PRIVACY) vap->iv_flags |= IEEE80211_F_DROPUNENC; else vap->iv_flags &= ~IEEE80211_F_DROPUNENC; } } if ((error == 0) && IS_UP(vap->iv_dev)) { /* * Device is up and running; we must kick it to * effect the change. If we're enabling/disabling * crypto use then we must re-initialize the device * so the 802.11 state machine is reset. Otherwise * the key state should have been updated above. */ if (wepchange && IS_UP_AUTO(vap)) ieee80211_new_state(vap, IEEE80211_S_SCAN, 0); }#ifdef ATH_SUPERG_XR /* set the same params on the xr vap device if exists */ if (!error && vap->iv_xrvap && !(vap->iv_flags & IEEE80211_F_XR)) ieee80211_ioctl_siwencode(vap->iv_xrvap->iv_dev, info, erq, keybuf);#endif return error;}static intieee80211_ioctl_giwencode(struct net_device *dev, struct iw_request_info *info, struct iw_point *erq, char *key){ struct ieee80211vap *vap = netdev_priv(dev); struct ieee80211_key *k; int error; ieee80211_keyix_t kix; if (vap->iv_flags & IEEE80211_F_PRIVACY) { error = getiwkeyix(vap, erq, &kix); if (error < 0) return error; k = &vap->iv_nw_keys[kix]; /* XXX no way to return cipher/key type */ erq->flags = kix + 1; /* NB: base 1 */ if (erq->length > k->wk_keylen) erq->length = k->wk_keylen; memcpy(key, k->wk_key, erq->length); erq->flags |= IW_ENCODE_ENABLED; } else { erq->length = 0; erq->flags = IW_ENCODE_DISABLED; } if (vap->iv_flags & IEEE80211_F_DROPUNENC) erq->flags |= IW_ENCODE_RESTRICTED; else erq->flags |= IW_ENCODE_OPEN; return 0;}#ifndef ifr_media#define ifr_media ifr_ifru.ifru_ivalue#endifstatic intieee80211_ioctl_siwrate(struct net_device *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra){ static const u_int mopts[] = { IFM_AUTO, IFM_IEEE80211_11A, IFM_IEEE80211_11B, IFM_IEEE80211_11G, IFM_IEEE80211_FH, IFM_IEEE80211_11A | IFM_IEEE80211_TURBO, IFM_IEEE80211_11G | IFM_IEEE80211_TURBO, }; struct ieee80211vap *vap = netdev_priv(dev); struct ieee80211com *ic = vap->iv_ic; struct ifreq ifr; int rate, retv; if (vap->iv_media.ifm_cur == NULL) return -EINVAL; memset(&ifr, 0, sizeof(ifr)); ifr.ifr_media = vap->iv_media.ifm_cur->ifm_media &~ (IFM_MMASK|IFM_TMASK); ifr.ifr_media |= mopts[vap->iv_des_mode]; if (rrq->fixed) { /* XXX fudge checking rates */ rate = ieee80211_rate2media(ic, 2 * rrq->value / 1000000, vap->iv_des_mode); if (rate == IFM_AUTO) /* NB: unknown rate */ return -EINVAL; } else rate = IFM_AUTO; ifr.ifr_media |= IFM_SUBTYPE(rate); /* refresh media capabilities based on channel */ ifmedia_removeall(&vap->iv_media); (void) ieee80211_media_setup(ic, &vap->iv_media, vap->iv_caps, vap->iv_media.ifm_change, vap->iv_media.ifm_status); retv = ifmedia_ioctl(vap->iv_dev, &ifr, &vap->iv_media, SIOCSIFMEDIA); if (retv == -ENETRESET) retv = IS_UP_AUTO(vap) ? ieee80211_open(vap->iv_dev) : 0; if (retv) IEEE80211_DPRINTF(vap, IEEE80211_MSG_DEBUG, "%s returns %d\n", __func__, retv); return retv;}static intieee80211_ioctl_giwrate(struct net_device *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra){ struct ieee80211vap *vap = netdev_priv(dev); struct ifmediareq imr; int rate; memset(&imr, 0, sizeof(imr)); vap->iv_media.ifm_status(vap->iv_dev, &imr); rrq->fixed = IFM_SUBTYPE(vap->iv_media.ifm_media) != IFM_AUTO; /* media status will have the current xmit rate if available */ rate = ieee80211_media2rate(imr.ifm_active); if (rate == -1) /* IFM_AUTO */ rate = 0; rrq->value = 1000000 * (rate / 2); return 0;}static intieee80211_ioctl_siwsens(struct net_device *dev, struct iw_request_info *info, struct iw_param *sens, char *extra){ return -EOPNOTSUPP;}static intieee80211_ioctl_giwsens(struct net_device *dev, struct iw_request_info *info, struct iw_param *sens, char *extra){ sens->value = 1; sens->fixed = 1; return 0;}static intieee80211_ioctl_siwrts(struct net_device *dev, struct iw_request_info *info, struct iw_param *rts, char *extra){ struct ieee80211vap *vap = netdev_priv(dev); struct ieee80211com *ic = vap->iv_ic; u16 val; if (rts->disabled) val = IEEE80211_RTS_MAX; else if ((IEEE80211_RTS_MIN <= rts->value) && (rts->value <= IEEE80211_RTS_MAX)) val = rts->value; else return -EINVAL; if (val != vap->iv_rtsthreshold) { vap->iv_rtsthreshold = val; if (IS_UP(vap->iv_dev)) return ic->ic_reset(ic->ic_dev); } return 0;}static intieee80211_ioctl_giwrts(struct net_device *dev, struct iw_request_info *info, struct iw_param *rts, char *extra){ struct ieee80211vap *vap = netdev_priv(dev); rts->value = vap->iv_rtsthreshold; rts->disabled = (rts->value == IEEE80211_RTS_MAX); rts->fixed = 1; return 0;}static intieee80211_ioctl_siwfrag(struct net_device *dev, struct iw_request_info *info, struct iw_param *rts, char *extra){ struct ieee80211vap *vap = netdev_priv(dev); struct ieee80211com *ic = vap->iv_ic; u16 val; if (rts->disabled) val = 2346; else if ((rts->value < 256) || (rts->value > 2346)) return -EINVAL; else val = (rts->value & ~0x1); if (val != vap->iv_fragthreshold) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -