aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2007-10-10 23:56:25 -0400
committerDavid S. Miller <davem@davemloft.net>2008-01-28 18:03:32 -0500
commit1e3428e9e327a6e4163b3674b260dbd719f59839 (patch)
tree98cb9a4e11e72db5da6070c6ff94311097020a13 /drivers
parent40faacc4078d0fef6daaf6f5d1d332d08631bdd8 (diff)
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: Dan Williams <dcbw@redhat.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/orinoco.c541
-rw-r--r--drivers/net/wireless/orinoco.h12
2 files changed, 313 insertions, 240 deletions
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
index ca6c2da7bc5d..100ae333df4d 100644
--- a/drivers/net/wireless/orinoco.c
+++ b/drivers/net/wireless/orinoco.c
@@ -270,6 +270,37 @@ static inline void set_port_type(struct orinoco_private *priv)
270 } 270 }
271} 271}
272 272
273#define ORINOCO_MAX_BSS_COUNT 64
274static int orinoco_bss_data_allocate(struct orinoco_private *priv)
275{
276 if (priv->bss_data)
277 return 0;
278
279 priv->bss_data =
280 kzalloc(ORINOCO_MAX_BSS_COUNT * sizeof(bss_element), GFP_KERNEL);
281 if (!priv->bss_data) {
282 printk(KERN_WARNING "Out of memory allocating beacons");
283 return -ENOMEM;
284 }
285 return 0;
286}
287
288static void orinoco_bss_data_free(struct orinoco_private *priv)
289{
290 kfree(priv->bss_data);
291 priv->bss_data = NULL;
292}
293
294static void orinoco_bss_data_init(struct orinoco_private *priv)
295{
296 int i;
297
298 INIT_LIST_HEAD(&priv->bss_free_list);
299 INIT_LIST_HEAD(&priv->bss_list);
300 for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++)
301 list_add_tail(&priv->bss_data[i].list, &priv->bss_free_list);
302}
303
273/********************************************************************/ 304/********************************************************************/
274/* Device methods */ 305/* Device methods */
275/********************************************************************/ 306/********************************************************************/
@@ -1083,6 +1114,121 @@ static void orinoco_send_wevents(struct work_struct *work)
1083 orinoco_unlock(priv, &flags); 1114 orinoco_unlock(priv, &flags);
1084} 1115}
1085 1116
1117
1118static inline void orinoco_clear_scan_results(struct orinoco_private *priv,
1119 unsigned long scan_age)
1120{
1121 bss_element *bss;
1122 bss_element *tmp_bss;
1123
1124 /* Blow away current list of scan results */
1125 list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) {
1126 if (!scan_age ||
1127 time_after(jiffies, bss->last_scanned + scan_age)) {
1128 list_move_tail(&bss->list, &priv->bss_free_list);
1129 /* Don't blow away ->list, just BSS data */
1130 memset(bss, 0, sizeof(bss->bss));
1131 bss->last_scanned = 0;
1132 }
1133 }
1134}
1135
1136static int orinoco_process_scan_results(struct net_device *dev,
1137 unsigned char *buf,
1138 int len)
1139{
1140 struct orinoco_private *priv = netdev_priv(dev);
1141 int offset; /* In the scan data */
1142 union hermes_scan_info *atom;
1143 int atom_len;
1144
1145 switch (priv->firmware_type) {
1146 case FIRMWARE_TYPE_AGERE:
1147 atom_len = sizeof(struct agere_scan_apinfo);
1148 offset = 0;
1149 break;
1150 case FIRMWARE_TYPE_SYMBOL:
1151 /* Lack of documentation necessitates this hack.
1152 * Different firmwares have 68 or 76 byte long atoms.
1153 * We try modulo first. If the length divides by both,
1154 * we check what would be the channel in the second
1155 * frame for a 68-byte atom. 76-byte atoms have 0 there.
1156 * Valid channel cannot be 0. */
1157 if (len % 76)
1158 atom_len = 68;
1159 else if (len % 68)
1160 atom_len = 76;
1161 else if (len >= 1292 && buf[68] == 0)
1162 atom_len = 76;
1163 else
1164 atom_len = 68;
1165 offset = 0;
1166 break;
1167 case FIRMWARE_TYPE_INTERSIL:
1168 offset = 4;
1169 if (priv->has_hostscan) {
1170 atom_len = le16_to_cpup((__le16 *)buf);
1171 /* Sanity check for atom_len */
1172 if (atom_len < sizeof(struct prism2_scan_apinfo)) {
1173 printk(KERN_ERR "%s: Invalid atom_len in scan "
1174 "data: %d\n", dev->name, atom_len);
1175 return -EIO;
1176 }
1177 } else
1178 atom_len = offsetof(struct prism2_scan_apinfo, atim);
1179 break;
1180 default:
1181 return -EOPNOTSUPP;
1182 }
1183
1184 /* Check that we got an whole number of atoms */
1185 if ((len - offset) % atom_len) {
1186 printk(KERN_ERR "%s: Unexpected scan data length %d, "
1187 "atom_len %d, offset %d\n", dev->name, len,
1188 atom_len, offset);
1189 return -EIO;
1190 }
1191
1192 orinoco_clear_scan_results(priv, msecs_to_jiffies(15000));
1193
1194 /* Read the entries one by one */
1195 for (; offset + atom_len <= len; offset += atom_len) {
1196 int found = 0;
1197 bss_element *bss;
1198
1199 /* Get next atom */
1200 atom = (union hermes_scan_info *) (buf + offset);
1201
1202 /* Try to update an existing bss first */
1203 list_for_each_entry(bss, &priv->bss_list, list) {
1204 if (compare_ether_addr(bss->bss.a.bssid, atom->a.bssid))
1205 continue;
1206 if (le16_to_cpu(bss->bss.a.essid_len) !=
1207 le16_to_cpu(atom->a.essid_len))
1208 continue;
1209 if (memcmp(bss->bss.a.essid, atom->a.essid,
1210 le16_to_cpu(atom->a.essid_len)))
1211 continue;
1212 bss->last_scanned = jiffies;
1213 found = 1;
1214 break;
1215 }
1216
1217 /* Grab a bss off the free list */
1218 if (!found && !list_empty(&priv->bss_free_list)) {
1219 bss = list_entry(priv->bss_free_list.next,
1220 bss_element, list);
1221 list_del(priv->bss_free_list.next);
1222
1223 memcpy(bss, atom, sizeof(bss->bss));
1224 bss->last_scanned = jiffies;
1225 list_add_tail(&bss->list, &priv->bss_list);
1226 }
1227 }
1228
1229 return 0;
1230}
1231
1086static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) 1232static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
1087{ 1233{
1088 struct orinoco_private *priv = netdev_priv(dev); 1234 struct orinoco_private *priv = netdev_priv(dev);
@@ -1208,6 +1354,9 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
1208 union iwreq_data wrqu; 1354 union iwreq_data wrqu;
1209 unsigned char *buf; 1355 unsigned char *buf;
1210 1356
1357 /* Scan is no longer in progress */
1358 priv->scan_inprogress = 0;
1359
1211 /* Sanity check */ 1360 /* Sanity check */
1212 if (len > 4096) { 1361 if (len > 4096) {
1213 printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n", 1362 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 break; 1364 break;
1216 } 1365 }
1217 1366
1218 /* We are a strict producer. If the previous scan results
1219 * have not been consumed, we just have to drop this
1220 * frame. We can't remove the previous results ourselves,
1221 * that would be *very* racy... Jean II */
1222 if (priv->scan_result != NULL) {
1223 printk(KERN_WARNING "%s: Previous scan results not consumed, dropping info frame.\n", dev->name);
1224 break;
1225 }
1226
1227 /* Allocate buffer for results */ 1367 /* Allocate buffer for results */
1228 buf = kmalloc(len, GFP_ATOMIC); 1368 buf = kmalloc(len, GFP_ATOMIC);
1229 if (buf == NULL) 1369 if (buf == NULL)
@@ -1248,18 +1388,17 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
1248 } 1388 }
1249#endif /* ORINOCO_DEBUG */ 1389#endif /* ORINOCO_DEBUG */
1250 1390
1251 /* Allow the clients to access the results */ 1391 if (orinoco_process_scan_results(dev, buf, len) == 0) {
1252 priv->scan_len = len; 1392 /* Send an empty event to user space.
1253 priv->scan_result = buf; 1393 * We don't send the received data on the event because
1254 1394 * it would require us to do complex transcoding, and
1255 /* Send an empty event to user space. 1395 * we want to minimise the work done in the irq handler
1256 * We don't send the received data on the event because 1396 * Use a request to extract the data - Jean II */
1257 * it would require us to do complex transcoding, and 1397 wrqu.data.length = 0;
1258 * we want to minimise the work done in the irq handler 1398 wrqu.data.flags = 0;
1259 * Use a request to extract the data - Jean II */ 1399 wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
1260 wrqu.data.length = 0; 1400 }
1261 wrqu.data.flags = 0; 1401 kfree(buf);
1262 wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
1263 } 1402 }
1264 break; 1403 break;
1265 case HERMES_INQ_SEC_STAT_AGERE: 1404 case HERMES_INQ_SEC_STAT_AGERE:
@@ -1896,8 +2035,7 @@ static void orinoco_reset(struct work_struct *work)
1896 orinoco_unlock(priv, &flags); 2035 orinoco_unlock(priv, &flags);
1897 2036
1898 /* Scanning support: Cleanup of driver struct */ 2037 /* Scanning support: Cleanup of driver struct */
1899 kfree(priv->scan_result); 2038 orinoco_clear_scan_results(priv, 0);
1900 priv->scan_result = NULL;
1901 priv->scan_inprogress = 0; 2039 priv->scan_inprogress = 0;
1902 2040
1903 if (priv->hard_reset) { 2041 if (priv->hard_reset) {
@@ -2412,6 +2550,10 @@ struct net_device *alloc_orinocodev(int sizeof_card,
2412 else 2550 else
2413 priv->card = NULL; 2551 priv->card = NULL;
2414 2552
2553 if (orinoco_bss_data_allocate(priv))
2554 goto err_out_free;
2555 orinoco_bss_data_init(priv);
2556
2415 /* Setup / override net_device fields */ 2557 /* Setup / override net_device fields */
2416 dev->init = orinoco_init; 2558 dev->init = orinoco_init;
2417 dev->hard_start_xmit = orinoco_xmit; 2559 dev->hard_start_xmit = orinoco_xmit;
@@ -2447,13 +2589,16 @@ struct net_device *alloc_orinocodev(int sizeof_card,
2447 2589
2448 return dev; 2590 return dev;
2449 2591
2592err_out_free:
2593 free_netdev(dev);
2594 return NULL;
2450} 2595}
2451 2596
2452void free_orinocodev(struct net_device *dev) 2597void free_orinocodev(struct net_device *dev)
2453{ 2598{
2454 struct orinoco_private *priv = netdev_priv(dev); 2599 struct orinoco_private *priv = netdev_priv(dev);
2455 2600
2456 kfree(priv->scan_result); 2601 orinoco_bss_data_free(priv);
2457 free_netdev(dev); 2602 free_netdev(dev);
2458} 2603}
2459 2604
@@ -3841,23 +3986,10 @@ static int orinoco_ioctl_setscan(struct net_device *dev,
3841 * we access scan variables in priv is critical. 3986 * we access scan variables in priv is critical.
3842 * o scan_inprogress : not touched by irq handler 3987 * o scan_inprogress : not touched by irq handler
3843 * o scan_mode : not touched by irq handler 3988 * o scan_mode : not touched by irq handler
3844 * o scan_result : irq is strict producer, non-irq is strict
3845 * consumer.
3846 * o scan_len : synchronised with scan_result 3989 * o scan_len : synchronised with scan_result
3847 * Before modifying anything on those variables, please think hard ! 3990 * Before modifying anything on those variables, please think hard !
3848 * Jean II */ 3991 * Jean II */
3849 3992
3850 /* If there is still some left-over scan results, get rid of it */
3851 if (priv->scan_result != NULL) {
3852 /* What's likely is that a client did crash or was killed
3853 * between triggering the scan request and reading the
3854 * results, so we need to reset everything.
3855 * Some clients that are too slow may suffer from that...
3856 * Jean II */
3857 kfree(priv->scan_result);
3858 priv->scan_result = NULL;
3859 }
3860
3861 /* Save flags */ 3993 /* Save flags */
3862 priv->scan_mode = srq->flags; 3994 priv->scan_mode = srq->flags;
3863 3995
@@ -3905,169 +4037,125 @@ static int orinoco_ioctl_setscan(struct net_device *dev,
3905 return err; 4037 return err;
3906} 4038}
3907 4039
4040#define MAX_CUSTOM_LEN 64
4041
3908/* Translate scan data returned from the card to a card independant 4042/* Translate scan data returned from the card to a card independant
3909 * format that the Wireless Tools will understand - Jean II 4043 * format that the Wireless Tools will understand - Jean II
3910 * Return message length or -errno for fatal errors */ 4044 * Return message length or -errno for fatal errors */
3911static inline int orinoco_translate_scan(struct net_device *dev, 4045static inline char *orinoco_translate_scan(struct net_device *dev,
3912 char *buffer, 4046 char *current_ev,
3913 char *scan, 4047 char *end_buf,
3914 int scan_len) 4048 union hermes_scan_info *bss,
4049 unsigned int last_scanned)
3915{ 4050{
3916 struct orinoco_private *priv = netdev_priv(dev); 4051 struct orinoco_private *priv = netdev_priv(dev);
3917 int offset; /* In the scan data */
3918 union hermes_scan_info *atom;
3919 int atom_len;
3920 u16 capabilities; 4052 u16 capabilities;
3921 u16 channel; 4053 u16 channel;
3922 struct iw_event iwe; /* Temporary buffer */ 4054 struct iw_event iwe; /* Temporary buffer */
3923 char * current_ev = buffer; 4055 char *p;
3924 char * end_buf = buffer + IW_SCAN_MAX_DATA; 4056 char custom[MAX_CUSTOM_LEN];
3925 4057
3926 switch (priv->firmware_type) { 4058 /* First entry *MUST* be the AP MAC address */
3927 case FIRMWARE_TYPE_AGERE: 4059 iwe.cmd = SIOCGIWAP;
3928 atom_len = sizeof(struct agere_scan_apinfo); 4060 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
3929 offset = 0; 4061 memcpy(iwe.u.ap_addr.sa_data, bss->a.bssid, ETH_ALEN);
3930 break; 4062 current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);
3931 case FIRMWARE_TYPE_SYMBOL: 4063
3932 /* Lack of documentation necessitates this hack. 4064 /* Other entries will be displayed in the order we give them */
3933 * Different firmwares have 68 or 76 byte long atoms. 4065
3934 * We try modulo first. If the length divides by both, 4066 /* Add the ESSID */
3935 * we check what would be the channel in the second 4067 iwe.u.data.length = le16_to_cpu(bss->a.essid_len);
3936 * frame for a 68-byte atom. 76-byte atoms have 0 there. 4068 if (iwe.u.data.length > 32)
3937 * Valid channel cannot be 0. */ 4069 iwe.u.data.length = 32;
3938 if (scan_len % 76) 4070 iwe.cmd = SIOCGIWESSID;
3939 atom_len = 68; 4071 iwe.u.data.flags = 1;
3940 else if (scan_len % 68) 4072 current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->a.essid);
3941 atom_len = 76; 4073
3942 else if (scan_len >= 1292 && scan[68] == 0) 4074 /* Add mode */
3943 atom_len = 76; 4075 iwe.cmd = SIOCGIWMODE;
4076 capabilities = le16_to_cpu(bss->a.capabilities);
4077 if (capabilities & 0x3) {
4078 if (capabilities & 0x1)
4079 iwe.u.mode = IW_MODE_MASTER;
3944 else 4080 else
3945 atom_len = 68; 4081 iwe.u.mode = IW_MODE_ADHOC;
3946 offset = 0; 4082 current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN);
3947 break; 4083 }
3948 case FIRMWARE_TYPE_INTERSIL: 4084
3949 offset = 4; 4085 channel = bss->s.channel;
3950 if (priv->has_hostscan) { 4086 if ((channel >= 1) && (channel <= NUM_CHANNELS)) {
3951 atom_len = le16_to_cpup((__le16 *)scan); 4087 /* Add frequency */
3952 /* Sanity check for atom_len */ 4088 iwe.cmd = SIOCGIWFREQ;
3953 if (atom_len < sizeof(struct prism2_scan_apinfo)) { 4089 iwe.u.freq.m = channel_frequency[channel-1] * 100000;
3954 printk(KERN_ERR "%s: Invalid atom_len in scan data: %d\n", 4090 iwe.u.freq.e = 1;
3955 dev->name, atom_len); 4091 current_ev = iwe_stream_add_event(current_ev, end_buf,
3956 return -EIO; 4092 &iwe, IW_EV_FREQ_LEN);
3957 } 4093 }
3958 } else 4094
3959 atom_len = offsetof(struct prism2_scan_apinfo, atim); 4095 /* Add quality statistics */
3960 break; 4096 iwe.cmd = IWEVQUAL;
3961 default: 4097 iwe.u.qual.updated = 0x10; /* no link quality */
3962 return -EOPNOTSUPP; 4098 iwe.u.qual.level = (__u8) le16_to_cpu(bss->a.level) - 0x95;
3963 } 4099 iwe.u.qual.noise = (__u8) le16_to_cpu(bss->a.noise) - 0x95;
3964 4100 /* Wireless tools prior to 27.pre22 will show link quality
3965 /* Check that we got an whole number of atoms */ 4101 * anyway, so we provide a reasonable value. */
3966 if ((scan_len - offset) % atom_len) { 4102 if (iwe.u.qual.level > iwe.u.qual.noise)
3967 printk(KERN_ERR "%s: Unexpected scan data length %d, " 4103 iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise;
3968 "atom_len %d, offset %d\n", dev->name, scan_len, 4104 else
3969 atom_len, offset); 4105 iwe.u.qual.qual = 0;
3970 return -EIO; 4106 current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
3971 }
3972
3973 /* Read the entries one by one */
3974 for (; offset + atom_len <= scan_len; offset += atom_len) {
3975 /* Get next atom */
3976 atom = (union hermes_scan_info *) (scan + offset);
3977
3978 /* First entry *MUST* be the AP MAC address */
3979 iwe.cmd = SIOCGIWAP;
3980 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
3981 memcpy(iwe.u.ap_addr.sa_data, atom->a.bssid, ETH_ALEN);
3982 current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);
3983
3984 /* Other entries will be displayed in the order we give them */
3985
3986 /* Add the ESSID */
3987 iwe.u.data.length = le16_to_cpu(atom->a.essid_len);
3988 if (iwe.u.data.length > 32)
3989 iwe.u.data.length = 32;
3990 iwe.cmd = SIOCGIWESSID;
3991 iwe.u.data.flags = 1;
3992 current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, atom->a.essid);
3993
3994 /* Add mode */
3995 iwe.cmd = SIOCGIWMODE;
3996 capabilities = le16_to_cpu(atom->a.capabilities);
3997 if (capabilities & 0x3) {
3998 if (capabilities & 0x1)
3999 iwe.u.mode = IW_MODE_MASTER;
4000 else
4001 iwe.u.mode = IW_MODE_ADHOC;
4002 current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN);
4003 }
4004
4005 channel = atom->s.channel;
4006 if ( (channel >= 1) && (channel <= NUM_CHANNELS) ) {
4007 /* Add frequency */
4008 iwe.cmd = SIOCGIWFREQ;
4009 iwe.u.freq.m = channel_frequency[channel-1] * 100000;
4010 iwe.u.freq.e = 1;
4011 current_ev = iwe_stream_add_event(current_ev, end_buf,
4012 &iwe, IW_EV_FREQ_LEN);
4013 }
4014 4107
4015 /* Add quality statistics */ 4108 /* Add encryption capability */
4016 iwe.cmd = IWEVQUAL; 4109 iwe.cmd = SIOCGIWENCODE;
4017 iwe.u.qual.updated = 0x10; /* no link quality */ 4110 if (capabilities & 0x10)
4018 iwe.u.qual.level = (__u8) le16_to_cpu(atom->a.level) - 0x95; 4111 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
4019 iwe.u.qual.noise = (__u8) le16_to_cpu(atom->a.noise) - 0x95; 4112 else
4020 /* Wireless tools prior to 27.pre22 will show link quality 4113 iwe.u.data.flags = IW_ENCODE_DISABLED;
4021 * anyway, so we provide a reasonable value. */ 4114 iwe.u.data.length = 0;
4022 if (iwe.u.qual.level > iwe.u.qual.noise) 4115 current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->a.essid);
4023 iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise; 4116
4024 else 4117 /* Add EXTRA: Age to display seconds since last beacon/probe response
4025 iwe.u.qual.qual = 0; 4118 * for given network. */
4026 current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); 4119 iwe.cmd = IWEVCUSTOM;
4120 p = custom;
4121 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
4122 " Last beacon: %dms ago",
4123 jiffies_to_msecs(jiffies - last_scanned));
4124 iwe.u.data.length = p - custom;
4125 if (iwe.u.data.length)
4126 current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, custom);
4127
4128 /* Bit rate is not available in Lucent/Agere firmwares */
4129 if (priv->firmware_type != FIRMWARE_TYPE_AGERE) {
4130 char *current_val = current_ev + IW_EV_LCP_LEN;
4131 int i;
4132 int step;
4027 4133
4028 /* Add encryption capability */ 4134 if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)
4029 iwe.cmd = SIOCGIWENCODE; 4135 step = 2;
4030 if (capabilities & 0x10)
4031 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
4032 else 4136 else
4033 iwe.u.data.flags = IW_ENCODE_DISABLED; 4137 step = 1;
4034 iwe.u.data.length = 0; 4138
4035 current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, atom->a.essid); 4139 iwe.cmd = SIOCGIWRATE;
4036 4140 /* Those two flags are ignored... */
4037 /* Bit rate is not available in Lucent/Agere firmwares */ 4141 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
4038 if (priv->firmware_type != FIRMWARE_TYPE_AGERE) { 4142 /* Max 10 values */
4039 char * current_val = current_ev + IW_EV_LCP_LEN; 4143 for (i = 0; i < 10; i += step) {
4040 int i; 4144 /* NULL terminated */
4041 int step; 4145 if (bss->p.rates[i] == 0x0)
4042 4146 break;
4043 if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL) 4147 /* Bit rate given in 500 kb/s units (+ 0x80) */
4044 step = 2; 4148 iwe.u.bitrate.value = ((bss->p.rates[i] & 0x7f) * 500000);
4045 else 4149 current_val = iwe_stream_add_value(current_ev, current_val,
4046 step = 1; 4150 end_buf, &iwe,
4047 4151 IW_EV_PARAM_LEN);
4048 iwe.cmd = SIOCGIWRATE;
4049 /* Those two flags are ignored... */
4050 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
4051 /* Max 10 values */
4052 for (i = 0; i < 10; i += step) {
4053 /* NULL terminated */
4054 if (atom->p.rates[i] == 0x0)
4055 break;
4056 /* Bit rate given in 500 kb/s units (+ 0x80) */
4057 iwe.u.bitrate.value = ((atom->p.rates[i] & 0x7f) * 500000);
4058 current_val = iwe_stream_add_value(current_ev, current_val,
4059 end_buf, &iwe,
4060 IW_EV_PARAM_LEN);
4061 }
4062 /* Check if we added any event */
4063 if ((current_val - current_ev) > IW_EV_LCP_LEN)
4064 current_ev = current_val;
4065 } 4152 }
4066 4153 /* Check if we added any event */
4067 /* The other data in the scan result are not really 4154 if ((current_val - current_ev) > IW_EV_LCP_LEN)
4068 * interesting, so for now drop it - Jean II */ 4155 current_ev = current_val;
4069 } 4156 }
4070 return current_ev - buffer; 4157
4158 return current_ev;
4071} 4159}
4072 4160
4073/* Return results of a scan */ 4161/* Return results of a scan */
@@ -4077,68 +4165,45 @@ static int orinoco_ioctl_getscan(struct net_device *dev,
4077 char *extra) 4165 char *extra)
4078{ 4166{
4079 struct orinoco_private *priv = netdev_priv(dev); 4167 struct orinoco_private *priv = netdev_priv(dev);
4168 bss_element *bss;
4080 int err = 0; 4169 int err = 0;
4081 unsigned long flags; 4170 unsigned long flags;
4171 char *current_ev = extra;
4082 4172
4083 if (orinoco_lock(priv, &flags) != 0) 4173 if (orinoco_lock(priv, &flags) != 0)
4084 return -EBUSY; 4174 return -EBUSY;
4085 4175
4086 /* If no results yet, ask to try again later */ 4176 if (priv->scan_inprogress) {
4087 if (priv->scan_result == NULL) { 4177 /* Important note : we don't want to block the caller
4088 if (priv->scan_inprogress) 4178 * until results are ready for various reasons.
4089 /* Important note : we don't want to block the caller 4179 * First, managing wait queues is complex and racy.
4090 * until results are ready for various reasons. 4180 * Second, we grab some rtnetlink lock before comming
4091 * First, managing wait queues is complex and racy. 4181 * here (in dev_ioctl()).
4092 * Second, we grab some rtnetlink lock before comming 4182 * Third, we generate an Wireless Event, so the
4093 * here (in dev_ioctl()). 4183 * caller can wait itself on that - Jean II */
4094 * Third, we generate an Wireless Event, so the 4184 err = -EAGAIN;
4095 * caller can wait itself on that - Jean II */ 4185 goto out;
4096 err = -EAGAIN; 4186 }
4097 else
4098 /* Client error, no scan results...
4099 * The caller need to restart the scan. */
4100 err = -ENODATA;
4101 } else {
4102 /* We have some results to push back to user space */
4103
4104 /* Translate to WE format */
4105 int ret = orinoco_translate_scan(dev, extra,
4106 priv->scan_result,
4107 priv->scan_len);
4108
4109 if (ret < 0) {
4110 err = ret;
4111 kfree(priv->scan_result);
4112 priv->scan_result = NULL;
4113 } else {
4114 srq->length = ret;
4115 4187
4116 /* Return flags */ 4188 list_for_each_entry(bss, &priv->bss_list, list) {
4117 srq->flags = (__u16) priv->scan_mode; 4189 /* Translate to WE format this entry */
4190 current_ev = orinoco_translate_scan(dev, current_ev,
4191 extra + srq->length,
4192 &bss->bss,
4193 bss->last_scanned);
4118 4194
4119 /* In any case, Scan results will be cleaned up in the 4195 /* Check if there is space for one more entry */
4120 * reset function and when exiting the driver. 4196 if ((extra + srq->length - current_ev) <= IW_EV_ADDR_LEN) {
4121 * The person triggering the scanning may never come to 4197 /* Ask user space to try again with a bigger buffer */
4122 * pick the results, so we need to do it in those places. 4198 err = -E2BIG;
4123 * Jean II */ 4199 goto out;
4124
4125#ifdef SCAN_SINGLE_READ
4126 /* If you enable this option, only one client (the first
4127 * one) will be able to read the result (and only one
4128 * time). If there is multiple concurent clients that
4129 * want to read scan results, this behavior is not
4130 * advisable - Jean II */
4131 kfree(priv->scan_result);
4132 priv->scan_result = NULL;
4133#endif /* SCAN_SINGLE_READ */
4134 /* Here, if too much time has elapsed since last scan,
4135 * we may want to clean up scan results... - Jean II */
4136 } 4200 }
4137
4138 /* Scan is no longer in progress */
4139 priv->scan_inprogress = 0;
4140 } 4201 }
4141 4202
4203 srq->length = (current_ev - extra);
4204 srq->flags = (__u16) priv->scan_mode;
4205
4206out:
4142 orinoco_unlock(priv, &flags); 4207 orinoco_unlock(priv, &flags);
4143 return err; 4208 return err;
4144} 4209}
diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h
index 4720fb20d66d..c6b1858abde8 100644
--- a/drivers/net/wireless/orinoco.h
+++ b/drivers/net/wireless/orinoco.h
@@ -36,6 +36,12 @@ typedef enum {
36 FIRMWARE_TYPE_SYMBOL 36 FIRMWARE_TYPE_SYMBOL
37} fwtype_t; 37} fwtype_t;
38 38
39typedef struct {
40 union hermes_scan_info bss;
41 unsigned long last_scanned;
42 struct list_head list;
43} bss_element;
44
39struct orinoco_private { 45struct orinoco_private {
40 void *card; /* Pointer to card dependent structure */ 46 void *card; /* Pointer to card dependent structure */
41 int (*hard_reset)(struct orinoco_private *); 47 int (*hard_reset)(struct orinoco_private *);
@@ -105,10 +111,12 @@ struct orinoco_private {
105 int promiscuous, mc_count; 111 int promiscuous, mc_count;
106 112
107 /* Scanning support */ 113 /* Scanning support */
114 struct list_head bss_list;
115 struct list_head bss_free_list;
116 bss_element *bss_data;
117
108 int scan_inprogress; /* Scan pending... */ 118 int scan_inprogress; /* Scan pending... */
109 u32 scan_mode; /* Type of scan done */ 119 u32 scan_mode; /* Type of scan done */
110 char * scan_result; /* Result of previous scan */
111 int scan_len; /* Lenght of result */
112}; 120};
113 121
114#ifdef ORINOCO_DEBUG 122#ifdef ORINOCO_DEBUG