aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless')
-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