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