• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 /* Host AP driver Info Frame processing (part of hostap.o module) */
3 
4 #include <linux/if_arp.h>
5 #include <linux/sched.h>
6 #include <linux/slab.h>
7 #include <linux/export.h>
8 #include <linux/etherdevice.h>
9 #include "hostap_wlan.h"
10 #include "hostap.h"
11 #include "hostap_ap.h"
12 
13 /* Called only as a tasklet (software IRQ) */
prism2_info_commtallies16(local_info_t * local,unsigned char * buf,int left)14 static void prism2_info_commtallies16(local_info_t *local, unsigned char *buf,
15 				      int left)
16 {
17 	struct hfa384x_comm_tallies *tallies;
18 
19 	if (left < sizeof(struct hfa384x_comm_tallies)) {
20 		printk(KERN_DEBUG "%s: too short (len=%d) commtallies "
21 		       "info frame\n", local->dev->name, left);
22 		return;
23 	}
24 
25 	tallies = (struct hfa384x_comm_tallies *) buf;
26 #define ADD_COMM_TALLIES(name) \
27 local->comm_tallies.name += le16_to_cpu(tallies->name)
28 	ADD_COMM_TALLIES(tx_unicast_frames);
29 	ADD_COMM_TALLIES(tx_multicast_frames);
30 	ADD_COMM_TALLIES(tx_fragments);
31 	ADD_COMM_TALLIES(tx_unicast_octets);
32 	ADD_COMM_TALLIES(tx_multicast_octets);
33 	ADD_COMM_TALLIES(tx_deferred_transmissions);
34 	ADD_COMM_TALLIES(tx_single_retry_frames);
35 	ADD_COMM_TALLIES(tx_multiple_retry_frames);
36 	ADD_COMM_TALLIES(tx_retry_limit_exceeded);
37 	ADD_COMM_TALLIES(tx_discards);
38 	ADD_COMM_TALLIES(rx_unicast_frames);
39 	ADD_COMM_TALLIES(rx_multicast_frames);
40 	ADD_COMM_TALLIES(rx_fragments);
41 	ADD_COMM_TALLIES(rx_unicast_octets);
42 	ADD_COMM_TALLIES(rx_multicast_octets);
43 	ADD_COMM_TALLIES(rx_fcs_errors);
44 	ADD_COMM_TALLIES(rx_discards_no_buffer);
45 	ADD_COMM_TALLIES(tx_discards_wrong_sa);
46 	ADD_COMM_TALLIES(rx_discards_wep_undecryptable);
47 	ADD_COMM_TALLIES(rx_message_in_msg_fragments);
48 	ADD_COMM_TALLIES(rx_message_in_bad_msg_fragments);
49 #undef ADD_COMM_TALLIES
50 }
51 
52 
53 /* Called only as a tasklet (software IRQ) */
prism2_info_commtallies32(local_info_t * local,unsigned char * buf,int left)54 static void prism2_info_commtallies32(local_info_t *local, unsigned char *buf,
55 				      int left)
56 {
57 	struct hfa384x_comm_tallies32 *tallies;
58 
59 	if (left < sizeof(struct hfa384x_comm_tallies32)) {
60 		printk(KERN_DEBUG "%s: too short (len=%d) commtallies32 "
61 		       "info frame\n", local->dev->name, left);
62 		return;
63 	}
64 
65 	tallies = (struct hfa384x_comm_tallies32 *) buf;
66 #define ADD_COMM_TALLIES(name) \
67 local->comm_tallies.name += le32_to_cpu(tallies->name)
68 	ADD_COMM_TALLIES(tx_unicast_frames);
69 	ADD_COMM_TALLIES(tx_multicast_frames);
70 	ADD_COMM_TALLIES(tx_fragments);
71 	ADD_COMM_TALLIES(tx_unicast_octets);
72 	ADD_COMM_TALLIES(tx_multicast_octets);
73 	ADD_COMM_TALLIES(tx_deferred_transmissions);
74 	ADD_COMM_TALLIES(tx_single_retry_frames);
75 	ADD_COMM_TALLIES(tx_multiple_retry_frames);
76 	ADD_COMM_TALLIES(tx_retry_limit_exceeded);
77 	ADD_COMM_TALLIES(tx_discards);
78 	ADD_COMM_TALLIES(rx_unicast_frames);
79 	ADD_COMM_TALLIES(rx_multicast_frames);
80 	ADD_COMM_TALLIES(rx_fragments);
81 	ADD_COMM_TALLIES(rx_unicast_octets);
82 	ADD_COMM_TALLIES(rx_multicast_octets);
83 	ADD_COMM_TALLIES(rx_fcs_errors);
84 	ADD_COMM_TALLIES(rx_discards_no_buffer);
85 	ADD_COMM_TALLIES(tx_discards_wrong_sa);
86 	ADD_COMM_TALLIES(rx_discards_wep_undecryptable);
87 	ADD_COMM_TALLIES(rx_message_in_msg_fragments);
88 	ADD_COMM_TALLIES(rx_message_in_bad_msg_fragments);
89 #undef ADD_COMM_TALLIES
90 }
91 
92 
93 /* Called only as a tasklet (software IRQ) */
prism2_info_commtallies(local_info_t * local,unsigned char * buf,int left)94 static void prism2_info_commtallies(local_info_t *local, unsigned char *buf,
95 				    int left)
96 {
97 	if (local->tallies32)
98 		prism2_info_commtallies32(local, buf, left);
99 	else
100 		prism2_info_commtallies16(local, buf, left);
101 }
102 
103 
104 #ifndef PRISM2_NO_STATION_MODES
105 #ifndef PRISM2_NO_DEBUG
hfa384x_linkstatus_str(u16 linkstatus)106 static const char* hfa384x_linkstatus_str(u16 linkstatus)
107 {
108 	switch (linkstatus) {
109 	case HFA384X_LINKSTATUS_CONNECTED:
110 		return "Connected";
111 	case HFA384X_LINKSTATUS_DISCONNECTED:
112 		return "Disconnected";
113 	case HFA384X_LINKSTATUS_AP_CHANGE:
114 		return "Access point change";
115 	case HFA384X_LINKSTATUS_AP_OUT_OF_RANGE:
116 		return "Access point out of range";
117 	case HFA384X_LINKSTATUS_AP_IN_RANGE:
118 		return "Access point in range";
119 	case HFA384X_LINKSTATUS_ASSOC_FAILED:
120 		return "Association failed";
121 	default:
122 		return "Unknown";
123 	}
124 }
125 #endif /* PRISM2_NO_DEBUG */
126 
127 
128 /* Called only as a tasklet (software IRQ) */
prism2_info_linkstatus(local_info_t * local,unsigned char * buf,int left)129 static void prism2_info_linkstatus(local_info_t *local, unsigned char *buf,
130 				    int left)
131 {
132 	u16 val;
133 	int non_sta_mode;
134 
135 	/* Alloc new JoinRequests to occur since LinkStatus for the previous
136 	 * has been received */
137 	local->last_join_time = 0;
138 
139 	if (left != 2) {
140 		printk(KERN_DEBUG "%s: invalid linkstatus info frame "
141 		       "length %d\n", local->dev->name, left);
142 		return;
143 	}
144 
145 	non_sta_mode = local->iw_mode == IW_MODE_MASTER ||
146 		local->iw_mode == IW_MODE_REPEAT ||
147 		local->iw_mode == IW_MODE_MONITOR;
148 
149 	val = buf[0] | (buf[1] << 8);
150 	if (!non_sta_mode || val != HFA384X_LINKSTATUS_DISCONNECTED) {
151 		PDEBUG(DEBUG_EXTRA, "%s: LinkStatus=%d (%s)\n",
152 		       local->dev->name, val, hfa384x_linkstatus_str(val));
153 	}
154 
155 	if (non_sta_mode) {
156 		netif_carrier_on(local->dev);
157 		netif_carrier_on(local->ddev);
158 		return;
159 	}
160 
161 	/* Get current BSSID later in scheduled task */
162 	set_bit(PRISM2_INFO_PENDING_LINKSTATUS, &local->pending_info);
163 	local->prev_link_status = val;
164 	schedule_work(&local->info_queue);
165 }
166 
167 
prism2_host_roaming(local_info_t * local)168 static void prism2_host_roaming(local_info_t *local)
169 {
170 	struct hfa384x_join_request req;
171 	struct net_device *dev = local->dev;
172 	struct hfa384x_hostscan_result *selected, *entry;
173 	int i;
174 	unsigned long flags;
175 
176 	if (local->last_join_time &&
177 	    time_before(jiffies, local->last_join_time + 10 * HZ)) {
178 		PDEBUG(DEBUG_EXTRA, "%s: last join request has not yet been "
179 		       "completed - waiting for it before issuing new one\n",
180 		       dev->name);
181 		return;
182 	}
183 
184 	/* ScanResults are sorted: first ESS results in decreasing signal
185 	 * quality then IBSS results in similar order.
186 	 * Trivial roaming policy: just select the first entry.
187 	 * This could probably be improved by adding hysteresis to limit
188 	 * number of handoffs, etc.
189 	 *
190 	 * Could do periodic RID_SCANREQUEST or Inquire F101 to get new
191 	 * ScanResults */
192 	spin_lock_irqsave(&local->lock, flags);
193 	if (local->last_scan_results == NULL ||
194 	    local->last_scan_results_count == 0) {
195 		spin_unlock_irqrestore(&local->lock, flags);
196 		PDEBUG(DEBUG_EXTRA, "%s: no scan results for host roaming\n",
197 		       dev->name);
198 		return;
199 	}
200 
201 	selected = &local->last_scan_results[0];
202 
203 	if (local->preferred_ap[0] || local->preferred_ap[1] ||
204 	    local->preferred_ap[2] || local->preferred_ap[3] ||
205 	    local->preferred_ap[4] || local->preferred_ap[5]) {
206 		/* Try to find preferred AP */
207 		PDEBUG(DEBUG_EXTRA, "%s: Preferred AP BSSID %pM\n",
208 		       dev->name, local->preferred_ap);
209 		for (i = 0; i < local->last_scan_results_count; i++) {
210 			entry = &local->last_scan_results[i];
211 			if (memcmp(local->preferred_ap, entry->bssid, 6) == 0)
212 			{
213 				PDEBUG(DEBUG_EXTRA, "%s: using preferred AP "
214 				       "selection\n", dev->name);
215 				selected = entry;
216 				break;
217 			}
218 		}
219 	}
220 
221 	memcpy(req.bssid, selected->bssid, ETH_ALEN);
222 	req.channel = selected->chid;
223 	spin_unlock_irqrestore(&local->lock, flags);
224 
225 	PDEBUG(DEBUG_EXTRA, "%s: JoinRequest: BSSID=%pM"
226 	       " channel=%d\n",
227 	       dev->name, req.bssid, le16_to_cpu(req.channel));
228 	if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req,
229 				 sizeof(req))) {
230 		printk(KERN_DEBUG "%s: JoinRequest failed\n", dev->name);
231 	}
232 	local->last_join_time = jiffies;
233 }
234 
235 
hostap_report_scan_complete(local_info_t * local)236 static void hostap_report_scan_complete(local_info_t *local)
237 {
238 	union iwreq_data wrqu;
239 
240 	/* Inform user space about new scan results (just empty event,
241 	 * SIOCGIWSCAN can be used to fetch data */
242 	wrqu.data.length = 0;
243 	wrqu.data.flags = 0;
244 	wireless_send_event(local->dev, SIOCGIWSCAN, &wrqu, NULL);
245 
246 	/* Allow SIOCGIWSCAN handling to occur since we have received
247 	 * scanning result */
248 	local->scan_timestamp = 0;
249 }
250 
251 
252 /* Called only as a tasklet (software IRQ) */
prism2_info_scanresults(local_info_t * local,unsigned char * buf,int left)253 static void prism2_info_scanresults(local_info_t *local, unsigned char *buf,
254 				    int left)
255 {
256 	u16 *pos;
257 	int new_count, i;
258 	unsigned long flags;
259 	struct hfa384x_scan_result *res;
260 	struct hfa384x_hostscan_result *results, *prev;
261 
262 	if (left < 4) {
263 		printk(KERN_DEBUG "%s: invalid scanresult info frame "
264 		       "length %d\n", local->dev->name, left);
265 		return;
266 	}
267 
268 	pos = (u16 *) buf;
269 	pos++;
270 	pos++;
271 	left -= 4;
272 
273 	new_count = left / sizeof(struct hfa384x_scan_result);
274 	results = kmalloc_array(new_count,
275 				sizeof(struct hfa384x_hostscan_result),
276 				GFP_ATOMIC);
277 	if (results == NULL)
278 		return;
279 
280 	/* Convert to hostscan result format. */
281 	res = (struct hfa384x_scan_result *) pos;
282 	for (i = 0; i < new_count; i++) {
283 		memcpy(&results[i], &res[i],
284 		       sizeof(struct hfa384x_scan_result));
285 		results[i].atim = 0;
286 	}
287 
288 	spin_lock_irqsave(&local->lock, flags);
289 	local->last_scan_type = PRISM2_SCAN;
290 	prev = local->last_scan_results;
291 	local->last_scan_results = results;
292 	local->last_scan_results_count = new_count;
293 	spin_unlock_irqrestore(&local->lock, flags);
294 	kfree(prev);
295 
296 	hostap_report_scan_complete(local);
297 
298 	/* Perform rest of ScanResults handling later in scheduled task */
299 	set_bit(PRISM2_INFO_PENDING_SCANRESULTS, &local->pending_info);
300 	schedule_work(&local->info_queue);
301 }
302 
303 
304 /* Called only as a tasklet (software IRQ) */
prism2_info_hostscanresults(local_info_t * local,unsigned char * buf,int left)305 static void prism2_info_hostscanresults(local_info_t *local,
306 					unsigned char *buf, int left)
307 {
308 	int i, result_size, copy_len, new_count;
309 	struct hfa384x_hostscan_result *results, *prev;
310 	unsigned long flags;
311 	__le16 *pos;
312 	u8 *ptr;
313 
314 	wake_up_interruptible(&local->hostscan_wq);
315 
316 	if (left < 4) {
317 		printk(KERN_DEBUG "%s: invalid hostscanresult info frame "
318 		       "length %d\n", local->dev->name, left);
319 		return;
320 	}
321 
322 	pos = (__le16 *) buf;
323 	copy_len = result_size = le16_to_cpu(*pos);
324 	if (result_size == 0) {
325 		printk(KERN_DEBUG "%s: invalid result_size (0) in "
326 		       "hostscanresults\n", local->dev->name);
327 		return;
328 	}
329 	if (copy_len > sizeof(struct hfa384x_hostscan_result))
330 		copy_len = sizeof(struct hfa384x_hostscan_result);
331 
332 	pos++;
333 	pos++;
334 	left -= 4;
335 	ptr = (u8 *) pos;
336 
337 	new_count = left / result_size;
338 	results = kcalloc(new_count, sizeof(struct hfa384x_hostscan_result),
339 			  GFP_ATOMIC);
340 	if (results == NULL)
341 		return;
342 
343 	for (i = 0; i < new_count; i++) {
344 		memcpy(&results[i], ptr, copy_len);
345 		ptr += result_size;
346 		left -= result_size;
347 	}
348 
349 	if (left) {
350 		printk(KERN_DEBUG "%s: short HostScan result entry (%d/%d)\n",
351 		       local->dev->name, left, result_size);
352 	}
353 
354 	spin_lock_irqsave(&local->lock, flags);
355 	local->last_scan_type = PRISM2_HOSTSCAN;
356 	prev = local->last_scan_results;
357 	local->last_scan_results = results;
358 	local->last_scan_results_count = new_count;
359 	spin_unlock_irqrestore(&local->lock, flags);
360 	kfree(prev);
361 
362 	hostap_report_scan_complete(local);
363 }
364 #endif /* PRISM2_NO_STATION_MODES */
365 
366 
367 /* Called only as a tasklet (software IRQ) */
hostap_info_process(local_info_t * local,struct sk_buff * skb)368 void hostap_info_process(local_info_t *local, struct sk_buff *skb)
369 {
370 	struct hfa384x_info_frame *info;
371 	unsigned char *buf;
372 	int left;
373 #ifndef PRISM2_NO_DEBUG
374 	int i;
375 #endif /* PRISM2_NO_DEBUG */
376 
377 	info = (struct hfa384x_info_frame *) skb->data;
378 	buf = skb->data + sizeof(*info);
379 	left = skb->len - sizeof(*info);
380 
381 	switch (le16_to_cpu(info->type)) {
382 	case HFA384X_INFO_COMMTALLIES:
383 		prism2_info_commtallies(local, buf, left);
384 		break;
385 
386 #ifndef PRISM2_NO_STATION_MODES
387 	case HFA384X_INFO_LINKSTATUS:
388 		prism2_info_linkstatus(local, buf, left);
389 		break;
390 
391 	case HFA384X_INFO_SCANRESULTS:
392 		prism2_info_scanresults(local, buf, left);
393 		break;
394 
395 	case HFA384X_INFO_HOSTSCANRESULTS:
396 		prism2_info_hostscanresults(local, buf, left);
397 		break;
398 #endif /* PRISM2_NO_STATION_MODES */
399 
400 #ifndef PRISM2_NO_DEBUG
401 	default:
402 		PDEBUG(DEBUG_EXTRA, "%s: INFO - len=%d type=0x%04x\n",
403 		       local->dev->name, le16_to_cpu(info->len),
404 		       le16_to_cpu(info->type));
405 		PDEBUG(DEBUG_EXTRA, "Unknown info frame:");
406 		for (i = 0; i < (left < 100 ? left : 100); i++)
407 			PDEBUG2(DEBUG_EXTRA, " %02x", buf[i]);
408 		PDEBUG2(DEBUG_EXTRA, "\n");
409 		break;
410 #endif /* PRISM2_NO_DEBUG */
411 	}
412 }
413 
414 
415 #ifndef PRISM2_NO_STATION_MODES
handle_info_queue_linkstatus(local_info_t * local)416 static void handle_info_queue_linkstatus(local_info_t *local)
417 {
418 	int val = local->prev_link_status;
419 	int connected;
420 	union iwreq_data wrqu;
421 
422 	connected =
423 		val == HFA384X_LINKSTATUS_CONNECTED ||
424 		val == HFA384X_LINKSTATUS_AP_CHANGE ||
425 		val == HFA384X_LINKSTATUS_AP_IN_RANGE;
426 
427 	if (local->func->get_rid(local->dev, HFA384X_RID_CURRENTBSSID,
428 				 local->bssid, ETH_ALEN, 1) < 0) {
429 		printk(KERN_DEBUG "%s: could not read CURRENTBSSID after "
430 		       "LinkStatus event\n", local->dev->name);
431 	} else {
432 		PDEBUG(DEBUG_EXTRA, "%s: LinkStatus: BSSID=%pM\n",
433 		       local->dev->name,
434 		       (unsigned char *) local->bssid);
435 		if (local->wds_type & HOSTAP_WDS_AP_CLIENT)
436 			hostap_add_sta(local->ap, local->bssid);
437 	}
438 
439 	/* Get BSSID if we have a valid AP address */
440 	if (connected) {
441 		netif_carrier_on(local->dev);
442 		netif_carrier_on(local->ddev);
443 		memcpy(wrqu.ap_addr.sa_data, local->bssid, ETH_ALEN);
444 	} else {
445 		netif_carrier_off(local->dev);
446 		netif_carrier_off(local->ddev);
447 		eth_zero_addr(wrqu.ap_addr.sa_data);
448 	}
449 	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
450 
451 	/*
452 	 * Filter out sequential disconnect events in order not to cause a
453 	 * flood of SIOCGIWAP events that have a race condition with EAPOL
454 	 * frames and can confuse wpa_supplicant about the current association
455 	 * status.
456 	 */
457 	if (connected || local->prev_linkstatus_connected)
458 		wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL);
459 	local->prev_linkstatus_connected = connected;
460 }
461 
462 
handle_info_queue_scanresults(local_info_t * local)463 static void handle_info_queue_scanresults(local_info_t *local)
464 {
465 	if (local->host_roaming == 1 && local->iw_mode == IW_MODE_INFRA)
466 		prism2_host_roaming(local);
467 
468 	if (local->host_roaming == 2 && local->iw_mode == IW_MODE_INFRA &&
469 	    !is_zero_ether_addr(local->preferred_ap)) {
470 		/*
471 		 * Firmware seems to be getting into odd state in host_roaming
472 		 * mode 2 when hostscan is used without join command, so try
473 		 * to fix this by re-joining the current AP. This does not
474 		 * actually trigger a new association if the current AP is
475 		 * still in the scan results.
476 		 */
477 		prism2_host_roaming(local);
478 	}
479 }
480 
481 
482 /* Called only as scheduled task after receiving info frames (used to avoid
483  * pending too much time in HW IRQ handler). */
handle_info_queue(struct work_struct * work)484 static void handle_info_queue(struct work_struct *work)
485 {
486 	local_info_t *local = container_of(work, local_info_t, info_queue);
487 
488 	if (test_and_clear_bit(PRISM2_INFO_PENDING_LINKSTATUS,
489 			       &local->pending_info))
490 		handle_info_queue_linkstatus(local);
491 
492 	if (test_and_clear_bit(PRISM2_INFO_PENDING_SCANRESULTS,
493 			       &local->pending_info))
494 		handle_info_queue_scanresults(local);
495 }
496 #endif /* PRISM2_NO_STATION_MODES */
497 
498 
hostap_info_init(local_info_t * local)499 void hostap_info_init(local_info_t *local)
500 {
501 	skb_queue_head_init(&local->info_list);
502 #ifndef PRISM2_NO_STATION_MODES
503 	INIT_WORK(&local->info_queue, handle_info_queue);
504 #endif /* PRISM2_NO_STATION_MODES */
505 }
506 
507 
508 EXPORT_SYMBOL(hostap_info_init);
509 EXPORT_SYMBOL(hostap_info_process);
510