1 /*
2 * Copyright (c) 2019 The Linux Foundation. All rights reserved.
3 *
4 * wpa_supplicant/hostapd control interface library
5 * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
6 *
7 * This software may be distributed under the terms of the BSD license.
8 * redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name(s) of the above-listed copyright holder(s) nor the
20 * names of its contributors may be used to endorse or promote products
21 * derived from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 #include "wifi_hal_ctrl.h"
37
wifihal_ctrl_open2(const char * ctrl_path,const char * cli_path)38 struct wifihal_ctrl * wifihal_ctrl_open2(const char *ctrl_path,
39 const char *cli_path)
40 {
41 struct wifihal_ctrl *ctrl;
42 static int counter = 0;
43 int retval;
44 size_t res;
45 int tries = 0;
46 int flags;
47 #ifdef ANDROID
48 struct group *grp_wifi;
49 gid_t gid_wifi;
50 struct passwd *pwd_system;
51 uid_t uid_system;
52 #endif
53
54 if (ctrl_path == NULL)
55 return NULL;
56
57 ctrl = malloc(sizeof(*ctrl));
58 if (ctrl == NULL) {
59 return NULL;
60 }
61
62 memset(ctrl, 0, sizeof(*ctrl));
63 ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);
64 if (ctrl->s < 0) {
65 free(ctrl);
66 return NULL;
67 }
68
69 ctrl->local.sun_family = AF_UNIX;
70
71 try_again:
72 if (cli_path && cli_path[0] == '/') {
73 res = strlcpy(ctrl->local.sun_path, cli_path,
74 sizeof(ctrl->local.sun_path));
75
76 if (res >= sizeof(ctrl->local.sun_path)) {
77 close(ctrl->s);
78 free(ctrl);
79 return NULL;
80 }
81
82 } else {
83 counter++;
84 retval = snprintf(ctrl->local.sun_path,
85 sizeof(ctrl->local.sun_path),
86 CONFIG_CTRL_IFACE_CLIENT_DIR "/"
87 CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d",
88 (int) getpid(), counter);
89 }
90 tries++;
91 if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
92 sizeof(ctrl->local)) < 0) {
93 if (errno == EADDRINUSE && tries < 2) {
94 /*
95 * getpid() returns unique identifier for this instance
96 * of wifihal_ctrl, so the existing socket file must have
97 * been left by unclean termination of an earlier run.
98 * Remove the file and try again.
99 */
100 unlink(ctrl->local.sun_path);
101 goto try_again;
102 }
103 close(ctrl->s);
104 free(ctrl);
105 return NULL;
106 }
107
108 #ifdef ANDROID
109 chmod(ctrl->local.sun_path, S_IRWXU | S_IRWXG );
110
111 /* Set group even if we do not have privileges to change owner */
112 grp_wifi = getgrnam("wifi");
113 gid_wifi = grp_wifi ? grp_wifi->gr_gid : 0;
114 pwd_system = getpwnam("system");
115 uid_system = pwd_system ? pwd_system->pw_uid : 0;
116 if (!gid_wifi || !uid_system) {
117 close(ctrl->s);
118 unlink(ctrl->local.sun_path);
119 free(ctrl);
120 return NULL;
121 }
122 chown(ctrl->local.sun_path, -1, gid_wifi);
123 chown(ctrl->local.sun_path, uid_system, gid_wifi);
124
125
126 if (*ctrl_path != '/') {
127 free(ctrl);
128 return NULL;
129 }
130 #endif /* ANDROID */
131
132 ctrl->dest.sun_family = AF_UNIX;
133 res = strlcpy(ctrl->dest.sun_path, ctrl_path,
134 sizeof(ctrl->dest.sun_path));
135 if (res >= sizeof(ctrl->dest.sun_path)) {
136 close(ctrl->s);
137 free(ctrl);
138 return NULL;
139 }
140 if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
141 sizeof(ctrl->dest)) < 0) {
142 close(ctrl->s);
143 unlink(ctrl->local.sun_path);
144 free(ctrl);
145 return NULL;
146 }
147 /*
148 * Make socket non-blocking so that we don't hang forever if
149 * target dies unexpectedly.
150 */
151 flags = fcntl(ctrl->s, F_GETFL);
152 if (flags >= 0) {
153 flags |= O_NONBLOCK;
154 if (fcntl(ctrl->s, F_SETFL, flags) < 0) {
155 perror("fcntl(ctrl->s, O_NONBLOCK)");
156 /* Not fatal, continue on.*/
157 }
158 }
159 return ctrl;
160 }
161
wifihal_ctrl_open(const char * ctrl_path)162 struct wifihal_ctrl * wifihal_ctrl_open(const char *ctrl_path)
163 {
164 return wifihal_ctrl_open2(ctrl_path, NULL);
165 }
166
wifihal_ctrl_close(struct wifihal_ctrl * ctrl)167 void wifihal_ctrl_close(struct wifihal_ctrl *ctrl)
168 {
169 if (ctrl == NULL)
170 return;
171 unlink(ctrl->local.sun_path);
172 if (ctrl->s >= 0)
173 close(ctrl->s);
174 free(ctrl);
175 }
176
wifihal_ctrl_request(struct wifihal_ctrl * ctrl,const char * cmd,size_t cmd_len,char * reply,size_t * reply_len)177 int wifihal_ctrl_request(struct wifihal_ctrl *ctrl, const char *cmd, size_t cmd_len,
178 char *reply, size_t *reply_len)
179 {
180 struct timeval tv;
181 int counter = 0, res;
182 fd_set rfds;
183 const char *_cmd;
184 size_t _cmd_len;
185 char *cmd_buf = NULL;
186
187 _cmd = cmd;
188 _cmd_len = cmd_len;
189
190 errno = 0;
191 retry_send:
192 if (sendto(ctrl->s, _cmd, _cmd_len, 0, (struct sockaddr *)&ctrl->dest, sizeof(ctrl->dest)) < 0) {
193 if (errno == EAGAIN || errno == EBUSY || errno == EWOULDBLOCK)
194 {
195 /*
196 * Must be a non-blocking socket... Try for a bit
197 * longer before giving up.
198 */
199 if(counter == 5) {
200 goto send_err;
201 } else {
202 counter++;
203 }
204 sleep(1);
205 goto retry_send;
206 }
207 send_err:
208 free(cmd_buf);
209 return -1;
210 }
211 free(cmd_buf);
212
213 for (;;) {
214 tv.tv_sec = 10;
215 tv.tv_usec = 0;
216 FD_ZERO(&rfds);
217 FD_SET(ctrl->s, &rfds);
218 res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
219 if (res < 0 && errno == EINTR)
220 continue;
221 if (res < 0)
222 return res;
223 if (FD_ISSET(ctrl->s, &rfds)) {
224 res = recv(ctrl->s, reply, *reply_len, 0);
225 if (res < 0)
226 return res;
227 *reply_len = res;
228 break;
229 } else {
230 return -2;
231 }
232 }
233 return 0;
234 }
235