extractedLnx/linux-2.5.9/drivers/net/wireless/airo.c_airo_ioctl.c
static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
int i, rc = 0;
#ifdef WIRELESS_EXT
struct airo_info *local = (struct airo_info*) dev->priv;
struct iwreq *wrq = (struct iwreq *) rq;
ConfigRid config; /* Configuration info */
CapabilityRid cap_rid; /* Card capability info */
StatusRid status_rid; /* Card status info */
#ifdef CISCO_EXT
if (cmd != SIOCGIWPRIV && cmd != AIROIOCTL && cmd != AIROIDIFC
#ifdef AIROOLDIOCTL
&& cmd != AIROOLDIOCTL && cmd != AIROOLDIDIFC
#endif
)
#endif /* CISCO_EXT */
{
/* If the command read some stuff, we better get it out of
* the card first... */
if(IW_IS_GET(cmd))
readStatusRid(local, &status_rid);
if(IW_IS_GET(cmd) || (cmd == SIOCSIWRATE) || (cmd == SIOCSIWENCODE))
readCapabilityRid(local, &cap_rid);
/* Get config in all cases, because SET will just modify it */
readConfigRid(local, &config);
}
#endif /* WIRELESS_EXT */
switch (cmd) {
#ifdef WIRELESS_EXT
// Get name
case SIOCGIWNAME:
strcpy(wrq->u.name, "IEEE 802.11-DS");
break;
// Set frequency/channel
case SIOCSIWFREQ:
/* If setting by frequency, convert to a channel */
if((wrq->u.freq.e == 1) &&
(wrq->u.freq.m >= (int) 2.412e8) &&
(wrq->u.freq.m <= (int) 2.487e8)) {
int f = wrq->u.freq.m / 100000;
int c = 0;
while((c < 14) && (f != frequency_list[c]))
c++;
/* Hack to fall through... */
wrq->u.freq.e = 0;
wrq->u.freq.m = c + 1;
}
/* Setting by channel number */
if((wrq->u.freq.m > 1000) || (wrq->u.freq.e > 0))
rc = -EOPNOTSUPP;
else {
int channel = wrq->u.freq.m;
/* We should do a better check than that,
* based on the card capability !!! */
if((channel < 1) || (channel > 16)) {
printk(KERN_DEBUG "%s: New channel value of %d is invalid!\n", dev->name, wrq->u.freq.m);
rc = -EINVAL;
} else {
/* Yes ! We can set it !!! */
config.channelSet = (u16)(channel - 1);
local->need_commit = 1;
}
}
break;
// Get frequency/channel
case SIOCGIWFREQ:
#ifdef WEXT_USECHANNELS
wrq->u.freq.m = ((int)status_rid.channel) + 1;
wrq->u.freq.e = 0;
#else
{
int f = (int)status_rid.channel;
wrq->u.freq.m = frequency_list[f] * 100000;
wrq->u.freq.e = 1;
}
#endif
break;
// Set desired network name (ESSID)
case SIOCSIWESSID:
if (wrq->u.data.pointer) {
char essid[IW_ESSID_MAX_SIZE + 1];
SsidRid SSID_rid; /* SSIDs */
/* Reload the list of current SSID */
readSsidRid(local, &SSID_rid);
/* Check if we asked for `any' */
if(wrq->u.data.flags == 0) {
/* Just send an empty SSID list */
memset(&SSID_rid, 0, sizeof(SSID_rid));
} else {
int index = (wrq->u.data.flags &
IW_ENCODE_INDEX) - 1;
/* Check the size of the string */
if(wrq->u.data.length > IW_ESSID_MAX_SIZE+1) {
rc = -E2BIG;
break;
}
/* Check if index is valid */
if((index < 0) || (index >= 4)) {
rc = -EINVAL;
break;
}
/* Set the SSID */
memset(essid, 0, sizeof(essid));
if (copy_from_user(essid,
wrq->u.data.pointer,
wrq->u.data.length)) {
rc = -EFAULT;
break;
}
memcpy(SSID_rid.ssids[index].ssid, essid,
sizeof(essid) - 1);
SSID_rid.ssids[index].len = wrq->u.data.length - 1;
}
/* Write it to the card */
writeSsidRid(local, &SSID_rid);
}
break;
// Get current network name (ESSID)
case SIOCGIWESSID:
if (wrq->u.data.pointer) {
char essid[IW_ESSID_MAX_SIZE + 1];
/* Note : if wrq->u.data.flags != 0, we should
* get the relevant SSID from the SSID list... */
/* Get the current SSID */
memcpy(essid, status_rid.SSID, status_rid.SSIDlen);
essid[status_rid.SSIDlen] = '\0';
/* If none, we may want to get the one that was set */
/* Push it out ! */
wrq->u.data.length = strlen(essid) + 1;
wrq->u.data.flags = 1; /* active */
if (copy_to_user(wrq->u.data.pointer, essid, sizeof(essid)))
rc = -EFAULT;
}
break;
case SIOCSIWAP:
if (wrq->u.ap_addr.sa_family != ARPHRD_ETHER)
rc = -EINVAL;
else {
APListRid APList_rid;
memset(&APList_rid, 0, sizeof(APList_rid));
APList_rid.len = sizeof(APList_rid);
memcpy(APList_rid.ap[0], wrq->u.ap_addr.sa_data, 6);
writeAPListRid(local, &APList_rid);
local->need_commit = 1;
}
break;
// Get current Access Point (BSSID)
case SIOCGIWAP:
/* Tentative. This seems to work, wow, I'm lucky !!! */
memcpy(wrq->u.ap_addr.sa_data, status_rid.bssid[0], 6);
wrq->u.ap_addr.sa_family = ARPHRD_ETHER;
break;
// Set desired station name
case SIOCSIWNICKN:
if (wrq->u.data.pointer) {
char name[16 + 1];
/* Check the size of the string */
if(wrq->u.data.length > 16 + 1) {
rc = -E2BIG;
break;
}
memset(name, 0, sizeof(name));
if (copy_from_user(name, wrq->u.data.pointer,
wrq->u.data.length)) {
rc = -EFAULT;
break;
}
memcpy(config.nodeName, name, 16);
local->need_commit = 1;
}
break;
// Get current station name
case SIOCGIWNICKN:
if (wrq->u.data.pointer) {
char name[IW_ESSID_MAX_SIZE + 1];
strncpy(name, config.nodeName, 16);
name[16] = '\0';
wrq->u.data.length = strlen(name) + 1;
if (copy_to_user(wrq->u.data.pointer, name, sizeof(name)))
rc = -EFAULT;
}
break;
// Set the desired bit-rate
case SIOCSIWRATE:
{
/* First : get a valid bit rate value */
u8 brate = 0;
int i;
/* Which type of value ? */
if((wrq->u.bitrate.value < 8) &&
(wrq->u.bitrate.value >= 0)) {
/* Setting by rate index */
/* Find value in the magic rate table */
brate = cap_rid.supportedRates[wrq->u.bitrate.value];
} else {
/* Setting by frequency value */
u8 normvalue = (u8) (wrq->u.bitrate.value/500000);
/* Check if rate is valid */
for(i = 0 ; i < 8 ; i++) {
if(normvalue == cap_rid.supportedRates[i]) {
brate = normvalue;
break;
}
}
}
/* -1 designed the max rate (mostly auto mode) */
if(wrq->u.bitrate.value == -1) {
/* Get the highest available rate */
for(i = 0 ; i < 8 ; i++) {
if(cap_rid.supportedRates[i] == 0)
break;
}
if(i != 0)
brate = cap_rid.supportedRates[i - 1];
}
/* Check that it is valid */
if(brate == 0) {
rc = -EINVAL;
break;
}
/* Now, check if we want a fixed or auto value */
if(wrq->u.bitrate.fixed == 0) {
/* Fill all the rates up to this max rate */
memset(config.rates, 0, 8);
for(i = 0 ; i < 8 ; i++) {
config.rates[i] = cap_rid.supportedRates[i];
if(config.rates[i] == brate)
break;
}
local->need_commit = 1;
} else {
/* Fixed mode */
/* One rate, fixed */
memset(config.rates, 0, 8);
config.rates[0] = brate;
local->need_commit = 1;
}
break;
}
// Get the current bit-rate
case SIOCGIWRATE:
{
int brate = status_rid.currentXmitRate;
wrq->u.bitrate.value = brate * 500000;
/* If more than one rate, set auto */
wrq->u.rts.fixed = (config.rates[1] == 0);
}
break;
// Set the desired RTS threshold
case SIOCSIWRTS:
{
int rthr = wrq->u.rts.value;
if(wrq->u.rts.disabled)
rthr = 2312;
if((rthr < 0) || (rthr > 2312)) {
rc = -EINVAL;
} else {
config.rtsThres = rthr;
local->need_commit = 1;
}
}
break;
// Get the current RTS threshold
case SIOCGIWRTS:
wrq->u.rts.value = config.rtsThres;
wrq->u.rts.disabled = (wrq->u.rts.value >= 2312);
wrq->u.rts.fixed = 1;
break;
// Set the desired fragmentation threshold
case SIOCSIWFRAG:
{
int fthr = wrq->u.frag.value;
if(wrq->u.frag.disabled)
fthr = 2312;
if((fthr < 256) || (fthr > 2312)) {
rc = -EINVAL;
} else {
fthr &= ~0x1; /* Get an even value */
config.fragThresh = (u16)fthr;
local->need_commit = 1;
}
}
break;
// Get the current fragmentation threshold
case SIOCGIWFRAG:
wrq->u.frag.value = config.fragThresh;
wrq->u.frag.disabled = (wrq->u.frag.value >= 2312);
wrq->u.frag.fixed = 1;
break;
// Set mode of operation
case SIOCSIWMODE:
switch(wrq->u.mode) {
case IW_MODE_ADHOC:
config.opmode = MODE_STA_IBSS;
local->need_commit = 1;
break;
case IW_MODE_INFRA:
config.opmode = MODE_STA_ESS;
local->need_commit = 1;
break;
case IW_MODE_MASTER:
config.opmode = MODE_AP;
local->need_commit = 1;
break;
case IW_MODE_REPEAT:
config.opmode = MODE_AP_RPTR;
local->need_commit = 1;
break;
default:
rc = -EINVAL;
}
break;
// Get mode of operation
case SIOCGIWMODE:
/* If not managed, assume it's ad-hoc */
switch (config.opmode & 0xFF) {
case MODE_STA_ESS:
wrq->u.mode = IW_MODE_INFRA;
break;
case MODE_AP:
wrq->u.mode = IW_MODE_MASTER;
break;
case MODE_AP_RPTR:
wrq->u.mode = IW_MODE_REPEAT;
break;
default:
wrq->u.mode = IW_MODE_ADHOC;
}
break;
// Set WEP keys and mode
case SIOCSIWENCODE:
/* Is WEP supported ? */
/* Older firmware doesn't support this...
if(!(cap_rid.softCap & 2)) {
rc = -EOPNOTSUPP;
break;
} */
/* Basic checking: do we have a key to set ? */
if (wrq->u.encoding.pointer != (caddr_t) 0) {
wep_key_t key;
int index = (wrq->u.encoding.flags & IW_ENCODE_INDEX) - 1;
int current_index = get_wep_key(local, 0xffff);
/* Check the size of the key */
if (wrq->u.encoding.length > MAX_KEY_SIZE) {
rc = -EINVAL;
break;
}
/* Check the index (none -> use current) */
if ((index < 0) || (index>=(cap_rid.softCap&0x80)?4:1))
index = current_index;
/* Set the length */
if (wrq->u.encoding.length > MIN_KEY_SIZE)
key.len = MAX_KEY_SIZE;
else
if (wrq->u.encoding.length > 0)
key.len = MIN_KEY_SIZE;
else
/* Disable the key */
key.len = 0;
/* Check if the key is not marked as invalid */
if(!(wrq->u.encoding.flags & IW_ENCODE_NOKEY)) {
/* Cleanup */
memset(key.key, 0, MAX_KEY_SIZE);
/* Copy the key in the driver */
if(copy_from_user(key.key,
wrq->u.encoding.pointer,
wrq->u.encoding.length)) {
key.len = 0;
rc = -EFAULT;
break;
}
/* Send the key to the card */
set_wep_key(local, index, key.key,
key.len, 1);
}
/* WE specify that if a valid key is set, encryption
* should be enabled (user may turn it off later)
* This is also how "iwconfig ethX key on" works */
if((index == current_index) && (key.len > 0) &&
(config.authType == AUTH_OPEN)) {
config.authType = AUTH_ENCRYPT;
local->need_commit = 1;
}
} else {
/* Do we want to just set the transmit key index ? */
int index = (wrq->u.encoding.flags & IW_ENCODE_INDEX) - 1;
if ((index>=0) && (index<(cap_rid.softCap&0x80)?4:1)) {
set_wep_key(local, index, 0, 0, 1);
} else
/* Don't complain if only change the mode */
if(!wrq->u.encoding.flags & IW_ENCODE_MODE) {
rc = -EINVAL;
break;
}
}
/* Read the flags */
if(wrq->u.encoding.flags & IW_ENCODE_DISABLED)
config.authType = AUTH_OPEN; // disable encryption
if(wrq->u.encoding.flags & IW_ENCODE_RESTRICTED)
config.authType = AUTH_SHAREDKEY; // Only Both
if(wrq->u.encoding.flags & IW_ENCODE_OPEN)
config.authType = AUTH_ENCRYPT; // Only Wep
/* Commit the changes if needed */
if(wrq->u.encoding.flags & IW_ENCODE_MODE)
local->need_commit = 1;
break;
// Get the WEP keys and mode
case SIOCGIWENCODE:
/* Is it supported ? */
if(!(cap_rid.softCap & 2)) {
rc = -EOPNOTSUPP;
break;
}
// Only super-user can see WEP key
if (!capable(CAP_NET_ADMIN)) {
rc = -EPERM;
break;
}
// Basic checking...
if (wrq->u.encoding.pointer != (caddr_t) 0) {
char zeros[16];
int index = (wrq->u.encoding.flags & IW_ENCODE_INDEX) - 1;
memset(zeros,0, sizeof(zeros));
/* Check encryption mode */
wrq->u.encoding.flags = IW_ENCODE_NOKEY;
/* Is WEP enabled ??? */
switch(config.authType) {
case AUTH_ENCRYPT:
wrq->u.encoding.flags |= IW_ENCODE_OPEN;
break;
case AUTH_SHAREDKEY:
wrq->u.encoding.flags |= IW_ENCODE_RESTRICTED;
break;
default:
case AUTH_OPEN:
wrq->u.encoding.flags |= IW_ENCODE_DISABLED;
break;
}
/* Which key do we want ? -1 -> tx index */
if((index < 0) || (index >= (cap_rid.softCap&0x80)?4:1))
index = get_wep_key(local, 0xffff);
wrq->u.encoding.flags |= index + 1;
/* Copy the key to the user buffer */
wrq->u.encoding.length = get_wep_key(local, index);
if (wrq->u.encoding.length > 16) {
wrq->u.encoding.length=0;
}
if(copy_to_user(wrq->u.encoding.pointer, zeros,
wrq->u.encoding.length))
rc = -EFAULT;
}
break;
#if WIRELESS_EXT > 9
// Get the current Tx-Power
case SIOCGIWTXPOW:
wrq->u.txpower.value = config.txPower;
wrq->u.txpower.fixed = 1; /* No power control */
wrq->u.txpower.disabled = (local->flags & FLAG_RADIO_OFF);
wrq->u.txpower.flags = IW_TXPOW_MWATT;
break;
case SIOCSIWTXPOW:
if (wrq->u.txpower.disabled) {
local->flags |= FLAG_RADIO_OFF;
local->need_commit = 1;
break;
}
if (wrq->u.txpower.flags != IW_TXPOW_MWATT) {
rc = -EINVAL;
break;
}
local->flags &= ~FLAG_RADIO_OFF;
rc = -EINVAL;
for (i = 0; cap_rid.txPowerLevels[i] && (i < 8); i++)
if ((wrq->u.txpower.value==cap_rid.txPowerLevels[i])) {
config.txPower = wrq->u.txpower.value;
local->need_commit = 1;
rc = 0;
break;
}
break;
#endif /* WIRELESS_EXT > 9 */
#if WIRELESS_EXT > 10
case SIOCSIWRETRY:
if(wrq->u.retry.disabled) {
rc = -EINVAL;
break;
}
local->need_commit = 0;
if(wrq->u.retry.flags & IW_RETRY_LIMIT) {
if(wrq->u.retry.flags & IW_RETRY_MAX)
config.longRetryLimit = wrq->u.retry.value;
else if (wrq->u.retry.flags & IW_RETRY_MIN)
config.shortRetryLimit = wrq->u.retry.value;
else {
/* No modifier : set both */
config.longRetryLimit = wrq->u.retry.value;
config.shortRetryLimit = wrq->u.retry.value;
}
local->need_commit = 1;
}
if(wrq->u.retry.flags & IW_RETRY_LIFETIME) {
config.txLifetime = wrq->u.retry.value / 1024;
local->need_commit = 1;
}
if(local->need_commit == 0) {
rc = -EINVAL;
}
break;
case SIOCGIWRETRY:
wrq->u.retry.disabled = 0; /* Can't be disabled */
/* Note : by default, display the min retry number */
if((wrq->u.retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
wrq->u.retry.flags = IW_RETRY_LIFETIME;
wrq->u.retry.value = (int)config.txLifetime * 1024;
} else if((wrq->u.retry.flags & IW_RETRY_MAX)) {
wrq->u.retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
wrq->u.retry.value = (int)config.longRetryLimit;
} else {
wrq->u.retry.flags = IW_RETRY_LIMIT;
wrq->u.retry.value = (int)config.shortRetryLimit;
if((int)config.shortRetryLimit != (int)config.longRetryLimit)
wrq->u.retry.flags |= IW_RETRY_MIN;
}
break;
#endif /* WIRELESS_EXT > 10 */
// Get range of parameters
case SIOCGIWRANGE:
if (wrq->u.data.pointer) {
struct iw_range range;
int i;
int k;
wrq->u.data.length = sizeof(range);
memset(&range, 0, sizeof(range));
range.min_nwid = 0x0000;
range.max_nwid = 0x0000;
range.num_channels = 14;
/* Should be based on cap_rid.country to give only
* what the current card support */
k = 0;
for(i = 0; i < 14; i++) {
range.freq[k].i = i + 1; /* List index */
range.freq[k].m = frequency_list[i] * 100000;
range.freq[k++].e = 1; /* Values in table in MHz -> * 10^5 * 10 */
}
range.num_frequency = k;
/* Hum... Should put the right values there */
range.max_qual.qual = 10;
range.max_qual.level = 0x100 - 120; /* -120 dBm */
range.max_qual.noise = 0;
range.sensitivity = 65535;
for(i = 0 ; i < 8 ; i++) {
range.bitrate[i] = cap_rid.supportedRates[i] * 500000;
if(range.bitrate[i] == 0)
break;
}
range.num_bitrates = i;
/* Set an indication of the max TCP throughput
* in bit/s that we can expect using this interface.
* May be use for QoS stuff... Jean II */
if(i > 2)
range.throughput = 5 * 1000 * 1000;
else
range.throughput = 1.5 * 1000 * 1000;
range.min_rts = 0;
range.max_rts = 2312;
range.min_frag = 256;
range.max_frag = 2312;
if(cap_rid.softCap & 2) {
// WEP: RC4 40 bits
range.encoding_size[0] = 5;
// RC4 ~128 bits
if (cap_rid.softCap & 0x100) {
range.encoding_size[1] = 13;
range.num_encoding_sizes = 2;
} else
range.num_encoding_sizes = 1;
range.max_encoding_tokens = (cap_rid.softCap & 0x80) ? 4 : 1;
} else {
range.num_encoding_sizes = 0;
range.max_encoding_tokens = 0;
}
#if WIRELESS_EXT > 9
range.min_pmp = 0;
range.max_pmp = 5000000; /* 5 secs */
range.min_pmt = 0;
range.max_pmt = 65535 * 1024; /* ??? */
range.pmp_flags = IW_POWER_PERIOD;
range.pmt_flags = IW_POWER_TIMEOUT;
range.pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
/* Transmit Power - values are in mW */
for(i = 0 ; i < 8 ; i++) {
range.txpower[i] = cap_rid.txPowerLevels[i];
if(range.txpower[i] == 0)
break;
}
range.num_txpower = i;
range.txpower_capa = IW_TXPOW_MWATT;
#endif /* WIRELESS_EXT > 9 */
#if WIRELESS_EXT > 10
range.we_version_source = 12;
range.we_version_compiled = WIRELESS_EXT;
range.retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
range.retry_flags = IW_RETRY_LIMIT;
range.r_time_flags = IW_RETRY_LIFETIME;
range.min_retry = 1;
range.max_retry = 65535;
range.min_r_time = 1024;
range.max_r_time = 65535 * 1024;
#endif /* WIRELESS_EXT > 10 */
#if WIRELESS_EXT > 11
/* Experimental measurements - boundary 11/5.5 Mb/s */
/* Note : with or without the (local->rssi), results
* are somewhat different. - Jean II */
range.avg_qual.qual = 6;
if (local->rssi)
range.avg_qual.level = 186; /* -70 dBm */
else
range.avg_qual.level = 176; /* -80 dBm */
range.avg_qual.noise = 0;
#endif /* WIRELESS_EXT > 11 */
if (copy_to_user(wrq->u.data.pointer, &range, sizeof(struct iw_range)))
rc = -EFAULT;
}
break;
case SIOCGIWPOWER:
{
int mode = config.powerSaveMode;
if ((wrq->u.power.disabled = (mode == POWERSAVE_CAM)))
break;
if ((wrq->u.power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
wrq->u.power.value = (int)config.fastListenDelay * 1024;
wrq->u.power.flags = IW_POWER_TIMEOUT;
} else {
wrq->u.power.value = (int)config.fastListenInterval * 1024;
wrq->u.power.flags = IW_POWER_PERIOD;
}
if ((config.rmode & 0xFF) == RXMODE_ADDR)
wrq->u.power.flags |= IW_POWER_UNICAST_R;
else
wrq->u.power.flags |= IW_POWER_ALL_R;
}
break;
case SIOCSIWPOWER:
if (wrq->u.power.disabled) {
if ((config.rmode & 0xFF) >= RXMODE_RFMON) {
rc = -EINVAL;
break;
}
config.powerSaveMode = POWERSAVE_CAM;
config.rmode &= 0xFF00;
config.rmode |= RXMODE_BC_MC_ADDR;
local->need_commit = 1;
break;
}
if ((wrq->u.power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
config.fastListenDelay = (wrq->u.power.value + 500) / 1024;
config.powerSaveMode = POWERSAVE_PSPCAM;
local->need_commit = 1;
} else if ((wrq->u.power.flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
config.fastListenInterval = config.listenInterval = (wrq->u.power.value + 500) / 1024;
config.powerSaveMode = POWERSAVE_PSPCAM;
local->need_commit = 1;
}
switch (wrq->u.power.flags & IW_POWER_MODE) {
case IW_POWER_UNICAST_R:
if ((config.rmode & 0xFF) >= RXMODE_RFMON) {
rc = -EINVAL;
break;
}
config.rmode &= 0xFF00;
config.rmode |= RXMODE_ADDR;
local->need_commit = 1;
break;
case IW_POWER_ALL_R:
if ((config.rmode & 0xFF) >= RXMODE_RFMON) {
rc = -EINVAL;
break;
}
config.rmode &= 0xFF00;
config.rmode |= RXMODE_BC_MC_ADDR;
local->need_commit = 1;
case IW_POWER_ON:
break;
default:
rc = -EINVAL;
}
break;
case SIOCGIWSENS:
wrq->u.sens.value = config.rssiThreshold;
wrq->u.sens.disabled = (wrq->u.sens.value == 0);
wrq->u.sens.fixed = 1;
break;
case SIOCSIWSENS:
config.rssiThreshold = wrq->u.sens.disabled ? RSSI_DEFAULT : wrq->u.sens.value;
local->need_commit = 1;
break;
case SIOCGIWAPLIST:
if (wrq->u.data.pointer) {
int i, rc;
struct sockaddr s[IW_MAX_AP];
struct iw_quality qual[IW_MAX_AP];
BSSListRid BSSList;
int loseSync = capable(CAP_NET_ADMIN) ? 1: -1;
for (i = 0; i < IW_MAX_AP; i++) {
if (readBSSListRid(local, loseSync, &BSSList))
break;
loseSync = 0;
memcpy(s[i].sa_data, BSSList.bssid, 6);
s[i].sa_family = ARPHRD_ETHER;
if (local->rssi)
qual[i].level = 0x100 - local->rssi[BSSList.rssi].rssidBm;
else
qual[i].level = (BSSList.rssi + 321) / 2;
qual[i].qual = qual[i].noise = 0;
qual[i].updated = 2;
if (BSSList.index == 0xffff) break;
}
if (!i) {
for (i = 0;
i < min(IW_MAX_AP, 4) &&
(status_rid.bssid[i][0]
& status_rid.bssid[i][1]
& status_rid.bssid[i][2]
& status_rid.bssid[i][3]
& status_rid.bssid[i][4]
& status_rid.bssid[i][5])!=-1 &&
(status_rid.bssid[i][0]
| status_rid.bssid[i][1]
| status_rid.bssid[i][2]
| status_rid.bssid[i][3]
| status_rid.bssid[i][4]
| status_rid.bssid[i][5]);
i++) {
memcpy(s[i].sa_data,
status_rid.bssid[i], 6);
s[i].sa_family = ARPHRD_ETHER;
}
} else {
wrq->u.data.flags = 1; /* Should be define'd */
if (copy_to_user(wrq->u.data.pointer
+ sizeof(struct sockaddr)*i,
&qual,
sizeof(struct iw_quality)*i))
rc = -EFAULT;
}
wrq->u.data.length = i;
if (copy_to_user(wrq->u.data.pointer, &s,
sizeof(struct sockaddr)*i))
rc = -EFAULT;
}
break;
#ifdef WIRELESS_SPY
// Set the spy list
case SIOCSIWSPY:
if (wrq->u.data.length > IW_MAX_SPY)
{
rc = -E2BIG;
break;
}
local->spy_number = wrq->u.data.length;
if (local->spy_number > 0)
{
struct sockaddr address[IW_MAX_SPY];
int i;
if (copy_from_user(address, wrq->u.data.pointer,
sizeof(struct sockaddr) * local->spy_number)) {
rc = -EFAULT;
break;
}
for (i=0; i<local->spy_number; i++)
memcpy(local->spy_address[i], address[i].sa_data, 6);
memset(local->spy_stat, 0, sizeof(struct iw_quality) * IW_MAX_SPY);
}
break;
// Get the spy list
case SIOCGIWSPY:
wrq->u.data.length = local->spy_number;
if ((local->spy_number > 0) && (wrq->u.data.pointer))
{
struct sockaddr address[IW_MAX_SPY];
int i;
rc = verify_area(VERIFY_WRITE, wrq->u.data.pointer, (sizeof(struct iw_quality)+sizeof(struct sockaddr)) * IW_MAX_SPY);
if (rc)
break;
for (i=0; i<local->spy_number; i++)
{
memcpy(address[i].sa_data, local->spy_address[i], 6);
address[i].sa_family = AF_UNIX;
}
if (copy_to_user(wrq->u.data.pointer, address, sizeof(struct sockaddr) * local->spy_number)) {
rc = -EFAULT;
break;
}
if (copy_to_user(wrq->u.data.pointer + (sizeof(struct sockaddr)*local->spy_number), local->spy_stat, sizeof(struct iw_quality) * local->spy_number)) {
rc = -EFAULT;
break;
}
for (i=0; i<local->spy_number; i++)
local->spy_stat[i].updated = 0;
}
break;
#endif /* WIRELESS_SPY */
#ifdef CISCO_EXT
case SIOCGIWPRIV:
if(wrq->u.data.pointer)
{
struct iw_priv_args priv[] =
{ /* cmd, set_args, get_args, name */
{ AIROIOCTL, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof (aironet_ioctl), IW_PRIV_TYPE_BYTE | 2047, "airoioctl" },
{ AIROIDIFC, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof (aironet_ioctl), IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "airoidifc" },
};
/* Set the number of ioctl available */
wrq->u.data.length = 2;
/* Copy structure to the user buffer */
if(copy_to_user(wrq->u.data.pointer, (u_char *) priv,
sizeof(priv)))
rc = -EFAULT;
}
break;
#endif /* CISCO_EXT */
#endif /* WIRELESS_EXT */
#ifdef CISCO_EXT
case AIROIDIFC:
#ifdef AIROOLDIDIFC
case AIROOLDIDIFC:
#endif
{
int val = AIROMAGIC;
aironet_ioctl com;
if (copy_from_user(&com,rq->ifr_data,sizeof(com)))
rc = -EFAULT;
else if (copy_to_user(com.data,(char *)&val,sizeof(val)))
rc = -EFAULT;
}
break;
case AIROIOCTL:
#ifdef AIROOLDIOCTL
case AIROOLDIOCTL:
#endif
/* Get the command struct and hand it off for evaluation by
* the proper subfunction
*/
{
aironet_ioctl com;
if (copy_from_user(&com,rq->ifr_data,sizeof(com))) {
rc = -EFAULT;
break;
}
/* Seperate R/W functions bracket legality here
*/
if ( com.command <= AIROGSTATSD32 )
rc = readrids(dev,&com);
else if ( com.command >= AIROPCAP && com.command <= AIROPLEAPUSR )
rc = writerids(dev,&com);
else if ( com.command >= AIROFLSHRST && com.command <= AIRORESTART )
rc = flashcard(dev,&com);
else
rc = -EINVAL; /* Bad command in ioctl */
}
break;
#endif /* CISCO_EXT */
// All other calls are currently unsupported
default:
rc = -EOPNOTSUPP;
}
#ifdef WIRELESS_EXT
/* Some of the "SET" function may have modified some of the
* parameters. It's now time to commit them in the card */
if(local->need_commit) {
/* A classical optimisation here is to not commit any change
* if the card is not "opened". This is what we do in
* wvlan_cs (see for details).
* For that, we would need to have the config RID saved in
* the airo_info struct and make sure to not re-read it if
* local->need_commit != 0. Then, you need to patch "open"
* to do the final commit of all parameters...
* Jean II */
Resp rsp;
disable_MAC(local);
local->config = config; /* ???? config is local !!! */
checkThrottle(&config);
writeConfigRid(local, &config);
enable_MAC(local, &rsp);
local->need_commit = 0;
}
#endif /* WIRELESS_EXT */
return(rc);
}
Generated by GNU enscript 1.6.4.