3 * Copyright (c) 2012 Samsung Electronics Co., Ltd.
5 * Licensed under the Apache License, Version 2.0 (the License);
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
21 #include <sys/ioctl.h>
23 #include <glib-object.h>
24 #include <dbus/dbus-glib.h>
31 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
36 #include <linux/wireless.h>
37 #include <openssl/evp.h>
38 #include <openssl/sha.h>
40 #include "mobileap_common.h"
41 #include "mobileap_softap.h"
42 #include "mobileap_handler.h"
43 #include "mobileap_wifi.h"
44 #include "mobileap_iptables.h"
46 #define NETCONFIG_SERVICE "net.netconfig"
47 #define NETCONFIG_WIFI_INTERFACE "net.netconfig.wifi"
48 #define NETCONFIG_WIFI_PATH "/net/netconfig/wifi"
50 #define NETCONFIG_DBUS_REPLY_TIMEOUT (10 * 1000)
52 static pid_t dnsmasq_pid = 0;
53 static pid_t hostapd_pid = 0;
54 static int hostapd_ctrl_fd = 0;
55 static int hostapd_monitor_fd = 0;
56 static GIOChannel *hostapd_io_channel = NULL;
57 static guint hostapd_io_source = 0;
58 GSList *sta_timer_list = NULL;
60 static gboolean __hostapd_connect_timer_cb(gpointer user_data);
62 static char *__find_first_caps_char(char *str)
65 ERR("NULL string passes\n");
78 static int __issue_ioctl(int sock_fd, char *if_name, char *cmd, char *buf)
80 int ret_val = MOBILE_AP_ERROR_NONE;
83 memset(buf, 0, MAX_BUF_SIZE);
84 memset(&iwr, 0, sizeof(iwr));
86 /* Configure ioctl parameters */
87 g_strlcpy(iwr.ifr_name, if_name, IFNAMSIZ);
88 g_strlcpy(buf, cmd, MAX_BUF_SIZE);
89 iwr.u.data.pointer = buf;
90 iwr.u.data.length = MAX_BUF_SIZE;
95 if ((ioctl(sock_fd, SIOCSIWPRIV, &iwr)) < 0) {
96 ERR("ioctl failed...!!!\n");
97 ret_val = MOBILE_AP_ERROR_INTERNAL;
103 static int __get_psk_hexascii(const char *pass, const unsigned char *salt,
104 char *psk, unsigned int psk_len)
106 if (pass == NULL || salt == NULL || psk == NULL || psk_len <
107 (SHA256_DIGEST_LENGTH * 2 + 1)) {
108 ERR("Invalid parameter\n");
109 return MOBILE_AP_ERROR_INVALID_PARAM;
115 unsigned char buf[SHA256_DIGEST_LENGTH] = {0, };
117 if (!PKCS5_PBKDF2_HMAC_SHA1(pass, strlen(pass),
118 salt, strlen((const char *)salt),
119 PSK_ITERATION_COUNT, sizeof(buf), buf)) {
120 ERR("Getting psk is failed\n");
121 return MOBILE_AP_ERROR_RESOURCE;
124 for (i = 0; i < SHA256_DIGEST_LENGTH; i++) {
128 psk[i << 1] = d_16 < 10 ? d_16 + '0' : d_16 - 10 + 'a';
129 psk[(i << 1) + 1] = r_16 < 10 ? r_16 + '0' : r_16 - 10 + 'a';
133 return MOBILE_AP_ERROR_NONE;
136 static int __execute_hostapd(const mobile_ap_type_e type, const char *ssid,
137 const char *security, const char *passphrase, int hide_mode)
143 char buf[HOSTAPD_CONF_LEN] = "";
147 char key[MOBILE_AP_WIFI_KEY_MAX_LEN + 1];
149 snprintf(buf, sizeof(buf), HOSTAPD_CONF,
151 HOSTAPD_CTRL_INTF_DIR,
153 MOBILE_AP_WIFI_CHANNEL,
155 MOBILE_AP_MAX_WIFI_STA);
156 conf = g_strdup(buf);
158 /* Vendor elements conf. */
159 if (type == MOBILE_AP_TYPE_WIFI) {
160 snprintf(buf, sizeof(buf),
161 "vendor_elements=%s\n", HOSTAPD_VENDOR_ELEMENTS_TETH);
162 } else if (type == MOBILE_AP_TYPE_WIFI_AP) {
163 snprintf(buf, sizeof(buf),
164 "vendor_elements=%s\n", HOSTAPD_VENDOR_ELEMENTS_WIFI_AP);
166 ERR("Unknown type: %d\n", type);
168 return MOBILE_AP_ERROR_INVALID_PARAM;
171 conf = g_strconcat(old_conf, buf, NULL);
175 if (security != NULL && !strcmp(security, "wpa2-psk")) {
176 ret = __get_psk_hexascii(passphrase, (const unsigned char *)ssid, key, sizeof(key));
177 if (ret != MOBILE_AP_ERROR_NONE) {
179 ERR("hex conversion failed\n");
180 return MOBILE_AP_ERROR_RESOURCE;
182 snprintf(buf, sizeof(buf),
183 "wpa=2\nrsn_pairwise=CCMP\nwpa_psk=%s\n", key);
186 conf = g_strconcat(old_conf, buf, NULL);
190 fp = fopen(HOSTAPD_CONF_FILE, "w");
192 ERR("Could not create the file.\n");
194 return MOBILE_AP_ERROR_RESOURCE;
202 ERR("fork failed\n");
203 return MOBILE_AP_ERROR_RESOURCE;
207 if (execl(HOSTAPD_BIN, HOSTAPD_BIN, "-e", HOSTAPD_ENTROPY_FILE,
209 "-f", HOSTAPD_DEBUG_FILE, "-ddd",
211 ERR("execl failed\n");
214 ERR("Should not get here!");
215 return MOBILE_AP_ERROR_RESOURCE;
220 return MOBILE_AP_ERROR_NONE;
223 static int __terminate_hostapd()
229 if (hostapd_pid == 0) {
230 ERR("There is no hostapd\n");
231 return MOBILE_AP_ERROR_NONE;
234 kill(hostapd_pid, SIGTERM);
235 waitpid(hostapd_pid, NULL, 0);
238 ret = unlink(HOSTAPD_CONF_FILE);
240 ERR("unlink is failed : %s\n", strerror(errno));
243 return MOBILE_AP_ERROR_NONE;
247 * number NUM_STA(void)
248 * addr STA-FIRST(void)
249 * addr STA-NEXT(addr)
250 * void DISASSOCIATE(addr)
251 * void READ_WHITELIST(filename)
252 * void SET_MAXCLIENT(number)
254 static int __send_hostapd_req(int fd, const char *req, const int req_len,
255 char *buf, int *buf_len)
257 if (fd < 0 || req == NULL || req_len <= 0 ||
258 buf == NULL || buf_len == NULL || *buf_len <= 0) {
259 ERR("Invalid param\n");
260 return MOBILE_AP_ERROR_INVALID_PARAM;
263 struct timeval tv = {10, 0};
267 ret = send(fd, req, req_len, 0);
269 ERR("send is failed : %s\n", strerror(errno));
270 return MOBILE_AP_ERROR_INTERNAL;
276 ret = select(fd + 1, &fds, NULL, NULL, &tv);
278 return MOBILE_AP_ERROR_INTERNAL;
279 } else if (ret == 0) {
280 ERR("There is no response from hostapd\n");
281 return MOBILE_AP_ERROR_INTERNAL;
282 } else if (!FD_ISSET(fd, &fds)) {
283 ERR("Unknown case\n");
284 return MOBILE_AP_ERROR_INTERNAL;
287 ret = recv(fd, buf, (*buf_len) - 1, 0);
289 ERR("recv is failed\n");
290 return MOBILE_AP_ERROR_INTERNAL;
294 ERR("Unsolicited message\n");
301 ERR("socket is closed\n");
307 return MOBILE_AP_ERROR_NONE;
310 static int __open_hostapd_intf(int *fd, const char *intf)
312 if (fd == NULL || intf == NULL) {
314 return MOBILE_AP_ERROR_INVALID_PARAM;
320 char ctrl_intf[255] = {0, };
321 struct sockaddr_un src;
322 struct sockaddr_un dest;
323 struct stat stat_buf;
325 *fd = socket(PF_UNIX, SOCK_DGRAM, 0);
327 ERR("socket is failed\n");
328 return MOBILE_AP_ERROR_INTERNAL;
331 src.sun_family = AF_UNIX;
332 g_strlcpy(src.sun_path, intf, sizeof(src.sun_path));
334 if (stat(src.sun_path, &stat_buf) == 0) {
335 unlink(src.sun_path);
338 if (bind(*fd, (struct sockaddr *)&src, sizeof(src)) < 0) {
339 ERR("bind is failed\n");
342 unlink(src.sun_path);
343 return MOBILE_AP_ERROR_INTERNAL;
346 snprintf(ctrl_intf, sizeof(ctrl_intf), "%s/%s",
347 HOSTAPD_CTRL_INTF_DIR, WIFI_IF);
348 dest.sun_family = AF_UNIX;
349 g_strlcpy(dest.sun_path, ctrl_intf, sizeof(dest.sun_path));
351 while (connect(*fd, (struct sockaddr *)&dest, sizeof(dest)) < 0) {
352 if (++retry >= HOSTAPD_RETRY_MAX)
354 usleep(HOSTAPD_RETRY_DELAY);
357 return MOBILE_AP_ERROR_NONE;
360 ERR("Cannot make connection to hostapd\n");
363 unlink(src.sun_path);
365 return MOBILE_AP_ERROR_INTERNAL;
368 static int __close_hostapd_intf(int *fd)
374 return MOBILE_AP_ERROR_INVALID_PARAM;
381 return MOBILE_AP_ERROR_NONE;
384 static gboolean __hostapd_monitor_cb(GIOChannel *source)
389 char buf[HOSTAPD_REQ_MAX_LEN + 1] = {0, };
394 sta_timer_t *ptr = NULL;
397 gboolean discon_event = FALSE;
400 #if !GLIB_CHECK_VERSION(2, 31, 0)
403 ret = g_io_channel_read(hostapd_io_channel, buf,
404 HOSTAPD_REQ_MAX_LEN, &read);
405 if (ret != G_IO_ERROR_NONE) {
406 ERR("g_io_channel_read is failed\n");
413 ios = g_io_channel_read_chars(hostapd_io_channel, buf,
414 HOSTAPD_REQ_MAX_LEN, &read, &err);
416 ERR("g_io_channel_read_chars is failed : %s\n", err->message);
419 } else if (ios != G_IO_STATUS_NORMAL) {
420 ERR("g_io_channel_read_chars is failed : %d\n", ios);
426 pbuf = strrchr(buf, '\n');
430 SDBG("Read string from hostapd = [%s]\n", buf);
432 /* concatenated string, containing multiple events can arrive */
433 while (pbuf && *pbuf) {
434 pbuf = __find_first_caps_char(pbuf);
435 if (!pbuf || !*pbuf) {
439 if (!strncmp(pbuf, HOSTAPD_STA_CONN, HOSTAPD_STA_CONN_LEN)) {
440 pbuf = pbuf + HOSTAPD_STA_CONN_LEN;
441 if (!pbuf || !*pbuf) {
442 ERR("No mac address\n");
446 end = strchr(pbuf, '<');
448 mac = g_strndup(pbuf, (long)(end - pbuf));
451 mac = g_strdup(pbuf);
456 ERR("strdup failed\n");
460 for (l = sta_timer_list; l != NULL; l = g_slist_next(l)) {
461 ptr = (sta_timer_t *)l->data;
466 if (g_strcmp0(ptr->mac_addr, mac) == 0) {
473 /* Matched station found, so skip */
478 SDBG("%s%s\n", HOSTAPD_STA_CONN, mac);
479 ptr = (sta_timer_t *)g_malloc(sizeof(sta_timer_t));
481 ERR("g_malloc failed\n");
487 ptr->tid = g_timeout_add(HOSTAPD_DHCP_MAX_INTERVAL,
488 __hostapd_connect_timer_cb, mac);
489 sta_timer_list = g_slist_append(sta_timer_list, ptr);
491 } else if (!strncmp(pbuf, HOSTAPD_STA_DISCONN, HOSTAPD_STA_DISCONN_LEN)) {
492 pbuf = pbuf + HOSTAPD_STA_DISCONN_LEN;
493 if (!pbuf || !*pbuf) {
497 end = strchr(pbuf, '<');
499 mac = g_strndup(pbuf, (long)(end - pbuf));
502 mac = g_strdup(pbuf);
507 ERR("strdup failed\n");
511 SDBG("%s%s\n", HOSTAPD_STA_DISCONN, mac);
512 _remove_station_info(mac, _slist_find_station_by_mac);
515 * Destroy the timer if its not expired before disconnection
517 _destroy_dhcp_ack_timer(mac);
523 pbuf = strchr(pbuf, '>');
530 if (discon_event == FALSE)
533 if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI)) {
534 type = MOBILE_AP_TYPE_WIFI;
535 } else if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI_AP)) {
536 type = MOBILE_AP_TYPE_WIFI_AP;
541 _get_station_count((gconstpointer)type,
542 _slist_find_station_by_interface, &n_station);
544 if (n_station == 0) {
545 if (type == MOBILE_AP_TYPE_WIFI)
546 _start_timeout_cb(type, time(NULL) + TETHERING_CONN_TIMEOUT);
547 else if (type == MOBILE_AP_TYPE_WIFI_AP)
548 _start_timeout_cb(type, time(NULL) + WIFI_AP_CONN_TIMEOUT);
554 static int __open_hostapd_monitor(int *fd)
558 return MOBILE_AP_ERROR_INVALID_PARAM;
563 char buf[HOSTAPD_REQ_MAX_LEN] = {0, };
566 if (__open_hostapd_intf(fd, MH_MONITOR_INTF) != MOBILE_AP_ERROR_NONE) {
567 ERR("__open_hostapd_intf() is failed\n");
568 return MOBILE_AP_ERROR_INTERNAL;
571 hostapd_io_channel = g_io_channel_unix_new(*fd);
572 if (hostapd_io_channel == NULL) {
573 ERR("g_io_channel_unix_new is failed\n");
574 return MOBILE_AP_ERROR_INTERNAL;
577 g_io_channel_set_encoding(hostapd_io_channel, NULL, NULL);
578 g_io_channel_set_flags(hostapd_io_channel,
579 G_IO_FLAG_APPEND | G_IO_FLAG_NONBLOCK, NULL);
581 hostapd_io_source = g_io_add_watch(hostapd_io_channel, G_IO_IN,
582 (GIOFunc)__hostapd_monitor_cb, NULL);
584 buf_len = sizeof(buf);
585 __send_hostapd_req(*fd, HOSTAPD_MONITOR_ATTACH,
586 strlen(HOSTAPD_MONITOR_ATTACH), buf, &buf_len);
588 return MOBILE_AP_ERROR_NONE;
591 static int __close_hostapd_monitor(int *fd)
594 char buf[HOSTAPD_REQ_MAX_LEN] = {0, };
597 buf_len = sizeof(buf);
598 __send_hostapd_req(*fd, HOSTAPD_MONITOR_DETACH,
599 strlen(HOSTAPD_MONITOR_DETACH), buf, &buf_len);
601 if (hostapd_io_source != 0) {
602 g_source_remove(hostapd_io_source);
603 hostapd_io_source = 0;
606 if (hostapd_io_channel != NULL) {
607 g_io_channel_shutdown(hostapd_io_channel, TRUE, &err);
608 g_io_channel_unref(hostapd_io_channel);
609 hostapd_io_channel = NULL;
612 __close_hostapd_intf(fd);
614 return MOBILE_AP_ERROR_NONE;
617 static mobile_ap_drv_interface_e __get_drv_interface(void)
619 static mobile_ap_drv_interface_e drv_interface = MOBILE_AP_DRV_INTERFACE_NONE;
621 if (drv_interface != MOBILE_AP_DRV_INTERFACE_NONE) {
622 return drv_interface;
625 const char *drv_rfkill_path = "/sys/devices/platform";
626 const char *wext_drv[] = {
627 "bcm4329-b1", "bcm4330-b0",
628 "bcm4330-b1", "bcm4330-b2",
631 char path[MAX_BUF_SIZE] = { 0 };
632 struct stat stat_buf = { 0 };
636 drv_interface = MOBILE_AP_NL80211;
638 for (i = 0; wext_drv[i] != NULL; i++) {
639 snprintf(path, sizeof(path), "%s/%s",
640 drv_rfkill_path, wext_drv[i]);
641 fd = open(path, O_RDONLY);
645 if (fstat(fd, &stat_buf) == 0 && S_ISDIR(stat_buf.st_mode)) {
646 drv_interface = MOBILE_AP_WEXT;
654 return drv_interface;
657 static int __mh_core_softap_firmware_start(void)
661 DBusMessageIter iter;
662 DBusMessage *reply = NULL;
663 DBusMessage *message = NULL;
664 DBusConnection *connection = NULL;
665 const char *device = "softap";
667 connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
668 if (connection == NULL) {
669 ERR("Failed to get system bus");
673 message = dbus_message_new_method_call(NETCONFIG_SERVICE,
674 NETCONFIG_WIFI_PATH, NETCONFIG_WIFI_INTERFACE ".Firmware", "Start");
675 if (message == NULL) {
676 ERR("Failed DBus method call");
677 dbus_connection_unref(connection);
681 dbus_message_iter_init_append(message, &iter);
682 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &device);
684 dbus_error_init(&error);
686 reply = dbus_connection_send_with_reply_and_block(connection, message,
687 NETCONFIG_DBUS_REPLY_TIMEOUT, &error);
688 if (dbus_error_is_set(&error) == TRUE) {
689 if (NULL != strstr(error.message, ".AlreadyExists")) {
690 // softap already enabled
692 ERR("dbus_connection_send_with_reply_and_block() failed. "
693 "DBus error [%s: %s]", error.name, error.message);
697 dbus_error_free(&error);
700 dbus_error_free(&error);
704 dbus_message_unref(reply);
706 dbus_message_unref(message);
707 dbus_connection_unref(connection);
712 static int __mh_core_softap_firmware_stop(void)
716 DBusMessageIter iter;
717 DBusMessage *reply = NULL;
718 DBusMessage *message = NULL;
719 DBusConnection *connection = NULL;
720 const char *device = "softap";
722 connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
723 if (connection == NULL) {
724 ERR("Failed to get system bus");
728 message = dbus_message_new_method_call(NETCONFIG_SERVICE,
729 NETCONFIG_WIFI_PATH, NETCONFIG_WIFI_INTERFACE ".Firmware", "Stop");
730 if (message == NULL) {
731 ERR("Failed DBus method call");
732 dbus_connection_unref(connection);
736 dbus_message_iter_init_append(message, &iter);
737 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &device);
739 dbus_error_init(&error);
741 reply = dbus_connection_send_with_reply_and_block(connection, message,
742 NETCONFIG_DBUS_REPLY_TIMEOUT, &error);
743 if (dbus_error_is_set(&error) == TRUE) {
744 if (NULL != strstr(error.message, ".AlreadyExists")) {
745 // softap already disabled
747 ERR("dbus_connection_send_with_reply_and_block() failed. "
748 "DBus error [%s: %s]", error.name, error.message);
752 dbus_error_free(&error);
755 dbus_error_free(&error);
759 dbus_message_unref(reply);
761 dbus_message_unref(message);
762 dbus_connection_unref(connection);
767 int _mh_core_enable_softap(const mobile_ap_type_e type, const char *ssid,
768 const char *security, const char *key, int hide_mode)
770 if (ssid == NULL || security == NULL || key == NULL) {
771 ERR("Invalid param\n");
772 return MOBILE_AP_ERROR_INTERNAL;
775 char cmd[MAX_BUF_SIZE];
776 int ret_status = MOBILE_AP_ERROR_NONE;
777 mobile_ap_drv_interface_e drv_interface = MOBILE_AP_DRV_INTERFACE_NONE;
780 char *if_name = WIFI_IF;
781 char buf[MAX_BUF_SIZE] = { 0 };
783 char wext_ssid[MOBILE_AP_WIFI_SSID_MAX_LEN] = { 0 };
786 if (__mh_core_softap_firmware_start() < 0)
787 return MOBILE_AP_ERROR_INTERNAL;
789 drv_interface = __get_drv_interface();
791 switch (drv_interface) {
793 if ((sock_fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
794 ERR("Failed to open socket...!!!\n");
795 ret_status = MOBILE_AP_ERROR_RESOURCE;
800 * In case of Wireless extension interface,
801 * 32 byte SSID including null character can be accepted.
803 g_strlcpy(wext_ssid, ssid, sizeof(wext_ssid));
804 if (!g_utf8_validate(wext_ssid, -1, (const char **)&ptr))
807 snprintf(cmd, MAX_BUF_SIZE, "ASCII_CMD=AP_CFG,"
808 "SSID_LEN=%d,SSID=%s,"
809 "SEC=%s,KEY_LEN=%d,KEY=%s,CHANNEL=%d,"
810 "PREAMBLE=0,MAX_SCB=%d,HIDE=%d,END",
811 strlen(wext_ssid), wext_ssid,
812 security, strlen(key), key,
813 MOBILE_AP_WIFI_CHANNEL,
814 MOBILE_AP_MAX_WIFI_STA, hide_mode);
815 ret_status = __issue_ioctl(sock_fd, if_name, cmd, buf);
816 if (ret_status != MOBILE_AP_ERROR_NONE) {
817 ERR("__issue_ioctl failed...!!!\n");
822 /* Start broadcasting of BSS. */
823 snprintf(cmd, MAX_BUF_SIZE, "ASCII_CMD=AP_BSS_START");
824 ret_status = __issue_ioctl(sock_fd, if_name, cmd, buf);
825 if (ret_status != MOBILE_AP_ERROR_NONE) {
826 ERR("__issue_ioctl failed...!!!\n");
833 ret_status = _mh_core_set_ip_address(SOFTAP_IF,
835 if (ret_status != MOBILE_AP_ERROR_NONE) {
836 ERR("_mh_core_set_ip_address of SOFTAP_IF is failed\n");
840 ret_status = _mh_core_set_ip_address(WIFI_IF,
842 if (ret_status != MOBILE_AP_ERROR_NONE) {
843 ERR("_mh_core_set_ip_address of WIFI_IF is failed\n");
848 case MOBILE_AP_NL80211:
850 ret_status = _mh_core_set_ip_address(WIFI_IF,
852 if (ret_status != MOBILE_AP_ERROR_NONE) {
853 ERR("_mh_core_set_ip_address is failed\n");
857 ret_status = __execute_hostapd(type, ssid, security, key, hide_mode);
858 if (ret_status != MOBILE_AP_ERROR_NONE) {
859 ERR("__execute_hostapd is failed\n");
863 ret_status = __open_hostapd_intf(&hostapd_ctrl_fd, MH_CTRL_INTF);
864 if (ret_status != MOBILE_AP_ERROR_NONE) {
865 ERR("__open_hostapd_intf is failed\n");
866 __terminate_hostapd();
870 ret_status = __open_hostapd_monitor(&hostapd_monitor_fd);
871 if (ret_status != MOBILE_AP_ERROR_NONE) {
872 ERR("__open_hostapd_monitor is failed\n");
873 __close_hostapd_intf(&hostapd_ctrl_fd);
874 __terminate_hostapd();
881 ERR("Unknown driver interface : %d\n", drv_interface);
885 if (ret_status != MOBILE_AP_ERROR_NONE)
886 __mh_core_softap_firmware_stop();
891 int _mh_core_disable_softap(void)
893 char cmd[MAX_BUF_SIZE] = { 0 };
894 int ret_status = MOBILE_AP_ERROR_NONE;
895 mobile_ap_drv_interface_e drv_interface = MOBILE_AP_DRV_INTERFACE_NONE;
898 char buf[MAX_BUF_SIZE] = { 0 };
899 char *if_name = WIFI_IF;
901 drv_interface = __get_drv_interface();
903 switch (drv_interface) {
905 if ((sock_fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
906 ERR("Failed to open socket...!!!\n");
907 ret_status = MOBILE_AP_ERROR_RESOURCE;
911 /* Stop broadcasting of BSS. */
912 snprintf(cmd, MAX_BUF_SIZE, "ASCII_CMD=AP_BSS_STOP");
913 ret_status = __issue_ioctl(sock_fd, if_name, cmd, buf);
914 if (ret_status != MOBILE_AP_ERROR_NONE) {
915 ERR("__issue_ioctl failed...!!!\n");
923 case MOBILE_AP_NL80211:
924 ret_status = __close_hostapd_intf(&hostapd_ctrl_fd);
925 if (ret_status != MOBILE_AP_ERROR_NONE)
926 ERR("hostapd termination is failed\n");
928 ret_status = __close_hostapd_monitor(&hostapd_monitor_fd);
929 if (ret_status != MOBILE_AP_ERROR_NONE)
930 ERR("hostapd termination is failed\n");
932 ret_status = __terminate_hostapd();
933 if (ret_status != MOBILE_AP_ERROR_NONE) {
934 ERR("hostapd termination is failed\n");
939 ERR("Unknown driver interface : %d\n", drv_interface);
943 if (__mh_core_softap_firmware_stop() < 0)
944 ret_status = MOBILE_AP_ERROR_INTERNAL;
949 static int __get_device_info_by_wext(softap_device_info_t *di)
952 char *if_name = SOFTAP_IF;
953 char cmd[MAX_BUF_SIZE];
954 char buf[MAX_BUF_SIZE] = { 0 };
955 int ret = MOBILE_AP_ERROR_NONE;
957 char *buf_ptr = NULL;
960 if ((sock_fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
961 ERR("Failed to open socket...!!!\n");
963 return MOBILE_AP_ERROR_RESOURCE;
966 snprintf(cmd, MAX_BUF_SIZE, "AP_GET_STA_LIST");
967 ret = __issue_ioctl(sock_fd, if_name, cmd, buf);
968 if (ret != MOBILE_AP_ERROR_NONE) {
969 ERR("__issue_ioctl failed...!!!\n");
977 sscanf(buf_ptr, "%02x", &di->number);
980 for (i = 0; i < di->number; i++) {
981 unsigned int l_bssid[MOBILE_AP_WIFI_BSSID_LEN];
982 sscanf(buf_ptr, "%02X%02X%02X%02X%02X%02X", &l_bssid[0],
983 &l_bssid[1], &l_bssid[2], &l_bssid[3],
984 &l_bssid[4], &l_bssid[5]);
985 snprintf(di->bssid[i], MOBILE_AP_STR_INFO_LEN,
986 "%02X:%02X:%02X:%02X:%02X:%02X",
987 l_bssid[0], l_bssid[1], l_bssid[2],
988 l_bssid[3], l_bssid[4], l_bssid[5]);
990 SDBG("STA[%d] address[%s]\n", i, di->bssid[i]);
1000 static int __get_device_info_by_nl80211(softap_device_info_t *di)
1005 char req[HOSTAPD_REQ_MAX_LEN] = {0, };
1006 char buf[MOBILE_AP_STR_INFO_LEN] = {0, };
1008 buf_len = sizeof(buf);
1009 g_strlcpy(req, "NUM_STA", sizeof(req));
1010 ret = __send_hostapd_req(hostapd_ctrl_fd,
1011 req, strlen(req), buf, &buf_len);
1012 if (ret != MOBILE_AP_ERROR_NONE) {
1013 ERR("__send_hostapd_req is failed : %d\n", ret);
1017 DBG("The number of station : %s\n", buf);
1018 if (atoi(buf) == 0) {
1019 DBG("There is no station\n");
1020 return MOBILE_AP_ERROR_NONE;
1023 buf_len = sizeof(buf);
1024 g_strlcpy(req, "STA-FIRST", sizeof(req));
1025 ret = __send_hostapd_req(hostapd_ctrl_fd,
1026 req, strlen(req), buf, &buf_len);
1027 if (ret != MOBILE_AP_ERROR_NONE) {
1028 ERR("__send_hostapd_req is failed : %d\n", ret);
1033 if (!strncmp(buf, "FAIL", 4)) {
1034 ERR("FAIL is returned\n");
1038 if (buf[0] == '\0') {
1039 ERR("NULL string\n");
1043 SDBG("Station : %s\n", buf);
1044 g_strlcpy(di->bssid[no_of_sta++], buf, MOBILE_AP_STR_INFO_LEN);
1046 buf_len = sizeof(buf);
1047 snprintf(req, sizeof(req), "STA-NEXT %s", buf);
1048 ret = __send_hostapd_req(hostapd_ctrl_fd,
1049 req, strlen(req), buf, &buf_len);
1050 } while (ret == MOBILE_AP_ERROR_NONE);
1052 di->number = no_of_sta;
1057 int _mh_core_get_device_info(softap_device_info_t *di)
1060 ERR("Invalid param\n");
1061 return MOBILE_AP_ERROR_INVALID_PARAM;
1064 int ret = MOBILE_AP_ERROR_NONE;
1066 switch (__get_drv_interface()) {
1067 case MOBILE_AP_WEXT:
1068 ret = __get_device_info_by_wext(di);
1071 case MOBILE_AP_NL80211:
1072 ret = __get_device_info_by_nl80211(di);
1076 ERR("Unknown interface\n");
1083 int _mh_core_execute_dhcp_server(void)
1085 char buf[DNSMASQ_CONF_LEN] = "";
1089 fp = fopen(DNSMASQ_CONF_FILE, "w");
1091 ERR("Could not create the file.\n");
1092 return MOBILE_AP_ERROR_RESOURCE;
1094 snprintf(buf, DNSMASQ_CONF_LEN, DNSMASQ_CONF);
1100 ERR("fork failed\n");
1101 return MOBILE_AP_ERROR_RESOURCE;
1107 * -C file : Configuration file path
1109 if (execl("/usr/bin/dnsmasq", "/usr/bin/dnsmasq", "-d",
1110 "-p", "0", "-C", DNSMASQ_CONF_FILE,
1112 ERR("execl failed\n");
1115 ERR("Should not get here!");
1116 return MOBILE_AP_ERROR_RESOURCE;
1121 return MOBILE_AP_ERROR_NONE;
1124 int _mh_core_terminate_dhcp_server(void)
1128 if (dnsmasq_pid == 0) {
1129 ERR("There is no dnsmasq\n");
1130 return MOBILE_AP_ERROR_NONE;
1133 kill(dnsmasq_pid, SIGTERM);
1134 waitpid(dnsmasq_pid, NULL, 0);
1137 ret = unlink(DNSMASQ_CONF_FILE);
1139 ERR("unlink is failed : %s\n", strerror(errno));
1142 return MOBILE_AP_ERROR_NONE;
1145 int _mh_core_enable_masquerade(const char *ext_if)
1147 if (ext_if == NULL || strlen(ext_if) == 0) {
1148 ERR("ext_if[%s] is invalid\n", ext_if);
1149 return MOBILE_AP_ERROR_INVALID_PARAM;
1154 fd = open(IP_FORWARD, O_WRONLY);
1156 ERR("open failed\n");
1157 return MOBILE_AP_ERROR_RESOURCE;
1160 if (write(fd, "1", 1) != 1) {
1161 ERR("write failed\n");
1163 return MOBILE_AP_ERROR_INTERNAL;
1167 _iptables_create_chain(TABLE_NAT, TETH_NAT_POST);
1168 _iptables_add_rule(PKT_REDIRECTION_RULE, TABLE_NAT, CHAIN_POST,
1170 _iptables_add_rule(MASQ_RULE, TABLE_NAT, TETH_NAT_POST, ext_if);
1172 _iptables_create_chain(TABLE_FILTER, TETH_FILTER_FW);
1174 _iptables_add_rule(PKT_REDIRECTION_RULE, TABLE_FILTER, CHAIN_FW,
1177 _iptables_add_rule(CLAMP_MSS_RULE, TABLE_FILTER, TETH_FILTER_FW);
1179 _iptables_add_rule(FORWARD_RULE_WITH_ACTION_AND_STATE, TABLE_FILTER, TETH_FILTER_FW,
1180 BT_IF_ALL, ext_if, ACTION_RETURN, STATE_RELATED_ESTAB);
1181 _iptables_add_rule(FORWARD_RULE_WITH_ACTION_AND_STATE, TABLE_FILTER, TETH_FILTER_FW,
1182 WIFI_IF, ext_if, ACTION_RETURN, STATE_RELATED_ESTAB);
1183 _iptables_add_rule(FORWARD_RULE_WITH_ACTION_AND_STATE, TABLE_FILTER, TETH_FILTER_FW,
1184 USB_IF, ext_if, ACTION_RETURN, STATE_RELATED_ESTAB);
1186 _iptables_add_rule(FORWARD_RULE_WITH_ACTION_AND_STATE, TABLE_FILTER, TETH_FILTER_FW,
1187 ext_if, BT_IF_ALL, ACTION_DROP, STATE_INVALID);
1188 _iptables_add_rule(FORWARD_RULE_WITH_ACTION_AND_STATE, TABLE_FILTER, TETH_FILTER_FW,
1189 ext_if, WIFI_IF, ACTION_DROP, STATE_INVALID);
1190 _iptables_add_rule(FORWARD_RULE_WITH_ACTION_AND_STATE, TABLE_FILTER, TETH_FILTER_FW,
1191 ext_if, USB_IF, ACTION_DROP, STATE_INVALID);
1193 _iptables_add_rule(FORWARD_RULE_WITH_ACTION, TABLE_FILTER, TETH_FILTER_FW,
1194 ext_if, BT_IF_ALL, ACTION_RETURN);
1195 _iptables_add_rule(FORWARD_RULE_WITH_ACTION, TABLE_FILTER, TETH_FILTER_FW,
1196 ext_if, WIFI_IF, ACTION_RETURN);
1197 _iptables_add_rule(FORWARD_RULE_WITH_ACTION, TABLE_FILTER, TETH_FILTER_FW,
1198 ext_if, USB_IF, ACTION_RETURN);
1200 _iptables_add_rule(FORWARD_RULE_WITH_ACTION, TABLE_FILTER, TETH_FILTER_FW,
1201 BT_IF_ALL, ext_if, ACTION_RETURN);
1202 _iptables_add_rule(FORWARD_RULE_WITH_ACTION, TABLE_FILTER, TETH_FILTER_FW,
1203 WIFI_IF, ext_if, ACTION_RETURN);
1204 _iptables_add_rule(FORWARD_RULE_WITH_ACTION, TABLE_FILTER, TETH_FILTER_FW,
1205 USB_IF, ext_if, ACTION_RETURN);
1207 _iptables_add_rule(DEFAULT_RULE, TABLE_FILTER, TETH_FILTER_FW,
1210 return MOBILE_AP_ERROR_NONE;
1213 int _mh_core_disable_masquerade(const char *ext_if)
1215 if (ext_if == NULL || strlen(ext_if) == 0) {
1216 ERR("ext_if[%s] is invalid\n", ext_if);
1217 return MOBILE_AP_ERROR_INVALID_PARAM;
1222 fd = open(IP_FORWARD, O_WRONLY);
1224 ERR("open failed\n");
1225 return MOBILE_AP_ERROR_RESOURCE;
1228 if (write(fd, "0", 1) != 1) {
1229 ERR("write failed\n");
1231 return MOBILE_AP_ERROR_INTERNAL;
1235 _iptables_delete_rule(PKT_REDIRECTION_RULE, TABLE_NAT, CHAIN_POST,
1237 _iptables_flush_rules(TABLE_NAT, TETH_NAT_POST);
1238 _iptables_delete_chain(TABLE_NAT, TETH_NAT_POST);
1240 _iptables_delete_rule(PKT_REDIRECTION_RULE, TABLE_FILTER, CHAIN_FW,
1242 _iptables_flush_rules(TABLE_FILTER, TETH_FILTER_FW);
1243 _iptables_delete_chain(TABLE_FILTER, TETH_FILTER_FW);
1245 return MOBILE_AP_ERROR_NONE;
1248 void _mh_core_add_data_to_array(GPtrArray *array, guint type, gchar *dev_name)
1250 GValue value = {0, {{0}}};
1252 g_value_init(&value, DBUS_STRUCT_UINT_STRING);
1253 g_value_take_boxed(&value,
1254 dbus_g_type_specialized_construct(DBUS_STRUCT_UINT_STRING));
1255 dbus_g_type_struct_set(&value, 0, type, 1, dev_name, G_MAXUINT);
1256 g_ptr_array_add(array, g_value_get_boxed(&value));
1259 int _mh_core_set_ip_address(const char *if_name, const in_addr_t ip)
1262 struct sockaddr_in addr;
1265 SDBG("if_name : %s ip address : 0x%X\n", if_name, ip);
1267 if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
1268 ERR("socket open failed!!!\n");
1269 return MOBILE_AP_ERROR_RESOURCE;
1272 g_strlcpy(ifr.ifr_name, if_name, IFNAMSIZ);
1274 memset(&addr, 0, sizeof(struct sockaddr));
1275 addr.sin_family = AF_INET;
1277 addr.sin_addr.s_addr = htonl(ip);
1279 memcpy(&ifr.ifr_addr, &addr, sizeof(struct sockaddr));
1280 if (ioctl(sock_fd, SIOCSIFADDR, &ifr) < 0) {
1281 ERR("ioctl failed...!!!\n");
1283 return MOBILE_AP_ERROR_INTERNAL;
1286 if (ioctl(sock_fd, SIOCGIFFLAGS, &ifr) < 0) {
1287 ERR("ioctl failed...!!!\n");
1289 return MOBILE_AP_ERROR_INTERNAL;
1292 ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
1293 if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr) < 0) {
1294 ERR("ioctl failed...!!!\n");
1296 return MOBILE_AP_ERROR_INTERNAL;
1301 return MOBILE_AP_ERROR_NONE;
1304 static gboolean __send_station_event_cb(gpointer data)
1306 int sig = GPOINTER_TO_INT(data);
1309 mobile_ap_station_info_t *si = NULL;
1311 if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI))
1312 type = MOBILE_AP_TYPE_WIFI;
1313 else if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI_AP))
1314 type = MOBILE_AP_TYPE_WIFI_AP;
1318 if (sig == SIGUSR1) {
1319 DBG("STA connected(%d)\n", sig);
1320 /* STA connection is handled in the dnsmasq signal handler */
1321 } else if (sig == SIGUSR2) {
1322 DBG("STA disconnected(%d)\n", sig);
1324 /* Temporarily care only one station.
1325 * Driver team should be support detail information */
1326 if (_get_station_info((gconstpointer)type,
1327 _slist_find_station_by_interface,
1328 &si) != MOBILE_AP_ERROR_NONE) {
1331 _remove_station_info(si->mac, _slist_find_station_by_mac);
1333 _get_station_count((gconstpointer)type,
1334 _slist_find_station_by_interface, &n_station);
1335 if (n_station == 0) {
1336 if (type == MOBILE_AP_TYPE_WIFI)
1337 _start_timeout_cb(type, time(NULL) + TETHERING_CONN_TIMEOUT);
1338 else if (type == MOBILE_AP_TYPE_WIFI_AP)
1339 _start_timeout_cb(type, time(NULL) + WIFI_AP_CONN_TIMEOUT);
1346 static void __handle_station_signal(int sig)
1348 g_idle_add(__send_station_event_cb, GINT_TO_POINTER(sig));
1352 void _register_wifi_station_handler(void)
1354 struct sigaction sa;
1356 if (__get_drv_interface() != MOBILE_AP_WEXT)
1359 memset(&sa, 0, sizeof(sa));
1360 sa.sa_handler = __handle_station_signal;
1361 sigaction(SIGUSR1, &sa, NULL);
1362 sigaction(SIGUSR2, &sa, NULL);
1367 void _unregister_wifi_station_handler(void)
1369 struct sigaction sa;
1371 if (__get_drv_interface() != MOBILE_AP_WEXT)
1374 memset(&sa, 0, sizeof(sa));
1375 sa.sa_handler = SIG_DFL;
1376 sigaction(SIGUSR1, &sa, NULL);
1377 sigaction(SIGUSR2, &sa, NULL);
1382 static gboolean __hostapd_connect_timer_cb(gpointer user_data)
1384 char *mac = (char *)user_data;
1386 GSList *temp = NULL;
1387 sta_timer_t *ptr = NULL;
1388 mobile_ap_station_info_t *info = NULL;
1394 if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI))
1395 type = MOBILE_AP_TYPE_WIFI;
1396 else if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI_AP))
1397 type = MOBILE_AP_TYPE_WIFI_AP;
1401 for (l = sta_timer_list; l != NULL; l = g_slist_next(l)) {
1402 ptr = (sta_timer_t *)l->data;
1406 if (!g_strcmp0(ptr->mac_addr, mac)) {
1407 DBG("client with Static IP, Add station\n");
1409 info = (mobile_ap_station_info_t *)g_malloc(sizeof(mobile_ap_station_info_t));
1411 ERR("g_malloc failed\n");
1412 g_free(ptr->mac_addr);
1415 l = g_slist_next(l);
1416 sta_timer_list = g_slist_delete_link(sta_timer_list, temp);
1422 info->interface = type;
1423 g_strlcpy(info->ip, "", sizeof(info->ip));
1424 g_strlcpy(info->mac, mac, sizeof(info->mac));
1426 ret = _get_wifi_name_from_lease_info(mac, &info->hostname);
1427 if (ret != MOBILE_AP_ERROR_NONE)
1428 info->hostname = g_strdup(MOBILE_AP_NAME_UNKNOWN);
1430 g_free(ptr->mac_addr);
1433 l = g_slist_next(l);
1434 sta_timer_list = g_slist_delete_link(sta_timer_list, temp);
1443 if (_add_station_info(info) != MOBILE_AP_ERROR_NONE) {
1444 g_free(info->hostname);
1449 _get_station_count((gconstpointer)type,
1450 _slist_find_station_by_interface, &n_station);
1452 _stop_timeout_cb(type);
1454 _send_dbus_station_info("DhcpConnected", info);
1459 void _flush_dhcp_ack_timer(void)
1464 GSList *temp = NULL;
1465 sta_timer_t *ptr = NULL;
1467 for (l = sta_timer_list; l != NULL; l = g_slist_next(l)) {
1468 ptr = (sta_timer_t *)l->data;
1470 if (ptr->tid != 0) {
1471 g_source_remove(ptr->tid);
1474 g_free(ptr->mac_addr);
1479 l = g_slist_next(l);
1480 sta_timer_list = g_slist_delete_link(sta_timer_list, temp);
1487 void _destroy_dhcp_ack_timer(char *mac_addr)
1490 if (mac_addr == NULL) {
1491 ERR("mac address passed NULL\n");
1496 GSList *temp = NULL;
1497 sta_timer_t *ptr = NULL;
1499 for (l = sta_timer_list; l != NULL; l = g_slist_next(l)) {
1501 ptr = (sta_timer_t *)l->data;
1505 if (!g_strcmp0(ptr->mac_addr, mac_addr)) {
1507 if (ptr->tid != 0) {
1508 g_source_remove(ptr->tid);
1511 g_free(ptr->mac_addr);
1514 l = g_slist_next(l);
1515 sta_timer_list = g_slist_delete_link(sta_timer_list,