Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 95dd91fb authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Jeff Garzik
Browse files

[PATCH] orinoco: scanning support

Patch from Pavel Roskin
parent 16739b06
Loading
Loading
Loading
Loading
+522 −21
Original line number Diff line number Diff line
@@ -514,6 +514,10 @@ MODULE_PARM_DESC(ignore_disconnect, "Don't report lost link to the network layer
/* Internal constants                                               */
/********************************************************************/

/* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */
static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
#define ENCAPS_OVERHEAD		(sizeof(encaps_hdr) + 2)

#define ORINOCO_MIN_MTU		256
#define ORINOCO_MAX_MTU		(IEEE802_11_DATA_LEN - ENCAPS_OVERHEAD)

@@ -579,25 +583,42 @@ static struct {
/* Data types                                                       */
/********************************************************************/

struct header_struct {
	/* 802.3 */
	u8 dest[ETH_ALEN];
	u8 src[ETH_ALEN];
	u16 len;
	/* 802.2 */
/* Used in Event handling.
 * We avoid nested structres as they break on ARM -- Moustafa */
struct hermes_tx_descriptor_802_11 {
	/* hermes_tx_descriptor */
	u16 status;
	u16 reserved1;
	u16 reserved2;
	u32 sw_support;
	u8 retry_count;
	u8 tx_rate;
	u16 tx_control;

	/* ieee802_11_hdr */
	u16 frame_ctl;
	u16 duration_id;
	u8 addr1[ETH_ALEN];
	u8 addr2[ETH_ALEN];
	u8 addr3[ETH_ALEN];
	u16 seq_ctl;
	u8 addr4[ETH_ALEN];
	u16 data_len;

	/* ethhdr */
	unsigned char   h_dest[ETH_ALEN];       /* destination eth addr */
	unsigned char   h_source[ETH_ALEN];     /* source ether addr    */
	unsigned short  h_proto;                /* packet type ID field */

	/* p8022_hdr */
	u8 dsap;
	u8 ssap;
	u8 ctrl;
	/* SNAP */
	u8 oui[3];

	u16 ethertype;
} __attribute__ ((packed));

/* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */
u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};

#define ENCAPS_OVERHEAD		(sizeof(encaps_hdr) + 2)

struct hermes_rx_descriptor {
	u16 status;
	u32 time;
@@ -958,26 +979,55 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
	struct orinoco_private *priv = netdev_priv(dev);
	struct net_device_stats *stats = &priv->stats;
	u16 fid = hermes_read_regn(hw, TXCOMPLFID);
	struct hermes_tx_descriptor desc;
	struct hermes_tx_descriptor_802_11 hdr;
	int err = 0;

	if (fid == DUMMY_FID)
		return; /* Nothing's really happened */

	err = hermes_bap_pread(hw, IRQ_BAP, &desc, sizeof(desc), fid, 0);
	/* Read the frame header */
	err = hermes_bap_pread(hw, IRQ_BAP, &hdr,
			       sizeof(struct hermes_tx_descriptor) +
			       sizeof(struct ieee80211_hdr),
			       fid, 0);

	hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
	stats->tx_errors++;

	if (err) {
		printk(KERN_WARNING "%s: Unable to read descriptor on Tx error "
		       "(FID=%04X error %d)\n",
		       dev->name, fid, err);
	} else {
		DEBUG(1, "%s: Tx error, status %d\n",
		      dev->name, le16_to_cpu(desc.status));
		return;
	}
	
	stats->tx_errors++;
	DEBUG(1, "%s: Tx error, err %d (FID=%04X)\n", dev->name,
	      err, fid);
    
	/* We produce a TXDROP event only for retry or lifetime
	 * exceeded, because that's the only status that really mean
	 * that this particular node went away.
	 * Other errors means that *we* screwed up. - Jean II */
	hdr.status = le16_to_cpu(hdr.status);
	if (hdr.status & (HERMES_TXSTAT_RETRYERR | HERMES_TXSTAT_AGEDERR)) {
		union iwreq_data	wrqu;

		/* Copy 802.11 dest address.
		 * We use the 802.11 header because the frame may
		 * not be 802.3 or may be mangled...
		 * In Ad-Hoc mode, it will be the node address.
		 * In managed mode, it will be most likely the AP addr
		 * User space will figure out how to convert it to
		 * whatever it needs (IP address or else).
		 * - Jean II */
		memcpy(wrqu.addr.sa_data, hdr.addr1, ETH_ALEN);
		wrqu.addr.sa_family = ARPHRD_ETHER;

		/* Send event to user space */
		wireless_send_event(dev, IWEVTXDROP, &wrqu, NULL);
	}

	netif_wake_queue(dev);
	hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
}

static void orinoco_tx_timeout(struct net_device *dev)
@@ -1316,6 +1366,30 @@ static void orinoco_join_ap(struct net_device *dev)
	orinoco_unlock(priv, &flags);
}

/* Send new BSSID to userspace */
static void orinoco_send_wevents(struct net_device *dev)
{
	struct orinoco_private *priv = netdev_priv(dev);
	struct hermes *hw = &priv->hw;
	union iwreq_data wrqu;
	int err;
	unsigned long flags;

	if (orinoco_lock(priv, &flags) != 0)
		return;

	err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENTBSSID,
			      ETH_ALEN, NULL, wrqu.ap_addr.sa_data);
	if (err != 0)
		return;

	wrqu.ap_addr.sa_family = ARPHRD_ETHER;

	/* Send event to user space */
	wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
	orinoco_unlock(priv, &flags);
}

