blob: 745a13fc026e412e8018f1f9ec621b3051e62d57 [file] [log] [blame]
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001/*
2 * Generic advertisement service (GAS) server
3 * Copyright (c) 2017, Qualcomm Atheros, Inc.
Hai Shalom899fcc72020-10-19 14:38:18 -07004 * Copyright (c) 2020, The Linux Foundation
Hai Shaloma20dcd72022-02-04 13:43:00 -08005 * Copyright (c) 2022, Qualcomm Innovation Center, Inc.
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006 *
7 * This software may be distributed under the terms of the BSD license.
8 * See README for more details.
9 */
10
11#include "includes.h"
12
13#include "utils/common.h"
14#include "utils/list.h"
15#include "utils/eloop.h"
16#include "ieee802_11_defs.h"
17#include "gas.h"
18#include "gas_server.h"
19
20
21#define MAX_ADV_PROTO_ID_LEN 10
Hai Shaloma20dcd72022-02-04 13:43:00 -080022#define GAS_QUERY_TIMEOUT 60
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070023
24struct gas_server_handler {
25 struct dl_list list;
26 u8 adv_proto_id[MAX_ADV_PROTO_ID_LEN];
27 u8 adv_proto_id_len;
Hai Shalom899fcc72020-10-19 14:38:18 -070028 struct wpabuf * (*req_cb)(void *ctx, void *resp_ctx, const u8 *sa,
29 const u8 *query, size_t query_len,
Hai Shaloma20dcd72022-02-04 13:43:00 -080030 int *comeback_delay);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070031 void (*status_cb)(void *ctx, struct wpabuf *resp, int ok);
32 void *ctx;
33 struct gas_server *gas;
34};
35
36struct gas_server_response {
37 struct dl_list list;
38 size_t offset;
39 u8 frag_id;
40 struct wpabuf *resp;
41 int freq;
42 u8 dst[ETH_ALEN];
43 u8 dialog_token;
44 struct gas_server_handler *handler;
Hai Shalom899fcc72020-10-19 14:38:18 -070045 u16 comeback_delay;
Hai Shaloma20dcd72022-02-04 13:43:00 -080046 bool initial_resp_sent;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070047};
48
49struct gas_server {
50 struct dl_list handlers; /* struct gas_server_handler::list */
51 struct dl_list responses; /* struct gas_server_response::list */
52 void (*tx)(void *ctx, int freq, const u8 *da, struct wpabuf *resp,
53 unsigned int wait_time);
54 void *ctx;
55};
56
57static void gas_server_free_response(struct gas_server_response *response);
58
59
60static void gas_server_response_timeout(void *eloop_ctx, void *user_ctx)
61{
62 struct gas_server_response *response = eloop_ctx;
63
64 wpa_printf(MSG_DEBUG, "GAS: Response @%p timeout for " MACSTR
65 " (dialog_token=%u freq=%d frag_id=%u sent=%lu/%lu) - drop pending data",
66 response, MAC2STR(response->dst), response->dialog_token,
67 response->freq, response->frag_id,
68 (unsigned long) response->offset,
Hai Shalom899fcc72020-10-19 14:38:18 -070069 (unsigned long) (response->resp ?
70 wpabuf_len(response->resp) : 0));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070071 response->handler->status_cb(response->handler->ctx,
72 response->resp, 0);
73 response->resp = NULL;
74 dl_list_del(&response->list);
75 gas_server_free_response(response);
76}
77
78
79static void gas_server_free_response(struct gas_server_response *response)
80{
81 if (!response)
82 return;
83 wpa_printf(MSG_DEBUG, "DPP: Free GAS response @%p", response);
84 eloop_cancel_timeout(gas_server_response_timeout, response, NULL);
85 wpabuf_free(response->resp);
86 os_free(response);
87}
88
89
90static void
Hai Shaloma20dcd72022-02-04 13:43:00 -080091gas_server_send_resp(struct gas_server *gas,
Hai Shalom899fcc72020-10-19 14:38:18 -070092 struct gas_server_response *response,
Hai Shalom899fcc72020-10-19 14:38:18 -070093 struct wpabuf *query_resp, u16 comeback_delay)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070094{
Hai Shaloma20dcd72022-02-04 13:43:00 -080095 struct gas_server_handler *handler = response->handler;
96 size_t max_len = (response->freq > 56160) ? 928 : 1400;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070097 size_t hdr_len = 24 + 2 + 5 + 3 + handler->adv_proto_id_len + 2;
98 size_t resp_frag_len;
99 struct wpabuf *resp;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700100
Hai Shalom899fcc72020-10-19 14:38:18 -0700101 if (comeback_delay == 0 && !query_resp) {
Hai Shaloma20dcd72022-02-04 13:43:00 -0800102 dl_list_del(&response->list);
Hai Shalom899fcc72020-10-19 14:38:18 -0700103 gas_server_free_response(response);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700104 return;
Hai Shalom74f70d42019-02-11 14:42:39 -0800105 }
Hai Shalom899fcc72020-10-19 14:38:18 -0700106
Hai Shalom899fcc72020-10-19 14:38:18 -0700107 if (comeback_delay) {
108 /* Need more time to prepare the response */
109 resp_frag_len = 0;
110 response->comeback_delay = comeback_delay;
111 } else if (hdr_len + wpabuf_len(query_resp) > max_len) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700112 /* Need to use comeback to initiate fragmentation */
113 comeback_delay = 1;
114 resp_frag_len = 0;
115 } else {
116 /* Full response fits into the initial response */
117 comeback_delay = 0;
118 resp_frag_len = wpabuf_len(query_resp);
119 }
120
Hai Shaloma20dcd72022-02-04 13:43:00 -0800121 resp = gas_build_initial_resp(response->dialog_token,
122 WLAN_STATUS_SUCCESS,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700123 comeback_delay,
124 handler->adv_proto_id_len +
125 resp_frag_len);
126 if (!resp) {
Hai Shalom74f70d42019-02-11 14:42:39 -0800127 wpabuf_free(query_resp);
Hai Shaloma20dcd72022-02-04 13:43:00 -0800128 dl_list_del(&response->list);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700129 gas_server_free_response(response);
130 return;
131 }
132
133 /* Advertisement Protocol element */
134 wpabuf_put_u8(resp, WLAN_EID_ADV_PROTO);
135 wpabuf_put_u8(resp, 1 + handler->adv_proto_id_len); /* Length */
136 wpabuf_put_u8(resp, 0x7f);
137 /* Advertisement Protocol ID */
138 wpabuf_put_data(resp, handler->adv_proto_id, handler->adv_proto_id_len);
139
140 /* Query Response Length */
141 wpabuf_put_le16(resp, resp_frag_len);
Hai Shalom899fcc72020-10-19 14:38:18 -0700142 if (!comeback_delay && query_resp)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700143 wpabuf_put_buf(resp, query_resp);
144
Hai Shalom899fcc72020-10-19 14:38:18 -0700145 if (comeback_delay && !query_resp) {
146 wpa_printf(MSG_DEBUG, "GAS: No response available yet");
147 } else if (comeback_delay) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700148 wpa_printf(MSG_DEBUG,
149 "GAS: Need to fragment query response");
150 } else {
151 wpa_printf(MSG_DEBUG,
152 "GAS: Full query response fits in the GAS Initial Response frame");
153 }
154 response->offset = resp_frag_len;
155 response->resp = query_resp;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800156 response->initial_resp_sent = true;
157 gas->tx(gas->ctx, response->freq, response->dst, resp,
158 comeback_delay ? 2000 : 0);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700159 wpabuf_free(resp);
160 eloop_register_timeout(GAS_QUERY_TIMEOUT, 0,
161 gas_server_response_timeout, response, NULL);
162}
163
164
165static int
166gas_server_rx_initial_req(struct gas_server *gas, const u8 *da, const u8 *sa,
167 const u8 *bssid, int freq, u8 dialog_token,
168 const u8 *data, size_t len)
169{
170 const u8 *pos, *end, *adv_proto, *query_req;
171 u8 adv_proto_len;
172 u16 query_req_len;
173 struct gas_server_handler *handler;
174 struct wpabuf *resp;
Hai Shalom899fcc72020-10-19 14:38:18 -0700175 struct gas_server_response *response;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700176
177 wpa_hexdump(MSG_MSGDUMP, "GAS: Received GAS Initial Request frame",
178 data, len);
179 pos = data;
180 end = data + len;
181
182 if (end - pos < 2 || pos[0] != WLAN_EID_ADV_PROTO) {
183 wpa_printf(MSG_DEBUG,
184 "GAS: No Advertisement Protocol element found");
185 return -1;
186 }
187 pos++;
188 adv_proto_len = *pos++;
189 if (end - pos < adv_proto_len || adv_proto_len < 2) {
190 wpa_printf(MSG_DEBUG,
191 "GAS: Truncated Advertisement Protocol element");
192 return -1;
193 }
194
195 adv_proto = pos;
196 pos += adv_proto_len;
197 wpa_hexdump(MSG_MSGDUMP, "GAS: Advertisement Protocol element",
198 adv_proto, adv_proto_len);
199
200 if (end - pos < 2) {
201 wpa_printf(MSG_DEBUG, "GAS: No Query Request Length field");
202 return -1;
203 }
204 query_req_len = WPA_GET_LE16(pos);
205 pos += 2;
206 if (end - pos < query_req_len) {
207 wpa_printf(MSG_DEBUG, "GAS: Truncated Query Request field");
208 return -1;
209 }
210 query_req = pos;
211 pos += query_req_len;
212 wpa_hexdump(MSG_MSGDUMP, "GAS: Query Request",
213 query_req, query_req_len);
214
215 if (pos < end) {
216 wpa_hexdump(MSG_MSGDUMP,
217 "GAS: Ignored extra data after Query Request field",
218 pos, end - pos);
219 }
220
Hai Shalom899fcc72020-10-19 14:38:18 -0700221 response = os_zalloc(sizeof(*response));
222 if (!response)
223 return -1;
224
225 wpa_printf(MSG_DEBUG, "DPP: Allocated GAS response @%p", response);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700226 dl_list_for_each(handler, &gas->handlers, struct gas_server_handler,
227 list) {
Hai Shaloma20dcd72022-02-04 13:43:00 -0800228 int comeback_delay = 0;
Hai Shalom899fcc72020-10-19 14:38:18 -0700229
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700230 if (adv_proto_len < 1 + handler->adv_proto_id_len ||
231 os_memcmp(adv_proto + 1, handler->adv_proto_id,
232 handler->adv_proto_id_len) != 0)
233 continue;
234
Hai Shaloma20dcd72022-02-04 13:43:00 -0800235 response->freq = freq;
236 response->handler = handler;
237 os_memcpy(response->dst, sa, ETH_ALEN);
238 response->dialog_token = dialog_token;
239 dl_list_add(&gas->responses, &response->list);
240
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700241 wpa_printf(MSG_DEBUG,
242 "GAS: Calling handler for the requested Advertisement Protocol ID");
Hai Shalom899fcc72020-10-19 14:38:18 -0700243 resp = handler->req_cb(handler->ctx, response, sa, query_req,
244 query_req_len, &comeback_delay);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700245 wpa_hexdump_buf(MSG_MSGDUMP, "GAS: Response from the handler",
246 resp);
Hai Shaloma20dcd72022-02-04 13:43:00 -0800247 if (comeback_delay < 0) {
248 wpa_printf(MSG_DEBUG,
249 "GAS: Handler requested short delay before sending out the initial response");
250 return 0;
251 }
Hai Shalom899fcc72020-10-19 14:38:18 -0700252 if (comeback_delay)
253 wpa_printf(MSG_DEBUG,
254 "GAS: Handler requested comeback delay: %u TU",
255 comeback_delay);
Hai Shaloma20dcd72022-02-04 13:43:00 -0800256 gas_server_send_resp(gas, response, resp, comeback_delay);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700257 return 0;
258 }
259
260 wpa_printf(MSG_DEBUG,
261 "GAS: No registered handler for the requested Advertisement Protocol ID");
Hai Shalom899fcc72020-10-19 14:38:18 -0700262 gas_server_free_response(response);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700263 return -1;
264}
265
266
267static void
268gas_server_handle_rx_comeback_req(struct gas_server_response *response)
269{
270 struct gas_server_handler *handler = response->handler;
271 struct gas_server *gas = handler->gas;
272 size_t max_len = (response->freq > 56160) ? 928 : 1400;
273 size_t hdr_len = 24 + 2 + 6 + 3 + handler->adv_proto_id_len + 2;
274 size_t remaining, resp_frag_len;
275 struct wpabuf *resp;
Hai Shalom899fcc72020-10-19 14:38:18 -0700276 unsigned int wait_time = 0;
277
278 if (!response->resp) {
279 resp = gas_build_comeback_resp(response->dialog_token,
280 WLAN_STATUS_SUCCESS, 0, 0,
281 response->comeback_delay,
282 handler->adv_proto_id_len);
283 if (!resp) {
284 dl_list_del(&response->list);
285 gas_server_free_response(response);
286 return;
287 }
288
289 /* Advertisement Protocol element */
290 wpabuf_put_u8(resp, WLAN_EID_ADV_PROTO);
291 wpabuf_put_u8(resp, 1 + handler->adv_proto_id_len); /* Length */
292 wpabuf_put_u8(resp, 0x7f);
293 /* Advertisement Protocol ID */
294 wpabuf_put_data(resp, handler->adv_proto_id,
295 handler->adv_proto_id_len);
296
297 /* Query Response Length */
298 wpabuf_put_le16(resp, 0);
299 goto send_resp;
300 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700301
302 remaining = wpabuf_len(response->resp) - response->offset;
303 if (hdr_len + remaining > max_len)
304 resp_frag_len = max_len - hdr_len;
305 else
306 resp_frag_len = remaining;
307 wpa_printf(MSG_DEBUG,
308 "GAS: Sending out %u/%u remaining Query Response octets",
309 (unsigned int) resp_frag_len, (unsigned int) remaining);
310
311 resp = gas_build_comeback_resp(response->dialog_token,
312 WLAN_STATUS_SUCCESS,
313 response->frag_id++,
314 resp_frag_len < remaining, 0,
315 handler->adv_proto_id_len +
316 resp_frag_len);
317 if (!resp) {
Hai Shalom74f70d42019-02-11 14:42:39 -0800318 dl_list_del(&response->list);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700319 gas_server_free_response(response);
320 return;
321 }
322
323 /* Advertisement Protocol element */
324 wpabuf_put_u8(resp, WLAN_EID_ADV_PROTO);
325 wpabuf_put_u8(resp, 1 + handler->adv_proto_id_len); /* Length */
326 wpabuf_put_u8(resp, 0x7f);
327 /* Advertisement Protocol ID */
328 wpabuf_put_data(resp, handler->adv_proto_id, handler->adv_proto_id_len);
329
330 /* Query Response Length */
331 wpabuf_put_le16(resp, resp_frag_len);
332 wpabuf_put_data(resp, wpabuf_head_u8(response->resp) + response->offset,
333 resp_frag_len);
334
335 response->offset += resp_frag_len;
336
Hai Shalom899fcc72020-10-19 14:38:18 -0700337 if (remaining > resp_frag_len)
338 wait_time = 2000;
339
340send_resp:
341 gas->tx(gas->ctx, response->freq, response->dst, resp, wait_time);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700342 wpabuf_free(resp);
343}
344
345
346static int
347gas_server_rx_comeback_req(struct gas_server *gas, const u8 *da, const u8 *sa,
348 const u8 *bssid, int freq, u8 dialog_token)
349{
350 struct gas_server_response *response;
351
352 dl_list_for_each(response, &gas->responses, struct gas_server_response,
353 list) {
354 if (response->dialog_token != dialog_token ||
355 os_memcmp(sa, response->dst, ETH_ALEN) != 0)
356 continue;
357 gas_server_handle_rx_comeback_req(response);
358 return 0;
359 }
360
361 wpa_printf(MSG_DEBUG, "GAS: No pending GAS response for " MACSTR
362 " (dialog token %u)", MAC2STR(sa), dialog_token);
363 return -1;
364}
365
366
367/**
368 * gas_query_rx - Indicate reception of a Public Action or Protected Dual frame
369 * @gas: GAS query data from gas_server_init()
370 * @da: Destination MAC address of the Action frame
371 * @sa: Source MAC address of the Action frame
372 * @bssid: BSSID of the Action frame
373 * @categ: Category of the Action frame
374 * @data: Payload of the Action frame
375 * @len: Length of @data
376 * @freq: Frequency (in MHz) on which the frame was received
377 * Returns: 0 if the Public Action frame was a GAS request frame or -1 if not
378 */
379int gas_server_rx(struct gas_server *gas, const u8 *da, const u8 *sa,
380 const u8 *bssid, u8 categ, const u8 *data, size_t len,
381 int freq)
382{
383 u8 action, dialog_token;
384 const u8 *pos, *end;
385
386 if (!gas || len < 2)
387 return -1;
388
389 if (categ == WLAN_ACTION_PROTECTED_DUAL)
390 return -1; /* Not supported for now */
391
392 pos = data;
393 end = data + len;
394 action = *pos++;
395 dialog_token = *pos++;
396
397 if (action != WLAN_PA_GAS_INITIAL_REQ &&
398 action != WLAN_PA_GAS_COMEBACK_REQ)
399 return -1; /* Not a GAS request */
400
401 wpa_printf(MSG_DEBUG, "GAS: Received GAS %s Request frame DA=" MACSTR
402 " SA=" MACSTR " BSSID=" MACSTR
403 " freq=%d dialog_token=%u len=%u",
404 action == WLAN_PA_GAS_INITIAL_REQ ? "Initial" : "Comeback",
405 MAC2STR(da), MAC2STR(sa), MAC2STR(bssid), freq, dialog_token,
406 (unsigned int) len);
407
408 if (action == WLAN_PA_GAS_INITIAL_REQ)
409 return gas_server_rx_initial_req(gas, da, sa, bssid,
410 freq, dialog_token,
411 pos, end - pos);
412 return gas_server_rx_comeback_req(gas, da, sa, bssid,
413 freq, dialog_token);
414}
415
416
417static void gas_server_handle_tx_status(struct gas_server_response *response,
418 int ack)
419{
Hai Shalom899fcc72020-10-19 14:38:18 -0700420 if (ack && response->resp &&
421 response->offset < wpabuf_len(response->resp)) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700422 wpa_printf(MSG_DEBUG,
423 "GAS: More fragments remaining - keep pending entry");
424 return;
425 }
426
Hai Shalom899fcc72020-10-19 14:38:18 -0700427 if (ack && !response->resp && response->comeback_delay) {
428 wpa_printf(MSG_DEBUG,
429 "GAS: Waiting for response - keep pending entry");
430 return;
431 }
432
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700433 if (!ack)
434 wpa_printf(MSG_DEBUG,
435 "GAS: No ACK received - drop pending entry");
436 else
437 wpa_printf(MSG_DEBUG,
438 "GAS: Last fragment of the response sent out - drop pending entry");
439
440 response->handler->status_cb(response->handler->ctx,
441 response->resp, ack);
442 response->resp = NULL;
443 dl_list_del(&response->list);
444 gas_server_free_response(response);
445}
446
447
448void gas_server_tx_status(struct gas_server *gas, const u8 *dst, const u8 *data,
449 size_t data_len, int ack)
450{
451 const u8 *pos;
452 u8 action, code, dialog_token;
453 struct gas_server_response *response;
454
455 if (data_len < 24 + 3)
456 return;
457 pos = data + 24;
458 action = *pos++;
459 code = *pos++;
460 dialog_token = *pos++;
461 if (action != WLAN_ACTION_PUBLIC ||
462 (code != WLAN_PA_GAS_INITIAL_RESP &&
463 code != WLAN_PA_GAS_COMEBACK_RESP))
464 return;
465 wpa_printf(MSG_DEBUG, "GAS: TX status dst=" MACSTR
466 " ack=%d %s dialog_token=%u",
467 MAC2STR(dst), ack,
468 code == WLAN_PA_GAS_INITIAL_RESP ? "initial" : "comeback",
469 dialog_token);
470 dl_list_for_each(response, &gas->responses, struct gas_server_response,
471 list) {
472 if (response->dialog_token != dialog_token ||
473 os_memcmp(dst, response->dst, ETH_ALEN) != 0)
474 continue;
475 gas_server_handle_tx_status(response, ack);
476 return;
477 }
478
479 wpa_printf(MSG_DEBUG, "GAS: No pending response matches TX status");
480}
481
482
Hai Shalom899fcc72020-10-19 14:38:18 -0700483int gas_server_set_resp(struct gas_server *gas, void *resp_ctx,
484 struct wpabuf *resp)
485{
486 struct gas_server_response *tmp, *response = NULL;
487
488 dl_list_for_each(tmp, &gas->responses, struct gas_server_response,
489 list) {
490 if (tmp == resp_ctx) {
491 response = tmp;
492 break;
493 }
494 }
495
496 if (!response || response->resp)
497 return -1;
498
Hai Shaloma20dcd72022-02-04 13:43:00 -0800499 if (!response->initial_resp_sent) {
500 wpa_printf(MSG_DEBUG, "GAS: Send the delayed initial response");
501 gas_server_send_resp(gas, response, resp, 0);
502 return 0;
503 }
504
Hai Shalom899fcc72020-10-19 14:38:18 -0700505 response->resp = resp;
506 return 0;
507}
508
509
Hai Shaloma20dcd72022-02-04 13:43:00 -0800510int gas_server_set_comeback_delay(struct gas_server *gas, void *resp_ctx,
511 u16 comeback_delay)
512{
513 struct gas_server_response *tmp, *response = NULL;
514
515 dl_list_for_each(tmp, &gas->responses, struct gas_server_response,
516 list) {
517 if (tmp == resp_ctx) {
518 response = tmp;
519 break;
520 }
521 }
522
523 if (!response || response->initial_resp_sent)
524 return -1;
525
526 wpa_printf(MSG_DEBUG,
527 "GAS: Send the delayed initial response with comeback delay %u",
528 comeback_delay);
529 gas_server_send_resp(gas, response, NULL, comeback_delay);
530
531 return 0;
532}
533
534
Hai Shalom60840252021-02-19 19:02:11 -0800535bool gas_server_response_sent(struct gas_server *gas, void *resp_ctx)
536{
537 struct gas_server_response *tmp;
538
539 dl_list_for_each(tmp, &gas->responses, struct gas_server_response,
540 list) {
541 if (tmp == resp_ctx)
542 return tmp->resp &&
543 tmp->offset == wpabuf_len(tmp->resp);
544 }
545
546 return false;
547}
548
549
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700550struct gas_server * gas_server_init(void *ctx,
551 void (*tx)(void *ctx, int freq,
552 const u8 *da,
553 struct wpabuf *buf,
554 unsigned int wait_time))
555{
556 struct gas_server *gas;
557
558 gas = os_zalloc(sizeof(*gas));
559 if (!gas)
560 return NULL;
561 gas->ctx = ctx;
562 gas->tx = tx;
563 dl_list_init(&gas->handlers);
564 dl_list_init(&gas->responses);
565 return gas;
566}
567
568
569void gas_server_deinit(struct gas_server *gas)
570{
571 struct gas_server_handler *handler, *tmp;
572 struct gas_server_response *response, *tmp_r;
573
574 if (!gas)
575 return;
576
577 dl_list_for_each_safe(handler, tmp, &gas->handlers,
578 struct gas_server_handler, list) {
579 dl_list_del(&handler->list);
580 os_free(handler);
581 }
582
583 dl_list_for_each_safe(response, tmp_r, &gas->responses,
584 struct gas_server_response, list) {
585 dl_list_del(&response->list);
586 gas_server_free_response(response);
587 }
588
589 os_free(gas);
590}
591
592
593int gas_server_register(struct gas_server *gas,
594 const u8 *adv_proto_id, u8 adv_proto_id_len,
595 struct wpabuf *
Hai Shalom899fcc72020-10-19 14:38:18 -0700596 (*req_cb)(void *ctx, void *resp_ctx, const u8 *sa,
597 const u8 *query, size_t query_len,
Hai Shaloma20dcd72022-02-04 13:43:00 -0800598 int *comeback_delay),
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700599 void (*status_cb)(void *ctx, struct wpabuf *resp,
600 int ok),
601 void *ctx)
602{
603 struct gas_server_handler *handler;
604
605 if (!gas || adv_proto_id_len > MAX_ADV_PROTO_ID_LEN)
606 return -1;
607 handler = os_zalloc(sizeof(*handler));
608 if (!handler)
609 return -1;
610
611 os_memcpy(handler->adv_proto_id, adv_proto_id, adv_proto_id_len);
612 handler->adv_proto_id_len = adv_proto_id_len;
613 handler->req_cb = req_cb;
614 handler->status_cb = status_cb;
615 handler->ctx = ctx;
616 handler->gas = gas;
617 dl_list_add(&gas->handlers, &handler->list);
618
619 return 0;
620}