2 * WPA Supplicant / Windows Named Pipe -based control interface
3 * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
14 #include "eapol_supp/eapol_supp_sm.h"
15 #include "wpa_supplicant_i.h"
16 #include "ctrl_iface.h"
17 #include "common/wpa_ctrl.h"
19 #ifdef __MINGW32_VERSION
20 /* mingw-w32api v3.1 does not yet include sddl.h, so define needed parts here
22 #define SDDL_REVISION_1 1
23 BOOL WINAPI
ConvertStringSecurityDescriptorToSecurityDescriptorA(
24 LPCSTR
, DWORD
, PSECURITY_DESCRIPTOR
*, PULONG
);
25 BOOL WINAPI
ConvertStringSecurityDescriptorToSecurityDescriptorW(
26 LPCWSTR
, DWORD
, PSECURITY_DESCRIPTOR
*, PULONG
);
28 #define ConvertStringSecurityDescriptorToSecurityDescriptor \
29 ConvertStringSecurityDescriptorToSecurityDescriptorW
31 #define ConvertStringSecurityDescriptorToSecurityDescriptor \
32 ConvertStringSecurityDescriptorToSecurityDescriptorA
34 #else /* __MINGW32_VERSION */
36 #define _WIN32_WINNT 0x0500
39 #endif /* __MINGW32_VERSION */
41 #ifndef WPA_SUPPLICANT_NAMED_PIPE
42 #define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant"
44 #define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE)
46 /* Per-interface ctrl_iface */
48 #define REQUEST_BUFSIZE 256
49 #define REPLY_BUFSIZE 4096
51 struct ctrl_iface_priv
;
54 * struct wpa_ctrl_dst - Internal data structure of control interface clients
56 * This structure is used to store information about registered control
57 * interface monitors into struct wpa_supplicant. This data is private to
58 * ctrl_iface_named_pipe.c and should not be touched directly from other files.
61 /* Note: OVERLAPPED must be the first member of struct wpa_ctrl_dst */
63 struct wpa_ctrl_dst
*next
, *prev
;
64 struct ctrl_iface_priv
*priv
;
69 char req_buf
[REQUEST_BUFSIZE
];
75 struct ctrl_iface_priv
{
76 struct wpa_supplicant
*wpa_s
;
77 struct wpa_ctrl_dst
*ctrl_dst
;
78 SECURITY_ATTRIBUTES attr
;
83 static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv
*priv
,
84 int level
, const char *buf
,
87 static void ctrl_close_pipe(struct wpa_ctrl_dst
*dst
);
88 static void wpa_supplicant_ctrl_iface_receive(void *, void *);
89 static VOID WINAPI
ctrl_iface_read_completed(DWORD err
, DWORD bytes
,
90 LPOVERLAPPED overlap
);
92 struct wpa_global_dst
;
93 static void global_close_pipe(struct wpa_global_dst
*dst
);
94 static void wpa_supplicant_global_iface_receive(void *eloop_data
,
96 static VOID WINAPI
global_iface_read_completed(DWORD err
, DWORD bytes
,
97 LPOVERLAPPED overlap
);
100 static int ctrl_broken_pipe(HANDLE pipe
, int used
)
104 if (PeekNamedPipe(pipe
, NULL
, 0, NULL
, NULL
, NULL
))
107 err
= GetLastError();
108 if (err
== ERROR_BROKEN_PIPE
|| (err
== ERROR_BAD_PIPE
&& used
))
114 static void ctrl_flush_broken_pipes(struct ctrl_iface_priv
*priv
)
116 struct wpa_ctrl_dst
*dst
, *next
;
118 dst
= priv
->ctrl_dst
;
122 if (ctrl_broken_pipe(dst
->pipe
, dst
->used
)) {
123 wpa_printf(MSG_DEBUG
, "CTRL: closing broken pipe %p",
125 ctrl_close_pipe(dst
);
132 static int ctrl_open_pipe(struct ctrl_iface_priv
*priv
)
134 struct wpa_ctrl_dst
*dst
;
138 dst
= os_zalloc(sizeof(*dst
));
141 wpa_printf(MSG_DEBUG
, "CTRL: Open pipe %p", dst
);
144 dst
->debug_level
= MSG_INFO
;
145 dst
->pipe
= INVALID_HANDLE_VALUE
;
147 dst
->overlap
.hEvent
= CreateEvent(NULL
, TRUE
, TRUE
, NULL
);
148 if (dst
->overlap
.hEvent
== NULL
) {
149 wpa_printf(MSG_ERROR
, "CTRL: CreateEvent failed: %d",
150 (int) GetLastError());
154 eloop_register_event(dst
->overlap
.hEvent
,
155 sizeof(dst
->overlap
.hEvent
),
156 wpa_supplicant_ctrl_iface_receive
, dst
, NULL
);
159 _snwprintf(name
, 256, NAMED_PIPE_PREFIX
TEXT("-%S"),
160 priv
->wpa_s
->ifname
);
162 os_snprintf(name
, 256, NAMED_PIPE_PREFIX
"-%s",
163 priv
->wpa_s
->ifname
);
166 /* TODO: add support for configuring access list for the pipe */
167 dst
->pipe
= CreateNamedPipe(name
,
168 PIPE_ACCESS_DUPLEX
| FILE_FLAG_OVERLAPPED
,
170 PIPE_READMODE_MESSAGE
|
172 15, REPLY_BUFSIZE
, REQUEST_BUFSIZE
,
174 priv
->sec_attr_set
? &priv
->attr
: NULL
);
175 if (dst
->pipe
== INVALID_HANDLE_VALUE
) {
176 wpa_printf(MSG_ERROR
, "CTRL: CreateNamedPipe failed: %d",
177 (int) GetLastError());
181 if (ConnectNamedPipe(dst
->pipe
, &dst
->overlap
)) {
182 wpa_printf(MSG_ERROR
, "CTRL: ConnectNamedPipe failed: %d",
183 (int) GetLastError());
184 CloseHandle(dst
->pipe
);
189 err
= GetLastError();
191 case ERROR_IO_PENDING
:
192 wpa_printf(MSG_DEBUG
, "CTRL: ConnectNamedPipe: connection in "
195 case ERROR_PIPE_CONNECTED
:
196 wpa_printf(MSG_DEBUG
, "CTRL: ConnectNamedPipe: already "
198 if (SetEvent(dst
->overlap
.hEvent
))
202 wpa_printf(MSG_DEBUG
, "CTRL: ConnectNamedPipe error: %d",
204 CloseHandle(dst
->pipe
);
209 dst
->next
= priv
->ctrl_dst
;
211 dst
->next
->prev
= dst
;
212 priv
->ctrl_dst
= dst
;
217 ctrl_close_pipe(dst
);
222 static void ctrl_close_pipe(struct wpa_ctrl_dst
*dst
)
224 wpa_printf(MSG_DEBUG
, "CTRL: close pipe %p", dst
);
226 if (dst
->overlap
.hEvent
) {
227 eloop_unregister_event(dst
->overlap
.hEvent
,
228 sizeof(dst
->overlap
.hEvent
));
229 CloseHandle(dst
->overlap
.hEvent
);
232 if (dst
->pipe
!= INVALID_HANDLE_VALUE
) {
234 * Could use FlushFileBuffers() here to guarantee that all data
235 * gets delivered to the client, but that can block, so let's
236 * not do this for now.
237 * FlushFileBuffers(dst->pipe);
239 CloseHandle(dst
->pipe
);
243 dst
->prev
->next
= dst
->next
;
245 dst
->priv
->ctrl_dst
= dst
->next
;
247 dst
->next
->prev
= dst
->prev
;
249 os_free(dst
->rsp_buf
);
254 static VOID WINAPI
ctrl_iface_write_completed(DWORD err
, DWORD bytes
,
255 LPOVERLAPPED overlap
)
257 struct wpa_ctrl_dst
*dst
= (struct wpa_ctrl_dst
*) overlap
;
258 wpa_printf(MSG_DEBUG
, "CTRL: Overlapped write completed: dst=%p "
259 "err=%d bytes=%d", dst
, (int) err
, (int) bytes
);
261 ctrl_close_pipe(dst
);
265 os_free(dst
->rsp_buf
);
268 if (!ReadFileEx(dst
->pipe
, dst
->req_buf
, sizeof(dst
->req_buf
),
269 &dst
->overlap
, ctrl_iface_read_completed
)) {
270 wpa_printf(MSG_DEBUG
, "CTRL: ReadFileEx failed: %d",
271 (int) GetLastError());
272 ctrl_close_pipe(dst
);
275 wpa_printf(MSG_DEBUG
, "CTRL: Overlapped read started for %p", dst
);
279 static void wpa_supplicant_ctrl_iface_rx(struct wpa_ctrl_dst
*dst
, size_t len
)
281 struct wpa_supplicant
*wpa_s
= dst
->priv
->wpa_s
;
282 char *reply
= NULL
, *send_buf
;
283 size_t reply_len
= 0, send_len
;
284 int new_attached
= 0;
285 char *buf
= dst
->req_buf
;
288 if (len
>= REQUEST_BUFSIZE
)
289 len
= REQUEST_BUFSIZE
- 1;
292 if (os_strcmp(buf
, "ATTACH") == 0) {
294 wpa_printf(MSG_DEBUG
, "CTRL_IFACE monitor attached");
297 } else if (os_strcmp(buf
, "DETACH") == 0) {
299 wpa_printf(MSG_DEBUG
, "CTRL_IFACE monitor detached");
301 } else if (os_strncmp(buf
, "LEVEL ", 6) == 0) {
302 wpa_printf(MSG_DEBUG
, "CTRL_IFACE LEVEL %s", buf
+ 6);
303 dst
->debug_level
= atoi(buf
+ 6);
306 reply
= wpa_supplicant_ctrl_iface_process(wpa_s
, buf
,
312 send_len
= reply_len
;
313 } else if (reply_len
== 2) {
321 os_free(dst
->rsp_buf
);
322 dst
->rsp_buf
= os_malloc(send_len
);
323 if (dst
->rsp_buf
== NULL
) {
324 ctrl_close_pipe(dst
);
328 os_memcpy(dst
->rsp_buf
, send_buf
, send_len
);
331 if (!WriteFileEx(dst
->pipe
, dst
->rsp_buf
, send_len
, &dst
->overlap
,
332 ctrl_iface_write_completed
)) {
333 wpa_printf(MSG_DEBUG
, "CTRL: WriteFileEx failed: %d",
334 (int) GetLastError());
335 ctrl_close_pipe(dst
);
337 wpa_printf(MSG_DEBUG
, "CTRL: Overlapped write started for %p",
342 eapol_sm_notify_ctrl_attached(wpa_s
->eapol
);
346 static VOID WINAPI
ctrl_iface_read_completed(DWORD err
, DWORD bytes
,
347 LPOVERLAPPED overlap
)
349 struct wpa_ctrl_dst
*dst
= (struct wpa_ctrl_dst
*) overlap
;
350 wpa_printf(MSG_DEBUG
, "CTRL: Overlapped read completed: dst=%p err=%d "
351 "bytes=%d", dst
, (int) err
, (int) bytes
);
352 if (err
== 0 && bytes
> 0)
353 wpa_supplicant_ctrl_iface_rx(dst
, bytes
);
357 static void wpa_supplicant_ctrl_iface_receive(void *eloop_data
, void *user_ctx
)
359 struct wpa_ctrl_dst
*dst
= eloop_data
;
360 struct ctrl_iface_priv
*priv
= dst
->priv
;
363 wpa_printf(MSG_DEBUG
, "CTRL: wpa_supplicant_ctrl_iface_receive");
364 ResetEvent(dst
->overlap
.hEvent
);
366 if (!GetOverlappedResult(dst
->pipe
, &dst
->overlap
, &bytes
, FALSE
)) {
367 wpa_printf(MSG_DEBUG
, "CTRL: GetOverlappedResult failed: %d",
368 (int) GetLastError());
371 wpa_printf(MSG_DEBUG
, "CTRL: GetOverlappedResult: New client "
374 /* Open a new named pipe for the next client. */
375 ctrl_open_pipe(priv
);
377 /* Use write completion function to start reading a command */
378 ctrl_iface_write_completed(0, 0, &dst
->overlap
);
380 ctrl_flush_broken_pipes(priv
);
384 static int ctrl_iface_parse(struct ctrl_iface_priv
*priv
, const char *params
)
386 const char *sddl
= NULL
;
389 if (os_strncmp(params
, "SDDL=", 5) == 0)
392 sddl
= os_strstr(params
, " SDDL=");
400 wpa_printf(MSG_DEBUG
, "CTRL: SDDL='%s'", sddl
);
401 os_memset(&priv
->attr
, 0, sizeof(priv
->attr
));
402 priv
->attr
.nLength
= sizeof(priv
->attr
);
403 priv
->attr
.bInheritHandle
= FALSE
;
404 t_sddl
= wpa_strdup_tchar(sddl
);
407 if (!ConvertStringSecurityDescriptorToSecurityDescriptor(
408 t_sddl
, SDDL_REVISION_1
,
409 (PSECURITY_DESCRIPTOR
*) (void *)
410 &priv
->attr
.lpSecurityDescriptor
,
413 wpa_printf(MSG_ERROR
, "CTRL: SDDL='%s' - could not convert to "
414 "security descriptor: %d",
415 sddl
, (int) GetLastError());
420 priv
->sec_attr_set
= 1;
426 static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx
, int level
,
427 enum wpa_msg_type type
,
428 const char *txt
, size_t len
)
430 struct wpa_supplicant
*wpa_s
= ctx
;
431 if (wpa_s
== NULL
|| wpa_s
->ctrl_iface
== NULL
)
433 wpa_supplicant_ctrl_iface_send(wpa_s
->ctrl_iface
, level
, txt
, len
);
437 struct ctrl_iface_priv
*
438 wpa_supplicant_ctrl_iface_init(struct wpa_supplicant
*wpa_s
)
440 struct ctrl_iface_priv
*priv
;
442 priv
= os_zalloc(sizeof(*priv
));
447 if (wpa_s
->conf
->ctrl_interface
== NULL
)
450 if (ctrl_iface_parse(priv
, wpa_s
->conf
->ctrl_interface
) < 0) {
455 if (ctrl_open_pipe(priv
) < 0) {
460 wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb
);
466 void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv
*priv
)
468 while (priv
->ctrl_dst
)
469 ctrl_close_pipe(priv
->ctrl_dst
);
470 if (priv
->sec_attr_set
)
471 LocalFree(priv
->attr
.lpSecurityDescriptor
);
476 static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv
*priv
,
477 int level
, const char *buf
,
480 struct wpa_ctrl_dst
*dst
, *next
;
487 dst
= priv
->ctrl_dst
;
491 os_snprintf(levelstr
, sizeof(levelstr
), "<%d>", level
);
493 llen
= os_strlen(levelstr
);
494 sbuf
= os_malloc(llen
+ len
);
498 os_memcpy(sbuf
, levelstr
, llen
);
499 os_memcpy(sbuf
+ llen
, buf
, len
);
504 if (dst
->attached
&& level
>= dst
->debug_level
) {
505 wpa_printf(MSG_DEBUG
, "CTRL_IFACE monitor send %p",
507 if (!WriteFile(dst
->pipe
, sbuf
, llen
+ len
, &written
,
509 wpa_printf(MSG_DEBUG
, "CTRL: WriteFile to dst "
511 dst
, (int) GetLastError());
513 if (dst
->errors
> 10)
514 ctrl_close_pipe(dst
);
525 void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv
*priv
)
527 wpa_printf(MSG_DEBUG
, "CTRL_IFACE - %s - wait for monitor",
528 priv
->wpa_s
->ifname
);
529 if (priv
->ctrl_dst
== NULL
)
531 WaitForSingleObject(priv
->ctrl_dst
->pipe
, INFINITE
);
535 /* Global ctrl_iface */
537 struct ctrl_iface_global_priv
;
539 struct wpa_global_dst
{
540 /* Note: OVERLAPPED must be the first member of struct wpa_global_dst
543 struct wpa_global_dst
*next
, *prev
;
544 struct ctrl_iface_global_priv
*priv
;
546 char req_buf
[REQUEST_BUFSIZE
];
551 struct ctrl_iface_global_priv
{
552 struct wpa_global
*global
;
553 struct wpa_global_dst
*ctrl_dst
;
557 static void global_flush_broken_pipes(struct ctrl_iface_global_priv
*priv
)
559 struct wpa_global_dst
*dst
, *next
;
561 dst
= priv
->ctrl_dst
;
565 if (ctrl_broken_pipe(dst
->pipe
, dst
->used
)) {
566 wpa_printf(MSG_DEBUG
, "CTRL: closing broken pipe %p",
568 global_close_pipe(dst
);
575 static int global_open_pipe(struct ctrl_iface_global_priv
*priv
)
577 struct wpa_global_dst
*dst
;
580 dst
= os_zalloc(sizeof(*dst
));
583 wpa_printf(MSG_DEBUG
, "CTRL: Open pipe %p", dst
);
586 dst
->pipe
= INVALID_HANDLE_VALUE
;
588 dst
->overlap
.hEvent
= CreateEvent(NULL
, TRUE
, TRUE
, NULL
);
589 if (dst
->overlap
.hEvent
== NULL
) {
590 wpa_printf(MSG_ERROR
, "CTRL: CreateEvent failed: %d",
591 (int) GetLastError());
595 eloop_register_event(dst
->overlap
.hEvent
,
596 sizeof(dst
->overlap
.hEvent
),
597 wpa_supplicant_global_iface_receive
, dst
, NULL
);
599 /* TODO: add support for configuring access list for the pipe */
600 dst
->pipe
= CreateNamedPipe(NAMED_PIPE_PREFIX
,
601 PIPE_ACCESS_DUPLEX
| FILE_FLAG_OVERLAPPED
,
603 PIPE_READMODE_MESSAGE
|
605 10, REPLY_BUFSIZE
, REQUEST_BUFSIZE
,
607 if (dst
->pipe
== INVALID_HANDLE_VALUE
) {
608 wpa_printf(MSG_ERROR
, "CTRL: CreateNamedPipe failed: %d",
609 (int) GetLastError());
613 if (ConnectNamedPipe(dst
->pipe
, &dst
->overlap
)) {
614 wpa_printf(MSG_ERROR
, "CTRL: ConnectNamedPipe failed: %d",
615 (int) GetLastError());
616 CloseHandle(dst
->pipe
);
621 err
= GetLastError();
623 case ERROR_IO_PENDING
:
624 wpa_printf(MSG_DEBUG
, "CTRL: ConnectNamedPipe: connection in "
627 case ERROR_PIPE_CONNECTED
:
628 wpa_printf(MSG_DEBUG
, "CTRL: ConnectNamedPipe: already "
630 if (SetEvent(dst
->overlap
.hEvent
))
634 wpa_printf(MSG_DEBUG
, "CTRL: ConnectNamedPipe error: %d",
636 CloseHandle(dst
->pipe
);
641 dst
->next
= priv
->ctrl_dst
;
643 dst
->next
->prev
= dst
;
644 priv
->ctrl_dst
= dst
;
649 global_close_pipe(dst
);
654 static void global_close_pipe(struct wpa_global_dst
*dst
)
656 wpa_printf(MSG_DEBUG
, "CTRL: close pipe %p", dst
);
658 if (dst
->overlap
.hEvent
) {
659 eloop_unregister_event(dst
->overlap
.hEvent
,
660 sizeof(dst
->overlap
.hEvent
));
661 CloseHandle(dst
->overlap
.hEvent
);
664 if (dst
->pipe
!= INVALID_HANDLE_VALUE
) {
666 * Could use FlushFileBuffers() here to guarantee that all data
667 * gets delivered to the client, but that can block, so let's
668 * not do this for now.
669 * FlushFileBuffers(dst->pipe);
671 CloseHandle(dst
->pipe
);
675 dst
->prev
->next
= dst
->next
;
677 dst
->priv
->ctrl_dst
= dst
->next
;
679 dst
->next
->prev
= dst
->prev
;
681 os_free(dst
->rsp_buf
);
686 static VOID WINAPI
global_iface_write_completed(DWORD err
, DWORD bytes
,
687 LPOVERLAPPED overlap
)
689 struct wpa_global_dst
*dst
= (struct wpa_global_dst
*) overlap
;
690 wpa_printf(MSG_DEBUG
, "CTRL: Overlapped write completed: dst=%p "
691 "err=%d bytes=%d", dst
, (int) err
, (int) bytes
);
693 global_close_pipe(dst
);
697 os_free(dst
->rsp_buf
);
700 if (!ReadFileEx(dst
->pipe
, dst
->req_buf
, sizeof(dst
->req_buf
),
701 &dst
->overlap
, global_iface_read_completed
)) {
702 wpa_printf(MSG_DEBUG
, "CTRL: ReadFileEx failed: %d",
703 (int) GetLastError());
704 global_close_pipe(dst
);
705 /* FIX: if this was the pipe waiting for new global
706 * connections, at this point there are no open global pipes..
707 * Should try to open a new pipe.. */
710 wpa_printf(MSG_DEBUG
, "CTRL: Overlapped read started for %p", dst
);
714 static void wpa_supplicant_global_iface_rx(struct wpa_global_dst
*dst
,
717 struct wpa_global
*global
= dst
->priv
->global
;
718 char *reply
= NULL
, *send_buf
;
719 size_t reply_len
= 0, send_len
;
720 char *buf
= dst
->req_buf
;
723 if (len
>= REQUEST_BUFSIZE
)
724 len
= REQUEST_BUFSIZE
- 1;
727 reply
= wpa_supplicant_global_ctrl_iface_process(global
, buf
,
731 send_len
= reply_len
;
732 } else if (reply_len
) {
736 os_free(dst
->rsp_buf
);
741 os_free(dst
->rsp_buf
);
742 dst
->rsp_buf
= os_malloc(send_len
);
743 if (dst
->rsp_buf
== NULL
) {
744 global_close_pipe(dst
);
748 os_memcpy(dst
->rsp_buf
, send_buf
, send_len
);
751 if (!WriteFileEx(dst
->pipe
, dst
->rsp_buf
, send_len
, &dst
->overlap
,
752 global_iface_write_completed
)) {
753 wpa_printf(MSG_DEBUG
, "CTRL: WriteFileEx failed: %d",
754 (int) GetLastError());
755 global_close_pipe(dst
);
757 wpa_printf(MSG_DEBUG
, "CTRL: Overlapped write started for %p",
763 static VOID WINAPI
global_iface_read_completed(DWORD err
, DWORD bytes
,
764 LPOVERLAPPED overlap
)
766 struct wpa_global_dst
*dst
= (struct wpa_global_dst
*) overlap
;
767 wpa_printf(MSG_DEBUG
, "CTRL: Overlapped read completed: dst=%p err=%d "
768 "bytes=%d", dst
, (int) err
, (int) bytes
);
769 if (err
== 0 && bytes
> 0)
770 wpa_supplicant_global_iface_rx(dst
, bytes
);
774 static void wpa_supplicant_global_iface_receive(void *eloop_data
,
777 struct wpa_global_dst
*dst
= eloop_data
;
778 struct ctrl_iface_global_priv
*priv
= dst
->priv
;
781 wpa_printf(MSG_DEBUG
, "CTRL: wpa_supplicant_global_iface_receive");
782 ResetEvent(dst
->overlap
.hEvent
);
784 if (!GetOverlappedResult(dst
->pipe
, &dst
->overlap
, &bytes
, FALSE
)) {
785 wpa_printf(MSG_DEBUG
, "CTRL: GetOverlappedResult failed: %d",
786 (int) GetLastError());
789 wpa_printf(MSG_DEBUG
, "CTRL: GetOverlappedResult: New client "
792 /* Open a new named pipe for the next client. */
793 if (global_open_pipe(priv
) < 0) {
794 wpa_printf(MSG_DEBUG
, "CTRL: global_open_pipe failed");
798 /* Use write completion function to start reading a command */
799 global_iface_write_completed(0, 0, &dst
->overlap
);
801 global_flush_broken_pipes(priv
);
805 struct ctrl_iface_global_priv
*
806 wpa_supplicant_global_ctrl_iface_init(struct wpa_global
*global
)
808 struct ctrl_iface_global_priv
*priv
;
810 priv
= os_zalloc(sizeof(*priv
));
813 priv
->global
= global
;
815 if (global_open_pipe(priv
) < 0) {
825 wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv
*priv
)
827 while (priv
->ctrl_dst
)
828 global_close_pipe(priv
->ctrl_dst
);