Enscript Output

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.