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>
38 #include "wmesh-log.h"
39 #include "wmesh-util.h"
40 #include "wmesh-service.h"
41 #include "wmesh-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/wmesh/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;
76 static char *g_passphrase = NULL;
78 static int __get_psk_hexascii(const char *pass, const unsigned char *salt,
79 char *psk, unsigned int psk_len)
84 unsigned char buf[SHA256_DIGEST_LENGTH] = {0, };
86 if (pass == NULL || salt == NULL || psk == NULL
87 || psk_len < (SHA256_DIGEST_LENGTH * 2 + 1)) {
88 WMESH_LOGE("Invalid parameter");
89 return WMESHD_ERROR_INVALID_PARAMETER;
92 if (!PKCS5_PBKDF2_HMAC_SHA1(pass, strlen(pass),
93 salt, strlen((const char *)salt),
94 PSK_ITERATION_COUNT, sizeof(buf), buf)) {
95 WMESH_LOGE("Getting psk is failed");
96 return WMESHD_ERROR_OPERATION_FAILED;
99 for (i = 0; i < SHA256_DIGEST_LENGTH; i++) {
103 psk[i << 1] = d_16 < 10 ? d_16 + '0' : d_16 - 10 + 'a';
104 psk[(i << 1) + 1] = r_16 < 10 ? r_16 + '0' : r_16 - 10 + 'a';
108 return WMESHD_ERROR_NONE;
111 static int __config_hostapd(const char *softap_interface, const char *ssid,
112 const char *security, const char *passphrase, const char* mode,
113 int channel, int visibility, int mac_filter, int max_sta)
117 char buf[HOSTAPD_CONF_LEN] = "";
120 char key[MOBILE_AP_WIFI_KEY_MAX_LEN + 1];
121 char *hw_mode = NULL;
124 hw_mode = g_strdup("g");
126 hw_mode = g_strdup(mode);
129 snprintf(buf, sizeof(buf), HOSTAPD_CONF,
131 HOSTAPD_CTRL_INTF_DIR,
134 (visibility ? 0 : 2),
138 HOSTAPD_ALLOWED_LIST,
139 HOSTAPD_BLOCKED_LIST);
140 conf = g_strdup(buf);
144 /* Vendor elements conf. */
145 snprintf(buf, sizeof(buf),
146 "vendor_elements=%s\n", HOSTAPD_VENDOR_ELEMENTS_WIFI_AP);
148 conf = g_strconcat(old_conf, buf, NULL);
152 if (security != NULL && g_strcmp0(security, "wpa2-psk") == 0) {
153 ret = __get_psk_hexascii(passphrase,
154 (const unsigned char *)ssid, key, sizeof(key));
155 if (ret != WMESHD_ERROR_NONE) {
157 WMESH_LOGE("hex conversion failed");
158 return WMESHD_ERROR_OPERATION_FAILED;
160 snprintf(buf, sizeof(buf),
161 "wpa=2\nrsn_pairwise=CCMP\nwpa_psk=%s\n", key);
164 conf = g_strconcat(old_conf, buf, NULL);
167 WMESH_LOGD("Open connection [%s]", security);
170 fp = fopen(HOSTAPD_MESH_CONF_FILE, "w");
172 WMESH_LOGE("Could not create the file [%s].", HOSTAPD_MESH_CONF_FILE);
174 return WMESHD_ERROR_IO_ERROR;
183 return WMESHD_ERROR_NONE;
186 static int __read_hostapd_config(char **softap_interface, char **ssid,
187 char **mode, int *channel, int *visibility, int *max_sta, int *security,
193 fp = fopen(HOSTAPD_MESH_CONF_FILE, "r");
195 WMESH_LOGE("Failed to read file");
196 return WMESHD_ERROR_IO_ERROR;
199 if (!softap_interface || !ssid || !security || !passphrase || !mode ||
200 !channel || !visibility || !max_sta)
201 return WMESHD_ERROR_INVALID_PARAMETER;
205 while (NULL != fgets(buf, sizeof(buf), fp)) {
206 if (strncmp(buf, "interface", strlen("interface")) == 0) {
207 *softap_interface = g_strdup(strrchr(buf, '=') + 1);
208 WMESH_LOGD("Interface: %s", *softap_interface);
209 } else if (strncmp(buf, "ssid", strlen("ssid")) == 0) {
210 *ssid = g_strdup(strrchr(buf, '=') + 1);
211 WMESH_LOGD("SSID: %s", *ssid);
212 } else if (strncmp(buf, "hw_mode", strlen("hw_mode")) == 0) {
213 *mode = g_strdup(strrchr(buf, '=') + 1);
214 WMESH_LOGD("Mode: %s", *mode);
215 } else if (strncmp(buf, "channel", strlen("channel")) == 0) {
216 *channel = atoi(strrchr(buf, '=') + 1);
217 WMESH_LOGD("Channel: %d", *channel);
218 } else if (strncmp(buf, "ignore_broadcast_ssid",
219 strlen("ignore_broadcast_ssid")) == 0) {
220 *visibility = atoi(strrchr(buf, '=') + 1) == 0 ? 1 : 0;
221 WMESH_LOGD("Visibility: %d", *visibility);
222 } else if (strncmp(buf, "max_num_sta", strlen("max_num_sta")) == 0) {
223 *max_sta = atoi(strrchr(buf, '=') + 1);
224 WMESH_LOGD("Max Station: %d", *max_sta);
225 } else if (strncmp(buf, "wpa=", strlen("wpa=")) == 0) {
227 *passphrase = g_strdup(g_passphrase);
228 WMESH_LOGD("Security: %d", *security);
229 WMESH_LOGD("Passphrase: %s", *passphrase);
233 return WMESHD_ERROR_NONE;
236 static int __open_hostapd_intf(const char* softap_interface, int *fd,
240 char ctrl_intf[255] = {0, };
241 struct sockaddr_un src;
242 struct sockaddr_un dest;
243 struct stat stat_buf;
245 if (fd == NULL || intf == NULL) {
246 WMESH_LOGE("fd is NULL");
247 return WMESHD_ERROR_INVALID_PARAMETER;
250 *fd = socket(PF_UNIX, SOCK_DGRAM, 0);
252 WMESH_LOGE("socket is failed");
253 return WMESHD_ERROR_OPERATION_FAILED;
256 src.sun_family = AF_UNIX;
257 g_strlcpy(src.sun_path, intf, sizeof(src.sun_path));
259 if (stat(src.sun_path, &stat_buf) == 0)
260 unlink(src.sun_path);
262 if (bind(*fd, (struct sockaddr *)&src, sizeof(src)) < 0) {
263 WMESH_LOGE("bind is failed");
266 unlink(src.sun_path);
267 return WMESHD_ERROR_OPERATION_FAILED;
270 snprintf(ctrl_intf, sizeof(ctrl_intf), "%s/%s",
271 HOSTAPD_CTRL_INTF_DIR, softap_interface);
272 dest.sun_family = AF_UNIX;
273 g_strlcpy(dest.sun_path, ctrl_intf, sizeof(dest.sun_path));
275 while (connect(*fd, (struct sockaddr *)&dest, sizeof(dest)) < 0) {
276 if (++retry >= HOSTAPD_RETRY_MAX)
278 usleep(HOSTAPD_RETRY_DELAY);
280 WMESH_LOGD("Successfully open interface[%s] to hostapd", intf);
282 return WMESHD_ERROR_NONE;
285 WMESH_LOGE("Cannot make connection to hostapd");
288 unlink(src.sun_path);
290 return WMESHD_ERROR_OPERATION_FAILED;
293 static int __close_hostapd_intf(int *fd)
296 WMESH_LOGE("fd is NULL");
297 return WMESHD_ERROR_INVALID_PARAMETER;
304 return WMESHD_ERROR_NONE;
307 static int __get_pid_of_hostapd(pid_t *pid)
312 char error_buf[256] = {0, };
313 char file_path[256] = {0, };
315 snprintf(file_path, 256, "%s", HOSTAPD_PID_FILE);
317 if (0 == access(file_path, F_OK)) {
318 fd = fopen(file_path, "r");
320 WMESH_LOGE("Error! Could not open pid file");
321 return WMESHD_ERROR_IO_ERROR;
324 WMESH_LOGE("Error! Could not access pid file");
325 return WMESHD_ERROR_IO_ERROR;
329 rv = fscanf(fd, "%d", &ret);
331 strerror_r(errno, error_buf, 256);
332 WMESH_LOGE("Error! Failed to read from file, rv:[%d], error:[%s]",
335 return WMESHD_ERROR_IO_ERROR;
339 WMESH_LOGD(" PID: [%d]", ret);
342 return WMESHD_ERROR_NONE;
345 static int __terminate_hostapd()
348 pid_t hostapd_pid = 0;
351 ret = __get_pid_of_hostapd(&hostapd_pid);
352 if (WMESHD_ERROR_NONE != ret) {
353 WMESH_LOGE("There is no hostapd");
354 return WMESHD_ERROR_NONE;
357 if (hostapd_pid == 0) {
358 WMESH_LOGE("There is no hostapd");
359 return WMESHD_ERROR_NONE;
362 ret = __close_hostapd_intf(&hostapd_ctrl_fd);
363 if (ret != WMESHD_ERROR_NONE)
364 WMESH_LOGE("__close_hostapd_intf is failed");
366 kill(hostapd_pid, SIGTERM);
368 return WMESHD_ERROR_NONE;
371 static int __execute_hostapd()
375 int ret = WMESHD_ERROR_NONE;
377 ret = __get_pid_of_hostapd(&pid);
379 WMESH_LOGE("hostapd is running already");
380 return WMESHD_ERROR_NONE;
385 WMESH_LOGE("fork failed");
386 return WMESHD_ERROR_IO_ERROR;
390 if (execl(HOSTAPD_BIN, HOSTAPD_BIN, "-e", HOSTAPD_ENTROPY_FILE,
391 HOSTAPD_MESH_CONF_FILE,
392 "-f", HOSTAPD_DEBUG_FILE,
393 "-P", HOSTAPD_PID_FILE,
396 WMESH_LOGE("execl failed");
399 WMESH_LOGE("Should not get here!");
403 waitpid(pid, &status, 0);
404 WMESH_LOGD(" child [%d] reaped with status(%d)", pid, status);
407 return WMESHD_ERROR_NONE;
410 int wmesh_softap_set_configuration(const char* softap_interface,
411 const char *ssid, const char* mode, int channel, int visibility,
412 int max_sta, int security, const char* passphrase)
414 int ret = WMESHD_ERROR_NONE;
415 const char *sec = (security == 0) ? NULL : "wpa2-psk";
418 ret = __config_hostapd(softap_interface, ssid, sec, passphrase,
419 mode, channel, visibility, mac_filter, max_sta);
421 if (ret == WMESHD_ERROR_NONE) {
422 g_free(g_passphrase);
423 g_passphrase = g_strdup(passphrase);
429 int wmesh_softap_get_configuration(char **softap_interface, char **ssid,
430 char **mode, int *channel, int *visibility,
431 int *max_sta, int *security, char **passphrase)
433 int ret = WMESHD_ERROR_NONE;
435 ret = __read_hostapd_config(softap_interface, ssid, mode, channel,
436 visibility, max_sta, security, passphrase);
441 int wmesh_softap_enable_softap(const char* softap_interface)
443 int ret = WMESHD_ERROR_NONE;
445 if (NULL == softap_interface) {
446 WMESH_LOGE("Invalid parameter");
447 return WMESHD_ERROR_INVALID_PARAMETER;
450 ret = __execute_hostapd();
451 if (ret != WMESHD_ERROR_NONE) {
452 WMESH_LOGE("__execute_hostapd is failed");
453 return WMESHD_ERROR_OPERATION_FAILED;
456 ret = __open_hostapd_intf(softap_interface,
457 &hostapd_ctrl_fd, MH_CTRL_INTF);
458 if (ret != WMESHD_ERROR_NONE) {
459 WMESH_LOGE("__open_hostapd_intf is failed");
460 __terminate_hostapd();
466 int wmesh_softap_disable_softap()
468 int ret = WMESHD_ERROR_NONE;
470 ret = __terminate_hostapd();
471 if (ret != WMESHD_ERROR_NONE) {
472 WMESH_LOGE("__execute_hostapd is failed");
473 return WMESHD_ERROR_OPERATION_FAILED;