Commit 1e3428e9 authored by Dan Williams's avatar Dan Williams Committed by David S. Miller

orinoco: more reliable scan handling

Bring scan result handling more in line with drivers like ipw.  Scan
results are aggregated and a BSS dropped after 15 seconds if no beacon
is received.  This allows the driver to interact better with userspace
where more than one process may request scans or results at any time.
Signed-off-by: default avatarDan Williams <dcbw@redhat.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 40faacc4
...@@ -270,6 +270,37 @@ static inline void set_port_type(struct orinoco_private *priv) ...@@ -270,6 +270,37 @@ static inline void set_port_type(struct orinoco_private *priv)
} }
} }
#define ORINOCO_MAX_BSS_COUNT 64
static int orinoco_bss_data_allocate(struct orinoco_private *priv)
{
if (priv->bss_data)
return 0;
priv->bss_data =
kzalloc(ORINOCO_MAX_BSS_COUNT * sizeof(bss_element), GFP_KERNEL);
if (!priv->bss_data) {
printk(KERN_WARNING "Out of memory allocating beacons");
return -ENOMEM;
}
return 0;
}
static void orinoco_bss_data_free(struct orinoco_private *priv)
{
kfree(priv->bss_data);
priv->bss_data = NULL;
}
static void orinoco_bss_data_init(struct orinoco_private *priv)
{
int i;
INIT_LIST_HEAD(&priv->bss_free_list);
INIT_LIST_HEAD(&priv->bss_list);
for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++)
list_add_tail(&priv->bss_data[i].list, &priv->bss_free_list);
}
/********************************************************************/ /********************************************************************/
/* Device methods */ /* Device methods */
/********************************************************************/ /********************************************************************/
...@@ -1083,6 +1114,121 @@ static void orinoco_send_wevents(struct work_struct *work) ...@@ -1083,6 +1114,121 @@ static void orinoco_send_wevents(struct work_struct *work)
orinoco_unlock(priv, &flags); orinoco_unlock(priv, &flags);
} }
static inline void orinoco_clear_scan_results(struct orinoco_private *priv,
unsigned long scan_age)
{
bss_element *bss;
bss_element *tmp_bss;
/* Blow away current list of scan results */
list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) {
if (!scan_age ||
time_after(jiffies, bss->last_scanned + scan_age)) {
list_move_tail(&bss->list, &priv->bss_free_list);
/* Don't blow away ->list, just BSS data */
memset(bss, 0, sizeof(bss->bss));
bss->last_scanned = 0;
}
}
}
static int orinoco_process_scan_results(struct net_device *dev,
unsigned char *buf,
int len)
{
struct orinoco_private *priv = netdev_priv(dev);
int offset; /* In the scan data */
union hermes_scan_info *atom;
int atom_len;
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 (len % 76)
atom_len = 68;
else if (len % 68)
atom_len = 76;
else if (len >= 1292 && buf[68] == 0)
atom_len = 76;
else
atom_len = 68;
offset = 0;
break;
case FIRMWARE_TYPE_INTERSIL:
offset = 4;
if (priv->has_hostscan) {
atom_len = le16_to_cpup((__le16 *)buf);
/* Sanity check for atom_len */
if (atom_len < sizeof(struct prism2_scan_apinfo)) {
printk(KERN_ERR "%s: Invalid atom_len in scan "
"data: %d\n", dev->name, atom_len);
return -EIO;
}
} else
atom_len = offsetof(struct prism2_scan_apinfo, atim);
break;
default:
return -EOPNOTSUPP;
}
/* Check that we got an whole number of atoms */
if ((len - offset) % atom_len) {
printk(KERN_ERR "%s: Unexpected scan data length %d, "
"atom_len %d, offset %d\n", dev->name, len,
atom_len, offset);
return -EIO;
}
orinoco_clear_scan_results(priv, msecs_to_jiffies(15000));
/* Read the entries one by one */
for (; offset + atom_len <= len; offset += atom_len) {
int found = 0;
bss_element *bss;
/* Get next atom */
atom = (union hermes_scan_info *) (buf + offset);
/* Try to update an existing bss first */
list_for_each_entry(bss, &priv->bss_list, list) {
if (compare_ether_addr(bss->bss.a.bssid, atom->a.bssid))
continue;
if (le16_to_cpu(bss->bss.a.essid_len) !=
le16_to_cpu(atom->a.essid_len))
continue;
if (memcmp(bss->bss.a.essid, atom->a.essid,
le16_to_cpu(atom->a.essid_len)))
continue;
bss->last_scanned = jiffies;
found = 1;
break;
}
/* Grab a bss off the free list */
if (!found && !list_empty(&priv->bss_free_list)) {
bss = list_entry(priv->bss_free_list.next,
bss_element, list);
list_del(priv->bss_free_list.next);
memcpy(bss, atom, sizeof(bss->bss));
bss->last_scanned = jiffies;
list_add_tail(&bss->list, &priv->bss_list);
}
}
return 0;
}
static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
...@@ -1208,6 +1354,9 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) ...@@ -1208,6 +1354,9 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
union iwreq_data wrqu; union iwreq_data wrqu;
unsigned char *buf; unsigned char *buf;
/* Scan is no longer in progress */
priv->scan_inprogress = 0;
/* Sanity check */ /* Sanity check */
if (len > 4096) { if (len > 4096) {
printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n", printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n",
...@@ -1215,15 +1364,6 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) ...@@ -1215,15 +1364,6 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
break; break;
} }
/* 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 */ /* Allocate buffer for results */
buf = kmalloc(len, GFP_ATOMIC); buf = kmalloc(len, GFP_ATOMIC);
if (buf == NULL) if (buf == NULL)
...@@ -1248,10 +1388,7 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) ...@@ -1248,10 +1388,7 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
} }
#endif /* ORINOCO_DEBUG */ #endif /* ORINOCO_DEBUG */
/* Allow the clients to access the results */ if (orinoco_process_scan_results(dev, buf, len) == 0) {
priv->scan_len = len;
priv->scan_result = buf;
/* Send an empty event to user space. /* Send an empty event to user space.
* We don't send the received data on the event because * We don't send the received data on the event because
* it would require us to do complex transcoding, and * it would require us to do complex transcoding, and
...@@ -1261,6 +1398,8 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) ...@@ -1261,6 +1398,8 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
wrqu.data.flags = 0; wrqu.data.flags = 0;
wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
} }
kfree(buf);
}
break; break;
case HERMES_INQ_SEC_STAT_AGERE: case HERMES_INQ_SEC_STAT_AGERE:
/* Security status (Agere specific) */ /* Security status (Agere specific) */
...@@ -1896,8 +2035,7 @@ static void orinoco_reset(struct work_struct *work) ...@@ -1896,8 +2035,7 @@ static void orinoco_reset(struct work_struct *work)
orinoco_unlock(priv, &flags); orinoco_unlock(priv, &flags);
/* Scanning support: Cleanup of driver struct */ /* Scanning support: Cleanup of driver struct */
kfree(priv->scan_result); orinoco_clear_scan_results(priv, 0);
priv->scan_result = NULL;
priv->scan_inprogress = 0; priv->scan_inprogress = 0;
if (priv->hard_reset) { if (priv->hard_reset) {
...@@ -2412,6 +2550,10 @@ struct net_device *alloc_orinocodev(int sizeof_card, ...@@ -2412,6 +2550,10 @@ struct net_device *alloc_orinocodev(int sizeof_card,
else else
priv->card = NULL; priv->card = NULL;
if (orinoco_bss_data_allocate(priv))
goto err_out_free;
orinoco_bss_data_init(priv);
/* Setup / override net_device fields */ /* Setup / override net_device fields */
dev->init = orinoco_init; dev->init = orinoco_init;
dev->hard_start_xmit = orinoco_xmit; dev->hard_start_xmit = orinoco_xmit;
...@@ -2447,13 +2589,16 @@ struct net_device *alloc_orinocodev(int sizeof_card, ...@@ -2447,13 +2589,16 @@ struct net_device *alloc_orinocodev(int sizeof_card,
return dev; return dev;
err_out_free:
free_netdev(dev);
return NULL;
} }
void free_orinocodev(struct net_device *dev) void free_orinocodev(struct net_device *dev)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
kfree(priv->scan_result); orinoco_bss_data_free(priv);
free_netdev(dev); free_netdev(dev);
} }
...@@ -3841,23 +3986,10 @@ static int orinoco_ioctl_setscan(struct net_device *dev, ...@@ -3841,23 +3986,10 @@ static int orinoco_ioctl_setscan(struct net_device *dev,
* we access scan variables in priv is critical. * we access scan variables in priv is critical.
* o scan_inprogress : not touched by irq handler * o scan_inprogress : not touched by irq handler
* o scan_mode : 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 * o scan_len : synchronised with scan_result
* Before modifying anything on those variables, please think hard ! * Before modifying anything on those variables, please think hard !
* Jean II */ * 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 */ /* Save flags */
priv->scan_mode = srq->flags; priv->scan_mode = srq->flags;
...@@ -3905,95 +4037,43 @@ static int orinoco_ioctl_setscan(struct net_device *dev, ...@@ -3905,95 +4037,43 @@ static int orinoco_ioctl_setscan(struct net_device *dev,
return err; return err;
} }
#define MAX_CUSTOM_LEN 64
/* Translate scan data returned from the card to a card independant /* Translate scan data returned from the card to a card independant
* format that the Wireless Tools will understand - Jean II * format that the Wireless Tools will understand - Jean II
* Return message length or -errno for fatal errors */ * Return message length or -errno for fatal errors */
static inline int orinoco_translate_scan(struct net_device *dev, static inline char *orinoco_translate_scan(struct net_device *dev,
char *buffer, char *current_ev,
char *scan, char *end_buf,
int scan_len) union hermes_scan_info *bss,
unsigned int last_scanned)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
int offset; /* In the scan data */
union hermes_scan_info *atom;
int atom_len;
u16 capabilities; u16 capabilities;
u16 channel; u16 channel;
struct iw_event iwe; /* Temporary buffer */ struct iw_event iwe; /* Temporary buffer */
char * current_ev = buffer; char *p;
char * end_buf = buffer + IW_SCAN_MAX_DATA; char custom[MAX_CUSTOM_LEN];
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 = le16_to_cpup((__le16 *)scan);
/* Sanity check for atom_len */
if (atom_len < sizeof(struct prism2_scan_apinfo)) {
printk(KERN_ERR "%s: Invalid atom_len in scan data: %d\n",
dev->name, atom_len);
return -EIO;
}
} else
atom_len = offsetof(struct prism2_scan_apinfo, atim);
break;
default:
return -EOPNOTSUPP;
}
/* 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 -EIO;
}
/* 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 */ /* First entry *MUST* be the AP MAC address */
iwe.cmd = SIOCGIWAP; iwe.cmd = SIOCGIWAP;
iwe.u.ap_addr.sa_family = ARPHRD_ETHER; iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
memcpy(iwe.u.ap_addr.sa_data, atom->a.bssid, ETH_ALEN); memcpy(iwe.u.ap_addr.sa_data, bss->a.bssid, ETH_ALEN);
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN); 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 */ /* Other entries will be displayed in the order we give them */
/* Add the ESSID */ /* Add the ESSID */
iwe.u.data.length = le16_to_cpu(atom->a.essid_len); iwe.u.data.length = le16_to_cpu(bss->a.essid_len);
if (iwe.u.data.length > 32) if (iwe.u.data.length > 32)
iwe.u.data.length = 32; iwe.u.data.length = 32;
iwe.cmd = SIOCGIWESSID; iwe.cmd = SIOCGIWESSID;
iwe.u.data.flags = 1; iwe.u.data.flags = 1;
current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, atom->a.essid); current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->a.essid);
/* Add mode */ /* Add mode */
iwe.cmd = SIOCGIWMODE; iwe.cmd = SIOCGIWMODE;
capabilities = le16_to_cpu(atom->a.capabilities); capabilities = le16_to_cpu(bss->a.capabilities);
if (capabilities & 0x3) { if (capabilities & 0x3) {
if (capabilities & 0x1) if (capabilities & 0x1)
iwe.u.mode = IW_MODE_MASTER; iwe.u.mode = IW_MODE_MASTER;
...@@ -4002,8 +4082,8 @@ static inline int orinoco_translate_scan(struct net_device *dev, ...@@ -4002,8 +4082,8 @@ static inline int orinoco_translate_scan(struct net_device *dev,
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN); current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN);
} }
channel = atom->s.channel; channel = bss->s.channel;
if ( (channel >= 1) && (channel <= NUM_CHANNELS) ) { if ((channel >= 1) && (channel <= NUM_CHANNELS)) {
/* Add frequency */ /* Add frequency */
iwe.cmd = SIOCGIWFREQ; iwe.cmd = SIOCGIWFREQ;
iwe.u.freq.m = channel_frequency[channel-1] * 100000; iwe.u.freq.m = channel_frequency[channel-1] * 100000;
...@@ -4015,8 +4095,8 @@ static inline int orinoco_translate_scan(struct net_device *dev, ...@@ -4015,8 +4095,8 @@ static inline int orinoco_translate_scan(struct net_device *dev,
/* Add quality statistics */ /* Add quality statistics */
iwe.cmd = IWEVQUAL; iwe.cmd = IWEVQUAL;
iwe.u.qual.updated = 0x10; /* no link quality */ iwe.u.qual.updated = 0x10; /* no link quality */
iwe.u.qual.level = (__u8) le16_to_cpu(atom->a.level) - 0x95; iwe.u.qual.level = (__u8) le16_to_cpu(bss->a.level) - 0x95;
iwe.u.qual.noise = (__u8) le16_to_cpu(atom->a.noise) - 0x95; iwe.u.qual.noise = (__u8) le16_to_cpu(bss->a.noise) - 0x95;
/* Wireless tools prior to 27.pre22 will show link quality /* Wireless tools prior to 27.pre22 will show link quality
* anyway, so we provide a reasonable value. */ * anyway, so we provide a reasonable value. */
if (iwe.u.qual.level > iwe.u.qual.noise) if (iwe.u.qual.level > iwe.u.qual.noise)
...@@ -4032,11 +4112,22 @@ static inline int orinoco_translate_scan(struct net_device *dev, ...@@ -4032,11 +4112,22 @@ static inline int orinoco_translate_scan(struct net_device *dev,
else else
iwe.u.data.flags = IW_ENCODE_DISABLED; iwe.u.data.flags = IW_ENCODE_DISABLED;
iwe.u.data.length = 0; iwe.u.data.length = 0;
current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, atom->a.essid); current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->a.essid);
/* Add EXTRA: Age to display seconds since last beacon/probe response
* for given network. */
iwe.cmd = IWEVCUSTOM;
p = custom;
p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
" Last beacon: %dms ago",
jiffies_to_msecs(jiffies - last_scanned));
iwe.u.data.length = p - custom;
if (iwe.u.data.length)
current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, custom);
/* Bit rate is not available in Lucent/Agere firmwares */ /* Bit rate is not available in Lucent/Agere firmwares */
if (priv->firmware_type != FIRMWARE_TYPE_AGERE) { if (priv->firmware_type != FIRMWARE_TYPE_AGERE) {
char * current_val = current_ev + IW_EV_LCP_LEN; char *current_val = current_ev + IW_EV_LCP_LEN;
int i; int i;
int step; int step;
...@@ -4051,10 +4142,10 @@ static inline int orinoco_translate_scan(struct net_device *dev, ...@@ -4051,10 +4142,10 @@ static inline int orinoco_translate_scan(struct net_device *dev,
/* Max 10 values */ /* Max 10 values */
for (i = 0; i < 10; i += step) { for (i = 0; i < 10; i += step) {
/* NULL terminated */ /* NULL terminated */
if (atom->p.rates[i] == 0x0) if (bss->p.rates[i] == 0x0)
break; break;
/* Bit rate given in 500 kb/s units (+ 0x80) */ /* Bit rate given in 500 kb/s units (+ 0x80) */
iwe.u.bitrate.value = ((atom->p.rates[i] & 0x7f) * 500000); iwe.u.bitrate.value = ((bss->p.rates[i] & 0x7f) * 500000);
current_val = iwe_stream_add_value(current_ev, current_val, current_val = iwe_stream_add_value(current_ev, current_val,
end_buf, &iwe, end_buf, &iwe,
IW_EV_PARAM_LEN); IW_EV_PARAM_LEN);
...@@ -4064,10 +4155,7 @@ static inline int orinoco_translate_scan(struct net_device *dev, ...@@ -4064,10 +4155,7 @@ static inline int orinoco_translate_scan(struct net_device *dev,
current_ev = current_val; current_ev = current_val;
} }
/* The other data in the scan result are not really return current_ev;
* interesting, so for now drop it - Jean II */
}
return current_ev - buffer;
} }
/* Return results of a scan */ /* Return results of a scan */
...@@ -4077,15 +4165,15 @@ static int orinoco_ioctl_getscan(struct net_device *dev, ...@@ -4077,15 +4165,15 @@ static int orinoco_ioctl_getscan(struct net_device *dev,
char *extra) char *extra)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
bss_element *bss;
int err = 0; int err = 0;
unsigned long flags; unsigned long flags;
char *current_ev = extra;
if (orinoco_lock(priv, &flags) != 0) if (orinoco_lock(priv, &flags) != 0)
return -EBUSY; return -EBUSY;
/* If no results yet, ask to try again later */ if (priv->scan_inprogress) {
if (priv->scan_result == NULL) {
if (priv->scan_inprogress)
/* Important note : we don't want to block the caller /* Important note : we don't want to block the caller
* until results are ready for various reasons. * until results are ready for various reasons.
* First, managing wait queues is complex and racy. * First, managing wait queues is complex and racy.
...@@ -4094,51 +4182,28 @@ static int orinoco_ioctl_getscan(struct net_device *dev, ...@@ -4094,51 +4182,28 @@ static int orinoco_ioctl_getscan(struct net_device *dev,
* Third, we generate an Wireless Event, so the * Third, we generate an Wireless Event, so the
* caller can wait itself on that - Jean II */ * caller can wait itself on that - Jean II */
err = -EAGAIN; err = -EAGAIN;
else goto out;
/* 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 */
int ret = orinoco_translate_scan(dev, extra,
priv->scan_result,
priv->scan_len);
if (ret < 0) {
err = ret;
kfree(priv->scan_result);
priv->scan_result = NULL;
} else {
srq->length = ret;
/* Return flags */
srq->flags = (__u16) priv->scan_mode;
/* In any case, Scan results will be cleaned up in the list_for_each_entry(bss, &priv->bss_list, list) {
* reset function and when exiting the driver. /* Translate to WE format this entry */
* The person triggering the scanning may never come to current_ev = orinoco_translate_scan(dev, current_ev,
* pick the results, so we need to do it in those places. extra + srq->length,
* Jean II */ &bss->bss,
bss->last_scanned);
#ifdef SCAN_SINGLE_READ /* Check if there is space for one more entry */
/* If you enable this option, only one client (the first if ((extra + srq->length - current_ev) <= IW_EV_ADDR_LEN) {
* one) will be able to read the result (and only one /* Ask user space to try again with a bigger buffer */
* time). If there is multiple concurent clients that err = -E2BIG;
* want to read scan results, this behavior is not goto out;
* 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 */
} }
/* Scan is no longer in progress */
priv->scan_inprogress = 0;
} }
srq->length = (current_ev - extra);
srq->flags = (__u16) priv->scan_mode;
out:
orinoco_unlock(priv, &flags); orinoco_unlock(priv, &flags);
return err; return err;
} }
......
...@@ -36,6 +36,12 @@ typedef enum { ...@@ -36,6 +36,12 @@ typedef enum {
FIRMWARE_TYPE_SYMBOL FIRMWARE_TYPE_SYMBOL
} fwtype_t; } fwtype_t;
typedef struct {
union hermes_scan_info bss;
unsigned long last_scanned;
struct list_head list;
} bss_element;
struct orinoco_private { struct orinoco_private {
void *card; /* Pointer to card dependent structure */ void *card; /* Pointer to card dependent structure */
int (*hard_reset)(struct orinoco_private *); int (*hard_reset)(struct orinoco_private *);
...@@ -105,10 +111,12 @@ struct orinoco_private { ...@@ -105,10 +111,12 @@ struct orinoco_private {
int promiscuous, mc_count; int promiscuous, mc_count;
/* Scanning support */ /* Scanning support */
struct list_head bss_list;
struct list_head bss_free_list;
bss_element *bss_data;
int scan_inprogress; /* Scan pending... */ int scan_inprogress; /* Scan pending... */
u32 scan_mode; /* Type of scan done */ u32 scan_mode; /* Type of scan done */
char * scan_result; /* Result of previous scan */
int scan_len; /* Lenght of result */
}; };
#ifdef ORINOCO_DEBUG #ifdef ORINOCO_DEBUG
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment