Change hostapd configuration file path
[platform/core/connectivity/wifi-mesh-manager.git] / src / mesh-softap.c
1 /*
2  * Network Configuration Module
3  *
4  * Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19 #include <glib.h>
20 #include <tzplatform_config.h>
21 #include <openssl/evp.h>
22 #include <openssl/sha.h>
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <netinet/in.h>
31 #include <sys/socket.h>
32 #include <sys/un.h>
33 #include <sys/wait.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36
37 #include "mesh.h"
38 #include "mesh-log.h"
39 #include "mesh-util.h"
40 #include "mesh-service.h"
41 #include "mesh-softap.h"
42
43 #define MOBILE_AP_WIFI_KEY_MAX_LEN      64      /**< Maximum length of wifi hash key */
44
45 #define HOSTAPD_VENDOR_ELEMENTS_WIFI_AP "DD050016321000"        /* Specific application mode AP (e.g. GroupPlay) */
46 #define HOSTAPD_CONF            "interface=%s\n" \
47                                 "driver=nl80211\n" \
48                                 "ctrl_interface=%s\n" \
49                                 "ssid=%s\n" \
50                                 "channel=%d\n" \
51                                 "ignore_broadcast_ssid=%d\n" \
52                                 "hw_mode=%s\n" \
53                                 "max_num_sta=%d\n" \
54                                 "macaddr_acl=%d\n" \
55                                 "accept_mac_file=%s\n" \
56                                 "deny_mac_file=%s\n" \
57                                 "ieee80211n=1\n"
58 #define HOSTAPD_CONF_LEN        1024
59 #define HOSTAPD_BIN             "/usr/sbin/hostapd"
60 #define HOSTAPD_DEBUG_FILE      "/var/log/mesh_hostapd.log"
61 #define HOSTAPD_ENTROPY_FILE    tzplatform_mkpath(TZ_SYS_VAR, "/lib/misc/hostapd.bin")
62 #define HOSTAPD_MESH_CONF_FILE  tzplatform_mkpath(TZ_SYS_VAR, "/lib/mesh/mesh_hostapd.conf")
63 #define HOSTAPD_CTRL_INTF_DIR   tzplatform_mkpath(TZ_SYS_RUN, "/hostapd")
64 #define HOSTAPD_ALLOWED_LIST    tzplatform_mkpath(TZ_SYS_VAR, "/lib/hostapd/hostapd.accept")
65 #define HOSTAPD_BLOCKED_LIST    tzplatform_mkpath(TZ_SYS_VAR, "/lib/hostapd/hostapd.deny")
66 #define HOSTAPD_RETRY_MAX       5
67 #define HOSTAPD_RETRY_DELAY     500000  /* us */
68
69 #define MH_CTRL_INTF            "/tmp/mesh_hostapd_wpa_ctrl"
70
71 #define PSK_ITERATION_COUNT     4096
72 #define MAX_BUF_SIZE            (256u)
73
74 static pid_t hostapd_pid = 0;
75 static int hostapd_ctrl_fd = 0;
76
77 static int __get_psk_hexascii(const char *pass, const unsigned char *salt,
78                 char *psk, unsigned int psk_len)
79 {
80         int i = 0;
81         int d_16 = 0;
82         int r_16 = 0;
83         unsigned char buf[SHA256_DIGEST_LENGTH] = {0, };
84
85         if (pass == NULL || salt == NULL || psk == NULL
86                         || psk_len < (SHA256_DIGEST_LENGTH * 2 + 1)) {
87                 MESH_LOGE("Invalid parameter");
88                 return MESHD_ERROR_INVALID_PARAMETER;
89         }
90
91         if (!PKCS5_PBKDF2_HMAC_SHA1(pass, strlen(pass),
92                                 salt, strlen((const char *)salt),
93                                 PSK_ITERATION_COUNT, sizeof(buf), buf)) {
94                 MESH_LOGE("Getting psk is failed");
95                 return MESHD_ERROR_OPERATION_FAILED;
96         }
97
98         for (i = 0; i < SHA256_DIGEST_LENGTH; i++) {
99                 d_16 = buf[i] >> 4;
100                 r_16 = buf[i] & 0xf;
101
102                 psk[i << 1] = d_16 < 10 ? d_16 + '0' : d_16 - 10 + 'a';
103                 psk[(i << 1) + 1] = r_16 < 10 ? r_16 + '0' : r_16 - 10 + 'a';
104         }
105         psk[i << 1] = '\0';
106
107         return MESHD_ERROR_NONE;
108 }
109
110 static int __config_hostapd(const char *softap_interface, const char *ssid,
111                 const char *security, const char *passphrase, const char* mode,
112                 int channel, int visibility, int mac_filter, int max_sta)
113 {
114         char *conf = NULL;
115         char *old_conf;
116         char buf[HOSTAPD_CONF_LEN] = "";
117         FILE *fp = NULL;
118         int ret;
119         char key[MOBILE_AP_WIFI_KEY_MAX_LEN + 1];
120         char *hw_mode = NULL;
121
122         if (mode == NULL)
123                 hw_mode = g_strdup("g");
124         else
125                 hw_mode = g_strdup(mode);
126
127         /* Default conf. */
128         snprintf(buf, sizeof(buf), HOSTAPD_CONF,
129                         softap_interface,
130                         HOSTAPD_CTRL_INTF_DIR,
131                         ssid,
132                         channel,
133                         (visibility ? 0 : 2),
134                         hw_mode,
135                         max_sta,
136                         mac_filter,
137                         HOSTAPD_ALLOWED_LIST,
138                         HOSTAPD_BLOCKED_LIST);
139         conf = g_strdup(buf);
140
141         free(hw_mode);
142
143         /* Vendor elements conf. */
144         snprintf(buf, sizeof(buf),
145                         "vendor_elements=%s\n", HOSTAPD_VENDOR_ELEMENTS_WIFI_AP);
146         old_conf = conf;
147         conf = g_strconcat(old_conf, buf, NULL);
148         g_free(old_conf);
149
150         /* Security conf. */
151         if (security != NULL && g_strcmp0(security, "wpa2-psk") == 0) {
152                 ret = __get_psk_hexascii(passphrase,
153                                 (const unsigned char *)ssid, key, sizeof(key));
154                 if (ret != MESHD_ERROR_NONE) {
155                         g_free(conf);
156                         MESH_LOGE("hex conversion failed");
157                         return MESHD_ERROR_OPERATION_FAILED;
158                 }
159                 snprintf(buf, sizeof(buf),
160                                 "wpa=2\nrsn_pairwise=CCMP\nwpa_psk=%s\n", key);
161
162                 old_conf = conf;
163                 conf = g_strconcat(old_conf, buf, NULL);
164                 g_free(old_conf);
165         } else {
166                 MESH_LOGD("Open connection [%s]", security);
167         }
168
169         fp = fopen(HOSTAPD_MESH_CONF_FILE, "w");
170         if (NULL == fp) {
171                 MESH_LOGE("Could not create the file.");
172                 g_free(conf);
173                 return MESHD_ERROR_IO_ERROR;
174         }
175
176         if (conf) {
177                 fputs(conf, fp);
178                 g_free(conf);
179         }
180         fclose(fp);
181
182         return MESHD_ERROR_NONE;
183 }
184
185 static int __open_hostapd_intf(const char* softap_interface, int *fd,
186                 const char *intf)
187 {
188         int retry = 0;
189         char ctrl_intf[255] = {0, };
190         struct sockaddr_un src;
191         struct sockaddr_un dest;
192         struct stat stat_buf;
193
194         if (fd == NULL || intf == NULL) {
195                 MESH_LOGE("fd is NULL");
196                 return MESHD_ERROR_INVALID_PARAMETER;
197         }
198
199         *fd = socket(PF_UNIX, SOCK_DGRAM, 0);
200         if (*fd < 0) {
201                 MESH_LOGE("socket is failed");
202                 return MESHD_ERROR_OPERATION_FAILED;
203         }
204
205         src.sun_family = AF_UNIX;
206         g_strlcpy(src.sun_path, intf, sizeof(src.sun_path));
207
208         if (stat(src.sun_path, &stat_buf) == 0)
209                 unlink(src.sun_path);
210
211         if (bind(*fd, (struct sockaddr *)&src, sizeof(src)) < 0) {
212                 MESH_LOGE("bind is failed");
213                 close(*fd);
214                 *fd = -1;
215                 unlink(src.sun_path);
216                 return MESHD_ERROR_OPERATION_FAILED;
217         }
218
219         snprintf(ctrl_intf, sizeof(ctrl_intf), "%s/%s",
220                         HOSTAPD_CTRL_INTF_DIR, softap_interface);
221         dest.sun_family = AF_UNIX;
222         g_strlcpy(dest.sun_path, ctrl_intf, sizeof(dest.sun_path));
223
224         while (connect(*fd, (struct sockaddr *)&dest, sizeof(dest)) < 0) {
225                 if (++retry >= HOSTAPD_RETRY_MAX)
226                         goto FAIL;
227                 usleep(HOSTAPD_RETRY_DELAY);
228         }
229         MESH_LOGD("Successfully open interface[%s] to hostapd", intf);
230
231         return MESHD_ERROR_NONE;
232
233 FAIL:
234         MESH_LOGE("Cannot make connection to hostapd");
235         close(*fd);
236         *fd = -1;
237         unlink(src.sun_path);
238
239         return MESHD_ERROR_OPERATION_FAILED;
240 }
241
242 static int __close_hostapd_intf(int *fd)
243 {
244         if (fd == NULL) {
245                 MESH_LOGE("fd is NULL");
246                 return MESHD_ERROR_INVALID_PARAMETER;
247         }
248
249         if (*fd > 0)
250                 close(*fd);
251         *fd = -1;
252
253         return MESHD_ERROR_NONE;
254 }
255
256 static int __terminate_hostapd()
257 {
258         int ret;
259
260         if (hostapd_pid == 0) {
261                 MESH_LOGE("There is no hostapd");
262                 return MESHD_ERROR_NONE;
263         }
264
265         ret = __close_hostapd_intf(&hostapd_ctrl_fd);
266         if (ret != MESHD_ERROR_NONE) {
267                 MESH_LOGE("__close_hostapd_intf is failed");
268         }
269
270         kill(hostapd_pid, SIGTERM);
271         waitpid(hostapd_pid, NULL, 0);
272         hostapd_pid = 0;
273
274         return MESHD_ERROR_NONE;
275 }
276
277 static int __execute_hostapd()
278 {
279         pid_t pid;
280
281         if (hostapd_pid) {
282                 MESH_LOGE("hostapd is running already");
283                 return MESHD_ERROR_OPERATION_FAILED;
284         }
285
286         pid = fork();
287         if (pid < 0) {
288                 MESH_LOGE("fork failed");
289                 return MESHD_ERROR_IO_ERROR;
290         }
291
292         if (pid == 0) {
293                 if (execl(HOSTAPD_BIN, HOSTAPD_BIN, "-e", HOSTAPD_ENTROPY_FILE,
294                                         HOSTAPD_MESH_CONF_FILE,
295                                         "-f", HOSTAPD_DEBUG_FILE, "-ddd",
296                                         (char *)NULL)) {
297                         MESH_LOGE("execl failed");
298                 }
299
300                 MESH_LOGE("Should not get here!");
301                 exit(1);
302         }
303
304         hostapd_pid = pid;
305
306         return MESHD_ERROR_NONE;
307 }
308
309 int mesh_softap_set_configuration(const char* softap_interface,
310                 const char *ssid, const char* mode, int channel, int visibility,
311                 int max_sta, int security, const char* passphrase)
312 {
313         int ret = MESHD_ERROR_NONE;
314         const char *sec = (security == 0) ? NULL : "wpa2-psk";
315         int mac_filter = 0;
316
317         ret = __config_hostapd(softap_interface, ssid, sec, passphrase,
318                         mode, channel, visibility, mac_filter, max_sta);
319
320         return ret;
321 }
322
323 int mesh_softap_enable_softap(const char* softap_interface)
324 {
325         int ret = MESHD_ERROR_NONE;
326
327         if (NULL == softap_interface) {
328                 MESH_LOGE("Invalid parameter");
329                 return MESHD_ERROR_INVALID_PARAMETER;
330         }
331
332         ret = __execute_hostapd();
333         if (ret != MESHD_ERROR_NONE) {
334                 MESH_LOGE("__execute_hostapd is failed");
335                 return MESHD_ERROR_OPERATION_FAILED;
336         }
337
338         ret = __open_hostapd_intf(softap_interface,
339                         &hostapd_ctrl_fd, MH_CTRL_INTF);
340         if (ret != MESHD_ERROR_NONE) {
341                 MESH_LOGE("__open_hostapd_intf is failed");
342                 __terminate_hostapd();
343         }
344
345         return ret;
346 }
347
348 int mesh_softap_disable_softap()
349 {
350         int ret = MESHD_ERROR_NONE;
351
352         ret = __terminate_hostapd();
353         if (ret != MESHD_ERROR_NONE) {
354                 MESH_LOGE("__execute_hostapd is failed");
355                 return MESHD_ERROR_OPERATION_FAILED;
356         }
357
358         return ret;     
359 }