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
, int global
,
427 const char *txt
, size_t len
)
429 struct wpa_supplicant
*wpa_s
= ctx
;
430 if (wpa_s
== NULL
|| wpa_s
->ctrl_iface
== NULL
)
432 wpa_supplicant_ctrl_iface_send(wpa_s
->ctrl_iface
, level
, txt
, len
);
436 struct ctrl_iface_priv
*
437 wpa_supplicant_ctrl_iface_init(struct wpa_supplicant
*wpa_s
)
439 struct ctrl_iface_priv
*priv
;
441 priv
= os_zalloc(sizeof(*priv
));
446 if (wpa_s
->conf
->ctrl_interface
== NULL
)
449 if (ctrl_iface_parse(priv
, wpa_s
->conf
->ctrl_interface
) < 0) {
454 if (ctrl_open_pipe(priv
) < 0) {
459 wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb
);
465 void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv
*priv
)
467 while (priv
->ctrl_dst
)
468 ctrl_close_pipe(priv
->ctrl_dst
);
469 if (priv
->sec_attr_set
)
470 LocalFree(priv
->attr
.lpSecurityDescriptor
);
475 static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv
*priv
,
476 int level
, const char *buf
,
479 struct wpa_ctrl_dst
*dst
, *next
;
486 dst
= priv
->ctrl_dst
;
490 os_snprintf(levelstr
, sizeof(levelstr
), "<%d>", level
);
492 llen
= os_strlen(levelstr
);
493 sbuf
= os_malloc(llen
+ len
);
497 os_memcpy(sbuf
, levelstr
, llen
);
498 os_memcpy(sbuf
+ llen
, buf
, len
);
503 if (dst
->attached
&& level
>= dst
->debug_level
) {
504 wpa_printf(MSG_DEBUG
, "CTRL_IFACE monitor send %p",
506 if (!WriteFile(dst
->pipe
, sbuf
, llen
+ len
, &written
,
508 wpa_printf(MSG_DEBUG
, "CTRL: WriteFile to dst "
510 dst
, (int) GetLastError());
512 if (dst
->errors
> 10)
513 ctrl_close_pipe(dst
);
524 void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv
*priv
)
526 wpa_printf(MSG_DEBUG
, "CTRL_IFACE - %s - wait for monitor",
527 priv
->wpa_s
->ifname
);
528 if (priv
->ctrl_dst
== NULL
)
530 WaitForSingleObject(priv
->ctrl_dst
->pipe
, INFINITE
);
534 /* Global ctrl_iface */
536 struct ctrl_iface_global_priv
;
538 struct wpa_global_dst
{
539 /* Note: OVERLAPPED must be the first member of struct wpa_global_dst
542 struct wpa_global_dst
*next
, *prev
;
543 struct ctrl_iface_global_priv
*priv
;
545 char req_buf
[REQUEST_BUFSIZE
];
550 struct ctrl_iface_global_priv
{
551 struct wpa_global
*global
;
552 struct wpa_global_dst
*ctrl_dst
;
556 static void global_flush_broken_pipes(struct ctrl_iface_global_priv
*priv
)
558 struct wpa_global_dst
*dst
, *next
;
560 dst
= priv
->ctrl_dst
;
564 if (ctrl_broken_pipe(dst
->pipe
, dst
->used
)) {
565 wpa_printf(MSG_DEBUG
, "CTRL: closing broken pipe %p",
567 global_close_pipe(dst
);
574 static int global_open_pipe(struct ctrl_iface_global_priv
*priv
)
576 struct wpa_global_dst
*dst
;
579 dst
= os_zalloc(sizeof(*dst
));
582 wpa_printf(MSG_DEBUG
, "CTRL: Open pipe %p", dst
);
585 dst
->pipe
= INVALID_HANDLE_VALUE
;
587 dst
->overlap
.hEvent
= CreateEvent(NULL
, TRUE
, TRUE
, NULL
);
588 if (dst
->overlap
.hEvent
== NULL
) {
589 wpa_printf(MSG_ERROR
, "CTRL: CreateEvent failed: %d",
590 (int) GetLastError());
594 eloop_register_event(dst
->overlap
.hEvent
,
595 sizeof(dst
->overlap
.hEvent
),
596 wpa_supplicant_global_iface_receive
, dst
, NULL
);
598 /* TODO: add support for configuring access list for the pipe */
599 dst
->pipe
= CreateNamedPipe(NAMED_PIPE_PREFIX
,
600 PIPE_ACCESS_DUPLEX
| FILE_FLAG_OVERLAPPED
,
602 PIPE_READMODE_MESSAGE
|
604 10, REPLY_BUFSIZE
, REQUEST_BUFSIZE
,
606 if (dst
->pipe
== INVALID_HANDLE_VALUE
) {
607 wpa_printf(MSG_ERROR
, "CTRL: CreateNamedPipe failed: %d",
608 (int) GetLastError());
612 if (ConnectNamedPipe(dst
->pipe
, &dst
->overlap
)) {
613 wpa_printf(MSG_ERROR
, "CTRL: ConnectNamedPipe failed: %d",
614 (int) GetLastError());
615 CloseHandle(dst
->pipe
);
620 err
= GetLastError();
622 case ERROR_IO_PENDING
:
623 wpa_printf(MSG_DEBUG
, "CTRL: ConnectNamedPipe: connection in "
626 case ERROR_PIPE_CONNECTED
:
627 wpa_printf(MSG_DEBUG
, "CTRL: ConnectNamedPipe: already "
629 if (SetEvent(dst
->overlap
.hEvent
))
633 wpa_printf(MSG_DEBUG
, "CTRL: ConnectNamedPipe error: %d",
635 CloseHandle(dst
->pipe
);
640 dst
->next
= priv
->ctrl_dst
;
642 dst
->next
->prev
= dst
;
643 priv
->ctrl_dst
= dst
;
648 global_close_pipe(dst
);
653 static void global_close_pipe(struct wpa_global_dst
*dst
)
655 wpa_printf(MSG_DEBUG
, "CTRL: close pipe %p", dst
);
657 if (dst
->overlap
.hEvent
) {
658 eloop_unregister_event(dst
->overlap
.hEvent
,
659 sizeof(dst
->overlap
.hEvent
));
660 CloseHandle(dst
->overlap
.hEvent
);
663 if (dst
->pipe
!= INVALID_HANDLE_VALUE
) {
665 * Could use FlushFileBuffers() here to guarantee that all data
666 * gets delivered to the client, but that can block, so let's
667 * not do this for now.
668 * FlushFileBuffers(dst->pipe);
670 CloseHandle(dst
->pipe
);
674 dst
->prev
->next
= dst
->next
;
676 dst
->priv
->ctrl_dst
= dst
->next
;
678 dst
->next
->prev
= dst
->prev
;
680 os_free(dst
->rsp_buf
);
685 static VOID WINAPI
global_iface_write_completed(DWORD err
, DWORD bytes
,
686 LPOVERLAPPED overlap
)
688 struct wpa_global_dst
*dst
= (struct wpa_global_dst
*) overlap
;
689 wpa_printf(MSG_DEBUG
, "CTRL: Overlapped write completed: dst=%p "
690 "err=%d bytes=%d", dst
, (int) err
, (int) bytes
);
692 global_close_pipe(dst
);
696 os_free(dst
->rsp_buf
);
699 if (!ReadFileEx(dst
->pipe
, dst
->req_buf
, sizeof(dst
->req_buf
),
700 &dst
->overlap
, global_iface_read_completed
)) {
701 wpa_printf(MSG_DEBUG
, "CTRL: ReadFileEx failed: %d",
702 (int) GetLastError());
703 global_close_pipe(dst
);
704 /* FIX: if this was the pipe waiting for new global
705 * connections, at this point there are no open global pipes..
706 * Should try to open a new pipe.. */
709 wpa_printf(MSG_DEBUG
, "CTRL: Overlapped read started for %p", dst
);
713 static void wpa_supplicant_global_iface_rx(struct wpa_global_dst
*dst
,
716 struct wpa_global
*global
= dst
->priv
->global
;
717 char *reply
= NULL
, *send_buf
;
718 size_t reply_len
= 0, send_len
;
719 char *buf
= dst
->req_buf
;
722 if (len
>= REQUEST_BUFSIZE
)
723 len
= REQUEST_BUFSIZE
- 1;
726 reply
= wpa_supplicant_global_ctrl_iface_process(global
, buf
,
730 send_len
= reply_len
;
731 } else if (reply_len
) {
735 os_free(dst
->rsp_buf
);
740 os_free(dst
->rsp_buf
);
741 dst
->rsp_buf
= os_malloc(send_len
);
742 if (dst
->rsp_buf
== NULL
) {
743 global_close_pipe(dst
);
747 os_memcpy(dst
->rsp_buf
, send_buf
, send_len
);
750 if (!WriteFileEx(dst
->pipe
, dst
->rsp_buf
, send_len
, &dst
->overlap
,
751 global_iface_write_completed
)) {
752 wpa_printf(MSG_DEBUG
, "CTRL: WriteFileEx failed: %d",
753 (int) GetLastError());
754 global_close_pipe(dst
);
756 wpa_printf(MSG_DEBUG
, "CTRL: Overlapped write started for %p",
762 static VOID WINAPI
global_iface_read_completed(DWORD err
, DWORD bytes
,
763 LPOVERLAPPED overlap
)
765 struct wpa_global_dst
*dst
= (struct wpa_global_dst
*) overlap
;
766 wpa_printf(MSG_DEBUG
, "CTRL: Overlapped read completed: dst=%p err=%d "
767 "bytes=%d", dst
, (int) err
, (int) bytes
);
768 if (err
== 0 && bytes
> 0)
769 wpa_supplicant_global_iface_rx(dst
, bytes
);
773 static void wpa_supplicant_global_iface_receive(void *eloop_data
,
776 struct wpa_global_dst
*dst
= eloop_data
;
777 struct ctrl_iface_global_priv
*priv
= dst
->priv
;
780 wpa_printf(MSG_DEBUG
, "CTRL: wpa_supplicant_global_iface_receive");
781 ResetEvent(dst
->overlap
.hEvent
);
783 if (!GetOverlappedResult(dst
->pipe
, &dst
->overlap
, &bytes
, FALSE
)) {
784 wpa_printf(MSG_DEBUG
, "CTRL: GetOverlappedResult failed: %d",
785 (int) GetLastError());
788 wpa_printf(MSG_DEBUG
, "CTRL: GetOverlappedResult: New client "
791 /* Open a new named pipe for the next client. */
792 if (global_open_pipe(priv
) < 0) {
793 wpa_printf(MSG_DEBUG
, "CTRL: global_open_pipe failed");
797 /* Use write completion function to start reading a command */
798 global_iface_write_completed(0, 0, &dst
->overlap
);
800 global_flush_broken_pipes(priv
);
804 struct ctrl_iface_global_priv
*
805 wpa_supplicant_global_ctrl_iface_init(struct wpa_global
*global
)
807 struct ctrl_iface_global_priv
*priv
;
809 priv
= os_zalloc(sizeof(*priv
));
812 priv
->global
= global
;
814 if (global_open_pipe(priv
) < 0) {
824 wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv
*priv
)
826 while (priv
->ctrl_dst
)
827 global_close_pipe(priv
->ctrl_dst
);