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