xref: /freebsd/contrib/wpa/src/ap/afc.c (revision 71e72c9e91c4b8007a4292e09669e8b549c29e97)
1 /*
2  * Automated Frequency Coordination
3  * Copyright (c) 2024, Lorenzo Bianconi <lorenzo@kernel.org>
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  */
8 
9 #include "utils/includes.h"
10 #include <sys/un.h>
11 #include <time.h>
12 
13 #include "utils/common.h"
14 #include "utils/eloop.h"
15 #include "utils/json.h"
16 #include "common/hw_features_common.h"
17 #include "common/wpa_ctrl.h"
18 #include "hostapd.h"
19 #include "acs.h"
20 #include "hw_features.h"
21 
22 #define HOSTAPD_AFC_RETRY_TIMEOUT	180
23 #define HOSTAPD_AFC_TIMEOUT		86400 /* 24h */
24 #define HOSTAPD_AFC_BUFSIZE		8192
25 
26 static void hostapd_afc_timeout_handler(void *eloop_ctx, void *timeout_ctx);
27 
28 
hostapd_afc_reset_channels(struct hostapd_iface * iface)29 static int hostapd_afc_reset_channels(struct hostapd_iface *iface)
30 {
31 	int ret;
32 
33 	ret = hostapd_get_hw_features(iface);
34 	if (ret) {
35 		wpa_printf(MSG_ERROR, "AFC: Failed to reset channel flags");
36 		return ret;
37 	}
38 
39 	ret = hostapd_set_current_hw_info(iface, iface->freq);
40 	if (ret)
41 		wpa_printf(MSG_ERROR,
42 			   "AFC: Failed to set current hardware info");
43 
44 	return ret;
45 }
46 
47 
48 static struct wpabuf *
hostapd_afc_build_location_request(struct hostapd_iface * iface)49 hostapd_afc_build_location_request(struct hostapd_iface *iface)
50 {
51 	struct wpabuf *location_obj, *ellipse_obj = NULL;
52 	struct hostapd_config *iconf = iface->conf;
53 	bool is_ap_indoor = he_reg_is_indoor(iconf->he_6ghz_reg_pwr_type);
54 	size_t location_len = 1024, ellipse_len = 128;
55 	unsigned int i;
56 
57 	location_obj = wpabuf_alloc(location_len);
58 	if (!location_obj)
59 		return NULL;
60 
61 	json_start_object(location_obj, "location");
62 	if (iconf->afc.location.type != AFC_LINEAR_POLYGON) {
63 		struct afc_linear_polygon *lp =
64 			iconf->afc.location.linear_polygon_data;
65 
66 		if (!lp)
67 			goto error;
68 
69 		ellipse_obj = wpabuf_alloc(ellipse_len);
70 		if (!ellipse_obj)
71 			goto error;
72 
73 		json_start_object(ellipse_obj, "center");
74 
75 		json_add_double(ellipse_obj, "longitude", lp->longitude);
76 		json_value_sep(ellipse_obj);
77 
78 		json_add_double(ellipse_obj, "latitude", lp->latitude);
79 		json_end_object(ellipse_obj);
80 		json_value_sep(ellipse_obj);
81 	}
82 
83 	switch (iconf->afc.location.type) {
84 	case AFC_LINEAR_POLYGON:
85 		json_start_object(location_obj, "linearPolygon");
86 		json_start_array(location_obj, "outerBoundary");
87 		for (i = 0; i < iconf->afc.location.n_linear_polygon_data; i++)
88 		{
89 			struct afc_linear_polygon *lp =
90 				&iconf->afc.location.linear_polygon_data[i];
91 
92 			json_start_object(location_obj, NULL);
93 
94 			json_add_double(location_obj, "longitude",
95 					lp->longitude);
96 			json_value_sep(location_obj);
97 
98 			json_add_double(location_obj, "latitude",
99 					lp->latitude);
100 
101 			json_end_object(location_obj);
102 			if (i < iconf->afc.location.n_linear_polygon_data - 1)
103 				json_value_sep(location_obj);
104 		}
105 		json_end_array(location_obj);
106 
107 		/* linearPolygon */
108 		json_end_object(location_obj);
109 		json_value_sep(location_obj);
110 		break;
111 	case AFC_RADIAL_POLYGON:
112 		json_start_object(location_obj, "radialPolygon");
113 		wpabuf_put_buf(location_obj, ellipse_obj);
114 
115 		json_start_array(location_obj, "outerBoundary");
116 		for (i = 0; i < iconf->afc.location.n_radial_polygon_data; i++)
117 		{
118 			struct afc_radial_polygon *rp =
119 				&iconf->afc.location.radial_polygon_data[i];
120 
121 			json_start_object(location_obj, NULL);
122 			json_add_double(location_obj, "length", rp->length);
123 			json_value_sep(location_obj);
124 
125 			json_add_double(location_obj, "angle", rp->angle);
126 			json_end_object(location_obj);
127 			if (i < iconf->afc.location.n_radial_polygon_data - 1)
128 				json_value_sep(location_obj);
129 		}
130 		json_end_array(location_obj);
131 
132 		/* radialPolygon */
133 		json_end_object(location_obj);
134 		json_value_sep(location_obj);
135 		break;
136 	case AFC_ELLIPSE:
137 	default:
138 		json_start_object(location_obj, "ellipse");
139 		wpabuf_put_buf(location_obj, ellipse_obj);
140 
141 		json_add_int(location_obj, "majorAxis",
142 			     iconf->afc.location.major_axis);
143 		json_value_sep(location_obj);
144 		json_add_int(location_obj, "minorAxis",
145 			     iconf->afc.location.minor_axis);
146 		json_value_sep(location_obj);
147 		json_add_int(location_obj, "orientation",
148 			     iconf->afc.location.orientation);
149 		/* ellipse */
150 		json_end_object(location_obj);
151 		json_value_sep(location_obj);
152 		break;
153 	}
154 
155 	json_start_object(location_obj, "elevation");
156 
157 	json_add_double(location_obj, "height", iconf->afc.location.height);
158 	json_value_sep(location_obj);
159 	if (iconf->afc.location.height_type) {
160 		json_add_string(location_obj, "heightType",
161 				iconf->afc.location.height_type);
162 		json_value_sep(location_obj);
163 	}
164 	json_add_int(location_obj, "verticalUncertainty",
165 		     iconf->afc.location.vertical_tolerance);
166 
167 	/* elevation */
168 	json_end_object(location_obj);
169 	json_value_sep(location_obj);
170 
171 	json_add_int(location_obj, "indoorDeployment", is_ap_indoor);
172 
173 	/* location */
174 	json_end_object(location_obj);
175 	json_value_sep(location_obj);
176 
177 	wpabuf_free(ellipse_obj);
178 	return location_obj;
179 
180 error:
181 	wpabuf_free(location_obj);
182 	wpabuf_free(ellipse_obj);
183 
184 	return NULL;
185 }
186 
187 
hostapd_afc_get_opclass_chan_list(u8 op_class)188 static struct wpabuf * hostapd_afc_get_opclass_chan_list(u8 op_class)
189 {
190 	struct wpabuf *chan_list_obj;
191 	const struct oper_class_map *oper_class;
192 	int chan_offset, chan;
193 	size_t ch_len = 512;
194 
195 	oper_class = get_oper_class(NULL, op_class);
196 	if (!oper_class)
197 		return NULL;
198 
199 	chan_list_obj = wpabuf_alloc(ch_len);
200 	if (!chan_list_obj)
201 		return NULL;
202 	json_start_array(chan_list_obj, "channelCfi");
203 
204 	switch (op_class) {
205 	case 132: /* 40 MHz */
206 		chan_offset = 2;
207 		break;
208 	case 133: /* 80 MHz */
209 		chan_offset = 6;
210 		break;
211 	case 134: /* 160 MHz */
212 		chan_offset = 14;
213 		break;
214 	case 137: /* 320 MHz */
215 		/*
216 		 * global_op_class already use the central channels for
217 		 * 320 MHz, so fallthrough and use 0 for chan_offset.
218 		 */
219 	default:
220 		chan_offset = 0;
221 		break;
222 	}
223 
224 	for (chan = oper_class->min_chan; chan <= oper_class->max_chan;
225 	     chan += oper_class->inc) {
226 		char ch_str[32];
227 
228 		if (chan + chan_offset > oper_class->max_chan)
229 			break;
230 
231 		os_snprintf(ch_str, sizeof(ch_str), "%s%d",
232 			    chan != oper_class->min_chan ? ", " : "",
233 			    chan + chan_offset);
234 		wpabuf_put_str(chan_list_obj, ch_str);
235 	}
236 	json_end_array(chan_list_obj);
237 
238 	return chan_list_obj;
239 }
240 
241 
242 static struct wpabuf *
hostapd_afc_build_req_chan_list(struct hostapd_iface * iface)243 hostapd_afc_build_req_chan_list(struct hostapd_iface *iface)
244 {
245 	struct wpabuf *op_class_list_obj;
246 	struct hostapd_config *iconf = iface->conf;
247 	unsigned int i, num;
248 
249 	op_class_list_obj = wpabuf_alloc(HOSTAPD_AFC_BUFSIZE);
250 	if (!op_class_list_obj)
251 		return NULL;
252 
253 	json_start_array(op_class_list_obj, "inquiredChannels");
254 	num = int_array_len(iconf->afc.op_class);
255 	for (i = 0; i < num; i++) {
256 		struct wpabuf *chan_list_obj = NULL;
257 		u8 op_class = iconf->afc.op_class[i];
258 
259 		if (!is_6ghz_op_class(op_class))
260 			continue;
261 
262 		json_start_object(op_class_list_obj, NULL);
263 
264 		json_add_int(op_class_list_obj, "globalOperatingClass",
265 			     op_class);
266 		json_value_sep(op_class_list_obj);
267 
268 		chan_list_obj = hostapd_afc_get_opclass_chan_list(op_class);
269 		if (!chan_list_obj)
270 			goto error;
271 
272 		wpabuf_put_buf(op_class_list_obj, chan_list_obj);
273 		json_end_object(op_class_list_obj);
274 
275 		if (i < num - 1)
276 			json_value_sep(op_class_list_obj);
277 
278 		wpabuf_free(chan_list_obj);
279 		chan_list_obj = NULL;
280 	}
281 	json_end_array(op_class_list_obj);
282 
283 	return op_class_list_obj;
284 
285 error:
286 	wpabuf_free(op_class_list_obj);
287 	return NULL;
288 }
289 
290 
291 static struct wpabuf *
hostapd_afc_build_request(struct hostapd_iface * iface)292 hostapd_afc_build_request(struct hostapd_iface *iface)
293 {
294 	struct wpabuf *req_obj, *location_obj, *op_class_list_obj = NULL;
295 	struct hostapd_config *iconf = iface->conf;
296 	unsigned int i;
297 	char request_id_str[16];
298 
299 	req_obj = wpabuf_alloc(HOSTAPD_AFC_BUFSIZE);
300 	if (!req_obj)
301 		return NULL;
302 
303 	json_start_object(req_obj, NULL);
304 
305 	if (iconf->afc.request.version) {
306 		json_add_string(req_obj, "version", iconf->afc.request.version);
307 		json_value_sep(req_obj);
308 	}
309 
310 	json_start_array(req_obj, "availableSpectrumInquiryRequests");
311 	json_start_object(req_obj, NULL);
312 
313 	iface->afc.request_id++;
314 	os_snprintf(request_id_str, sizeof(request_id_str), "%u",
315 		    iface->afc.request_id);
316 	json_add_string(req_obj, "requestId", request_id_str);
317 	json_value_sep(req_obj);
318 
319 	json_start_object(req_obj, "deviceDescriptor");
320 	if (iconf->afc.request.sn) {
321 		json_add_string(req_obj, "serialNumber", iconf->afc.request.sn);
322 		json_value_sep(req_obj);
323 	}
324 
325 	json_start_array(req_obj, "certificationId");
326 
327 	for (i = 0; i < iconf->afc.n_cert_ids; i++) {
328 		json_start_object(req_obj, NULL);
329 		json_add_string(req_obj, "rulesetId",
330 				iconf->afc.cert_ids[i].ruleset);
331 		json_value_sep(req_obj);
332 
333 		json_add_string(req_obj, "id", iconf->afc.cert_ids[i].id);
334 		json_end_object(req_obj);
335 
336 		if (i < iconf->afc.n_cert_ids - 1)
337 			json_value_sep(req_obj);
338 	}
339 	/* certificationId */
340 	json_end_array(req_obj);
341 
342 	/* deviceDescriptor */
343 	json_end_object(req_obj);
344 	json_value_sep(req_obj);
345 
346 	location_obj = hostapd_afc_build_location_request(iface);
347 	if (!location_obj)
348 		goto error;
349 
350 	wpabuf_put_buf(req_obj, location_obj);
351 
352 	if (iconf->afc.freqs.num) {
353 		json_start_array(req_obj, "inquiredFrequencyRange");
354 		for (i = 0; i < iconf->afc.freqs.num; i++) {
355 			struct wpa_freq_range *fr = &iconf->afc.freqs.range[i];
356 
357 			json_start_object(req_obj, NULL);
358 
359 			json_add_int(req_obj, "lowFrequency", fr->min);
360 			json_value_sep(req_obj);
361 			json_add_int(req_obj, "highFrequency", fr->max);
362 
363 			json_end_object(req_obj);
364 			if (i < iconf->afc.freqs.num - 1)
365 				json_value_sep(req_obj);
366 		}
367 		json_end_array(req_obj);
368 		json_value_sep(req_obj);
369 	}
370 
371 	op_class_list_obj = hostapd_afc_build_req_chan_list(iface);
372 	if (!op_class_list_obj)
373 		goto error;
374 
375 	wpabuf_put_buf(req_obj, op_class_list_obj);
376 
377 	if (iconf->afc.min_power) {
378 		json_value_sep(req_obj);
379 		json_add_int(req_obj, "minDesiredPower", iconf->afc.min_power);
380 	}
381 
382 	/* availableSpectrumInquiryRequests */
383 	json_end_object(req_obj);
384 	json_end_array(req_obj);
385 
386 	json_end_object(req_obj);
387 	wpa_hexdump_ascii_buf(MSG_MSGDUMP, "AFC: Pending request", req_obj);
388 
389 	wpabuf_free(location_obj);
390 	wpabuf_free(op_class_list_obj);
391 
392 	return req_obj;
393 
394 error:
395 	wpabuf_free(req_obj);
396 	wpabuf_free(location_obj);
397 	wpabuf_free(op_class_list_obj);
398 
399 	return NULL;
400 }
401 
402 
403 static int
hostad_afc_parse_available_freq_info(struct hostapd_iface * iface,struct json_token * freq_info)404 hostad_afc_parse_available_freq_info(struct hostapd_iface *iface,
405 				     struct json_token *freq_info)
406 {
407 	struct afc_freq_range_elem *f = NULL, *tmp;
408 	struct json_token *freq_obj;
409 	int count = 0;
410 
411 	for (freq_obj = freq_info->child; freq_obj;
412 	     freq_obj = freq_obj->sibling) {
413 		struct json_token *freq_range_obj, *token;
414 		int low_freq, high_freq;
415 		double max_psd;
416 
417 		freq_range_obj = json_get_member(freq_obj, "frequencyRange");
418 		if (!freq_range_obj || freq_range_obj->type != JSON_OBJECT)
419 			continue;
420 
421 		token = json_get_member(freq_range_obj, "lowFrequency");
422 		if (!token || token->type != JSON_NUMBER)
423 			continue;
424 		low_freq = token->number;
425 
426 		token = json_get_member(freq_range_obj, "highFrequency");
427 		if (!token || token->type != JSON_NUMBER)
428 			continue;
429 		high_freq = token->number;
430 
431 		token = json_get_member(freq_obj, "maxPsd");
432 		if (!token)
433 			token = json_get_member(freq_obj, "maxPSD");
434 		if (!token || (token->type != JSON_DOUBLE &&
435 			       token->type != JSON_NUMBER))
436 			continue;
437 		max_psd = token->type == JSON_DOUBLE ?
438 			token->dnumber : (double) token->number;
439 
440 		tmp = os_realloc_array(f, count + 1, sizeof(*f));
441 		if (!tmp) {
442 			os_free(f);
443 			return -ENOMEM;
444 		}
445 		f = tmp;
446 
447 		f[count].low_freq = low_freq;
448 		f[count].high_freq = high_freq;
449 		f[count++].max_psd = max_psd;
450 	}
451 	os_free(iface->afc.freq_range);
452 	iface->afc.freq_range = f;
453 	iface->afc.num_freq_range = count;
454 
455 	return 0;
456 }
457 
458 
hostad_afc_update_chan_info(struct afc_chan_info_elem ** chan_list,int * chan_list_size,u8 op_class,int center_chan,double power)459 static int hostad_afc_update_chan_info(struct afc_chan_info_elem **chan_list,
460 				       int *chan_list_size, u8 op_class,
461 				       int center_chan, double power)
462 {
463 	int op_class_pwr_index, num_low_subchan, channel;
464 	int count = *chan_list_size;
465 	struct afc_chan_info_elem *c = *chan_list, *tmp;
466 
467 	switch (op_class) {
468 	case 132: /* 40 MHz */
469 		op_class_pwr_index = 1;
470 		num_low_subchan = 2;
471 		break;
472 	case 133: /* 80 MHz */
473 		op_class_pwr_index = 2;
474 		num_low_subchan = 6;
475 		break;
476 	case 134: /* 160 MHz */
477 		op_class_pwr_index = 3;
478 		num_low_subchan = 14;
479 		break;
480 	case 137: /* 320 MHz */
481 		op_class_pwr_index = 4;
482 		num_low_subchan = 30;
483 		break;
484 	default:
485 		op_class_pwr_index = 0;
486 		num_low_subchan = 0;
487 		break;
488 	}
489 
490 	for (channel = center_chan - num_low_subchan;
491 	     channel <= center_chan + num_low_subchan; channel += 4) {
492 		int i;
493 
494 		for (i = 0; i < count; i++) {
495 			if (c[i].chan == channel)
496 				break;
497 		}
498 
499 		if (i == count) {
500 			tmp = os_realloc_array(c, count + 1, sizeof(*c));
501 			if (!tmp) {
502 				os_free(c);
503 				*chan_list = NULL;
504 				*chan_list_size = 0;
505 				return -ENOMEM;
506 			}
507 			c = tmp;
508 
509 			c[count].chan = channel;
510 			os_memset(c[count].power, 0, sizeof(c[count].power));
511 			count++;
512 		}
513 		c[i].power[op_class_pwr_index] = power;
514 	}
515 
516 	*chan_list_size = count;
517 	*chan_list = c;
518 
519 	return 0;
520 }
521 
522 
523 static int
hostad_afc_parse_available_chan_info(struct hostapd_iface * iface,struct json_token * chan_info)524 hostad_afc_parse_available_chan_info(struct hostapd_iface *iface,
525 				     struct json_token *chan_info)
526 {
527 	struct afc_chan_info_elem *c = NULL;
528 	struct json_token *chan_obj;
529 	int count = 0;
530 
531 	for (chan_obj = chan_info->child; chan_obj;
532 	     chan_obj = chan_obj->sibling) {
533 		struct json_token *chan_cfi, *max_eirp;
534 		struct json_token *token, *chan_arr, *power_arr;
535 		int op_class;
536 
537 		token = json_get_member(chan_obj, "globalOperatingClass");
538 		if (!token || token->type != JSON_NUMBER)
539 			continue;
540 		op_class = token->number;
541 
542 		chan_cfi = json_get_member(chan_obj, "channelCfi");
543 		if (!chan_cfi || chan_cfi->type != JSON_ARRAY)
544 			continue;
545 
546 		max_eirp = json_get_member(chan_obj, "maxEirp");
547 		if (!max_eirp || max_eirp->type != JSON_ARRAY)
548 			continue;
549 
550 		chan_arr = chan_cfi->child;
551 		power_arr = max_eirp->child;
552 		while (chan_arr && power_arr) {
553 			int channel, ret;
554 			double power;
555 
556 			if (chan_arr->type != JSON_NUMBER ||
557 			    (power_arr->type != JSON_DOUBLE &&
558 			     power_arr->type != JSON_NUMBER)) {
559 				wpa_printf(MSG_DEBUG,
560 					   "AFC: Failed to parse array at opclass %d",
561 					   op_class);
562 				break;
563 			}
564 
565 			channel = chan_arr->number;
566 			power = power_arr->type == JSON_DOUBLE ?
567 				power_arr->dnumber : (double) power_arr->number;
568 
569 			ret = hostad_afc_update_chan_info(&c, &count, op_class,
570 							  channel, power);
571 			if (ret) {
572 				iface->afc.chan_info_list = NULL;
573 				iface->afc.num_chan_info = 0;
574 				return ret;
575 			}
576 			chan_arr = chan_arr->sibling;
577 			power_arr = power_arr->sibling;
578 		}
579 	}
580 	os_free(iface->afc.chan_info_list);
581 	iface->afc.chan_info_list = c;
582 	iface->afc.num_chan_info = count;
583 
584 	return 0;
585 }
586 
587 
hostad_afc_get_timeout(struct json_token * obj)588 static int hostad_afc_get_timeout(struct json_token *obj)
589 {
590 	int year, month, day, hour, min, sec;
591 	os_time_t t;
592 	struct os_time now;
593 
594 	if (sscanf(obj->string, "%d-%d-%dT%d:%d:%dZ",
595 		   &year, &month, &day, &hour, &min, &sec) != 6)
596 		return HOSTAPD_AFC_TIMEOUT;
597 
598 	if (os_mktime(year, month, day, hour, min, sec, &t) < 0)
599 		return HOSTAPD_AFC_TIMEOUT;
600 
601 	os_get_time(&now);
602 
603 	return t < now.sec ?
604 		HOSTAPD_AFC_RETRY_TIMEOUT : (t - now.sec) * 80 / 100;
605 }
606 
607 
608 static int
hostapd_afc_parse_reply(struct hostapd_iface * iface,char * reply,size_t len)609 hostapd_afc_parse_reply(struct hostapd_iface *iface, char *reply, size_t len)
610 {
611 	struct hostapd_config *iconf = iface->conf;
612 	int request_timeout = -1, ret = -EINVAL;
613 	struct json_token *root = NULL, *reply_obj, *token;
614 
615 	wpa_hexdump_ascii(MSG_MSGDUMP, "AFC: Received reply", reply, len);
616 
617 	iface->afc_response = os_malloc(len + 1);
618 	if (!iface->afc_response) {
619 		wpa_printf(MSG_ERROR,
620 			   "AFC: Failed to alloc memory for storing reply");
621 		return -ENOMEM;
622 	}
623 	os_memcpy(iface->afc_response, reply, len);
624 	iface->afc_response[len] = '\0';
625 
626 	root = json_parse(reply, len);
627 	if (!root) {
628 		wpa_printf(MSG_ERROR, "AFC: Failed to parse reply payload");
629 		goto fail;
630 	}
631 
632 	token = json_get_member(root, "version");
633 	if (!token || token->type != JSON_STRING) {
634 		wpa_printf(MSG_ERROR, "AFC: Missing version in reply");
635 		goto fail;
636 	}
637 	if (iconf->afc.request.version &&
638 	    os_strcmp(iconf->afc.request.version, token->string) != 0) {
639 		wpa_printf(MSG_ERROR, "AFC: Mismatch in reply version");
640 		goto fail;
641 	}
642 
643 	reply_obj = json_get_member(root, "availableSpectrumInquiryResponses");
644 	if (!reply_obj || reply_obj->type != JSON_ARRAY) {
645 		wpa_printf(MSG_ERROR,
646 			   "AFC: Missing availableSpectrumInquiry in reply");
647 		goto fail;
648 	}
649 
650 	for (token = reply_obj->child; token; token = token->sibling) {
651 		struct json_token *reply_elem, *response;
652 		int status = -EINVAL, timeout;
653 		unsigned int j;
654 		char request_id_str[16];
655 
656 		reply_elem = json_get_member(token, "requestId");
657 		if (!reply_elem || reply_elem->type != JSON_STRING) {
658 			wpa_printf(MSG_DEBUG,
659 				   "AFC: Missing requestId in reply element");
660 			continue;
661 		}
662 
663 		snprintf(request_id_str, sizeof(request_id_str), "%u",
664 			 iface->afc.request_id);
665 		if (os_strcmp(request_id_str, reply_elem->string) != 0) {
666 			wpa_printf(MSG_DEBUG,
667 				   "AFC: RequestId mismatch in reply element");
668 			continue;
669 		}
670 
671 		reply_elem = json_get_member(token, "rulesetId");
672 		if (!reply_elem || reply_elem->type != JSON_STRING) {
673 			wpa_printf(MSG_DEBUG,
674 				   "AFC: Missing rulesetId in reply element");
675 			continue;
676 		}
677 
678 		for (j = 0; j < iconf->afc.n_cert_ids; j++) {
679 			if (os_strcmp(iconf->afc.cert_ids[j].ruleset,
680 				      reply_elem->string) == 0)
681 				break;
682 		}
683 
684 		if (j == iconf->afc.n_cert_ids) {
685 			wpa_printf(MSG_DEBUG,
686 				   "AFC: RulesetId mismatch in reply element");
687 			continue;
688 		}
689 
690 		response = json_get_member(token, "response");
691 		if (!response || response->type != JSON_OBJECT) {
692 			wpa_printf(MSG_DEBUG,
693 				   "AFC: Missing response field in reply element");
694 			continue;
695 		}
696 
697 		reply_elem = json_get_member(response, "shortDescription");
698 		if (reply_elem && reply_elem->type == JSON_STRING)
699 			wpa_printf(MSG_DEBUG, "AFC: Reply element: %s",
700 				   reply_elem->string);
701 
702 		reply_elem = json_get_member(response, "responseCode");
703 		if (reply_elem && reply_elem->type == JSON_NUMBER)
704 			status = reply_elem->number;
705 
706 		if (status < 0) {
707 			wpa_printf(MSG_DEBUG,
708 				   "AFC: Reply invalid responseCode: %d",
709 				   status);
710 			continue;
711 		}
712 		reply_elem = json_get_member(token, "availableFrequencyInfo");
713 		if (reply_elem && reply_elem->type == JSON_ARRAY &&
714 		    hostad_afc_parse_available_freq_info(iface, reply_elem)) {
715 			wpa_printf(MSG_DEBUG,
716 				   "AFC: Failed to parse availableFrequencyInfo");
717 			continue;
718 		}
719 
720 		reply_elem = json_get_member(token, "availableChannelInfo");
721 		if (reply_elem && reply_elem->type == JSON_ARRAY &&
722 		    hostad_afc_parse_available_chan_info(iface, reply_elem)) {
723 			wpa_printf(MSG_DEBUG,
724 				   "AFC: Failed to parse availableChannelInfo");
725 			continue;
726 		}
727 
728 		reply_elem = json_get_member(token, "availabilityExpireTime");
729 		if (!reply_elem || reply_elem->type != JSON_STRING) {
730 			wpa_printf(MSG_DEBUG,
731 				   "AFC: Missing expire time, use default timeout");
732 			continue;
733 		}
734 
735 		timeout = hostad_afc_get_timeout(reply_elem);
736 		if (request_timeout < 0 || timeout < request_timeout)
737 			request_timeout = timeout;
738 
739 		ret = status;
740 	}
741 
742 	iface->afc.data_valid = true;
743 	iface->afc.timeout = request_timeout;
744 	if (iface->afc.timeout < 0)
745 		iface->afc.timeout = HOSTAPD_AFC_RETRY_TIMEOUT;
746 
747 fail:
748 	json_free(root);
749 	return ret;
750 }
751 
752 
hostapd_afc_send_receive(struct hostapd_iface * iface)753 static int hostapd_afc_send_receive(struct hostapd_iface *iface)
754 {
755 	struct hostapd_config *iconf = iface->conf;
756 	struct wpabuf *request_obj = NULL;
757 	struct timeval sock_timeout = {
758 		.tv_sec = 10,
759 	};
760 	struct sockaddr_un addr = {
761 		.sun_family = AF_UNIX,
762 #ifdef __FreeBSD__
763 		.sun_len = sizeof(addr),
764 #endif /* __FreeBSD__ */
765 	};
766 	char *buf = NULL;
767 	int sockfd, ret;
768 	fd_set read_set;
769 
770 	if (iface->afc.data_valid) {
771 		/* AFC data already downloaded from the server */
772 		return 0;
773 	}
774 
775 	iface->afc.timeout = HOSTAPD_AFC_RETRY_TIMEOUT;
776 	if (!iconf->afc.socket) {
777 		wpa_printf(MSG_ERROR, "AFC: Missing socket string");
778 		return -EINVAL;
779 	}
780 
781 	if (os_strlen(iconf->afc.socket) >= sizeof(addr.sun_path)) {
782 		wpa_printf(MSG_ERROR, "AFC: Malformed socket string %s",
783 			   iconf->afc.socket);
784 		return -EINVAL;
785 	}
786 
787 	os_strlcpy(addr.sun_path, iconf->afc.socket, sizeof(addr.sun_path));
788 	sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
789 	if (sockfd < 0) {
790 		wpa_printf(MSG_ERROR, "AFC: Failed creating socket");
791 		return sockfd;
792 	}
793 
794 	if (connect(sockfd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
795 		wpa_printf(MSG_ERROR, "AFC: Failed connecting socket");
796 		ret = -EIO;
797 		goto close_sock;
798 	}
799 
800 	request_obj = hostapd_afc_build_request(iface);
801 	if (!request_obj) {
802 		ret = -EINVAL;
803 		goto close_sock;
804 	}
805 
806 	ret = send(sockfd, wpabuf_head(request_obj), wpabuf_len(request_obj),
807 		   0);
808 	if (ret < 0 || (size_t) ret != wpabuf_len(request_obj)) {
809 		wpa_printf(MSG_ERROR, "AFC: Failed sending request");
810 		ret = -EIO;
811 		goto close_sock;
812 	}
813 
814 	FD_ZERO(&read_set);
815 	FD_SET(sockfd, &read_set);
816 	if (select(sockfd + 1, &read_set, NULL, NULL, &sock_timeout) < 0) {
817 		wpa_printf(MSG_ERROR, "AFC: select() failed on socket");
818 		ret = -errno;
819 		goto close_sock;
820 	}
821 
822 	if (!FD_ISSET(sockfd, &read_set)) {
823 		ret = -EIO;
824 		goto close_sock;
825 	}
826 
827 	buf = os_zalloc(HOSTAPD_AFC_BUFSIZE);
828 	if (!buf) {
829 		ret = -ENOMEM;
830 		goto close_sock;
831 	}
832 
833 	ret = recv(sockfd, buf, HOSTAPD_AFC_BUFSIZE - 1, 0);
834 	if (!ret)
835 		ret = -EIO;
836 	if (ret < 0)
837 		goto close_sock;
838 
839 	ret = hostapd_afc_parse_reply(iface, buf, ret);
840 	if (ret) {
841 		wpa_printf(MSG_ERROR, "AFC: Failed parsing reply: %d", ret);
842 		goto close_sock;
843 	}
844 	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AFC_EVENT_RECEIVED);
845 close_sock:
846 	os_free(buf);
847 	wpabuf_free(iface->afc_request);
848 	iface->afc_request = request_obj;
849 	close(sockfd);
850 
851 	return ret;
852 }
853 
854 
hostapd_afc_has_usable_chans(struct hostapd_iface * iface)855 static bool hostapd_afc_has_usable_chans(struct hostapd_iface *iface)
856 {
857 	const struct oper_class_map *oper_class;
858 	int channel, chan_num;
859 
860 	oper_class = get_oper_class(NULL, iface->conf->op_class);
861 	if (!oper_class)
862 		return false;
863 
864 	switch (iface->conf->op_class) {
865 	case 132: /* 40 MHz */
866 		chan_num = 2;
867 		break;
868 	case 133: /* 80 MHz */
869 		chan_num = 4;
870 		break;
871 	case 134: /* 160 MHz */
872 		chan_num = 8;
873 		break;
874 	case 137: /* 320 MHz */
875 		chan_num = 16;
876 		break;
877 	default:
878 		chan_num = 1;
879 		break;
880 	}
881 
882 	for (channel = oper_class->min_chan; channel <= oper_class->max_chan;
883 	     channel += oper_class->inc) {
884 		struct hostapd_hw_modes *mode = iface->current_mode;
885 		struct hostapd_channel_data *chan = NULL;
886 		int i, start_ch = channel;
887 
888 		if (iface->conf->op_class == 137)
889 			start_ch = channel - 30;
890 
891 		for (i = 0; i < chan_num; i++) {
892 			chan = hw_get_channel_chan(mode, start_ch + i * 4,
893 						   NULL);
894 
895 			if (!chan || chan->flag & HOSTAPD_CHAN_DISABLED)
896 				break;
897 		}
898 
899 		if (i == chan_num)
900 			return true;
901 	}
902 
903 	return false;
904 }
905 
906 
hostapd_afc_handle_request(struct hostapd_iface * iface)907 int hostapd_afc_handle_request(struct hostapd_iface *iface)
908 {
909 	struct hostapd_config *iconf = iface->conf;
910 	int ret;
911 
912 	/* AFC is required just for standard power AP */
913 	if (!he_reg_is_sp(iconf->he_6ghz_reg_pwr_type))
914 		return 1;
915 
916 	if (!is_6ghz_op_class(iconf->op_class) || !is_6ghz_freq(iface->freq))
917 		return 1;
918 
919 	if (iface->state == HAPD_IFACE_ACS)
920 		return 1;
921 
922 	iface->afc.request_id = os_random();
923 	ret = hostapd_afc_send_receive(iface);
924 	if (ret < 0) {
925 		/*
926 		 * If the connection to the AFCD failed, reschedule for a
927 		 * future attempt.
928 		 */
929 		wpa_printf(MSG_ERROR, "AFC: Connection failed: %d", ret);
930 		if (ret == -EIO)
931 			ret = 0;
932 		goto resched;
933 	}
934 
935 	hostap_afc_disable_channels(iface);
936 	if (!hostapd_afc_has_usable_chans(iface))
937 		goto resched;
938 
939 	ret = hostapd_is_usable_chans(iface);
940 	if (ret != 1) {
941 		/* Trigger an ACS freq scan */
942 		iconf->channel = 0;
943 		iface->freq = 0;
944 		hostapd_set_and_check_bw320_offset(iface->conf, 0);
945 
946 		if (!ret && acs_init(iface) != HOSTAPD_CHAN_ACS) {
947 			wpa_printf(MSG_ERROR, "AFC: Could not start ACS");
948 			ret = -EINVAL;
949 		}
950 	}
951 
952 resched:
953 	eloop_cancel_timeout(hostapd_afc_timeout_handler, iface, NULL);
954 	eloop_register_timeout(iface->afc.timeout, 0,
955 			       hostapd_afc_timeout_handler, iface, NULL);
956 
957 	return ret;
958 }
959 
960 
hostapd_afc_delete_data_from_server(struct hostapd_iface * iface)961 static void hostapd_afc_delete_data_from_server(struct hostapd_iface *iface)
962 {
963 	wpabuf_free(iface->afc_request);
964 	os_free(iface->afc_response);
965 	os_free(iface->afc.chan_info_list);
966 	os_free(iface->afc.freq_range);
967 
968 	iface->afc_request = NULL;
969 	iface->afc_response = NULL;
970 
971 	iface->afc.num_freq_range = 0;
972 	iface->afc.num_chan_info = 0;
973 
974 	iface->afc.chan_info_list = NULL;
975 	iface->afc.freq_range = NULL;
976 
977 	iface->afc.data_valid = false;
978 }
979 
980 
hostapd_afc_timeout_handler(void * eloop_ctx,void * timeout_ctx)981 static void hostapd_afc_timeout_handler(void *eloop_ctx, void *timeout_ctx)
982 {
983 	struct hostapd_iface *iface = eloop_ctx;
984 	bool restart_iface = true;
985 
986 	hostapd_afc_delete_data_from_server(iface);
987 	if (iface->state != HAPD_IFACE_ENABLED) {
988 		/* hostapd is not fully enabled yet, toggle the interface */
989 		goto restart_interface;
990 	}
991 
992 	if (hostapd_afc_send_receive(iface) < 0 ||
993 	    hostapd_afc_reset_channels(iface)) {
994 		restart_iface = false;
995 		goto restart_interface;
996 	}
997 
998 	if (hostapd_is_usable_chans(iface) > 0) {
999 		wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AFC_EVENT_COMPLETE);
1000 		goto resched;
1001 	}
1002 
1003 	restart_iface = hostapd_afc_has_usable_chans(iface);
1004 	if (restart_iface) {
1005 		/* Trigger an ACS freq scan */
1006 		iface->conf->channel = 0;
1007 		iface->freq = 0;
1008 		hostapd_set_and_check_bw320_offset(iface->conf, 0);
1009 	} else {
1010 		wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AFC_EVENT_COMPLETE);
1011 	}
1012 
1013 restart_interface:
1014 	hostapd_disable_iface(iface);
1015 	if (restart_iface)
1016 		hostapd_enable_iface(iface);
1017 resched:
1018 	eloop_register_timeout(iface->afc.timeout, 0,
1019 			       hostapd_afc_timeout_handler, iface, NULL);
1020 }
1021 
1022 
hostapd_afc_send_request(struct hostapd_iface * iface)1023 void hostapd_afc_send_request(struct hostapd_iface *iface)
1024 {
1025 	eloop_cancel_timeout(hostapd_afc_timeout_handler, iface, NULL);
1026 	eloop_register_timeout(0, 0, hostapd_afc_timeout_handler, iface, NULL);
1027 }
1028 
1029 
hostapd_afc_stop(struct hostapd_iface * iface)1030 void hostapd_afc_stop(struct hostapd_iface *iface)
1031 {
1032 	eloop_cancel_timeout(hostapd_afc_timeout_handler, iface, NULL);
1033 }
1034 
1035 
hostap_afc_disable_channels(struct hostapd_iface * iface)1036 void hostap_afc_disable_channels(struct hostapd_iface *iface)
1037 {
1038 	struct hostapd_hw_modes *mode = NULL;
1039 	int i;
1040 
1041 	for (i = 0; i < iface->num_hw_features; i++) {
1042 		mode = &iface->hw_features[i];
1043 		if (mode->mode == HOSTAPD_MODE_IEEE80211A &&
1044 		    mode->is_6ghz)
1045 			break;
1046 	}
1047 
1048 	if (i == iface->num_hw_features ||
1049 	    !he_reg_is_sp(iface->conf->he_6ghz_reg_pwr_type) ||
1050 	    !iface->afc.data_valid)
1051 		return;
1052 
1053 	for (i = 0; i < mode->num_channels; i++) {
1054 		struct hostapd_channel_data *chan = &mode->channels[i];
1055 		unsigned int j;
1056 
1057 		if (!is_6ghz_freq(chan->freq))
1058 			continue;
1059 
1060 		for (j = 0; j < iface->afc.num_freq_range; j++) {
1061 			if (chan->freq >= iface->afc.freq_range[j].low_freq &&
1062 			    chan->freq <= iface->afc.freq_range[j].high_freq)
1063 				break;
1064 		}
1065 
1066 		if (j != iface->afc.num_freq_range)
1067 			continue;
1068 
1069 		for (j = 0; j < iface->afc.num_chan_info; j++) {
1070 			if (chan->chan == iface->afc.chan_info_list[j].chan)
1071 				break;
1072 		}
1073 
1074 		if (j != iface->afc.num_chan_info)
1075 			continue;
1076 
1077 		chan->flag |= HOSTAPD_CHAN_DISABLED;
1078 		wpa_printf(MSG_MSGDUMP,
1079 			   "AFC: Disabling freq=%d MHz (not allowed by AFC)",
1080 			   chan->freq);
1081 	}
1082 }
1083 
1084 
hostap_afc_get_chan_max_eirp_power(struct hostapd_iface * iface,bool psd,int * power)1085 int hostap_afc_get_chan_max_eirp_power(struct hostapd_iface *iface, bool psd,
1086 				       int *power)
1087 {
1088 	unsigned int i;
1089 
1090 	if (!he_reg_is_sp(iface->conf->he_6ghz_reg_pwr_type) ||
1091 	    !iface->afc.data_valid)
1092 		return -EINVAL;
1093 
1094 	if (psd) {
1095 		for (i = 0; i < iface->afc.num_freq_range; i++) {
1096 			struct afc_freq_range_elem *f;
1097 
1098 			f = &iface->afc.freq_range[i];
1099 			if (iface->freq >= f->low_freq &&
1100 			    iface->freq <= f->high_freq) {
1101 				*power = (int) (2 * f->max_psd);
1102 				return 0;
1103 			}
1104 		}
1105 	} else {
1106 		for (i = 0; i < iface->afc.num_chan_info; i++) {
1107 			struct afc_chan_info_elem *c;
1108 
1109 			c = &iface->afc.chan_info_list[i];
1110 			if (c->chan == iface->conf->channel) {
1111 				unsigned int j;
1112 
1113 				*power = 0;
1114 				for (j = 0; j < ARRAY_SIZE(c->power); j++)
1115 					*power = MAX(*power,
1116 						     (int) (2 * c->power[j]));
1117 				return 0;
1118 			}
1119 		}
1120 	}
1121 
1122 	return -EINVAL;
1123 }
1124