1 /* Helpers for managing scan queues
3 * See copyright notice in main.c
6 #include <linux/kernel.h>
7 #include <linux/string.h>
8 #include <linux/etherdevice.h>
15 #define ORINOCO_MAX_BSS_COUNT 64
17 #define PRIV_BSS ((struct bss_element *)priv->bss_xbss_data)
18 #define PRIV_XBSS ((struct xbss_element *)priv->bss_xbss_data)
20 int orinoco_bss_data_allocate(struct orinoco_private *priv)
22 if (priv->bss_xbss_data)
25 if (priv->has_ext_scan)
26 priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT *
27 sizeof(struct xbss_element),
30 priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT *
31 sizeof(struct bss_element),
34 if (!priv->bss_xbss_data) {
35 printk(KERN_WARNING "Out of memory allocating beacons");
41 void orinoco_bss_data_free(struct orinoco_private *priv)
43 kfree(priv->bss_xbss_data);
44 priv->bss_xbss_data = NULL;
47 void orinoco_bss_data_init(struct orinoco_private *priv)
51 INIT_LIST_HEAD(&priv->bss_free_list);
52 INIT_LIST_HEAD(&priv->bss_list);
53 if (priv->has_ext_scan)
54 for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++)
55 list_add_tail(&(PRIV_XBSS[i].list),
56 &priv->bss_free_list);
58 for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++)
59 list_add_tail(&(PRIV_BSS[i].list),
60 &priv->bss_free_list);
64 void orinoco_clear_scan_results(struct orinoco_private *priv,
65 unsigned long scan_age)
67 if (priv->has_ext_scan) {
68 struct xbss_element *bss;
69 struct xbss_element *tmp_bss;
71 /* Blow away current list of scan results */
72 list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) {
74 time_after(jiffies, bss->last_scanned + scan_age)) {
75 list_move_tail(&bss->list,
76 &priv->bss_free_list);
77 /* Don't blow away ->list, just BSS data */
78 memset(&bss->bss, 0, sizeof(bss->bss));
79 bss->last_scanned = 0;
83 struct bss_element *bss;
84 struct bss_element *tmp_bss;
86 /* Blow away current list of scan results */
87 list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) {
89 time_after(jiffies, bss->last_scanned + scan_age)) {
90 list_move_tail(&bss->list,
91 &priv->bss_free_list);
92 /* Don't blow away ->list, just BSS data */
93 memset(&bss->bss, 0, sizeof(bss->bss));
94 bss->last_scanned = 0;
100 void orinoco_add_ext_scan_result(struct orinoco_private *priv,
101 struct agere_ext_scan_info *atom)
103 struct xbss_element *bss = NULL;
106 /* Try to update an existing bss first */
107 list_for_each_entry(bss, &priv->bss_list, list) {
108 if (compare_ether_addr(bss->bss.bssid, atom->bssid))
111 if (bss->bss.data[1] != atom->data[1])
113 if (memcmp(&bss->bss.data[2], &atom->data[2],
120 /* Grab a bss off the free list */
121 if (!found && !list_empty(&priv->bss_free_list)) {
122 bss = list_entry(priv->bss_free_list.next,
123 struct xbss_element, list);
124 list_del(priv->bss_free_list.next);
126 list_add_tail(&bss->list, &priv->bss_list);
130 /* Always update the BSS to get latest beacon info */
131 memcpy(&bss->bss, atom, sizeof(bss->bss));
132 bss->last_scanned = jiffies;
136 int orinoco_process_scan_results(struct orinoco_private *priv,
140 int offset; /* In the scan data */
141 union hermes_scan_info *atom;
144 switch (priv->firmware_type) {
145 case FIRMWARE_TYPE_AGERE:
146 atom_len = sizeof(struct agere_scan_apinfo);
149 case FIRMWARE_TYPE_SYMBOL:
150 /* Lack of documentation necessitates this hack.
151 * Different firmwares have 68 or 76 byte long atoms.
152 * We try modulo first. If the length divides by both,
153 * we check what would be the channel in the second
154 * frame for a 68-byte atom. 76-byte atoms have 0 there.
155 * Valid channel cannot be 0. */
160 else if (len >= 1292 && buf[68] == 0)
166 case FIRMWARE_TYPE_INTERSIL:
168 if (priv->has_hostscan) {
169 atom_len = le16_to_cpup((__le16 *)buf);
170 /* Sanity check for atom_len */
171 if (atom_len < sizeof(struct prism2_scan_apinfo)) {
172 printk(KERN_ERR "%s: Invalid atom_len in scan "
173 "data: %d\n", priv->ndev->name,
178 atom_len = offsetof(struct prism2_scan_apinfo, atim);
184 /* Check that we got an whole number of atoms */
185 if ((len - offset) % atom_len) {
186 printk(KERN_ERR "%s: Unexpected scan data length %d, "
187 "atom_len %d, offset %d\n", priv->ndev->name, len,
192 orinoco_clear_scan_results(priv, msecs_to_jiffies(15000));
194 /* Read the entries one by one */
195 for (; offset + atom_len <= len; offset += atom_len) {
197 struct bss_element *bss = NULL;
200 atom = (union hermes_scan_info *) (buf + offset);
202 /* Try to update an existing bss first */
203 list_for_each_entry(bss, &priv->bss_list, list) {
204 if (compare_ether_addr(bss->bss.a.bssid, atom->a.bssid))
206 if (le16_to_cpu(bss->bss.a.essid_len) !=
207 le16_to_cpu(atom->a.essid_len))
209 if (memcmp(bss->bss.a.essid, atom->a.essid,
210 le16_to_cpu(atom->a.essid_len)))
216 /* Grab a bss off the free list */
217 if (!found && !list_empty(&priv->bss_free_list)) {
218 bss = list_entry(priv->bss_free_list.next,
219 struct bss_element, list);
220 list_del(priv->bss_free_list.next);
222 list_add_tail(&bss->list, &priv->bss_list);
226 /* Always update the BSS to get latest beacon info */
227 memcpy(&bss->bss, atom, sizeof(bss->bss));
228 bss->last_scanned = jiffies;