static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
{
	struct orinoco_private *priv = netdev_priv(dev);
@@ -1395,6 +1469,15 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
			break;
		newstatus = le16_to_cpu(linkstatus.linkstatus);

		/* Symbol firmware uses "out of range" to signal that
		 * the hostscan frame can be requested.  */
		if (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE &&
		    priv->firmware_type == FIRMWARE_TYPE_SYMBOL &&
		    priv->has_hostscan && priv->scan_inprogress) {
			hermes_inquire(hw, HERMES_INQ_HOSTSCAN_SYMBOL);
			break;
		}

		connected = (newstatus == HERMES_LINKSTATUS_CONNECTED)
			|| (newstatus == HERMES_LINKSTATUS_AP_CHANGE)
			|| (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE);
@@ -1404,12 +1487,89 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
		else if (!ignore_disconnect)
			netif_carrier_off(dev);

		if (newstatus != priv->last_linkstatus)
		if (newstatus != priv->last_linkstatus) {
			priv->last_linkstatus = newstatus;
			print_linkstatus(dev, newstatus);
			/* The info frame contains only one word which is the
			 * status (see hermes.h). The status is pretty boring
			 * in itself, that's why we export the new BSSID...
			 * Jean II */
			schedule_work(&priv->wevent_work);
		}
	}
	break;
	case HERMES_INQ_SCAN:
		if (!priv->scan_inprogress && priv->bssid_fixed &&
		    priv->firmware_type == FIRMWARE_TYPE_INTERSIL) {
			schedule_work(&priv->join_work);
			break;
		}
		/* fall through */
	case HERMES_INQ_HOSTSCAN:
	case HERMES_INQ_HOSTSCAN_SYMBOL: {
		/* Result of a scanning. Contains information about
		 * cells in the vicinity - Jean II */
		union iwreq_data	wrqu;
		unsigned char *buf;

		/* Sanity check */
		if (len > 4096) {
			printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n",
			       dev->name, len);
			break;
		}

		priv->last_linkstatus = newstatus;
		/* We are a strict producer. If the previous scan results
		 * have not been consumed, we just have to drop this
		 * frame. We can't remove the previous results ourselves,
		 * that would be *very* racy... Jean II */
		if (priv->scan_result != NULL) {
			printk(KERN_WARNING "%s: Previous scan results not consumed, dropping info frame.\n", dev->name);
			break;
		}

		/* Allocate buffer for results */
		buf = kmalloc(len, GFP_ATOMIC);
		if (buf == NULL)
			/* No memory, so can't printk()... */
			break;

		/* Read scan data */
		err = hermes_bap_pread(hw, IRQ_BAP, (void *) buf, len,
				       infofid, sizeof(info));
		if (err)
			break;

#ifdef ORINOCO_DEBUG
		{
			int	i;
			printk(KERN_DEBUG "Scan result [%02X", buf[0]);
			for(i = 1; i < (len * 2); i++)
				printk(":%02X", buf[i]);
			printk("]\n");
		}
