2 * Network Configuration Module
4 * Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved.
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 #include <tzplatform_config.h>
21 #include <openssl/evp.h>
22 #include <openssl/sha.h>
30 #include <netinet/in.h>
31 #include <sys/socket.h>
34 #include <sys/types.h>
39 #include "mesh-util.h"
40 #include "mesh-service.h"
41 #include "mesh-softap.h"
43 #define MOBILE_AP_WIFI_KEY_MAX_LEN 64 /**< Maximum length of wifi hash key */
45 #define HOSTAPD_VENDOR_ELEMENTS_WIFI_AP "DD050016321000" /* Specific application mode AP (e.g. GroupPlay) */
46 #define HOSTAPD_CONF "interface=%s\n" \
48 "ctrl_interface=%s\n" \
51 "ignore_broadcast_ssid=%d\n" \
55 "accept_mac_file=%s\n" \
56 "deny_mac_file=%s\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_PID_FILE tzplatform_mkpath(TZ_SYS_RUN, "/.mesh_hostapd.pid")
65 #define HOSTAPD_ALLOWED_LIST tzplatform_mkpath(TZ_SYS_VAR, "/lib/hostapd/hostapd.accept")
66 #define HOSTAPD_BLOCKED_LIST tzplatform_mkpath(TZ_SYS_VAR, "/lib/hostapd/hostapd.deny")
67 #define HOSTAPD_RETRY_MAX 5
68 #define HOSTAPD_RETRY_DELAY 500000 /* us */
70 #define MH_CTRL_INTF "/tmp/mesh_hostapd_wpa_ctrl"
72 #define PSK_ITERATION_COUNT 4096
73 #define MAX_BUF_SIZE (256u)
75 static int hostapd_ctrl_fd = 0;
77 static int __get_psk_hexascii(const char *pass, const unsigned char *salt,
78 char *psk, unsigned int psk_len)
83 unsigned char buf[SHA256_DIGEST_LENGTH] = {0, };
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;
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;
98 for (i = 0; i < SHA256_DIGEST_LENGTH; i++) {
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';
107 return MESHD_ERROR_NONE;
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)
116 char buf[HOSTAPD_CONF_LEN] = "";
119 char key[MOBILE_AP_WIFI_KEY_MAX_LEN + 1];
120 char *hw_mode = NULL;
123 hw_mode = g_strdup("g");
125 hw_mode = g_strdup(mode);
128 snprintf(buf, sizeof(buf), HOSTAPD_CONF,
130 HOSTAPD_CTRL_INTF_DIR,
133 (visibility ? 0 : 2),
137 HOSTAPD_ALLOWED_LIST,
138 HOSTAPD_BLOCKED_LIST);
139 conf = g_strdup(buf);
143 /* Vendor elements conf. */
144 snprintf(buf, sizeof(buf),
145 "vendor_elements=%s\n", HOSTAPD_VENDOR_ELEMENTS_WIFI_AP);
147 conf = g_strconcat(old_conf, buf, NULL);
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) {
156 MESH_LOGE("hex conversion failed");
157 return MESHD_ERROR_OPERATION_FAILED;
159 snprintf(buf, sizeof(buf),
160 "wpa=2\nrsn_pairwise=CCMP\nwpa_psk=%s\n", key);
163 conf = g_strconcat(old_conf, buf, NULL);
166 MESH_LOGD("Open connection [%s]", security);
169 fp = fopen(HOSTAPD_MESH_CONF_FILE, "w");
171 MESH_LOGE("Could not create the file.");
173 return MESHD_ERROR_IO_ERROR;
182 return MESHD_ERROR_NONE;
185 static int __open_hostapd_intf(const char* softap_interface, int *fd,
189 char ctrl_intf[255] = {0, };
190 struct sockaddr_un src;
191 struct sockaddr_un dest;
192 struct stat stat_buf;
194 if (fd == NULL || intf == NULL) {
195 MESH_LOGE("fd is NULL");
196 return MESHD_ERROR_INVALID_PARAMETER;
199 *fd = socket(PF_UNIX, SOCK_DGRAM, 0);
201 MESH_LOGE("socket is failed");
202 return MESHD_ERROR_OPERATION_FAILED;
205 src.sun_family = AF_UNIX;
206 g_strlcpy(src.sun_path, intf, sizeof(src.sun_path));
208 if (stat(src.sun_path, &stat_buf) == 0)
209 unlink(src.sun_path);
211 if (bind(*fd, (struct sockaddr *)&src, sizeof(src)) < 0) {
212 MESH_LOGE("bind is failed");
215 unlink(src.sun_path);
216 return MESHD_ERROR_OPERATION_FAILED;
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));
224 while (connect(*fd, (struct sockaddr *)&dest, sizeof(dest)) < 0) {
225 if (++retry >= HOSTAPD_RETRY_MAX)
227 usleep(HOSTAPD_RETRY_DELAY);
229 MESH_LOGD("Successfully open interface[%s] to hostapd", intf);
231 return MESHD_ERROR_NONE;
234 MESH_LOGE("Cannot make connection to hostapd");
237 unlink(src.sun_path);
239 return MESHD_ERROR_OPERATION_FAILED;
242 static int __close_hostapd_intf(int *fd)
245 MESH_LOGE("fd is NULL");
246 return MESHD_ERROR_INVALID_PARAMETER;
253 return MESHD_ERROR_NONE;
256 static int __get_pid_of_hostapd(pid_t *pid)
261 char error_buf[256] = {0, };
262 char file_path[256] = {0, };
264 snprintf(file_path, 256, "%s", HOSTAPD_PID_FILE);
266 if (0 == access(file_path, F_OK)) {
267 fd = fopen(file_path, "r");
269 MESH_LOGE("Error! Could not open pid file");
270 return MESHD_ERROR_IO_ERROR;
273 MESH_LOGE("Error! Could not access pid file");
274 return MESHD_ERROR_IO_ERROR;
278 rv = fscanf(fd, "%d", &ret);
280 strerror_r(errno, error_buf, 256);
281 MESH_LOGE("Error! Failed to read from file, rv:[%d], error:[%s]",
284 return MESHD_ERROR_IO_ERROR;
288 MESH_LOGD(" PID: [%d]", ret);
291 return MESHD_ERROR_NONE;
294 static int __terminate_hostapd()
297 pid_t hostapd_pid = 0;
300 ret = __get_pid_of_hostapd(&hostapd_pid);
301 if (MESHD_ERROR_NONE != ret) {
302 MESH_LOGE("There is no hostapd");
303 return MESHD_ERROR_NONE;
306 if (hostapd_pid == 0) {
307 MESH_LOGE("There is no hostapd");
308 return MESHD_ERROR_NONE;
311 ret = __close_hostapd_intf(&hostapd_ctrl_fd);
312 if (ret != MESHD_ERROR_NONE)
313 MESH_LOGE("__close_hostapd_intf is failed");
315 kill(hostapd_pid, SIGTERM);
317 return MESHD_ERROR_NONE;
320 static int __execute_hostapd()
324 int ret = MESHD_ERROR_NONE;
326 ret = __get_pid_of_hostapd(&pid);
328 MESH_LOGE("hostapd is running already");
329 return MESHD_ERROR_NONE;
334 MESH_LOGE("fork failed");
335 return MESHD_ERROR_IO_ERROR;
339 if (execl(HOSTAPD_BIN, HOSTAPD_BIN, "-e", HOSTAPD_ENTROPY_FILE,
340 HOSTAPD_MESH_CONF_FILE,
341 "-f", HOSTAPD_DEBUG_FILE,
342 "-P", HOSTAPD_PID_FILE,
345 MESH_LOGE("execl failed");
348 MESH_LOGE("Should not get here!");
352 waitpid(pid, &status, 0);
353 MESH_LOGD(" child [%d] reaped with status(%d)", pid, status);
356 return MESHD_ERROR_NONE;
359 int mesh_softap_set_configuration(const char* softap_interface,
360 const char *ssid, const char* mode, int channel, int visibility,
361 int max_sta, int security, const char* passphrase)
363 int ret = MESHD_ERROR_NONE;
364 const char *sec = (security == 0) ? NULL : "wpa2-psk";
367 ret = __config_hostapd(softap_interface, ssid, sec, passphrase,
368 mode, channel, visibility, mac_filter, max_sta);
373 int mesh_softap_enable_softap(const char* softap_interface)
375 int ret = MESHD_ERROR_NONE;
377 if (NULL == softap_interface) {
378 MESH_LOGE("Invalid parameter");
379 return MESHD_ERROR_INVALID_PARAMETER;
382 ret = __execute_hostapd();
383 if (ret != MESHD_ERROR_NONE) {
384 MESH_LOGE("__execute_hostapd is failed");
385 return MESHD_ERROR_OPERATION_FAILED;
388 ret = __open_hostapd_intf(softap_interface,
389 &hostapd_ctrl_fd, MH_CTRL_INTF);
390 if (ret != MESHD_ERROR_NONE) {
391 MESH_LOGE("__open_hostapd_intf is failed");
392 __terminate_hostapd();
398 int mesh_softap_disable_softap()
400 int ret = MESHD_ERROR_NONE;
402 ret = __terminate_hostapd();
403 if (ret != MESHD_ERROR_NONE) {
404 MESH_LOGE("__execute_hostapd is failed");
405 return MESHD_ERROR_OPERATION_FAILED;