1 /*
2 * Coordination of operations between processes
3 * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
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 <fcntl.h>
12 #include <dirent.h>
13
14 #include "utils/common.h"
15 #include "utils/eloop.h"
16 #include "utils/list.h"
17 #include "proc_coord.h"
18
19
20 struct proc_coord_msg_header {
21 u32 msg_type; /* enum proc_coord_message_types */
22 u32 cmd; /* proc_coord_commands */
23 u32 seq;
24 };
25
26 enum proc_coord_peer_state {
27 PROC_COORD_PEER_WAITING,
28 PROC_COORD_PEER_ACTIVE,
29 PROC_COORD_PEER_TIMED_OUT,
30 };
31
32 struct proc_coord_peer {
33 struct dl_list list;
34 pid_t pid;
35 enum proc_coord_peer_state state;
36 struct os_reltime last_rx;
37 };
38
39 struct proc_coord_pending_request {
40 struct dl_list list;
41 struct proc_coord_peer *peer;
42 enum proc_coord_commands cmd;
43 u32 seq;
44 proc_coord_response_cb cb;
45 void *cb_ctx;
46 struct os_reltime timeout;
47 };
48
49 struct proc_coord_handler {
50 struct dl_list list;
51 proc_coord_cb cb;
52 void *cb_ctx;
53 };
54
55 struct proc_coord {
56 pid_t pid;
57 char *dir;
58 char *own_sock;
59 int sock;
60 u32 next_seq;
61 struct dl_list handlers; /* struct proc_coord_handler::list */
62 struct dl_list peers; /* struct proc_coord_peer::list */
63 struct dl_list requests; /* struct proc_coord_pending_request::list */
64 };
65
66
67 static void proc_coord_set_req_expire_timer(struct proc_coord *pc);
68
69
proc_coord_get_peer(struct proc_coord * pc,pid_t pid)70 static struct proc_coord_peer * proc_coord_get_peer(struct proc_coord *pc,
71 pid_t pid)
72 {
73 struct proc_coord_peer *peer;
74
75 dl_list_for_each(peer, &pc->peers, struct proc_coord_peer, list) {
76 if (peer->pid == pid)
77 return peer;
78 }
79
80 return NULL;
81 }
82
83
proc_coord_add_peer(struct proc_coord * pc,pid_t pid)84 static struct proc_coord_peer * proc_coord_add_peer(struct proc_coord *pc,
85 pid_t pid)
86 {
87 struct proc_coord_peer *peer;
88
89 peer = os_zalloc(sizeof(*peer));
90 if (!peer)
91 return NULL;
92
93 peer->pid = pid;
94 peer->state = PROC_COORD_PEER_WAITING;
95 dl_list_add(&pc->peers, &peer->list);
96
97 return peer;
98 }
99
100
proc_coord_remove_req(struct proc_coord_pending_request * req)101 static void proc_coord_remove_req(struct proc_coord_pending_request *req)
102 {
103 dl_list_del(&req->list);
104 if (req->cb)
105 req->cb(req->cb_ctx, req->peer->pid, NULL);
106 os_free(req);
107 }
108
109
proc_coord_remove_peer(struct proc_coord * pc,struct proc_coord_peer * peer)110 static void proc_coord_remove_peer(struct proc_coord *pc,
111 struct proc_coord_peer *peer)
112 {
113 struct proc_coord_pending_request *req, *tmp;
114
115 dl_list_for_each_safe(req, tmp, &pc->requests,
116 struct proc_coord_pending_request, list) {
117 if (req->peer == peer)
118 proc_coord_remove_req(req);
119 }
120
121 dl_list_del(&peer->list);
122 os_free(peer);
123 }
124
125
proc_coord_expire_requests(void * eloop_ctx,void * timeout_ctx)126 static void proc_coord_expire_requests(void *eloop_ctx, void *timeout_ctx)
127 {
128 struct proc_coord *pc = eloop_ctx;
129 struct proc_coord_pending_request *req, *tmp;
130 struct os_reltime now;
131
132 os_get_reltime(&now);
133 dl_list_for_each_safe(req, tmp, &pc->requests,
134 struct proc_coord_pending_request, list) {
135 if (os_reltime_before(&req->timeout, &now)) {
136 wpa_printf(MSG_DEBUG,
137 "proc_coord: Pending request peer=%u cmd=%d seq=%u timed out",
138 req->peer->pid, req->cmd, req->seq);
139 proc_coord_remove_req(req);
140 }
141 }
142
143 proc_coord_set_req_expire_timer(pc);
144 }
145
146
proc_coord_cancel_wait(struct proc_coord * pc,proc_coord_response_cb cb,void * cb_ctx)147 void proc_coord_cancel_wait(struct proc_coord *pc, proc_coord_response_cb cb,
148 void *cb_ctx)
149 {
150 struct proc_coord_pending_request *req, *tmp;
151
152 dl_list_for_each_safe(req, tmp, &pc->requests,
153 struct proc_coord_pending_request, list) {
154 if (req->cb == cb && req->cb_ctx == cb_ctx) {
155 req->cb = NULL;
156 req->cb_ctx = NULL;
157 proc_coord_remove_req(req);
158 }
159 }
160
161 proc_coord_set_req_expire_timer(pc);
162 }
163
164
proc_coord_set_req_expire_timer(struct proc_coord * pc)165 static void proc_coord_set_req_expire_timer(struct proc_coord *pc)
166 {
167 struct proc_coord_pending_request *req;
168 struct os_reltime *first = NULL;
169
170 eloop_cancel_timeout(proc_coord_expire_requests, pc, NULL);
171 dl_list_for_each(req, &pc->requests, struct proc_coord_pending_request,
172 list) {
173 if (!first || os_reltime_before(&req->timeout, first))
174 first = &req->timeout;
175 }
176
177 if (first) {
178 struct os_reltime now, res;
179 unsigned int ms;
180
181 os_get_reltime(&now);
182 if (os_reltime_before(first, &now)) {
183 ms = 0;
184 } else {
185 os_reltime_sub(first, &now, &res);
186 ms = os_reltime_in_ms(&res);
187 }
188 eloop_register_timeout(ms / 1000, (ms % 1000) * 1000,
189 proc_coord_expire_requests, pc, NULL);
190 }
191 }
192
193
194 static struct proc_coord_pending_request *
proc_coord_get_request(struct proc_coord * pc,struct proc_coord_peer * peer,enum proc_coord_commands cmd,u32 seq)195 proc_coord_get_request(struct proc_coord *pc, struct proc_coord_peer *peer,
196 enum proc_coord_commands cmd, u32 seq)
197 {
198 struct proc_coord_pending_request *req;
199
200 dl_list_for_each(req, &pc->requests, struct proc_coord_pending_request,
201 list) {
202 if (req->peer == peer && req->cmd == cmd && req->seq == seq)
203 return req;
204 }
205
206 return NULL;
207 }
208
209
proc_coord_send_msg(struct proc_coord * pc,struct proc_coord_peer * peer,enum proc_coord_message_types msg_type,enum proc_coord_commands cmd,u32 seq,const struct wpabuf * msg)210 static int proc_coord_send_msg(struct proc_coord *pc,
211 struct proc_coord_peer *peer,
212 enum proc_coord_message_types msg_type,
213 enum proc_coord_commands cmd,
214 u32 seq, const struct wpabuf *msg)
215 {
216 struct proc_coord_msg_header hdr;
217 ssize_t res;
218 struct sockaddr_un addr;
219 struct msghdr mh;
220 struct iovec io[2];
221
222 wpa_printf(MSG_DEBUG,
223 "proc_coord: Send message to %d (msg_type=%u cmd=%u seq=%u)",
224 peer->pid, msg_type, cmd, seq);
225
226 os_memset(&hdr, 0, sizeof(hdr));
227 hdr.msg_type = msg_type;
228 hdr.cmd = cmd;
229 hdr.seq = seq;
230
231 os_memset(&addr, 0, sizeof(addr));
232 addr.sun_family = AF_UNIX;
233 os_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%u",
234 pc->dir, peer->pid);
235
236 io[0].iov_base = &hdr;
237 io[0].iov_len = sizeof(hdr);
238 if (msg) {
239 io[1].iov_base = (void *) wpabuf_head(msg);
240 io[1].iov_len = wpabuf_len(msg);
241 }
242
243 os_memset(&mh, 0, sizeof(mh));
244 mh.msg_iov = io;
245 mh.msg_iovlen = msg ? 2 : 1;
246 mh.msg_name = (void *) &addr;
247 mh.msg_namelen = sizeof(addr);
248
249 res = sendmsg(pc->sock, &mh, MSG_DONTWAIT);
250 if (res < 0) {
251 int err = errno;
252
253 wpa_printf(MSG_INFO, "proc_coord: sendmsg: %s",
254 strerror(errno));
255 if (err == ENOENT || err == ECONNREFUSED) {
256 wpa_printf(MSG_INFO,
257 "proc_coord: Remove peer %u due to connection being refused",
258 peer->pid);
259 proc_coord_remove_peer(pc, peer);
260 }
261 return -1;
262 }
263 return 0;
264 }
265
266
proc_coord_rx_starting(struct proc_coord * pc,pid_t pid)267 static void proc_coord_rx_starting(struct proc_coord *pc, pid_t pid)
268 {
269 wpa_printf(MSG_DEBUG, "proc_coord: Peer %u STARTING", pid);
270 }
271
272
proc_coord_rx_stopping(struct proc_coord * pc,pid_t pid)273 static void proc_coord_rx_stopping(struct proc_coord *pc, pid_t pid)
274 {
275 struct proc_coord_peer *peer;
276
277 wpa_printf(MSG_DEBUG, "proc_coord: Peer %u STOPPING", pid);
278
279 peer = proc_coord_get_peer(pc, pid);
280 if (peer) {
281 wpa_printf(MSG_INFO,
282 "proc_coord: Remove peer %u due to STOPPING event",
283 pid);
284 proc_coord_remove_peer(pc, peer);
285 }
286 }
287
288
proc_coord_rx_ping(struct proc_coord * pc,pid_t pid,enum proc_coord_message_types msg_type,u32 seq)289 static void proc_coord_rx_ping(struct proc_coord *pc, pid_t pid,
290 enum proc_coord_message_types msg_type, u32 seq)
291 {
292 if (msg_type != PROC_COORD_MSG_REQUEST)
293 return;
294
295 wpa_printf(MSG_DEBUG, "proc_coord: Reply to peer %u PING", pid);
296 proc_coord_send_response(pc, pid, PROC_COORD_CMD_PING, seq, NULL);
297 }
298
299
proc_coord_receive(int sock,void * eloop_ctx,void * sock_ctx)300 static void proc_coord_receive(int sock, void *eloop_ctx, void *sock_ctx)
301 {
302 struct proc_coord *pc = eloop_ctx;
303 struct sockaddr_un from;
304 struct wpabuf *msg;
305 size_t msg_len;
306 ssize_t res;
307 struct proc_coord_msg_header hdr;
308 pid_t pid;
309 char tmp[20], *pos, *end;
310 struct proc_coord_peer *peer;
311 struct msghdr mh;
312 struct iovec io[2];
313 struct proc_coord_handler *handler, *h_tmp;
314
315 res = recv(sock, tmp, 0, MSG_PEEK | MSG_TRUNC);
316 if (res < 0) {
317 wpa_printf(MSG_ERROR, "proc_coord: recv: %s",
318 strerror(errno));
319 return;
320 }
321 msg_len = res;
322 if (msg_len < sizeof(hdr))
323 return;
324 msg_len -= sizeof(hdr);
325
326 msg = wpabuf_alloc(msg_len);
327 if (!msg)
328 return;
329
330 io[0].iov_base = &hdr;
331 io[0].iov_len = sizeof(hdr);
332 io[1].iov_base = wpabuf_mhead(msg);
333 io[1].iov_len = msg_len;
334
335 os_memset(&mh, 0, sizeof(mh));
336 mh.msg_iov = io;
337 mh.msg_iovlen = 2;
338 mh.msg_name = (void *) &from;
339 mh.msg_namelen = sizeof(from);
340
341 res = recvmsg(sock, &mh, MSG_DONTWAIT);
342 if (res < 0) {
343 wpa_printf(MSG_ERROR, "proc_coord: recvmsg: %s",
344 strerror(errno));
345 goto out;
346 }
347 if ((size_t) res < sizeof(hdr))
348 goto out;
349
350 wpa_printf(MSG_DEBUG, "proc_coord: Received message from %s",
351 from.sun_path);
352 if ((size_t) res > sizeof(hdr)) {
353 wpabuf_put(msg, res - sizeof(hdr));
354 wpa_hexdump_buf(MSG_MSGDUMP,
355 "proc_coord: Received message payload", msg);
356 }
357
358 end = ((char *) &from) + mh.msg_namelen;
359
360 /* Require same directory for client socket */
361 if ((size_t) (end - from.sun_path) < os_strlen(pc->dir) ||
362 os_strncmp(pc->dir, from.sun_path, os_strlen(pc->dir)) != 0)
363 goto out;
364
365 /* Find the peer PID from the socket name */
366 pos = end - 1;
367 while (pos > from.sun_path) {
368 if (*pos == '/')
369 break;
370 pos--;
371 }
372 if (pos == from.sun_path)
373 goto out;
374 pos++;
375 os_memcpy(tmp, pos, end - pos);
376 pid = atoi(tmp);
377
378 wpa_printf(MSG_DEBUG, "proc_coord: pid=%u msg_type=%u cmd=%u seq=%u",
379 pid, hdr.msg_type, hdr.cmd, hdr.seq);
380
381 peer = proc_coord_get_peer(pc, pid);
382
383 switch (hdr.msg_type) {
384 case PROC_COORD_MSG_REQUEST:
385 break;
386 case PROC_COORD_MSG_RESPONSE: {
387 struct proc_coord_pending_request *req;
388
389 if (!peer) {
390 wpa_printf(MSG_DEBUG,
391 "proc_coord: Discard msg_type=RESPONSE from %u since there is no peer entry for it",
392 pid);
393 goto out;
394 }
395
396 req = proc_coord_get_request(pc, peer, hdr.cmd, hdr.seq);
397 if (!req) {
398 wpa_printf(MSG_DEBUG,
399 "proc_coord: Discard msg_type=RESPONSE from %u since there is no pending request for it",
400 pid);
401 goto out;
402 }
403 if (req->cb)
404 req->cb(req->cb_ctx, peer->pid, msg);
405 dl_list_del(&req->list);
406 os_free(req);
407 break;
408 }
409 case PROC_COORD_MSG_EVENT:
410 break;
411 default:
412 wpa_printf(MSG_DEBUG,
413 "proc_coord: Discard unknown msg_type=%u from %u",
414 hdr.msg_type, pid);
415 goto out;
416 }
417
418 if (!peer) {
419 wpa_printf(MSG_DEBUG,
420 "proc_coord: Add new peer entry for %d based on received message",
421 pid);
422 peer = proc_coord_add_peer(pc, pid);
423 if (!peer) {
424 wpa_printf(MSG_ERROR,
425 "proc_coord: Could not add peer entry for %u",
426 pid);
427 goto out;
428 }
429 }
430
431 if (peer->state != PROC_COORD_PEER_ACTIVE) {
432 wpa_printf(MSG_DEBUG,
433 "proc_coord: Mark peer %d active due to received message",
434 pid);
435 peer->state = PROC_COORD_PEER_ACTIVE;
436 }
437
438 os_get_reltime(&peer->last_rx);
439
440 switch (hdr.cmd) {
441 case PROC_COORD_CMD_STARTING :
442 proc_coord_rx_starting(pc, pid);
443 break;
444 case PROC_COORD_CMD_STOPPING:
445 proc_coord_rx_stopping(pc, pid);
446 break;
447 case PROC_COORD_CMD_PING:
448 proc_coord_rx_ping(pc, pid, hdr.msg_type, hdr.seq);
449 break;
450 default:
451 if (hdr.msg_type == PROC_COORD_MSG_RESPONSE)
452 break;
453
454 dl_list_for_each_safe(handler, h_tmp, &pc->handlers,
455 struct proc_coord_handler, list) {
456 if (handler->cb(handler->cb_ctx, pid, hdr.msg_type,
457 hdr.cmd, hdr.seq, msg))
458 break;
459 }
460 break;
461 }
462
463 out:
464 wpabuf_free(msg);
465 }
466
467
proc_coord_send_starting(struct proc_coord * pc)468 static void proc_coord_send_starting(struct proc_coord *pc)
469 {
470 struct proc_coord_peer *peer, *tmp;
471 int count = 0;
472
473 if (dl_list_empty(&pc->peers))
474 return;
475
476 wpa_printf(MSG_DEBUG, "proc_coord: Send STARTING event to all peers");
477 dl_list_for_each_safe(peer, tmp, &pc->peers, struct proc_coord_peer,
478 list) {
479 if (proc_coord_send_msg(pc, peer, PROC_COORD_MSG_EVENT,
480 PROC_COORD_CMD_STARTING, 0, NULL) == 0)
481 count++;
482 }
483 wpa_printf(MSG_DEBUG, "proc_coord: STARTING sent to %d peer(s)", count);
484 }
485
486
proc_coord_send_stopping(struct proc_coord * pc)487 static void proc_coord_send_stopping(struct proc_coord *pc)
488 {
489 if (dl_list_empty(&pc->peers))
490 return;
491
492 wpa_printf(MSG_DEBUG,
493 "proc_coord: Send STOPPING event to all active peers");
494 proc_coord_send_event(pc, 0, PROC_COORD_CMD_STOPPING, NULL);
495 }
496
497
proc_coord_cb_ping(void * ctx,int pid,const struct wpabuf * msg)498 static void proc_coord_cb_ping(void *ctx, int pid, const struct wpabuf *msg)
499 {
500 struct proc_coord *pc = ctx;
501 struct proc_coord_peer *peer;
502
503 peer = proc_coord_get_peer(pc, pid);
504 if (!peer)
505 return;
506 if (msg) {
507 if (peer->state != PROC_COORD_PEER_ACTIVE) {
508 wpa_printf(MSG_DEBUG,
509 "proc_coord: Mark peer %d active due to response to PING",
510 pid);
511 peer->state = PROC_COORD_PEER_ACTIVE;
512 }
513 } else {
514 if (peer->state != PROC_COORD_PEER_TIMED_OUT) {
515 wpa_printf(MSG_DEBUG,
516 "proc_coord: Mark peer %d timed out due to no response to PING",
517 pid);
518 peer->state = PROC_COORD_PEER_TIMED_OUT;
519 }
520 }
521 }
522
523
proc_coord_update_peers_from_dir(struct proc_coord * pc)524 static void proc_coord_update_peers_from_dir(struct proc_coord *pc)
525 {
526 DIR *dir;
527 struct dirent *de;
528 struct proc_coord_peer *peer, *tmp;
529
530 /* Remove peers that do not have a socket file */
531 dl_list_for_each_safe(peer, tmp, &pc->peers, struct proc_coord_peer,
532 list) {
533 char fname[256];
534
535 os_snprintf(fname, sizeof(fname), "%s/%d", pc->dir, peer->pid);
536 if (!os_file_exists(fname)) {
537 wpa_printf(MSG_DEBUG,
538 "proc_coord: Remove peer %d due to socket file not present",
539 peer->pid);
540 proc_coord_remove_peer(pc, peer);
541 }
542 }
543
544 /* Add peer entries for all new sockets in the directory */
545 dir = opendir(pc->dir);
546 if (!dir) {
547 wpa_printf(MSG_ERROR, "proc_coord: opendir: %s",
548 strerror(errno));
549 return;
550 }
551
552 while ((de = readdir(dir))) {
553 int pid = atoi(de->d_name);
554
555 if (pid <= 0 || pid == pc->pid)
556 continue;
557
558 peer = proc_coord_get_peer(pc, pid);
559 if (peer)
560 continue;
561
562 wpa_printf(MSG_DEBUG, "proc_coord: Add new peer entry for %u",
563 pid);
564 peer = proc_coord_add_peer(pc, pid);
565 if (!peer) {
566 wpa_printf(MSG_ERROR,
567 "proc_coord: Could not add peer entry for %u",
568 pid);
569 continue;
570 }
571
572 wpa_printf(MSG_DEBUG, "proc_coord: Ping new peer %u", pid);
573 proc_coord_send_request(pc, pid, PROC_COORD_CMD_PING, NULL,
574 10000, proc_coord_cb_ping, pc);
575 }
576
577 closedir(dir);
578 }
579
580
proc_coord_update_peers(void * eloop_ctx,void * timeout_ctx)581 static void proc_coord_update_peers(void *eloop_ctx, void *timeout_ctx)
582 {
583 struct proc_coord *pc = eloop_ctx;
584 struct proc_coord_peer *peer, *tmp;
585 struct os_reltime now;
586
587 proc_coord_update_peers_from_dir(pc);
588
589 os_get_reltime(&now);
590 dl_list_for_each_safe(peer, tmp, &pc->peers, struct proc_coord_peer,
591 list) {
592 if (!os_reltime_expired(&now, &peer->last_rx, 60))
593 continue;
594 proc_coord_send_request(pc, peer->pid, PROC_COORD_CMD_PING,
595 NULL, 10000, NULL, NULL);
596 }
597
598 eloop_register_timeout(10, 0, proc_coord_update_peers, pc, NULL);
599 }
600
601
proc_coord_init(const char * dir)602 struct proc_coord * proc_coord_init(const char *dir)
603 {
604 struct proc_coord *pc;
605 struct sockaddr_un addr;
606 size_t len;
607 int flags;
608
609 pc = os_zalloc(sizeof(*pc));
610 if (!pc)
611 return NULL;
612
613 dl_list_init(&pc->peers);
614 dl_list_init(&pc->requests);
615 dl_list_init(&pc->handlers);
616 pc->sock = -1;
617
618 pc->dir = os_strdup(dir);
619 if (!pc->dir)
620 goto fail;
621
622 len = os_strlen(dir) + 20;
623 pc->own_sock = os_zalloc(len);
624 if (!pc->own_sock)
625 goto fail;
626 pc->pid = getpid();
627 os_snprintf(pc->own_sock, len, "%s/%d", dir, pc->pid);
628 wpa_printf(MSG_DEBUG, "proc_coord: Own socket at %s", pc->own_sock);
629 unlink(pc->own_sock);
630
631 pc->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
632 if (pc->sock < 0) {
633 wpa_printf(MSG_ERROR, "proc_coord: socket(PF_UNIX): %s",
634 strerror(errno));
635 goto fail;
636 }
637
638 os_memset(&addr, 0, sizeof(addr));
639 addr.sun_family = AF_UNIX;
640 os_strlcpy(addr.sun_path, pc->own_sock, sizeof(addr.sun_path));
641 if (bind(pc->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
642 wpa_printf(MSG_ERROR, "proc_coord: bind(PF_UNIX) failed: %s",
643 strerror(errno));
644 goto fail;
645 }
646
647 flags = fcntl(pc->sock, F_GETFL);
648 if (flags >= 0) {
649 flags |= O_NONBLOCK;
650 if (fcntl(pc->sock, F_SETFL, flags) < 0) {
651 wpa_printf(MSG_INFO,
652 "proc_coord: fcntl(O_NONBLOCK): %s",
653 strerror(errno));
654 /* Not fatal, continue on.*/
655 }
656 }
657
658 eloop_register_read_sock(pc->sock, proc_coord_receive, pc, NULL);
659
660 proc_coord_update_peers_from_dir(pc);
661
662 /* Start periodic updates quickly to recover from potential race
663 * conditions if the processes are started at the same time. */
664 eloop_register_timeout(1, 0, proc_coord_update_peers, pc, NULL);
665
666 proc_coord_send_starting(pc);
667
668 return pc;
669
670 fail:
671 proc_coord_deinit(pc);
672 return NULL;
673 }
674
675
proc_coord_deinit(struct proc_coord * pc)676 void proc_coord_deinit(struct proc_coord *pc)
677 {
678 struct proc_coord_peer *peer, *tmp;
679 struct proc_coord_pending_request *req, *tmp2;
680
681 if (!pc)
682 return;
683
684 eloop_cancel_timeout(proc_coord_update_peers, pc, NULL);
685 eloop_cancel_timeout(proc_coord_expire_requests, pc, NULL);
686
687 if (pc->sock >= 0) {
688 proc_coord_send_stopping(pc);
689 eloop_unregister_read_sock(pc->sock);
690 close(pc->sock);
691 unlink(pc->own_sock);
692 }
693
694 dl_list_for_each_safe(peer, tmp, &pc->peers, struct proc_coord_peer,
695 list)
696 proc_coord_remove_peer(pc, peer);
697
698 dl_list_for_each_safe(req, tmp2, &pc->requests,
699 struct proc_coord_pending_request, list) {
700 dl_list_del(&req->list);
701 os_free(req);
702 }
703
704 os_free(pc->dir);
705 os_free(pc->own_sock);
706 os_free(pc);
707 }
708
709
proc_coord_register_handler(struct proc_coord * pc,proc_coord_cb cb,void * cb_ctx)710 int proc_coord_register_handler(struct proc_coord *pc, proc_coord_cb cb,
711 void *cb_ctx)
712 {
713 struct proc_coord_handler *handler;
714
715 handler = os_zalloc(sizeof(*handler));
716 if (!handler)
717 return -1;
718
719 handler->cb = cb;
720 handler->cb_ctx = cb_ctx;
721 dl_list_add(&pc->handlers, &handler->list);
722 return 0;
723 }
724
725
proc_coord_unregister_handler(struct proc_coord * pc,proc_coord_cb cb,void * cb_ctx)726 void proc_coord_unregister_handler(struct proc_coord *pc, proc_coord_cb cb,
727 void *cb_ctx)
728 {
729 struct proc_coord_handler *handler;
730
731 dl_list_for_each(handler, &pc->handlers, struct proc_coord_handler,
732 list) {
733 if (handler->cb == cb && handler->cb_ctx == cb_ctx) {
734 dl_list_del(&handler->list);
735 os_free(handler);
736 break;
737 }
738 }
739 }
740
741
proc_coord_send_event(struct proc_coord * pc,int dst,enum proc_coord_commands cmd,const struct wpabuf * msg)742 int proc_coord_send_event(struct proc_coord *pc, int dst,
743 enum proc_coord_commands cmd,
744 const struct wpabuf *msg)
745 {
746 struct proc_coord_peer *peer, *tmp;
747 int count = 0;
748 u32 seq = 0;
749
750 dl_list_for_each_safe(peer, tmp, &pc->peers, struct proc_coord_peer,
751 list) {
752 if (dst && peer->pid != dst)
753 continue;
754 if (!dst && peer->state != PROC_COORD_PEER_ACTIVE)
755 continue;
756 if (proc_coord_send_msg(pc, peer, PROC_COORD_MSG_EVENT, cmd,
757 seq, msg) == 0)
758 count++;
759 }
760
761 return count;
762 }
763
764
proc_coord_send_request(struct proc_coord * pc,int dst,enum proc_coord_commands cmd,const struct wpabuf * msg,unsigned int timeout_ms,proc_coord_response_cb cb,void * cb_ctx)765 int proc_coord_send_request(struct proc_coord *pc, int dst,
766 enum proc_coord_commands cmd,
767 const struct wpabuf *msg,
768 unsigned int timeout_ms,
769 proc_coord_response_cb cb,
770 void *cb_ctx)
771 {
772 struct proc_coord_peer *peer, *tmp;
773 int count = 0;
774 struct proc_coord_pending_request *req;
775
776 pc->next_seq++;
777
778 dl_list_for_each_safe(peer, tmp, &pc->peers, struct proc_coord_peer,
779 list) {
780 if (dst && peer->pid != dst)
781 continue;
782 if (!dst && peer->state != PROC_COORD_PEER_ACTIVE)
783 continue;
784 if (proc_coord_send_msg(pc, peer, PROC_COORD_MSG_REQUEST, cmd,
785 pc->next_seq, msg) < 0)
786 continue;
787 count++;
788
789 req = os_zalloc(sizeof(*req));
790 if (!req)
791 break;
792 req->peer = peer;
793 req->cmd = cmd;
794 req->seq = pc->next_seq;
795 req->cb = cb;
796 req->cb_ctx = cb_ctx;
797 os_get_reltime(&req->timeout);
798 os_reltime_add_ms(&req->timeout, timeout_ms);
799 dl_list_add(&pc->requests, &req->list);
800 }
801 proc_coord_set_req_expire_timer(pc);
802
803 return count;
804 }
805
806
proc_coord_send_response(struct proc_coord * pc,int dst,enum proc_coord_commands cmd,u32 seq,const struct wpabuf * msg)807 int proc_coord_send_response(struct proc_coord *pc, int dst,
808 enum proc_coord_commands cmd, u32 seq,
809 const struct wpabuf *msg)
810 {
811 struct proc_coord_peer *peer = proc_coord_get_peer(pc, dst);
812
813 if (!peer)
814 return -1;
815 return proc_coord_send_msg(pc, peer, PROC_COORD_MSG_RESPONSE, cmd,
816 seq, msg);
817 }
818