]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - net/ieee80211/softmac/ieee80211softmac_scan.c
30e79d45af6bebb074eaa158f255c0b9844a5ad9
[mirror_ubuntu-artful-kernel.git] / net / ieee80211 / softmac / ieee80211softmac_scan.c
1 /*
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 */
13 int
14 ieee80211softmac_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
37 void
38 ieee80211softmac_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
53 void
54 ieee80211softmac_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 */
71 void 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);
87 // 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);
95 schedule_delayed_work(&si->softmac_scan, IEEE80211SOFTMAC_PROBE_DELAY);
96 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
112 static 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
123 int 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);
160 schedule_work(&sm->scaninfo->softmac_scan);
161 spin_unlock_irqrestore(&sm->lock, flags);
162 return 0;
163 }
164
165 void 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
185 void 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 */
204 void 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
215 EXPORT_SYMBOL_GPL(ieee80211softmac_scan_finished);