#endif	/* ORINOCO_DEBUG */

		/* Allow the clients to access the results */
		priv->scan_len = len;
		priv->scan_result = buf;

		/* Send an empty event to user space.
		 * We don't send the received data on the event because
		 * it would require us to do complex transcoding, and
		 * we want to minimise the work done in the irq handler
		 * Use a request to extract the data - Jean II */
		wrqu.data.length = 0;
		wrqu.data.flags = 0;
		wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
	}
	break;
	case HERMES_INQ_SEC_STAT_AGERE:
		/* Security status (Agere specific) */
		/* Ignore this frame for now */
		if (priv->firmware_type == FIRMWARE_TYPE_AGERE)
			break;
		/* fall through */
	default:
		printk(KERN_DEBUG "%s: Unknown information frame received: "
		       "type 0x%04x, length %d\n", dev->name, type, len);
@@ -2010,6 +2170,11 @@ static void orinoco_reset(struct net_device *dev)

	orinoco_unlock(priv, &flags);

 	/* Scanning support: Cleanup of driver struct */
	kfree(priv->scan_result);
	priv->scan_result = NULL;
	priv->scan_inprogress = 0;

	if (priv->hard_reset) {
		err = (*priv->hard_reset)(priv);
		if (err) {
@@ -2248,6 +2413,7 @@ static int determine_firmware(struct net_device *dev)
		priv->has_mwo = (firmver >= 0x60000);
		priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */
		priv->ibss_port = 1;
		priv->has_hostscan = (firmver >= 0x8000a);

		/* Tested with Agere firmware :
		 *	1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
@@ -2293,6 +2459,8 @@ static int determine_firmware(struct net_device *dev)
		priv->ibss_port = 4;
 		priv->broken_disableport = (firmver == 0x25013) ||
 					   (firmver >= 0x30000 && firmver <= 0x31000);
		priv->has_hostscan = (firmver >= 0x31001) ||
				     (firmver >= 0x29057 && firmver < 0x30000);
		/* Tested with Intel firmware : 0x20015 => Jean II */
		/* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */
		break;
@@ -2312,6 +2480,7 @@ static int determine_firmware(struct net_device *dev)
		priv->has_ibss = (firmver >= 0x000700); /* FIXME */
		priv->has_big_wep = priv->has_wep = (firmver >= 0x000800);
		priv->has_pm = (firmver >= 0x000700);
		priv->has_hostscan = (firmver >= 0x010301);

		if (firmver >= 0x000800)
			priv->ibss_port = 0;
@@ -2539,6 +2708,7 @@ struct net_device *alloc_orinocodev(int sizeof_card,
				   * hardware */
	INIT_WORK(&priv->reset_work, (void (*)(void *))orinoco_reset, dev);
	INIT_WORK(&priv->join_work, (void (*)(void *))orinoco_join_ap, dev);
	INIT_WORK(&priv->wevent_work, (void (*)(void *))orinoco_send_wevents, dev);

	netif_carrier_off(dev);
	priv->last_linkstatus = 0xffff;
@@ -2549,6 +2719,9 @@ struct net_device *alloc_orinocodev(int sizeof_card,

void free_orinocodev(struct net_device *dev)
{
	struct orinoco_private *priv = netdev_priv(dev);

	kfree(priv->scan_result);
	free_netdev(dev);
}

@@ -3967,6 +4140,332 @@ static int orinoco_ioctl_getspy(struct net_device *dev,
	return 0;
}

/* Trigger a scan (look for other cells in the vicinity */
static int orinoco_ioctl_setscan(struct net_device *dev,
				 struct iw_request_info *info,
				 struct iw_param *srq,
				 char *extra)
{
	struct orinoco_private *priv = netdev_priv(dev);
	hermes_t *hw = &priv->hw;
	int err = 0;
	unsigned long flags;

	/* Note : you may have realised that, as this is a SET operation,
	 * this is priviledged and therefore a normal user can't
	 * perform scanning.
	 * This is not an error, while the device perform scanning,
	 * traffic doesn't flow, so it's a perfect DoS...
	 * Jean II */

	if (orinoco_lock(priv, &flags) != 0)
		return -EBUSY;

	/* Scanning with port 0 disabled would fail */
	if (!netif_running(dev)) {
		err = -ENETDOWN;
		goto out;
	}

	/* In monitor mode, the scan results are always empty.
	 * Probe responses are passed to the driver as received
	 * frames and could be processed in software. */
	if (priv->iw_mode == IW_MODE_MONITOR) {
		err = -EOPNOTSUPP;
		goto out;
	}

	/* Note : because we don't lock out the irq handler, the way
	 * we access scan variables in priv is critical.
	 *	o scan_inprogress : not touched by irq handler
	 *	o scan_mode : not touched by irq handler
	 *	o scan_result : irq is strict producer, non-irq is strict
	 *		consumer.
	 *	o scan_len : synchronised with scan_result
	 * Before modifying anything on those variables, please think hard !
	 * Jean II */

	/* If there is still some left-over scan results, get rid of it */
	if (priv->scan_result != NULL) {
		/* What's likely is that a client did crash or was killed
		 * between triggering the scan request and reading the
		 * results, so we need to reset everything.
		 * Some clients that are too slow may suffer from that...
		 * Jean II */
		kfree(priv->scan_result);
		priv->scan_result = NULL;
	}

	/* Save flags */
	priv->scan_mode = srq->flags;

	/* Always trigger scanning, even if it's in progress.
	 * This way, if the info frame get lost, we will recover somewhat
	 * gracefully  - Jean II */

	if (priv->has_hostscan) {
		switch (priv->firmware_type) {
		case FIRMWARE_TYPE_SYMBOL:
			err = hermes_write_wordrec(hw, USER_BAP,
						   HERMES_RID_CNFHOSTSCAN_SYMBOL,
						   HERMES_HOSTSCAN_SYMBOL_ONCE |
						   HERMES_HOSTSCAN_SYMBOL_BCAST);
			break;
		case FIRMWARE_TYPE_INTERSIL: {
			u16 req[3];

			req[0] = cpu_to_le16(0x3fff);	/* All channels */
			req[1] = cpu_to_le16(0x0001);	/* rate 1 Mbps */
			req[2] = 0;			/* Any ESSID */
			err = HERMES_WRITE_RECORD(hw, USER_BAP,
						  HERMES_RID_CNFHOSTSCAN, &req);
		}
		break;
		case FIRMWARE_TYPE_AGERE:
			err = hermes_write_wordrec(hw, USER_BAP,
						   HERMES_RID_CNFSCANSSID_AGERE,
						   0);	/* Any ESSID */
			if (err)
				break;

			err = hermes_inquire(hw, HERMES_INQ_SCAN);
			break;
		}
	} else
		err = hermes_inquire(hw, HERMES_INQ_SCAN);

	/* One more client */
	if (! err)
		priv->scan_inprogress = 1;

 out:
	orinoco_unlock(priv, &flags);
	return err;
}

/* Translate scan data returned from the card to a card independant
 * format that the Wireless Tools will understand - Jean II */
static inline int orinoco_translate_scan(struct net_device *dev,
					 char *buffer,
					 char *scan,
					 int scan_len)
{
	struct orinoco_private *priv = netdev_priv(dev);
	int			offset;		/* In the scan data */
	union hermes_scan_info *atom;
	int			atom_len;
	u16			capabilities;
	u16			channel;
	struct iw_event		iwe;		/* Temporary buffer */
	char *			current_ev = buffer;
	char *			end_buf = buffer + IW_SCAN_MAX_DATA;

	switch (priv->firmware_type) {
	case FIRMWARE_TYPE_AGERE:
		atom_len = sizeof(struct agere_scan_apinfo);
 		offset = 0;
		break;
	case FIRMWARE_TYPE_SYMBOL:
		/* Lack of documentation necessitates this hack.
		 * Different firmwares have 68 or 76 byte long atoms.
		 * We try modulo first.  If the length divides by both,
		 * we check what would be the channel in the second
		 * frame for a 68-byte atom.  76-byte atoms have 0 there.
		 * Valid channel cannot be 0.  */
		if (scan_len % 76)
			atom_len = 68;
		else if (scan_len % 68)
			atom_len = 76;
		else if (scan_len >= 1292 && scan[68] == 0)
			atom_len = 76;
		else
			atom_len = 68;
		offset = 0;
		break;
	case FIRMWARE_TYPE_INTERSIL:
		offset = 4;
		if (priv->has_hostscan)
			atom_len = scan[0] + (scan[1] << 8);
		else
			atom_len = offsetof(struct prism2_scan_apinfo, atim);
		break;
	default:
		return 0;
	}

	/* Check that we got an whole number of atoms */
	if ((scan_len - offset) % atom_len) {
		printk(KERN_ERR "%s: Unexpected scan data length %d, "
		       "atom_len %d, offset %d\n", dev->name, scan_len,
		       atom_len, offset);
		return 0;
	}

	/* Read the entries one by one */
	for (; offset + atom_len <= scan_len; offset += atom_len) {
		/* Get next atom */
		atom = (union hermes_scan_info *) (scan + offset);

		/* First entry *MUST* be the AP MAC address */
		iwe.cmd = SIOCGIWAP;
		iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
		memcpy(iwe.u.ap_addr.sa_data, atom->a.bssid, ETH_ALEN);
		current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);

		/* Other entries will be displayed in the order we give them */

		/* Add the ESSID */
		iwe.u.data.length = le16_to_cpu(atom->a.essid_len);
		if (iwe.u.data.length > 32)
			iwe.u.data.length = 32;
		iwe.cmd = SIOCGIWESSID;
		iwe.u.data.flags = 1;
		current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, atom->a.essid);

		/* Add mode */
		iwe.cmd = SIOCGIWMODE;
		capabilities = le16_to_cpu(atom->a.capabilities);
		if (capabilities & 0x3) {
			if (capabilities & 0x1)
				iwe.u.mode = IW_MODE_MASTER;
			else
				iwe.u.mode = IW_MODE_ADHOC;
			current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN);
		}

		channel = atom->s.channel;
		if ( (channel >= 1) && (channel <= NUM_CHANNELS) ) {
			/* Add frequency */
			iwe.cmd = SIOCGIWFREQ;
			iwe.u.freq.m = channel_frequency[channel-1] * 100000;
			iwe.u.freq.e = 1;
			current_ev = iwe_stream_add_event(current_ev, end_buf,
							  &iwe, IW_EV_FREQ_LEN);
		}

		/* Add quality statistics */
		iwe.cmd = IWEVQUAL;
		iwe.u.qual.updated = 0x10;	/* no link quality */
		iwe.u.qual.level = (__u8) le16_to_cpu(atom->a.level) - 0x95;
		iwe.u.qual.noise = (__u8) le16_to_cpu(atom->a.noise) - 0x95;
		/* Wireless tools prior to 27.pre22 will show link quality
		 * anyway, so we provide a reasonable value. */
		if (iwe.u.qual.level > iwe.u.qual.noise)
			iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise;
		else
			iwe.u.qual.qual = 0;
		current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);

		/* Add encryption capability */
		iwe.cmd = SIOCGIWENCODE;
		if (capabilities & 0x10)
			iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
		else
			iwe.u.data.flags = IW_ENCODE_DISABLED;
		iwe.u.data.length = 0;
		current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, atom->a.essid);

		/* Bit rate is not available in Lucent/Agere firmwares */
		if (priv->firmware_type != FIRMWARE_TYPE_AGERE) {
			char *	current_val = current_ev + IW_EV_LCP_LEN;
			int	i;
			int	step;

			if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)
				step = 2;
			else
				step = 1;

			iwe.cmd = SIOCGIWRATE;
			/* Those two flags are ignored... */
			iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
			/* Max 10 values */
			for (i = 0; i < 10; i += step) {
				/* NULL terminated */
				if (atom->p.rates[i] == 0x0)
					break;
				/* Bit rate given in 500 kb/s units (+ 0x80) */
				iwe.u.bitrate.value = ((atom->p.rates[i] & 0x7f) * 500000);
				current_val = iwe_stream_add_value(current_ev, current_val,
								   end_buf, &iwe,
								   IW_EV_PARAM_LEN);
			}
			/* Check if we added any event */
			if ((current_val - current_ev) > IW_EV_LCP_LEN)
				current_ev = current_val;
		}

		/* The other data in the scan result are not really
		 * interesting, so for now drop it - Jean II */
	}
	return current_ev - buffer;
}

