aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/orinoco
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/orinoco')
-rw-r--r--drivers/net/wireless/orinoco/Makefile2
-rw-r--r--drivers/net/wireless/orinoco/main.c220
-rw-r--r--drivers/net/wireless/orinoco/scan.c233
-rw-r--r--drivers/net/wireless/orinoco/scan.h29
4 files changed, 265 insertions, 219 deletions
diff --git a/drivers/net/wireless/orinoco/Makefile b/drivers/net/wireless/orinoco/Makefile
index d2ac78559728..efde451a687d 100644
--- a/drivers/net/wireless/orinoco/Makefile
+++ b/drivers/net/wireless/orinoco/Makefile
@@ -1,7 +1,7 @@
1# 1#
2# Makefile for the orinoco wireless device drivers. 2# Makefile for the orinoco wireless device drivers.
3# 3#
4orinoco-objs := main.o 4orinoco-objs := main.o scan.o
5 5
6obj-$(CONFIG_HERMES) += orinoco.o hermes.o hermes_dld.o 6obj-$(CONFIG_HERMES) += orinoco.o hermes.o hermes_dld.o
7obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o 7obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o
diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c
index 9e8da9cbee8c..1063f8cc84e6 100644
--- a/drivers/net/wireless/orinoco/main.c
+++ b/drivers/net/wireless/orinoco/main.c
@@ -95,6 +95,8 @@
95 95
96#include "hermes_rid.h" 96#include "hermes_rid.h"
97#include "hermes_dld.h" 97#include "hermes_dld.h"
98#include "scan.h"
99
98#include "orinoco.h" 100#include "orinoco.h"
99 101
100/********************************************************************/ 102/********************************************************************/
@@ -350,53 +352,6 @@ static inline void set_port_type(struct orinoco_private *priv)
350 } 352 }
351} 353}
352 354
353#define ORINOCO_MAX_BSS_COUNT 64
354static int orinoco_bss_data_allocate(struct orinoco_private *priv)
355{
356 if (priv->bss_xbss_data)
357 return 0;
358
359 if (priv->has_ext_scan)
360 priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT *
361 sizeof(struct xbss_element),
362 GFP_KERNEL);
363 else
364 priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT *
365 sizeof(struct bss_element),
366 GFP_KERNEL);
367
368 if (!priv->bss_xbss_data) {
369 printk(KERN_WARNING "Out of memory allocating beacons");
370 return -ENOMEM;
371 }
372 return 0;
373}
374
375static void orinoco_bss_data_free(struct orinoco_private *priv)
376{
377 kfree(priv->bss_xbss_data);
378 priv->bss_xbss_data = NULL;
379}
380
381#define PRIV_BSS ((struct bss_element *)priv->bss_xbss_data)
382#define PRIV_XBSS ((struct xbss_element *)priv->bss_xbss_data)
383static void orinoco_bss_data_init(struct orinoco_private *priv)
384{
385 int i;
386
387 INIT_LIST_HEAD(&priv->bss_free_list);
388 INIT_LIST_HEAD(&priv->bss_list);
389 if (priv->has_ext_scan)
390 for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++)
391 list_add_tail(&(PRIV_XBSS[i].list),
392 &priv->bss_free_list);
393 else
394 for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++)
395 list_add_tail(&(PRIV_BSS[i].list),
396 &priv->bss_free_list);
397
398}
399
400static inline u8 *orinoco_get_ie(u8 *data, size_t len, 355static inline u8 *orinoco_get_ie(u8 *data, size_t len,
401 enum ieee80211_eid eid) 356 enum ieee80211_eid eid)
402{ 357{
@@ -1857,177 +1812,6 @@ static void orinoco_send_wevents(struct work_struct *work)
1857 orinoco_unlock(priv, &flags); 1812 orinoco_unlock(priv, &flags);
1858} 1813}
1859 1814
1860static inline void orinoco_clear_scan_results(struct orinoco_private *priv,
1861 unsigned long scan_age)
1862{
1863 if (priv->has_ext_scan) {
1864 struct xbss_element *bss;
1865 struct xbss_element *tmp_bss;
1866
1867 /* Blow away current list of scan results */
1868 list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) {
1869 if (!scan_age ||
1870 time_after(jiffies, bss->last_scanned + scan_age)) {
1871 list_move_tail(&bss->list,
1872 &priv->bss_free_list);
1873 /* Don't blow away ->list, just BSS data */
1874 memset(&bss->bss, 0, sizeof(bss->bss));
1875 bss->last_scanned = 0;
1876 }
1877 }
1878 } else {
1879 struct bss_element *bss;
1880 struct bss_element *tmp_bss;
1881
1882 /* Blow away current list of scan results */
1883 list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) {
1884 if (!scan_age ||
1885 time_after(jiffies, bss->last_scanned + scan_age)) {
1886 list_move_tail(&bss->list,
1887 &priv->bss_free_list);
1888 /* Don't blow away ->list, just BSS data */
1889 memset(&bss->bss, 0, sizeof(bss->bss));
1890 bss->last_scanned = 0;
1891 }
1892 }
1893 }
1894}
1895
1896static void orinoco_add_ext_scan_result(struct orinoco_private *priv,
1897 struct agere_ext_scan_info *atom)
1898{
1899 struct xbss_element *bss = NULL;
1900 int found = 0;
1901
1902 /* Try to update an existing bss first */
1903 list_for_each_entry(bss, &priv->bss_list, list) {
1904 if (compare_ether_addr(bss->bss.bssid, atom->bssid))
1905 continue;
1906 /* ESSID lengths */
1907 if (bss->bss.data[1] != atom->data[1])
1908 continue;
1909 if (memcmp(&bss->bss.data[2], &atom->data[2],
1910 atom->data[1]))
1911 continue;
1912 found = 1;
1913 break;
1914 }
1915
1916 /* Grab a bss off the free list */
1917 if (!found && !list_empty(&priv->bss_free_list)) {
1918 bss = list_entry(priv->bss_free_list.next,
1919 struct xbss_element, list);
1920 list_del(priv->bss_free_list.next);
1921
1922 list_add_tail(&bss->list, &priv->bss_list);
1923 }
1924
1925 if (bss) {
1926 /* Always update the BSS to get latest beacon info */
1927 memcpy(&bss->bss, atom, sizeof(bss->bss));
1928 bss->last_scanned = jiffies;
1929 }
1930}
1931
1932static int orinoco_process_scan_results(struct orinoco_private *priv,
1933 unsigned char *buf,
1934 int len)
1935{
1936 int offset; /* In the scan data */
1937 union hermes_scan_info *atom;
1938 int atom_len;
1939
1940 switch (priv->firmware_type) {
1941 case FIRMWARE_TYPE_AGERE:
1942 atom_len = sizeof(struct agere_scan_apinfo);
1943 offset = 0;
1944 break;
1945 case FIRMWARE_TYPE_SYMBOL:
1946 /* Lack of documentation necessitates this hack.
1947 * Different firmwares have 68 or 76 byte long atoms.
1948 * We try modulo first. If the length divides by both,
1949 * we check what would be the channel in the second
1950 * frame for a 68-byte atom. 76-byte atoms have 0 there.
1951 * Valid channel cannot be 0. */
1952 if (len % 76)
1953 atom_len = 68;
1954 else if (len % 68)
1955 atom_len = 76;
1956 else if (len >= 1292 && buf[68] == 0)
1957 atom_len = 76;
1958 else
1959 atom_len = 68;
1960 offset = 0;
1961 break;
1962 case FIRMWARE_TYPE_INTERSIL:
1963 offset = 4;
1964 if (priv->has_hostscan) {
1965 atom_len = le16_to_cpup((__le16 *)buf);
1966 /* Sanity check for atom_len */
1967 if (atom_len < sizeof(struct prism2_scan_apinfo)) {
1968 printk(KERN_ERR "%s: Invalid atom_len in scan "
1969 "data: %d\n", priv->ndev->name,
1970 atom_len);
1971 return -EIO;
1972 }
1973 } else
1974 atom_len = offsetof(struct prism2_scan_apinfo, atim);
1975 break;
1976 default:
1977 return -EOPNOTSUPP;
1978 }
1979
1980 /* Check that we got an whole number of atoms */
1981 if ((len - offset) % atom_len) {
1982 printk(KERN_ERR "%s: Unexpected scan data length %d, "
1983 "atom_len %d, offset %d\n", priv->ndev->name, len,
1984 atom_len, offset);
1985 return -EIO;
1986 }
1987
1988 orinoco_clear_scan_results(priv, msecs_to_jiffies(15000));
1989
1990 /* Read the entries one by one */
1991 for (; offset + atom_len <= len; offset += atom_len) {
1992 int found = 0;
1993 struct bss_element *bss = NULL;
1994
1995 /* Get next atom */
1996 atom = (union hermes_scan_info *) (buf + offset);
1997
1998 /* Try to update an existing bss first */
1999 list_for_each_entry(bss, &priv->bss_list, list) {
2000 if (compare_ether_addr(bss->bss.a.bssid, atom->a.bssid))
2001 continue;
2002 if (le16_to_cpu(bss->bss.a.essid_len) !=
2003 le16_to_cpu(atom->a.essid_len))
2004 continue;
2005 if (memcmp(bss->bss.a.essid, atom->a.essid,
2006 le16_to_cpu(atom->a.essid_len)))
2007 continue;
2008 found = 1;
2009 break;
2010 }
2011
2012 /* Grab a bss off the free list */
2013 if (!found && !list_empty(&priv->bss_free_list)) {
2014 bss = list_entry(priv->bss_free_list.next,
2015 struct bss_element, list);
2016 list_del(priv->bss_free_list.next);
2017
2018 list_add_tail(&bss->list, &priv->bss_list);
2019 }
2020
2021 if (bss) {
2022 /* Always update the BSS to get latest beacon info */
2023 memcpy(&bss->bss, atom, sizeof(bss->bss));
2024 bss->last_scanned = jiffies;
2025 }
2026 }
2027
2028 return 0;
2029}
2030
2031static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) 1815static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
2032{ 1816{
2033 struct orinoco_private *priv = netdev_priv(dev); 1817 struct orinoco_private *priv = netdev_priv(dev);
diff --git a/drivers/net/wireless/orinoco/scan.c b/drivers/net/wireless/orinoco/scan.c
new file mode 100644
index 000000000000..89d699d4dfe6
--- /dev/null
+++ b/drivers/net/wireless/orinoco/scan.c
@@ -0,0 +1,233 @@
1/* Helpers for managing scan queues
2 *
3 * See copyright notice in main.c
4 */
5
6#include <linux/kernel.h>
7#include <linux/string.h>
8#include <linux/etherdevice.h>
9
10#include "hermes.h"
11#include "orinoco.h"
12
13#include "scan.h"
14
15#define ORINOCO_MAX_BSS_COUNT 64
16
17#define PRIV_BSS ((struct bss_element *)priv->bss_xbss_data)
18#define PRIV_XBSS ((struct xbss_element *)priv->bss_xbss_data)
19
20int orinoco_bss_data_allocate(struct orinoco_private *priv)
21{
22 if (priv->bss_xbss_data)
23 return 0;
24
25 if (priv->has_ext_scan)
26 priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT *
27 sizeof(struct xbss_element),
28 GFP_KERNEL);
29 else
30 priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT *
31 sizeof(struct bss_element),
32 GFP_KERNEL);
33
34 if (!priv->bss_xbss_data) {
35 printk(KERN_WARNING "Out of memory allocating beacons");
36 return -ENOMEM;
37 }
38 return 0;
39}
40
41void orinoco_bss_data_free(struct orinoco_private *priv)
42{
43 kfree(priv->bss_xbss_data);
44 priv->bss_xbss_data = NULL;
45}
46
47void orinoco_bss_data_init(struct orinoco_private *priv)
48{
49 int i;
50
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);
57 else
58 for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++)
59 list_add_tail(&(PRIV_BSS[i].list),
60 &priv->bss_free_list);
61
62}
63
64void orinoco_clear_scan_results(struct orinoco_private *priv,
65 unsigned long scan_age)
66{
67 if (priv->has_ext_scan) {
68 struct xbss_element *bss;
69 struct xbss_element *tmp_bss;
70
71 /* Blow away current list of scan results */
72 list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) {
73 if (!scan_age ||
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;
80 }
81 }
82 } else {
83 struct bss_element *bss;
84 struct bss_element *tmp_bss;
85
86 /* Blow away current list of scan results */
87 list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) {
88 if (!scan_age ||
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;
95 }
96 }
97 }
98}
99
100void orinoco_add_ext_scan_result(struct orinoco_private *priv,
101 struct agere_ext_scan_info *atom)
102{
103 struct xbss_element *bss = NULL;
104 int found = 0;
105
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))
109 continue;
110 /* ESSID lengths */
111 if (bss->bss.data[1] != atom->data[1])
112 continue;
113 if (memcmp(&bss->bss.data[2], &atom->data[2],
114 atom->data[1]))
115 continue;
116 found = 1;
117 break;
118 }
119
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);
125
126 list_add_tail(&bss->list, &priv->bss_list);
127 }
128
129 if (bss) {
130 /* Always update the BSS to get latest beacon info */
131 memcpy(&bss->bss, atom, sizeof(bss->bss));
132 bss->last_scanned = jiffies;
133 }
134}
135
136int orinoco_process_scan_results(struct orinoco_private *priv,
137 unsigned char *buf,
138 int len)
139{
140 int offset; /* In the scan data */
141 union hermes_scan_info *atom;
142 int atom_len;
143
144 switch (priv->firmware_type) {
145 case FIRMWARE_TYPE_AGERE:
146 atom_len = sizeof(struct agere_scan_apinfo);
147 offset = 0;
148 break;
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. */
156 if (len % 76)
157 atom_len = 68;
158 else if (len % 68)
159 atom_len = 76;
160 else if (len >= 1292 && buf[68] == 0)
161 atom_len = 76;
162 else
163 atom_len = 68;
164 offset = 0;
165 break;
166 case FIRMWARE_TYPE_INTERSIL:
167 offset = 4;
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,
174 atom_len);
175 return -EIO;
176 }
177 } else
178 atom_len = offsetof(struct prism2_scan_apinfo, atim);
179 break;
180 default:
181 return -EOPNOTSUPP;
182 }
183
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,
188 atom_len, offset);
189 return -EIO;
190 }
191
192 orinoco_clear_scan_results(priv, msecs_to_jiffies(15000));
193
194 /* Read the entries one by one */
195 for (; offset + atom_len <= len; offset += atom_len) {
196 int found = 0;
197 struct bss_element *bss = NULL;
198
199 /* Get next atom */
200 atom = (union hermes_scan_info *) (buf + offset);
201
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))
205 continue;
206 if (le16_to_cpu(bss->bss.a.essid_len) !=
207 le16_to_cpu(atom->a.essid_len))
208 continue;
209 if (memcmp(bss->bss.a.essid, atom->a.essid,
210 le16_to_cpu(atom->a.essid_len)))
211 continue;
212 found = 1;
213 break;
214 }
215
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);
221
222 list_add_tail(&bss->list, &priv->bss_list);
223 }
224
225 if (bss) {
226 /* Always update the BSS to get latest beacon info */
227 memcpy(&bss->bss, atom, sizeof(bss->bss));
228 bss->last_scanned = jiffies;
229 }
230 }
231
232 return 0;
233}
diff --git a/drivers/net/wireless/orinoco/scan.h b/drivers/net/wireless/orinoco/scan.h
new file mode 100644
index 000000000000..f319f7466af1
--- /dev/null
+++ b/drivers/net/wireless/orinoco/scan.h
@@ -0,0 +1,29 @@
1/* Helpers for managing scan queues
2 *
3 * See copyright notice in main.c
4 */
5#ifndef _ORINOCO_SCAN_H_
6#define _ORINOCO_SCAN_H_
7
8/* Forward declarations */
9struct orinoco_private;
10struct agere_ext_scan_info;
11
12/* Setup and free memory for scan results */
13int orinoco_bss_data_allocate(struct orinoco_private *priv);
14void orinoco_bss_data_free(struct orinoco_private *priv);
15void orinoco_bss_data_init(struct orinoco_private *priv);
16
17/* Add scan results */
18void orinoco_add_ext_scan_result(struct orinoco_private *priv,
19 struct agere_ext_scan_info *atom);
20int orinoco_process_scan_results(struct orinoco_private *dev,
21 unsigned char *buf,
22 int len);
23
24/* Clear scan results */
25void orinoco_clear_scan_results(struct orinoco_private *priv,
26 unsigned long scan_age);
27
28
29#endif /* _ORINOCO_SCAN_H_ */