diff options
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r-- | drivers/net/wireless/orinoco.c | 541 | ||||
-rw-r--r-- | drivers/net/wireless/orinoco.h | 12 |
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 | ||
274 | static 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 | |||
288 | static void orinoco_bss_data_free(struct orinoco_private *priv) | ||
289 | { | ||
290 | kfree(priv->bss_data); | ||
291 | priv->bss_data = NULL; | ||
292 | } | ||
293 | |||
294 | static 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 | |||
1118 | static 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 | |||
1136 | static 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 | |||
1086 | static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) | 1232 | static 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 | ||
2592 | err_out_free: | ||
2593 | free_netdev(dev); | ||
2594 | return NULL; | ||
2450 | } | 2595 | } |
2451 | 2596 | ||
2452 | void free_orinocodev(struct net_device *dev) | 2597 | void 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 */ |
3911 | static inline int orinoco_translate_scan(struct net_device *dev, | 4045 | static 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 | |||
4206 | out: | ||
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 | ||
39 | typedef struct { | ||
40 | union hermes_scan_info bss; | ||
41 | unsigned long last_scanned; | ||
42 | struct list_head list; | ||
43 | } bss_element; | ||
44 | |||
39 | struct orinoco_private { | 45 | struct 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 |