/* Return results of a scan */
static int orinoco_ioctl_getscan(struct net_device *dev,
				 struct iw_request_info *info,
				 struct iw_point *srq,
				 char *extra)
{
	struct orinoco_private *priv = netdev_priv(dev);
	int err = 0;
	unsigned long flags;

	if (orinoco_lock(priv, &flags) != 0)
		return -EBUSY;

	/* If no results yet, ask to try again later */
	if (priv->scan_result == NULL) {
		if (priv->scan_inprogress)
			/* Important note : we don't want to block the caller
			 * until results are ready for various reasons.
			 * First, managing wait queues is complex and racy.
			 * Second, we grab some rtnetlink lock before comming
			 * here (in dev_ioctl()).
			 * Third, we generate an Wireless Event, so the
			 * caller can wait itself on that - Jean II */
			err = -EAGAIN;
		else
			/* Client error, no scan results...
			 * The caller need to restart the scan. */
			err = -ENODATA;
	} else {
		/* We have some results to push back to user space */

		/* Translate to WE format */
		srq->length = orinoco_translate_scan(dev, extra,
						     priv->scan_result,
						     priv->scan_len);

		/* Return flags */
		srq->flags = (__u16) priv->scan_mode;

		/* Results are here, so scan no longer in progress */
		priv->scan_inprogress = 0;

		/* In any case, Scan results will be cleaned up in the
		 * reset function and when exiting the driver.
		 * The person triggering the scanning may never come to
		 * pick the results, so we need to do it in those places.
		 * Jean II */

#ifdef SCAN_SINGLE_READ
		/* If you enable this option, only one client (the first
		 * one) will be able to read the result (and only one
		 * time). If there is multiple concurent clients that
		 * want to read scan results, this behavior is not
		 * advisable - Jean II */
		kfree(priv->scan_result);
		priv->scan_result = NULL;
#endif /* SCAN_SINGLE_READ */
		/* Here, if too much time has elapsed since last scan,
		 * we may want to clean up scan results... - Jean II */
	}
	  
	orinoco_unlock(priv, &flags);
	return err;
}

