blob: 30e79d45af6bebb074eaa158f255c0b9844a5ad9 [file] [log] [blame]
Johannes Berg370121e2006-01-04 16:32:16 +01001/*
2 * Scanning routines.
3 *
4 * These are not exported because they're assigned to the function pointers.
5 */
6
7#include <linux/completion.h>
8#include "ieee80211softmac_priv.h"
9
10/* internal, use to trigger scanning if needed.
11 * Returns -EBUSY if already scanning,
12 * result of start_scan otherwise */
13int
14ieee80211softmac_start_scan(struct ieee80211softmac_device *sm)
15{
16 unsigned long flags;
17 int ret;
18
19 spin_lock_irqsave(&sm->lock, flags);
20 if (sm->scanning)
21 {
22 spin_unlock_irqrestore(&sm->lock, flags);
23 return -EINPROGRESS;
24 }
25 sm->scanning = 1;
26 spin_unlock_irqrestore(&sm->lock, flags);
27
28 ret = sm->start_scan(sm->dev);
29 if (ret) {
30 spin_lock_irqsave(&sm->lock, flags);
31 sm->scanning = 0;
32 spin_unlock_irqrestore(&sm->lock, flags);
33 }
34 return ret;
35}
36
37void
38ieee80211softmac_stop_scan(struct ieee80211softmac_device *sm)
39{
40 unsigned long flags;
41
42 spin_lock_irqsave(&sm->lock, flags);
43
44 if (!sm->scanning) {
45 spin_unlock_irqrestore(&sm->lock, flags);
46 return;
47 }
48
49 spin_unlock_irqrestore(&sm->lock, flags);
50 sm->stop_scan(sm->dev);
51}
52
53void
54ieee80211softmac_wait_for_scan(struct ieee80211softmac_device *sm)
55{
56 unsigned long flags;
57
58 spin_lock_irqsave(&sm->lock, flags);
59
60 if (!sm->scanning) {
61 spin_unlock_irqrestore(&sm->lock, flags);
62 return;
63 }
64
65 spin_unlock_irqrestore(&sm->lock, flags);
66 sm->wait_for_scan(sm->dev);
67}
68
69
70/* internal scanning implementation follows */
71void ieee80211softmac_scan(void *d)
72{
73 int invalid_channel;
74 u8 current_channel_idx;
75 struct ieee80211softmac_device *sm = (struct ieee80211softmac_device *)d;
76 struct ieee80211softmac_scaninfo *si = sm->scaninfo;
77 unsigned long flags;
78
79 while (!(si->stop) && (si->current_channel_idx < si->number_channels)) {
80 current_channel_idx = si->current_channel_idx;
81 si->current_channel_idx++; /* go to the next channel */
82
83 invalid_channel = (si->skip_flags & si->channels[current_channel_idx].flags);
84
85 if (!invalid_channel) {
86 sm->set_channel(sm->dev, si->channels[current_channel_idx].channel);
Johannes Berg370121e2006-01-04 16:32:16 +010087 // FIXME make this user configurable (active/passive)
88 if(ieee80211softmac_send_mgt_frame(sm, NULL, IEEE80211_STYPE_PROBE_REQ, 0))
89 printkl(KERN_DEBUG PFX "Sending Probe Request Failed\n");
90
91 /* also send directed management frame for the network we're looking for */
92 // TODO: is this if correct, or should we do this only if scanning from assoc request?
93 if (sm->associnfo.req_essid.len)
94 ieee80211softmac_send_mgt_frame(sm, &sm->associnfo.req_essid, IEEE80211_STYPE_PROBE_REQ, 0);
Johannes Berg5c4df6d2006-01-06 01:43:45 +010095 schedule_delayed_work(&si->softmac_scan, IEEE80211SOFTMAC_PROBE_DELAY);
Johannes Berg370121e2006-01-04 16:32:16 +010096 return;
97 } else {
98 dprintk(PFX "Not probing Channel %d (not allowed here)\n", si->channels[current_channel_idx].channel);
99 }
100 }
101
102 spin_lock_irqsave(&sm->lock, flags);
103 cancel_delayed_work(&si->softmac_scan);
104 si->started = 0;
105 spin_unlock_irqrestore(&sm->lock, flags);
106
107 dprintk(PFX "Scanning finished\n");
108 ieee80211softmac_scan_finished(sm);
109 complete_all(&sm->scaninfo->finished);
110}
111
112static inline struct ieee80211softmac_scaninfo *allocate_scaninfo(struct ieee80211softmac_device *mac)
113{
114 /* ugh. can we call this without having the spinlock held? */
115 struct ieee80211softmac_scaninfo *info = kmalloc(sizeof(struct ieee80211softmac_scaninfo), GFP_ATOMIC);
116 if (unlikely(!info))
117 return NULL;
118 INIT_WORK(&info->softmac_scan, ieee80211softmac_scan, mac);
119 init_completion(&info->finished);
120 return info;
121}
122
123int ieee80211softmac_start_scan_implementation(struct net_device *dev)
124{
125 struct ieee80211softmac_device *sm = ieee80211_priv(dev);
126 unsigned long flags;
127
128 if (!(dev->flags & IFF_UP))
129 return -ENODEV;
130
131 assert(ieee80211softmac_scan_handlers_check_self(sm));
132 if (!ieee80211softmac_scan_handlers_check_self(sm))
133 return -EINVAL;
134
135 spin_lock_irqsave(&sm->lock, flags);
136 /* it looks like we need to hold the lock here
137 * to make sure we don't allocate two of these... */
138 if (unlikely(!sm->scaninfo))
139 sm->scaninfo = allocate_scaninfo(sm);
140 if (unlikely(!sm->scaninfo)) {
141 spin_unlock_irqrestore(&sm->lock, flags);
142 return -ENOMEM;
143 }
144
145 sm->scaninfo->skip_flags = IEEE80211_CH_INVALID;
146 if (0 /* not scanning in IEEE802.11b */)//TODO
147 sm->scaninfo->skip_flags |= IEEE80211_CH_B_ONLY;
148 if (0 /* IEEE802.11a */) {//TODO
149 sm->scaninfo->channels = sm->ieee->geo.a;
150 sm->scaninfo->number_channels = sm->ieee->geo.a_channels;
151 } else {
152 sm->scaninfo->channels = sm->ieee->geo.bg;
153 sm->scaninfo->number_channels = sm->ieee->geo.bg_channels;
154 }
155 dprintk(PFX "Start scanning with channel: %d\n", sm->scaninfo->channels[0].channel);
156 dprintk(PFX "Scanning %d channels\n", sm->scaninfo->number_channels);
157 sm->scaninfo->current_channel_idx = 0;
158 sm->scaninfo->started = 1;
159 INIT_COMPLETION(sm->scaninfo->finished);
Johannes Berg5c4df6d2006-01-06 01:43:45 +0100160 schedule_work(&sm->scaninfo->softmac_scan);
Johannes Berg370121e2006-01-04 16:32:16 +0100161 spin_unlock_irqrestore(&sm->lock, flags);
162 return 0;
163}
164
165void ieee80211softmac_stop_scan_implementation(struct net_device *dev)
166{
167 struct ieee80211softmac_device *sm = ieee80211_priv(dev);
168 unsigned long flags;
169
170 assert(ieee80211softmac_scan_handlers_check_self(sm));
171 if (!ieee80211softmac_scan_handlers_check_self(sm))
172 return;
173
174 spin_lock_irqsave(&sm->lock, flags);
175 assert(sm->scaninfo != NULL);
176 if (sm->scaninfo) {
177 if (sm->scaninfo->started)
178 sm->scaninfo->stop = 1;
179 else
180 complete_all(&sm->scaninfo->finished);
181 }
182 spin_unlock_irqrestore(&sm->lock, flags);
183}
184
185void ieee80211softmac_wait_for_scan_implementation(struct net_device *dev)
186{
187 struct ieee80211softmac_device *sm = ieee80211_priv(dev);
188 unsigned long flags;
189
190 assert(ieee80211softmac_scan_handlers_check_self(sm));
191 if (!ieee80211softmac_scan_handlers_check_self(sm))
192 return;
193
194 spin_lock_irqsave(&sm->lock, flags);
195 if (!sm->scaninfo->started) {
196 spin_unlock_irqrestore(&sm->lock, flags);
197 return;
198 }
199 spin_unlock_irqrestore(&sm->lock, flags);
200 wait_for_completion(&sm->scaninfo->finished);
201}
202
203/* this is what drivers (that do scanning) call when they're done */
204void ieee80211softmac_scan_finished(struct ieee80211softmac_device *sm)
205{
206 unsigned long flags;
207
208 spin_lock_irqsave(&sm->lock, flags);
209 sm->scanning = 0;
210 spin_unlock_irqrestore(&sm->lock, flags);
211
212 ieee80211softmac_call_events(sm, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, NULL);
213}
214
215EXPORT_SYMBOL_GPL(ieee80211softmac_scan_finished);