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>
30 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
35 #include <linux/wireless.h>
36 #include <openssl/evp.h>
37 #include <openssl/sha.h>
39 #include "mobileap_common.h"
40 #include "mobileap_softap.h"
41 #include "mobileap_handler.h"
42 #include "mobileap_wifi.h"
43 #include "mobileap_iptables.h"
45 #define NETCONFIG_SERVICE "net.netconfig"
46 #define NETCONFIG_WIFI_INTERFACE "net.netconfig.wifi"
47 #define NETCONFIG_WIFI_PATH "/net/netconfig/wifi"
49 #define NETCONFIG_DBUS_REPLY_TIMEOUT (10 * 1000)
51 static pid_t dnsmasq_pid = 0;
52 static pid_t hostapd_pid = 0;
53 static int hostapd_ctrl_fd = 0;
54 static int hostapd_monitor_fd = 0;
55 static GIOChannel *hostapd_io_channel = NULL;
56 static guint hostapd_io_source = 0;
57 GSList *sta_timer_list = NULL;
59 static gboolean __hostapd_connect_timer_cb(gpointer user_data);
61 static char *__find_first_caps_char(char *str)
64 ERR("NULL string passes\n");
77 static int __issue_ioctl(int sock_fd, char *if_name, char *cmd, char *buf)
79 int ret_val = MOBILE_AP_ERROR_NONE;
82 memset(buf, 0, MAX_BUF_SIZE);
83 memset(&iwr, 0, sizeof(iwr));
85 /* Configure ioctl parameters */
86 g_strlcpy(iwr.ifr_name, if_name, IFNAMSIZ);
87 g_strlcpy(buf, cmd, MAX_BUF_SIZE);
88 iwr.u.data.pointer = buf;
89 iwr.u.data.length = MAX_BUF_SIZE;
94 if ((ioctl(sock_fd, SIOCSIWPRIV, &iwr)) < 0) {
95 ERR("ioctl failed...!!!\n");
96 ret_val = MOBILE_AP_ERROR_INTERNAL;
102 static int __get_psk_hexascii(const char *pass, const unsigned char *salt,
103 char *psk, unsigned int psk_len)
105 if (pass == NULL || salt == NULL || psk == NULL || psk_len <
106 (SHA256_DIGEST_LENGTH * 2 + 1)) {
107 ERR("Invalid parameter\n");
108 return MOBILE_AP_ERROR_INVALID_PARAM;
114 unsigned char buf[SHA256_DIGEST_LENGTH] = {0, };
116 if (!PKCS5_PBKDF2_HMAC_SHA1(pass, strlen(pass),
117 salt, strlen((const char *)salt),
118 PSK_ITERATION_COUNT, sizeof(buf), buf)) {
119 ERR("Getting psk is failed\n");
120 return MOBILE_AP_ERROR_RESOURCE;
123 for (i = 0; i < SHA256_DIGEST_LENGTH; i++) {
127 psk[i << 1] = d_16 < 10 ? d_16 + '0' : d_16 - 10 + 'a';
128 psk[(i << 1) + 1] = r_16 < 10 ? r_16 + '0' : r_16 - 10 + 'a';
132 return MOBILE_AP_ERROR_NONE;
135 static int __execute_hostapd(const mobile_ap_type_e type, const char *ssid,
136 const char *security, const char *passphrase, int hide_mode)
142 char buf[HOSTAPD_CONF_LEN] = "";
146 char key[MOBILE_AP_WIFI_KEY_MAX_LEN + 1];
148 snprintf(buf, sizeof(buf), HOSTAPD_CONF,
150 HOSTAPD_CTRL_INTF_DIR,
152 MOBILE_AP_WIFI_CHANNEL,
154 MOBILE_AP_MAX_WIFI_STA);
155 conf = g_strdup(buf);
157 /* Vendor elements conf. */
158 if (type == MOBILE_AP_TYPE_WIFI) {
159 snprintf(buf, sizeof(buf),
160 "vendor_elements=%s\n", HOSTAPD_VENDOR_ELEMENTS_TETH);
161 } else if (type == MOBILE_AP_TYPE_WIFI_AP) {
162 snprintf(buf, sizeof(buf),
163 "vendor_elements=%s\n", HOSTAPD_VENDOR_ELEMENTS_WIFI_AP);
165 ERR("Unknown type: %d\n", type);
167 return MOBILE_AP_ERROR_INVALID_PARAM;
170 conf = g_strconcat(old_conf, buf, NULL);
174 if (security != NULL && !strcmp(security, "wpa2-psk")) {
175 ret = __get_psk_hexascii(passphrase, (const unsigned char *)ssid, key, sizeof(key));
176 if (ret != MOBILE_AP_ERROR_NONE) {
178 ERR("hex conversion failed\n");
179 return MOBILE_AP_ERROR_RESOURCE;
181 snprintf(buf, sizeof(buf),
182 "wpa=2\nrsn_pairwise=CCMP\nwpa_psk=%s\n", key);
185 conf = g_strconcat(old_conf, buf, NULL);
189 fp = fopen(HOSTAPD_CONF_FILE, "w");
191 ERR("Could not create the file.\n");
193 return MOBILE_AP_ERROR_RESOURCE;
204 ERR("fork failed\n");
205 return MOBILE_AP_ERROR_RESOURCE;
209 if (execl(HOSTAPD_BIN, HOSTAPD_BIN, "-e", HOSTAPD_ENTROPY_FILE,
211 "-f", HOSTAPD_DEBUG_FILE, "-ddd",
213 ERR("execl failed\n");
216 ERR("Should not get here!");
217 return MOBILE_AP_ERROR_RESOURCE;
222 return MOBILE_AP_ERROR_NONE;
225 static int __terminate_hostapd()
231 if (hostapd_pid == 0) {
232 ERR("There is no hostapd\n");
233 return MOBILE_AP_ERROR_NONE;
236 kill(hostapd_pid, SIGTERM);
237 waitpid(hostapd_pid, NULL, 0);
240 ret = unlink(HOSTAPD_CONF_FILE);
242 ERR("unlink is failed : %s\n", strerror(errno));
245 return MOBILE_AP_ERROR_NONE;
249 * number NUM_STA(void)
250 * addr STA-FIRST(void)
251 * addr STA-NEXT(addr)
252 * void DISASSOCIATE(addr)
253 * void READ_WHITELIST(filename)
254 * void SET_MAXCLIENT(number)
256 static int __send_hostapd_req(int fd, const char *req, const int req_len,
257 char *buf, int *buf_len)
259 if (fd < 0 || req == NULL || req_len <= 0 ||
260 buf == NULL || buf_len == NULL || *buf_len <= 0) {
261 ERR("Invalid param\n");
262 return MOBILE_AP_ERROR_INVALID_PARAM;
265 struct timeval tv = {10, 0};
269 ret = send(fd, req, req_len, 0);
271 ERR("send is failed : %s\n", strerror(errno));
272 return MOBILE_AP_ERROR_INTERNAL;
278 ret = select(fd + 1, &fds, NULL, NULL, &tv);
280 return MOBILE_AP_ERROR_INTERNAL;
281 } else if (ret == 0) {
282 ERR("There is no response from hostapd\n");
283 return MOBILE_AP_ERROR_INTERNAL;
284 } else if (!FD_ISSET(fd, &fds)) {
285 ERR("Unknown case\n");
286 return MOBILE_AP_ERROR_INTERNAL;
289 ret = recv(fd, buf, (*buf_len) - 1, 0);
291 ERR("recv is failed\n");
292 return MOBILE_AP_ERROR_INTERNAL;
296 ERR("Unsolicited message\n");
303 ERR("socket is closed\n");
309 return MOBILE_AP_ERROR_NONE;
312 static int __open_hostapd_intf(int *fd, const char *intf)
314 if (fd == NULL || intf == NULL) {
316 return MOBILE_AP_ERROR_INVALID_PARAM;
322 char ctrl_intf[255] = {0, };
323 struct sockaddr_un src;
324 struct sockaddr_un dest;
325 struct stat stat_buf;
327 *fd = socket(PF_UNIX, SOCK_DGRAM, 0);
329 ERR("socket is failed\n");
330 return MOBILE_AP_ERROR_INTERNAL;
333 src.sun_family = AF_UNIX;
334 g_strlcpy(src.sun_path, intf, sizeof(src.sun_path));
336 if (stat(src.sun_path, &stat_buf) == 0) {
337 unlink(src.sun_path);
340 if (bind(*fd, (struct sockaddr *)&src, sizeof(src)) < 0) {
341 ERR("bind is failed\n");
344 unlink(src.sun_path);
345 return MOBILE_AP_ERROR_INTERNAL;
348 snprintf(ctrl_intf, sizeof(ctrl_intf), "%s/%s",
349 HOSTAPD_CTRL_INTF_DIR, WIFI_IF);
350 dest.sun_family = AF_UNIX;
351 g_strlcpy(dest.sun_path, ctrl_intf, sizeof(dest.sun_path));
353 while (connect(*fd, (struct sockaddr *)&dest, sizeof(dest)) < 0) {
354 if (++retry >= HOSTAPD_RETRY_MAX)
356 usleep(HOSTAPD_RETRY_DELAY);
359 return MOBILE_AP_ERROR_NONE;
362 ERR("Cannot make connection to hostapd\n");
365 unlink(src.sun_path);
367 return MOBILE_AP_ERROR_INTERNAL;
370 static int __close_hostapd_intf(int *fd)
376 return MOBILE_AP_ERROR_INVALID_PARAM;
383 return MOBILE_AP_ERROR_NONE;
386 static gboolean __hostapd_monitor_cb(GIOChannel *source)
391 char buf[HOSTAPD_REQ_MAX_LEN + 1] = {0, };
396 sta_timer_t *ptr = NULL;
399 gboolean discon_event = FALSE;
402 #if !GLIB_CHECK_VERSION(2, 31, 0)
405 ret = g_io_channel_read(hostapd_io_channel, buf,
406 HOSTAPD_REQ_MAX_LEN, &read);
407 if (ret != G_IO_ERROR_NONE) {
408 ERR("g_io_channel_read is failed\n");
415 ios = g_io_channel_read_chars(hostapd_io_channel, buf,
416 HOSTAPD_REQ_MAX_LEN, &read, &err);
418 ERR("g_io_channel_read_chars is failed : %s\n", err->message);
421 } else if (ios != G_IO_STATUS_NORMAL) {
422 ERR("g_io_channel_read_chars is failed : %d\n", ios);
428 pbuf = strrchr(buf, '\n');
432 SDBG("Read string from hostapd = [%s]\n", buf);
434 /* concatenated string, containing multiple events can arrive */
435 while (pbuf && *pbuf) {
436 pbuf = __find_first_caps_char(pbuf);
437 if (!pbuf || !*pbuf) {
441 if (!strncmp(pbuf, HOSTAPD_STA_CONN, HOSTAPD_STA_CONN_LEN)) {
442 pbuf = pbuf + HOSTAPD_STA_CONN_LEN;
443 if (!pbuf || !*pbuf) {
444 ERR("No mac address\n");
448 end = strchr(pbuf, '<');
450 mac = g_strndup(pbuf, (long)(end - pbuf));
453 mac = g_strdup(pbuf);
458 ERR("strdup failed\n");
462 for (l = sta_timer_list; l != NULL; l = g_slist_next(l)) {
463 ptr = (sta_timer_t *)l->data;
468 if (g_strcmp0(ptr->mac_addr, mac) == 0) {
475 /* Matched station found, so skip */
480 SDBG("%s%s\n", HOSTAPD_STA_CONN, mac);
481 ptr = (sta_timer_t *)g_malloc(sizeof(sta_timer_t));
483 ERR("g_malloc failed\n");
489 ptr->tid = g_timeout_add(HOSTAPD_DHCP_MAX_INTERVAL,
490 __hostapd_connect_timer_cb, mac);
491 sta_timer_list = g_slist_append(sta_timer_list, ptr);
493 } else if (!strncmp(pbuf, HOSTAPD_STA_DISCONN, HOSTAPD_STA_DISCONN_LEN)) {
494 pbuf = pbuf + HOSTAPD_STA_DISCONN_LEN;
495 if (!pbuf || !*pbuf) {
499 end = strchr(pbuf, '<');
501 mac = g_strndup(pbuf, (long)(end - pbuf));
504 mac = g_strdup(pbuf);
509 ERR("strdup failed\n");
513 SDBG("%s%s\n", HOSTAPD_STA_DISCONN, mac);
514 _remove_station_info(mac, _slist_find_station_by_mac);
517 * Destroy the timer if its not expired before disconnection
519 _destroy_dhcp_ack_timer(mac);
525 pbuf = strchr(pbuf, '>');
532 if (discon_event == FALSE)
535 if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI)) {
536 type = MOBILE_AP_TYPE_WIFI;
537 } else if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI_AP)) {
538 type = MOBILE_AP_TYPE_WIFI_AP;
543 _get_station_count((gconstpointer)type,
544 _slist_find_station_by_interface, &n_station);
546 if (n_station == 0) {
547 if (type == MOBILE_AP_TYPE_WIFI)
548 _start_timeout_cb(type, time(NULL) + TETHERING_CONN_TIMEOUT);
549 else if (type == MOBILE_AP_TYPE_WIFI_AP)
550 _start_timeout_cb(type, time(NULL) + WIFI_AP_CONN_TIMEOUT);
556 static int __open_hostapd_monitor(int *fd)
560 return MOBILE_AP_ERROR_INVALID_PARAM;
565 char buf[HOSTAPD_REQ_MAX_LEN] = {0, };
568 if (__open_hostapd_intf(fd, MH_MONITOR_INTF) != MOBILE_AP_ERROR_NONE) {
569 ERR("__open_hostapd_intf() is failed\n");
570 return MOBILE_AP_ERROR_INTERNAL;
573 hostapd_io_channel = g_io_channel_unix_new(*fd);
574 if (hostapd_io_channel == NULL) {
575 ERR("g_io_channel_unix_new is failed\n");
576 return MOBILE_AP_ERROR_INTERNAL;
579 g_io_channel_set_encoding(hostapd_io_channel, NULL, NULL);
580 g_io_channel_set_flags(hostapd_io_channel,
581 G_IO_FLAG_APPEND | G_IO_FLAG_NONBLOCK, NULL);
583 hostapd_io_source = g_io_add_watch(hostapd_io_channel, G_IO_IN,
584 (GIOFunc)__hostapd_monitor_cb, NULL);
586 buf_len = sizeof(buf);
587 __send_hostapd_req(*fd, HOSTAPD_MONITOR_ATTACH,
588 strlen(HOSTAPD_MONITOR_ATTACH), buf, &buf_len);
590 return MOBILE_AP_ERROR_NONE;
593 static int __close_hostapd_monitor(int *fd)
596 char buf[HOSTAPD_REQ_MAX_LEN] = {0, };
599 buf_len = sizeof(buf);
600 __send_hostapd_req(*fd, HOSTAPD_MONITOR_DETACH,
601 strlen(HOSTAPD_MONITOR_DETACH), buf, &buf_len);
603 if (hostapd_io_source != 0) {
604 g_source_remove(hostapd_io_source);
605 hostapd_io_source = 0;
608 if (hostapd_io_channel != NULL) {
609 g_io_channel_shutdown(hostapd_io_channel, TRUE, &err);
610 g_io_channel_unref(hostapd_io_channel);
611 hostapd_io_channel = NULL;
614 __close_hostapd_intf(fd);
616 return MOBILE_AP_ERROR_NONE;
619 static mobile_ap_drv_interface_e __get_drv_interface(void)
621 static mobile_ap_drv_interface_e drv_interface = MOBILE_AP_DRV_INTERFACE_NONE;
623 if (drv_interface != MOBILE_AP_DRV_INTERFACE_NONE) {
624 return drv_interface;
627 const char *drv_rfkill_path = "/sys/devices/platform";
628 const char *wext_drv[] = {
629 "bcm4329-b1", "bcm4330-b0",
630 "bcm4330-b1", "bcm4330-b2",
633 char path[MAX_BUF_SIZE] = { 0 };
634 struct stat stat_buf = { 0 };
638 drv_interface = MOBILE_AP_NL80211;
640 for (i = 0; wext_drv[i] != NULL; i++) {
641 snprintf(path, sizeof(path), "%s/%s",
642 drv_rfkill_path, wext_drv[i]);
643 fd = open(path, O_RDONLY);
647 if (fstat(fd, &stat_buf) == 0 && S_ISDIR(stat_buf.st_mode)) {
648 drv_interface = MOBILE_AP_WEXT;
656 return drv_interface;
659 static int __mh_core_softap_firmware_start(void)
663 DBusMessageIter iter;
664 DBusMessage *reply = NULL;
665 DBusMessage *message = NULL;
666 DBusConnection *connection = NULL;
667 const char *device = "softap";
669 connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
670 if (connection == NULL) {
671 ERR("Failed to get system bus");
675 message = dbus_message_new_method_call(NETCONFIG_SERVICE,
676 NETCONFIG_WIFI_PATH, NETCONFIG_WIFI_INTERFACE ".Firmware", "Start");
677 if (message == NULL) {
678 ERR("Failed DBus method call");
679 dbus_connection_unref(connection);
683 dbus_message_iter_init_append(message, &iter);
684 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &device);
686 dbus_error_init(&error);
688 reply = dbus_connection_send_with_reply_and_block(connection, message,
689 NETCONFIG_DBUS_REPLY_TIMEOUT, &error);
690 if (dbus_error_is_set(&error) == TRUE) {
691 if (NULL != strstr(error.message, ".AlreadyExists")) {
692 // softap already enabled
694 ERR("dbus_connection_send_with_reply_and_block() failed. "
695 "DBus error [%s: %s]", error.name, error.message);
699 dbus_error_free(&error);
702 dbus_error_free(&error);
706 dbus_message_unref(reply);
708 dbus_message_unref(message);
709 dbus_connection_unref(connection);
714 static int __mh_core_softap_firmware_stop(void)
718 DBusMessageIter iter;
719 DBusMessage *reply = NULL;
720 DBusMessage *message = NULL;
721 DBusConnection *connection = NULL;
722 const char *device = "softap";
724 connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
725 if (connection == NULL) {
726 ERR("Failed to get system bus");
730 message = dbus_message_new_method_call(NETCONFIG_SERVICE,
731 NETCONFIG_WIFI_PATH, NETCONFIG_WIFI_INTERFACE ".Firmware", "Stop");
732 if (message == NULL) {
733 ERR("Failed DBus method call");
734 dbus_connection_unref(connection);
738 dbus_message_iter_init_append(message, &iter);
739 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &device);
741 dbus_error_init(&error);
743 reply = dbus_connection_send_with_reply_and_block(connection, message,
744 NETCONFIG_DBUS_REPLY_TIMEOUT, &error);
745 if (dbus_error_is_set(&error) == TRUE) {
746 if (NULL != strstr(error.message, ".AlreadyExists")) {
747 // softap already disabled
749 ERR("dbus_connection_send_with_reply_and_block() failed. "
750 "DBus error [%s: %s]", error.name, error.message);
754 dbus_error_free(&error);
757 dbus_error_free(&error);
761 dbus_message_unref(reply);
763 dbus_message_unref(message);
764 dbus_connection_unref(connection);
769 int _mh_core_enable_softap(const mobile_ap_type_e type, const char *ssid,
770 const char *security, const char *key, int hide_mode)
772 if (ssid == NULL || security == NULL || key == NULL) {
773 ERR("Invalid param\n");
774 return MOBILE_AP_ERROR_INTERNAL;
777 char cmd[MAX_BUF_SIZE];
778 int ret_status = MOBILE_AP_ERROR_NONE;
779 mobile_ap_drv_interface_e drv_interface = MOBILE_AP_DRV_INTERFACE_NONE;
782 char *if_name = WIFI_IF;
783 char buf[MAX_BUF_SIZE] = { 0 };
785 char wext_ssid[MOBILE_AP_WIFI_SSID_MAX_LEN] = { 0 };
788 if (__mh_core_softap_firmware_start() < 0)
789 return MOBILE_AP_ERROR_INTERNAL;
791 drv_interface = __get_drv_interface();
793 switch (drv_interface) {
795 if ((sock_fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
796 ERR("Failed to open socket...!!!\n");
797 ret_status = MOBILE_AP_ERROR_RESOURCE;
802 * In case of Wireless extension interface,
803 * 32 byte SSID including null character can be accepted.
805 g_strlcpy(wext_ssid, ssid, sizeof(wext_ssid));
806 if (!g_utf8_validate(wext_ssid, -1, (const char **)&ptr))
809 snprintf(cmd, MAX_BUF_SIZE, "ASCII_CMD=AP_CFG,"
810 "SSID_LEN=%d,SSID=%s,"
811 "SEC=%s,KEY_LEN=%d,KEY=%s,CHANNEL=%d,"
812 "PREAMBLE=0,MAX_SCB=%d,HIDE=%d,END",
813 strlen(wext_ssid), wext_ssid,
814 security, strlen(key), key,
815 MOBILE_AP_WIFI_CHANNEL,
816 MOBILE_AP_MAX_WIFI_STA, hide_mode);
817 ret_status = __issue_ioctl(sock_fd, if_name, cmd, buf);
818 if (ret_status != MOBILE_AP_ERROR_NONE) {
819 ERR("__issue_ioctl failed...!!!\n");
824 /* Start broadcasting of BSS. */
825 snprintf(cmd, MAX_BUF_SIZE, "ASCII_CMD=AP_BSS_START");
826 ret_status = __issue_ioctl(sock_fd, if_name, cmd, buf);
827 if (ret_status != MOBILE_AP_ERROR_NONE) {
828 ERR("__issue_ioctl failed...!!!\n");
835 ret_status = _mh_core_set_ip_address(SOFTAP_IF,
837 if (ret_status != MOBILE_AP_ERROR_NONE) {
838 ERR("_mh_core_set_ip_address of SOFTAP_IF is failed\n");
842 ret_status = _mh_core_set_ip_address(WIFI_IF,
844 if (ret_status != MOBILE_AP_ERROR_NONE) {
845 ERR("_mh_core_set_ip_address of WIFI_IF is failed\n");
850 case MOBILE_AP_NL80211:
852 ret_status = _mh_core_set_ip_address(WIFI_IF,
854 if (ret_status != MOBILE_AP_ERROR_NONE) {
855 ERR("_mh_core_set_ip_address is failed\n");
859 ret_status = __execute_hostapd(type, ssid, security, key, hide_mode);
860 if (ret_status != MOBILE_AP_ERROR_NONE) {
861 ERR("__execute_hostapd is failed\n");
865 ret_status = __open_hostapd_intf(&hostapd_ctrl_fd, MH_CTRL_INTF);
866 if (ret_status != MOBILE_AP_ERROR_NONE) {
867 ERR("__open_hostapd_intf is failed\n");
868 __terminate_hostapd();
872 ret_status = __open_hostapd_monitor(&hostapd_monitor_fd);
873 if (ret_status != MOBILE_AP_ERROR_NONE) {
874 ERR("__open_hostapd_monitor is failed\n");
875 __close_hostapd_intf(&hostapd_ctrl_fd);
876 __terminate_hostapd();
883 ERR("Unknown driver interface : %d\n", drv_interface);
887 if (ret_status != MOBILE_AP_ERROR_NONE)
888 __mh_core_softap_firmware_stop();
893 int _mh_core_disable_softap(void)
895 char cmd[MAX_BUF_SIZE] = { 0 };
896 int ret_status = MOBILE_AP_ERROR_NONE;
897 mobile_ap_drv_interface_e drv_interface = MOBILE_AP_DRV_INTERFACE_NONE;
900 char buf[MAX_BUF_SIZE] = { 0 };
901 char *if_name = WIFI_IF;
903 drv_interface = __get_drv_interface();
905 switch (drv_interface) {
907 if ((sock_fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
908 ERR("Failed to open socket...!!!\n");
909 ret_status = MOBILE_AP_ERROR_RESOURCE;
913 /* Stop broadcasting of BSS. */
914 snprintf(cmd, MAX_BUF_SIZE, "ASCII_CMD=AP_BSS_STOP");
915 ret_status = __issue_ioctl(sock_fd, if_name, cmd, buf);
916 if (ret_status != MOBILE_AP_ERROR_NONE) {
917 ERR("__issue_ioctl failed...!!!\n");
925 case MOBILE_AP_NL80211:
926 ret_status = __close_hostapd_intf(&hostapd_ctrl_fd);
927 if (ret_status != MOBILE_AP_ERROR_NONE)
928 ERR("hostapd termination is failed\n");
930 ret_status = __close_hostapd_monitor(&hostapd_monitor_fd);
931 if (ret_status != MOBILE_AP_ERROR_NONE)
932 ERR("hostapd termination is failed\n");
934 ret_status = __terminate_hostapd();
935 if (ret_status != MOBILE_AP_ERROR_NONE) {
936 ERR("hostapd termination is failed\n");
941 ERR("Unknown driver interface : %d\n", drv_interface);
945 if (__mh_core_softap_firmware_stop() < 0)
946 ret_status = MOBILE_AP_ERROR_INTERNAL;
951 static int __get_device_info_by_wext(softap_device_info_t *di)
954 char *if_name = SOFTAP_IF;
955 char cmd[MAX_BUF_SIZE];
956 char buf[MAX_BUF_SIZE] = { 0 };
957 int ret = MOBILE_AP_ERROR_NONE;
959 char *buf_ptr = NULL;
962 if ((sock_fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
963 ERR("Failed to open socket...!!!\n");
965 return MOBILE_AP_ERROR_RESOURCE;
968 snprintf(cmd, MAX_BUF_SIZE, "AP_GET_STA_LIST");
969 ret = __issue_ioctl(sock_fd, if_name, cmd, buf);
970 if (ret != MOBILE_AP_ERROR_NONE) {
971 ERR("__issue_ioctl failed...!!!\n");
979 sscanf(buf_ptr, "%02x", &di->number);
982 for (i = 0; i < di->number; i++) {
983 unsigned int l_bssid[MOBILE_AP_WIFI_BSSID_LEN];
984 sscanf(buf_ptr, "%02X%02X%02X%02X%02X%02X", &l_bssid[0],
985 &l_bssid[1], &l_bssid[2], &l_bssid[3],
986 &l_bssid[4], &l_bssid[5]);
987 snprintf(di->bssid[i], MOBILE_AP_STR_INFO_LEN,
988 "%02X:%02X:%02X:%02X:%02X:%02X",
989 l_bssid[0], l_bssid[1], l_bssid[2],
990 l_bssid[3], l_bssid[4], l_bssid[5]);
992 SDBG("STA[%d] address[%s]\n", i, di->bssid[i]);
1002 static int __get_device_info_by_nl80211(softap_device_info_t *di)
1007 char req[HOSTAPD_REQ_MAX_LEN] = {0, };
1008 char buf[MOBILE_AP_STR_INFO_LEN] = {0, };
1010 buf_len = sizeof(buf);
1011 g_strlcpy(req, "NUM_STA", sizeof(req));
1012 ret = __send_hostapd_req(hostapd_ctrl_fd,
1013 req, strlen(req), buf, &buf_len);
1014 if (ret != MOBILE_AP_ERROR_NONE) {
1015 ERR("__send_hostapd_req is failed : %d\n", ret);
1019 DBG("The number of station : %s\n", buf);
1020 if (atoi(buf) == 0) {
1021 DBG("There is no station\n");
1022 return MOBILE_AP_ERROR_NONE;
1025 buf_len = sizeof(buf);
1026 g_strlcpy(req, "STA-FIRST", sizeof(req));
1027 ret = __send_hostapd_req(hostapd_ctrl_fd,
1028 req, strlen(req), buf, &buf_len);
1029 if (ret != MOBILE_AP_ERROR_NONE) {
1030 ERR("__send_hostapd_req is failed : %d\n", ret);
1035 if (!strncmp(buf, "FAIL", 4)) {
1036 ERR("FAIL is returned\n");
1040 if (buf[0] == '\0') {
1041 ERR("NULL string\n");
1045 SDBG("Station : %s\n", buf);
1046 g_strlcpy(di->bssid[no_of_sta++], buf, MOBILE_AP_STR_INFO_LEN);
1048 buf_len = sizeof(buf);
1049 snprintf(req, sizeof(req), "STA-NEXT %s", buf);
1050 ret = __send_hostapd_req(hostapd_ctrl_fd,
1051 req, strlen(req), buf, &buf_len);
1052 } while (ret == MOBILE_AP_ERROR_NONE);
1054 di->number = no_of_sta;
1059 int _mh_core_get_device_info(softap_device_info_t *di)
1062 ERR("Invalid param\n");
1063 return MOBILE_AP_ERROR_INVALID_PARAM;
1066 int ret = MOBILE_AP_ERROR_NONE;
1068 switch (__get_drv_interface()) {
1069 case MOBILE_AP_WEXT:
1070 ret = __get_device_info_by_wext(di);
1073 case MOBILE_AP_NL80211:
1074 ret = __get_device_info_by_nl80211(di);
1078 ERR("Unknown interface\n");
1085 int _mh_core_execute_dhcp_server(void)
1087 char buf[DNSMASQ_CONF_LEN] = "";
1091 fp = fopen(DNSMASQ_CONF_FILE, "w");
1093 ERR("Could not create the file.\n");
1094 return MOBILE_AP_ERROR_RESOURCE;
1096 snprintf(buf, DNSMASQ_CONF_LEN, DNSMASQ_CONF);
1102 ERR("fork failed\n");
1103 return MOBILE_AP_ERROR_RESOURCE;
1109 * -C file : Configuration file path
1111 if (execl("/usr/bin/dnsmasq", "/usr/bin/dnsmasq", "-d",
1112 "-p", "0", "-C", DNSMASQ_CONF_FILE,
1114 ERR("execl failed\n");
1117 ERR("Should not get here!");
1118 return MOBILE_AP_ERROR_RESOURCE;
1123 return MOBILE_AP_ERROR_NONE;
1126 int _mh_core_terminate_dhcp_server(void)
1130 if (dnsmasq_pid == 0) {
1131 ERR("There is no dnsmasq\n");
1132 return MOBILE_AP_ERROR_NONE;
1135 kill(dnsmasq_pid, SIGTERM);
1136 waitpid(dnsmasq_pid, NULL, 0);
1139 ret = unlink(DNSMASQ_CONF_FILE);
1141 ERR("unlink is failed : %s\n", strerror(errno));
1144 return MOBILE_AP_ERROR_NONE;
1147 int _mh_core_enable_masquerade(const char *ext_if)
1149 if (ext_if == NULL || strlen(ext_if) == 0) {
1150 ERR("ext_if[%s] is invalid\n", ext_if);
1151 return MOBILE_AP_ERROR_INVALID_PARAM;
1156 fd = open(IP_FORWARD, O_WRONLY);
1158 ERR("open failed\n");
1159 return MOBILE_AP_ERROR_RESOURCE;
1162 if (write(fd, "1", 1) != 1) {
1163 ERR("write failed\n");
1165 return MOBILE_AP_ERROR_INTERNAL;
1169 _iptables_create_chain(TABLE_NAT, TETH_NAT_POST);
1170 _iptables_add_rule(PKT_REDIRECTION_RULE, TABLE_NAT, CHAIN_POST,
1172 _iptables_add_rule(MASQ_RULE, TABLE_NAT, TETH_NAT_POST, ext_if);
1174 _iptables_create_chain(TABLE_FILTER, TETH_FILTER_FW);
1176 _iptables_add_rule(PKT_REDIRECTION_RULE, TABLE_FILTER, CHAIN_FW,
1179 _iptables_add_rule(CLAMP_MSS_RULE, TABLE_FILTER, TETH_FILTER_FW);
1181 _iptables_add_rule(FORWARD_RULE_WITH_ACTION_AND_STATE, TABLE_FILTER, TETH_FILTER_FW,
1182 BT_IF_ALL, ext_if, ACTION_RETURN, STATE_RELATED_ESTAB);
1183 _iptables_add_rule(FORWARD_RULE_WITH_ACTION_AND_STATE, TABLE_FILTER, TETH_FILTER_FW,
1184 WIFI_IF, ext_if, ACTION_RETURN, STATE_RELATED_ESTAB);
1185 _iptables_add_rule(FORWARD_RULE_WITH_ACTION_AND_STATE, TABLE_FILTER, TETH_FILTER_FW,
1186 USB_IF, ext_if, ACTION_RETURN, STATE_RELATED_ESTAB);
1188 _iptables_add_rule(FORWARD_RULE_WITH_ACTION_AND_STATE, TABLE_FILTER, TETH_FILTER_FW,
1189 ext_if, BT_IF_ALL, ACTION_DROP, STATE_INVALID);
1190 _iptables_add_rule(FORWARD_RULE_WITH_ACTION_AND_STATE, TABLE_FILTER, TETH_FILTER_FW,
1191 ext_if, WIFI_IF, ACTION_DROP, STATE_INVALID);
1192 _iptables_add_rule(FORWARD_RULE_WITH_ACTION_AND_STATE, TABLE_FILTER, TETH_FILTER_FW,
1193 ext_if, USB_IF, ACTION_DROP, STATE_INVALID);
1195 _iptables_add_rule(FORWARD_RULE_WITH_ACTION, TABLE_FILTER, TETH_FILTER_FW,
1196 ext_if, BT_IF_ALL, ACTION_RETURN);
1197 _iptables_add_rule(FORWARD_RULE_WITH_ACTION, TABLE_FILTER, TETH_FILTER_FW,
1198 ext_if, WIFI_IF, ACTION_RETURN);
1199 _iptables_add_rule(FORWARD_RULE_WITH_ACTION, TABLE_FILTER, TETH_FILTER_FW,
1200 ext_if, USB_IF, ACTION_RETURN);
1202 _iptables_add_rule(FORWARD_RULE_WITH_ACTION, TABLE_FILTER, TETH_FILTER_FW,
1203 BT_IF_ALL, ext_if, ACTION_RETURN);
1204 _iptables_add_rule(FORWARD_RULE_WITH_ACTION, TABLE_FILTER, TETH_FILTER_FW,
1205 WIFI_IF, ext_if, ACTION_RETURN);
1206 _iptables_add_rule(FORWARD_RULE_WITH_ACTION, TABLE_FILTER, TETH_FILTER_FW,
1207 USB_IF, ext_if, ACTION_RETURN);
1209 _iptables_add_rule(DEFAULT_RULE, TABLE_FILTER, TETH_FILTER_FW,
1212 return MOBILE_AP_ERROR_NONE;
1215 int _mh_core_disable_masquerade(const char *ext_if)
1217 if (ext_if == NULL || strlen(ext_if) == 0) {
1218 ERR("ext_if[%s] is invalid\n", ext_if);
1219 return MOBILE_AP_ERROR_INVALID_PARAM;
1224 fd = open(IP_FORWARD, O_WRONLY);
1226 ERR("open failed\n");
1227 return MOBILE_AP_ERROR_RESOURCE;
1230 if (write(fd, "0", 1) != 1) {
1231 ERR("write failed\n");
1233 return MOBILE_AP_ERROR_INTERNAL;
1237 _iptables_delete_rule(PKT_REDIRECTION_RULE, TABLE_NAT, CHAIN_POST,
1239 _iptables_flush_rules(TABLE_NAT, TETH_NAT_POST);
1240 _iptables_delete_chain(TABLE_NAT, TETH_NAT_POST);
1242 _iptables_delete_rule(PKT_REDIRECTION_RULE, TABLE_FILTER, CHAIN_FW,
1244 _iptables_flush_rules(TABLE_FILTER, TETH_FILTER_FW);
1245 _iptables_delete_chain(TABLE_FILTER, TETH_FILTER_FW);
1247 return MOBILE_AP_ERROR_NONE;
1250 int _mh_core_set_ip_address(const char *if_name, const in_addr_t ip)
1253 struct sockaddr_in addr;
1256 SDBG("if_name : %s ip address : 0x%X\n", if_name, ip);
1258 if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
1259 ERR("socket open failed!!!\n");
1260 return MOBILE_AP_ERROR_RESOURCE;
1263 g_strlcpy(ifr.ifr_name, if_name, IFNAMSIZ);
1265 memset(&addr, 0, sizeof(struct sockaddr));
1266 addr.sin_family = AF_INET;
1268 addr.sin_addr.s_addr = htonl(ip);
1270 memcpy(&ifr.ifr_addr, &addr, sizeof(struct sockaddr));
1271 if (ioctl(sock_fd, SIOCSIFADDR, &ifr) < 0) {
1272 ERR("ioctl failed...!!!\n");
1274 return MOBILE_AP_ERROR_INTERNAL;
1277 if (ioctl(sock_fd, SIOCGIFFLAGS, &ifr) < 0) {
1278 ERR("ioctl failed...!!!\n");
1280 return MOBILE_AP_ERROR_INTERNAL;
1283 ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
1284 if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr) < 0) {
1285 ERR("ioctl failed...!!!\n");
1287 return MOBILE_AP_ERROR_INTERNAL;
1292 return MOBILE_AP_ERROR_NONE;
1295 static gboolean __send_station_event_cb(gpointer data)
1297 int sig = GPOINTER_TO_INT(data);
1300 mobile_ap_station_info_t *si = NULL;
1302 if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI))
1303 type = MOBILE_AP_TYPE_WIFI;
1304 else if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI_AP))
1305 type = MOBILE_AP_TYPE_WIFI_AP;
1309 if (sig == SIGUSR1) {
1310 DBG("STA connected(%d)\n", sig);
1311 /* STA connection is handled in the dnsmasq signal handler */
1312 } else if (sig == SIGUSR2) {
1313 DBG("STA disconnected(%d)\n", sig);
1315 /* Temporarily care only one station.
1316 * Driver team should be support detail information */
1317 if (_get_station_info((gconstpointer)type,
1318 _slist_find_station_by_interface,
1319 &si) != MOBILE_AP_ERROR_NONE) {
1322 _remove_station_info(si->mac, _slist_find_station_by_mac);
1324 _get_station_count((gconstpointer)type,
1325 _slist_find_station_by_interface, &n_station);
1326 if (n_station == 0) {
1327 if (type == MOBILE_AP_TYPE_WIFI)
1328 _start_timeout_cb(type, time(NULL) + TETHERING_CONN_TIMEOUT);
1329 else if (type == MOBILE_AP_TYPE_WIFI_AP)
1330 _start_timeout_cb(type, time(NULL) + WIFI_AP_CONN_TIMEOUT);
1337 static void __handle_station_signal(int sig)
1340 idle_id = g_idle_add(__send_station_event_cb, GINT_TO_POINTER(sig));
1342 ERR("g_idle_add is failed\n");
1346 void _register_wifi_station_handler(void)
1348 struct sigaction sa;
1350 if (__get_drv_interface() != MOBILE_AP_WEXT)
1353 memset(&sa, 0, sizeof(sa));
1354 sa.sa_handler = __handle_station_signal;
1355 sigaction(SIGUSR1, &sa, NULL);
1356 sigaction(SIGUSR2, &sa, NULL);
1361 void _unregister_wifi_station_handler(void)
1363 struct sigaction sa;
1365 if (__get_drv_interface() != MOBILE_AP_WEXT)
1368 memset(&sa, 0, sizeof(sa));
1369 sa.sa_handler = SIG_DFL;
1370 sigaction(SIGUSR1, &sa, NULL);
1371 sigaction(SIGUSR2, &sa, NULL);
1376 static gboolean __hostapd_connect_timer_cb(gpointer user_data)
1378 char *mac = (char *)user_data;
1380 GSList *temp = NULL;
1381 sta_timer_t *ptr = NULL;
1382 mobile_ap_station_info_t *info = NULL;
1388 if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI))
1389 type = MOBILE_AP_TYPE_WIFI;
1390 else if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI_AP))
1391 type = MOBILE_AP_TYPE_WIFI_AP;
1395 for (l = sta_timer_list; l != NULL; l = g_slist_next(l)) {
1396 ptr = (sta_timer_t *)l->data;
1400 if (!g_strcmp0(ptr->mac_addr, mac)) {
1401 DBG("client with Static IP, Add station\n");
1403 info = (mobile_ap_station_info_t *)g_malloc(sizeof(mobile_ap_station_info_t));
1405 ERR("g_malloc failed\n");
1406 g_free(ptr->mac_addr);
1409 l = g_slist_next(l);
1410 sta_timer_list = g_slist_delete_link(sta_timer_list, temp);
1416 info->interface = type;
1417 g_strlcpy(info->ip, "", sizeof(info->ip));
1418 g_strlcpy(info->mac, mac, sizeof(info->mac));
1420 ret = _get_wifi_name_from_lease_info(mac, &info->hostname);
1421 if (ret != MOBILE_AP_ERROR_NONE)
1422 info->hostname = g_strdup(MOBILE_AP_NAME_UNKNOWN);
1424 g_free(ptr->mac_addr);
1427 l = g_slist_next(l);
1428 sta_timer_list = g_slist_delete_link(sta_timer_list, temp);
1437 if (_add_station_info(info) != MOBILE_AP_ERROR_NONE) {
1438 g_free(info->hostname);
1443 _get_station_count((gconstpointer)type,
1444 _slist_find_station_by_interface, &n_station);
1446 _stop_timeout_cb(type);
1448 _send_dbus_station_info("DhcpConnected", info);
1453 void _flush_dhcp_ack_timer(void)
1458 GSList *temp = NULL;
1459 sta_timer_t *ptr = NULL;
1461 for (l = sta_timer_list; l != NULL; l = g_slist_next(l)) {
1462 ptr = (sta_timer_t *)l->data;
1464 if (ptr->tid != 0) {
1465 g_source_remove(ptr->tid);
1468 g_free(ptr->mac_addr);
1473 l = g_slist_next(l);
1474 sta_timer_list = g_slist_delete_link(sta_timer_list, temp);
1481 void _destroy_dhcp_ack_timer(char *mac_addr)
1484 if (mac_addr == NULL) {
1485 ERR("mac address passed NULL\n");
1490 GSList *temp = NULL;
1491 sta_timer_t *ptr = NULL;
1493 for (l = sta_timer_list; l != NULL; l = g_slist_next(l)) {
1495 ptr = (sta_timer_t *)l->data;
1499 if (!g_strcmp0(ptr->mac_addr, mac_addr)) {
1501 if (ptr->tid != 0) {
1502 g_source_remove(ptr->tid);
1505 g_free(ptr->mac_addr);
1508 l = g_slist_next(l);
1509 sta_timer_list = g_slist_delete_link(sta_timer_list,