/* Commit handler, called after set operations */
static int orinoco_ioctl_commit(struct net_device *dev,
				struct iw_request_info *info,
@@ -4060,6 +4559,8 @@ static const iw_handler orinoco_handler[] = {
	[SIOCGIWSPY   -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getspy,
	[SIOCSIWAP    -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setwap,
	[SIOCGIWAP    -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getwap,
	[SIOCSIWSCAN  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setscan,
	[SIOCGIWSCAN  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getscan,
	[SIOCSIWESSID -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setessid,
	[SIOCGIWESSID -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getessid,
	[SIOCSIWNICKN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setnick,
+22 −0
Original line number Diff line number Diff line
@@ -32,6 +32,20 @@ struct orinoco_key {
	char data[ORINOCO_MAX_KEY_SIZE];
} __attribute__ ((packed));

struct header_struct {
	/* 802.3 */
	u8 dest[ETH_ALEN];
	u8 src[ETH_ALEN];
	u16 len;
	/* 802.2 */
	u8 dsap;
	u8 ssap;
	u8 ctrl;
	/* SNAP */
	u8 oui[3];
	u16 ethertype;
} __attribute__ ((packed));

typedef enum {
	FIRMWARE_TYPE_AGERE,
	FIRMWARE_TYPE_INTERSIL,
@@ -51,6 +65,7 @@ struct orinoco_private {
	int open;
	u16 last_linkstatus;
	struct work_struct join_work;
	struct work_struct wevent_work;

	/* Net device stuff */
	struct net_device *ndev;
@@ -77,6 +92,7 @@ struct orinoco_private {
	unsigned int has_pm:1;
	unsigned int has_preamble:1;
	unsigned int has_sensitivity:1;
	unsigned int has_hostscan:1;
	unsigned int broken_disableport:1;

	/* Configuration paramaters */
@@ -103,6 +119,12 @@ struct orinoco_private {
	/* Configuration dependent variables */
	int port_type, createibss;
	int promiscuous, mc_count;

	/* Scanning support */
	int	scan_inprogress;	/* Scan pending... */
	u32	scan_mode;		/* Type of scan done */
	char *	scan_result;		/* Result of previous scan */
	int	scan_len;		/* Lenght of result */
};

#ifdef ORINOCO_DEBUG