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 ptr->tid = g_timeout_add(HOSTAPD_DHCP_MAX_INTERVAL,
482 __hostapd_connect_timer_cb, mac);
483 sta_timer_list = g_slist_append(sta_timer_list, ptr);
485 } else if (!strncmp(pbuf, HOSTAPD_STA_DISCONN, HOSTAPD_STA_DISCONN_LEN)) {
486 pbuf = pbuf + HOSTAPD_STA_DISCONN_LEN;
487 if (!pbuf || !*pbuf) {
491 end = strchr(pbuf, '<');
493 mac = g_strndup(pbuf, (long)(end - pbuf));
496 mac = g_strdup(pbuf);
501 ERR("strdup failed\n");
505 SDBG("%s%s\n", HOSTAPD_STA_DISCONN, mac);
506 _remove_station_info(mac, _slist_find_station_by_mac);
509 * Destroy the timer if its not expired before disconnection
511 _destroy_dhcp_ack_timer(mac);
517 pbuf = strchr(pbuf, '>');
524 if (discon_event == FALSE)
527 if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI)) {
528 type = MOBILE_AP_TYPE_WIFI;
529 } else if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI_AP)) {
530 type = MOBILE_AP_TYPE_WIFI_AP;
535 _get_station_count((gconstpointer)type,
536 _slist_find_station_by_interface, &n_station);
538 if (n_station == 0) {
539 if (type == MOBILE_AP_TYPE_WIFI)
540 _start_timeout_cb(type, time(NULL) + TETHERING_CONN_TIMEOUT);
541 else if (type == MOBILE_AP_TYPE_WIFI_AP)
542 _start_timeout_cb(type, time(NULL) + WIFI_AP_CONN_TIMEOUT);
548 static int __open_hostapd_monitor(int *fd)
552 return MOBILE_AP_ERROR_INVALID_PARAM;
557 char buf[HOSTAPD_REQ_MAX_LEN] = {0, };
560 if (__open_hostapd_intf(fd, MH_MONITOR_INTF) != MOBILE_AP_ERROR_NONE) {
561 ERR("__open_hostapd_intf() is failed\n");
562 return MOBILE_AP_ERROR_INTERNAL;
565 hostapd_io_channel = g_io_channel_unix_new(*fd);
566 if (hostapd_io_channel == NULL) {
567 ERR("g_io_channel_unix_new is failed\n");
568 return MOBILE_AP_ERROR_INTERNAL;
571 g_io_channel_set_encoding(hostapd_io_channel, NULL, NULL);
572 g_io_channel_set_flags(hostapd_io_channel,
573 G_IO_FLAG_APPEND | G_IO_FLAG_NONBLOCK, NULL);
575 hostapd_io_source = g_io_add_watch(hostapd_io_channel, G_IO_IN,
576 (GIOFunc)__hostapd_monitor_cb, NULL);
578 buf_len = sizeof(buf);
579 __send_hostapd_req(*fd, HOSTAPD_MONITOR_ATTACH,
580 strlen(HOSTAPD_MONITOR_ATTACH), buf, &buf_len);
582 return MOBILE_AP_ERROR_NONE;
585 static int __close_hostapd_monitor(int *fd)
588 char buf[HOSTAPD_REQ_MAX_LEN] = {0, };
591 buf_len = sizeof(buf);
592 __send_hostapd_req(*fd, HOSTAPD_MONITOR_DETACH,
593 strlen(HOSTAPD_MONITOR_DETACH), buf, &buf_len);
595 if (hostapd_io_source != 0) {
596 g_source_remove(hostapd_io_source);
597 hostapd_io_source = 0;
600 if (hostapd_io_channel != NULL) {
601 g_io_channel_shutdown(hostapd_io_channel, TRUE, &err);
602 g_io_channel_unref(hostapd_io_channel);
603 hostapd_io_channel = NULL;
606 __close_hostapd_intf(fd);
608 return MOBILE_AP_ERROR_NONE;
611 static mobile_ap_drv_interface_e __get_drv_interface(void)
613 static mobile_ap_drv_interface_e drv_interface = MOBILE_AP_DRV_INTERFACE_NONE;
615 if (drv_interface != MOBILE_AP_DRV_INTERFACE_NONE) {
616 return drv_interface;
619 const char *drv_rfkill_path = "/sys/devices/platform";
620 const char *wext_drv[] = {
621 "bcm4329-b1", "bcm4330-b0",
622 "bcm4330-b1", "bcm4330-b2",
625 char path[MAX_BUF_SIZE] = { 0 };
626 struct stat stat_buf = { 0 };
630 drv_interface = MOBILE_AP_NL80211;
632 for (i = 0; wext_drv[i] != NULL; i++) {
633 snprintf(path, sizeof(path), "%s/%s",
634 drv_rfkill_path, wext_drv[i]);
635 fd = open(path, O_RDONLY);
639 if (fstat(fd, &stat_buf) == 0 && S_ISDIR(stat_buf.st_mode)) {
640 drv_interface = MOBILE_AP_WEXT;
648 return drv_interface;
651 static int __mh_core_softap_firmware_start(void)
655 DBusMessageIter iter;
656 DBusMessage *reply = NULL;
657 DBusMessage *message = NULL;
658 DBusConnection *connection = NULL;
659 const char *device = "softap";
661 connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
662 if (connection == NULL) {
663 ERR("Failed to get system bus");
667 message = dbus_message_new_method_call(NETCONFIG_SERVICE,
668 NETCONFIG_WIFI_PATH, NETCONFIG_WIFI_INTERFACE ".Firmware", "Start");
669 if (message == NULL) {
670 ERR("Failed DBus method call");
671 dbus_connection_unref(connection);
675 dbus_message_iter_init_append(message, &iter);
676 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &device);
678 dbus_error_init(&error);
680 reply = dbus_connection_send_with_reply_and_block(connection, message,
681 NETCONFIG_DBUS_REPLY_TIMEOUT, &error);
682 if (dbus_error_is_set(&error) == TRUE) {
683 if (NULL != strstr(error.message, ".AlreadyExists")) {
684 // softap already enabled
686 ERR("dbus_connection_send_with_reply_and_block() failed. "
687 "DBus error [%s: %s]", error.name, error.message);
691 dbus_error_free(&error);
694 dbus_error_free(&error);
698 dbus_message_unref(reply);
700 dbus_message_unref(message);
701 dbus_connection_unref(connection);
706 static int __mh_core_softap_firmware_stop(void)
710 DBusMessageIter iter;
711 DBusMessage *reply = NULL;
712 DBusMessage *message = NULL;
713 DBusConnection *connection = NULL;
714 const char *device = "softap";
716 connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
717 if (connection == NULL) {
718 ERR("Failed to get system bus");
722 message = dbus_message_new_method_call(NETCONFIG_SERVICE,
723 NETCONFIG_WIFI_PATH, NETCONFIG_WIFI_INTERFACE ".Firmware", "Stop");
724 if (message == NULL) {
725 ERR("Failed DBus method call");
726 dbus_connection_unref(connection);
730 dbus_message_iter_init_append(message, &iter);
731 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &device);
733 dbus_error_init(&error);
735 reply = dbus_connection_send_with_reply_and_block(connection, message,
736 NETCONFIG_DBUS_REPLY_TIMEOUT, &error);
737 if (dbus_error_is_set(&error) == TRUE) {
738 if (NULL != strstr(error.message, ".AlreadyExists")) {
739 // softap already disabled
741 ERR("dbus_connection_send_with_reply_and_block() failed. "
742 "DBus error [%s: %s]", error.name, error.message);
746 dbus_error_free(&error);
749 dbus_error_free(&error);
753 dbus_message_unref(reply);
755 dbus_message_unref(message);
756 dbus_connection_unref(connection);
761 int _mh_core_enable_softap(const mobile_ap_type_e type, const char *ssid,
762 const char *security, const char *key, int hide_mode)
764 if (ssid == NULL || security == NULL || key == NULL) {
765 ERR("Invalid param\n");
766 return MOBILE_AP_ERROR_INTERNAL;
769 char cmd[MAX_BUF_SIZE];
770 int ret_status = MOBILE_AP_ERROR_NONE;
771 mobile_ap_drv_interface_e drv_interface = MOBILE_AP_DRV_INTERFACE_NONE;
774 char *if_name = WIFI_IF;
775 char buf[MAX_BUF_SIZE] = { 0 };
777 char wext_ssid[MOBILE_AP_WIFI_SSID_MAX_LEN] = { 0 };
780 if (__mh_core_softap_firmware_start() < 0)
781 return MOBILE_AP_ERROR_INTERNAL;
783 drv_interface = __get_drv_interface();
785 switch (drv_interface) {
787 if ((sock_fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
788 ERR("Failed to open socket...!!!\n");
789 ret_status = MOBILE_AP_ERROR_RESOURCE;
794 * In case of Wireless extension interface,
795 * 32 byte SSID including null character can be accepted.
797 g_strlcpy(wext_ssid, ssid, sizeof(wext_ssid));
798 if (!g_utf8_validate(wext_ssid, -1, (const char **)&ptr))
801 snprintf(cmd, MAX_BUF_SIZE, "ASCII_CMD=AP_CFG,"
802 "SSID_LEN=%d,SSID=%s,"
803 "SEC=%s,KEY_LEN=%d,KEY=%s,CHANNEL=%d,"
804 "PREAMBLE=0,MAX_SCB=%d,HIDE=%d,END",
805 strlen(wext_ssid), wext_ssid,
806 security, strlen(key), key,
807 MOBILE_AP_WIFI_CHANNEL,
808 MOBILE_AP_MAX_WIFI_STA, hide_mode);
809 ret_status = __issue_ioctl(sock_fd, if_name, cmd, buf);
810 if (ret_status != MOBILE_AP_ERROR_NONE) {
811 ERR("__issue_ioctl failed...!!!\n");
816 /* Start broadcasting of BSS. */
817 snprintf(cmd, MAX_BUF_SIZE, "ASCII_CMD=AP_BSS_START");
818 ret_status = __issue_ioctl(sock_fd, if_name, cmd, buf);
819 if (ret_status != MOBILE_AP_ERROR_NONE) {
820 ERR("__issue_ioctl failed...!!!\n");
827 ret_status = _mh_core_set_ip_address(SOFTAP_IF,
829 if (ret_status != MOBILE_AP_ERROR_NONE) {
830 ERR("_mh_core_set_ip_address of SOFTAP_IF is failed\n");
834 ret_status = _mh_core_set_ip_address(WIFI_IF,
836 if (ret_status != MOBILE_AP_ERROR_NONE) {
837 ERR("_mh_core_set_ip_address of WIFI_IF is failed\n");
842 case MOBILE_AP_NL80211:
844 ret_status = _mh_core_set_ip_address(WIFI_IF,
846 if (ret_status != MOBILE_AP_ERROR_NONE) {
847 ERR("_mh_core_set_ip_address is failed\n");
851 ret_status = __execute_hostapd(type, ssid, security, key, hide_mode);
852 if (ret_status != MOBILE_AP_ERROR_NONE) {
853 ERR("__execute_hostapd is failed\n");
857 ret_status = __open_hostapd_intf(&hostapd_ctrl_fd, MH_CTRL_INTF);
858 if (ret_status != MOBILE_AP_ERROR_NONE) {
859 ERR("__open_hostapd_intf is failed\n");
860 __terminate_hostapd();
864 ret_status = __open_hostapd_monitor(&hostapd_monitor_fd);
865 if (ret_status != MOBILE_AP_ERROR_NONE) {
866 ERR("__open_hostapd_monitor is failed\n");
867 __close_hostapd_intf(&hostapd_ctrl_fd);
868 __terminate_hostapd();
875 ERR("Unknown driver interface : %d\n", drv_interface);
879 if (ret_status != MOBILE_AP_ERROR_NONE)
880 __mh_core_softap_firmware_stop();
885 int _mh_core_disable_softap(void)
887 char cmd[MAX_BUF_SIZE] = { 0 };
888 int ret_status = MOBILE_AP_ERROR_NONE;
889 mobile_ap_drv_interface_e drv_interface = MOBILE_AP_DRV_INTERFACE_NONE;
892 char buf[MAX_BUF_SIZE] = { 0 };
893 char *if_name = WIFI_IF;
895 drv_interface = __get_drv_interface();
897 switch (drv_interface) {
899 if ((sock_fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
900 ERR("Failed to open socket...!!!\n");
901 ret_status = MOBILE_AP_ERROR_RESOURCE;
905 /* Stop broadcasting of BSS. */
906 snprintf(cmd, MAX_BUF_SIZE, "ASCII_CMD=AP_BSS_STOP");
907 ret_status = __issue_ioctl(sock_fd, if_name, cmd, buf);
908 if (ret_status != MOBILE_AP_ERROR_NONE) {
909 ERR("__issue_ioctl failed...!!!\n");
917 case MOBILE_AP_NL80211:
918 ret_status = __close_hostapd_intf(&hostapd_ctrl_fd);
919 if (ret_status != MOBILE_AP_ERROR_NONE)
920 ERR("hostapd termination is failed\n");
922 ret_status = __close_hostapd_monitor(&hostapd_monitor_fd);
923 if (ret_status != MOBILE_AP_ERROR_NONE)
924 ERR("hostapd termination is failed\n");
926 ret_status = __terminate_hostapd();
927 if (ret_status != MOBILE_AP_ERROR_NONE) {
928 ERR("hostapd termination is failed\n");
933 ERR("Unknown driver interface : %d\n", drv_interface);
937 if (__mh_core_softap_firmware_stop() < 0)
938 ret_status = MOBILE_AP_ERROR_INTERNAL;
943 static int __get_device_info_by_wext(softap_device_info_t *di)
946 char *if_name = SOFTAP_IF;
947 char cmd[MAX_BUF_SIZE];
948 char buf[MAX_BUF_SIZE] = { 0 };
949 int ret = MOBILE_AP_ERROR_NONE;
951 char *buf_ptr = NULL;
954 if ((sock_fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
955 ERR("Failed to open socket...!!!\n");
957 return MOBILE_AP_ERROR_RESOURCE;
960 snprintf(cmd, MAX_BUF_SIZE, "AP_GET_STA_LIST");
961 ret = __issue_ioctl(sock_fd, if_name, cmd, buf);
962 if (ret != MOBILE_AP_ERROR_NONE) {
963 ERR("__issue_ioctl failed...!!!\n");
971 sscanf(buf_ptr, "%02x", &di->number);
974 for (i = 0; i < di->number; i++) {
975 unsigned int l_bssid[MOBILE_AP_WIFI_BSSID_LEN];
976 sscanf(buf_ptr, "%02X%02X%02X%02X%02X%02X", &l_bssid[0],
977 &l_bssid[1], &l_bssid[2], &l_bssid[3],
978 &l_bssid[4], &l_bssid[5]);
979 snprintf(di->bssid[i], MOBILE_AP_STR_INFO_LEN,
980 "%02X:%02X:%02X:%02X:%02X:%02X",
981 l_bssid[0], l_bssid[1], l_bssid[2],
982 l_bssid[3], l_bssid[4], l_bssid[5]);
984 SDBG("STA[%d] address[%s]\n", i, di->bssid[i]);
994 static int __get_device_info_by_nl80211(softap_device_info_t *di)
999 char req[HOSTAPD_REQ_MAX_LEN] = {0, };
1000 char buf[MOBILE_AP_STR_INFO_LEN] = {0, };
1002 buf_len = sizeof(buf);
1003 g_strlcpy(req, "NUM_STA", sizeof(req));
1004 ret = __send_hostapd_req(hostapd_ctrl_fd,
1005 req, strlen(req), buf, &buf_len);
1006 if (ret != MOBILE_AP_ERROR_NONE) {
1007 ERR("__send_hostapd_req is failed : %d\n", ret);
1011 DBG("The number of station : %s\n", buf);
1012 if (atoi(buf) == 0) {
1013 DBG("There is no station\n");
1014 return MOBILE_AP_ERROR_NONE;
1017 buf_len = sizeof(buf);
1018 g_strlcpy(req, "STA-FIRST", sizeof(req));
1019 ret = __send_hostapd_req(hostapd_ctrl_fd,
1020 req, strlen(req), buf, &buf_len);
1021 if (ret != MOBILE_AP_ERROR_NONE) {
1022 ERR("__send_hostapd_req is failed : %d\n", ret);
1027 if (!strncmp(buf, "FAIL", 4)) {
1028 ERR("FAIL is returned\n");
1032 if (buf[0] == '\0') {
1033 ERR("NULL string\n");
1037 SDBG("Station : %s\n", buf);
1038 g_strlcpy(di->bssid[no_of_sta++], buf, MOBILE_AP_STR_INFO_LEN);
1040 buf_len = sizeof(buf);
1041 snprintf(req, sizeof(req), "STA-NEXT %s", buf);
1042 ret = __send_hostapd_req(hostapd_ctrl_fd,
1043 req, strlen(req), buf, &buf_len);
1044 } while (ret == MOBILE_AP_ERROR_NONE);
1046 di->number = no_of_sta;
1051 int _mh_core_get_device_info(softap_device_info_t *di)
1054 ERR("Invalid param\n");
1055 return MOBILE_AP_ERROR_INVALID_PARAM;
1058 int ret = MOBILE_AP_ERROR_NONE;
1060 switch (__get_drv_interface()) {
1061 case MOBILE_AP_WEXT:
1062 ret = __get_device_info_by_wext(di);
1065 case MOBILE_AP_NL80211:
1066 ret = __get_device_info_by_nl80211(di);
1070 ERR("Unknown interface\n");
1077 int _mh_core_execute_dhcp_server(void)
1079 char buf[DNSMASQ_CONF_LEN] = "";
1083 fp = fopen(DNSMASQ_CONF_FILE, "w");
1085 ERR("Could not create the file.\n");
1086 return MOBILE_AP_ERROR_RESOURCE;
1088 snprintf(buf, DNSMASQ_CONF_LEN, DNSMASQ_CONF);
1094 ERR("fork failed\n");
1095 return MOBILE_AP_ERROR_RESOURCE;
1101 * -C file : Configuration file path
1103 if (execl("/usr/bin/dnsmasq", "/usr/bin/dnsmasq", "-d",
1104 "-p", "0", "-C", DNSMASQ_CONF_FILE,
1106 ERR("execl failed\n");
1109 ERR("Should not get here!");
1110 return MOBILE_AP_ERROR_RESOURCE;
1115 return MOBILE_AP_ERROR_NONE;
1118 int _mh_core_terminate_dhcp_server(void)
1122 if (dnsmasq_pid == 0) {
1123 ERR("There is no dnsmasq\n");
1124 return MOBILE_AP_ERROR_NONE;
1127 kill(dnsmasq_pid, SIGTERM);
1128 waitpid(dnsmasq_pid, NULL, 0);
1131 ret = unlink(DNSMASQ_CONF_FILE);
1133 ERR("unlink is failed : %s\n", strerror(errno));
1136 return MOBILE_AP_ERROR_NONE;
1139 int _mh_core_enable_masquerade(const char *ext_if)
1141 if (ext_if == NULL || strlen(ext_if) == 0) {
1142 ERR("ext_if[%s] is invalid\n", ext_if);
1143 return MOBILE_AP_ERROR_INVALID_PARAM;
1148 fd = open(IP_FORWARD, O_WRONLY);
1150 ERR("open failed\n");
1151 return MOBILE_AP_ERROR_RESOURCE;
1154 if (write(fd, "1", 1) != 1) {
1155 ERR("write failed\n");
1157 return MOBILE_AP_ERROR_INTERNAL;
1161 _iptables_create_chain(TABLE_NAT, TETH_NAT_POST);
1162 _iptables_add_rule(PKT_REDIRECTION_RULE, TABLE_NAT, CHAIN_POST,
1164 _iptables_add_rule(MASQ_RULE, TABLE_NAT, TETH_NAT_POST, ext_if);
1166 _iptables_create_chain(TABLE_FILTER, TETH_FILTER_FW);
1168 _iptables_add_rule(PKT_REDIRECTION_RULE, TABLE_FILTER, CHAIN_FW,
1171 _iptables_add_rule(CLAMP_MSS_RULE, TABLE_FILTER, TETH_FILTER_FW);
1173 _iptables_add_rule(FORWARD_RULE_WITH_ACTION_AND_STATE, TABLE_FILTER, TETH_FILTER_FW,
1174 BT_IF_ALL, ext_if, ACTION_RETURN, STATE_RELATED_ESTAB);
1175 _iptables_add_rule(FORWARD_RULE_WITH_ACTION_AND_STATE, TABLE_FILTER, TETH_FILTER_FW,
1176 WIFI_IF, ext_if, ACTION_RETURN, STATE_RELATED_ESTAB);
1177 _iptables_add_rule(FORWARD_RULE_WITH_ACTION_AND_STATE, TABLE_FILTER, TETH_FILTER_FW,
1178 USB_IF, ext_if, ACTION_RETURN, STATE_RELATED_ESTAB);
1180 _iptables_add_rule(FORWARD_RULE_WITH_ACTION_AND_STATE, TABLE_FILTER, TETH_FILTER_FW,
1181 ext_if, BT_IF_ALL, ACTION_DROP, STATE_INVALID);
1182 _iptables_add_rule(FORWARD_RULE_WITH_ACTION_AND_STATE, TABLE_FILTER, TETH_FILTER_FW,
1183 ext_if, WIFI_IF, ACTION_DROP, STATE_INVALID);
1184 _iptables_add_rule(FORWARD_RULE_WITH_ACTION_AND_STATE, TABLE_FILTER, TETH_FILTER_FW,
1185 ext_if, USB_IF, ACTION_DROP, STATE_INVALID);
1187 _iptables_add_rule(FORWARD_RULE_WITH_ACTION, TABLE_FILTER, TETH_FILTER_FW,
1188 ext_if, BT_IF_ALL, ACTION_RETURN);
1189 _iptables_add_rule(FORWARD_RULE_WITH_ACTION, TABLE_FILTER, TETH_FILTER_FW,
1190 ext_if, WIFI_IF, ACTION_RETURN);
1191 _iptables_add_rule(FORWARD_RULE_WITH_ACTION, TABLE_FILTER, TETH_FILTER_FW,
1192 ext_if, USB_IF, ACTION_RETURN);
1194 _iptables_add_rule(FORWARD_RULE_WITH_ACTION, TABLE_FILTER, TETH_FILTER_FW,
1195 BT_IF_ALL, ext_if, ACTION_RETURN);
1196 _iptables_add_rule(FORWARD_RULE_WITH_ACTION, TABLE_FILTER, TETH_FILTER_FW,
1197 WIFI_IF, ext_if, ACTION_RETURN);
1198 _iptables_add_rule(FORWARD_RULE_WITH_ACTION, TABLE_FILTER, TETH_FILTER_FW,
1199 USB_IF, ext_if, ACTION_RETURN);
1201 _iptables_add_rule(DEFAULT_RULE, TABLE_FILTER, TETH_FILTER_FW,
1204 return MOBILE_AP_ERROR_NONE;
1207 int _mh_core_disable_masquerade(const char *ext_if)
1209 if (ext_if == NULL || strlen(ext_if) == 0) {
1210 ERR("ext_if[%s] is invalid\n", ext_if);
1211 return MOBILE_AP_ERROR_INVALID_PARAM;
1216 fd = open(IP_FORWARD, O_WRONLY);
1218 ERR("open failed\n");
1219 return MOBILE_AP_ERROR_RESOURCE;
1222 if (write(fd, "0", 1) != 1) {
1223 ERR("write failed\n");
1225 return MOBILE_AP_ERROR_INTERNAL;
1229 _iptables_delete_rule(PKT_REDIRECTION_RULE, TABLE_NAT, CHAIN_POST,
1231 _iptables_flush_rules(TABLE_NAT, TETH_NAT_POST);
1232 _iptables_delete_chain(TABLE_NAT, TETH_NAT_POST);
1234 _iptables_delete_rule(PKT_REDIRECTION_RULE, TABLE_FILTER, CHAIN_FW,
1236 _iptables_flush_rules(TABLE_FILTER, TETH_FILTER_FW);
1237 _iptables_delete_chain(TABLE_FILTER, TETH_FILTER_FW);
1239 return MOBILE_AP_ERROR_NONE;
1242 void _mh_core_add_data_to_array(GPtrArray *array, guint type, gchar *dev_name)
1244 GValue value = {0, {{0}}};
1246 g_value_init(&value, DBUS_STRUCT_UINT_STRING);
1247 g_value_take_boxed(&value,
1248 dbus_g_type_specialized_construct(DBUS_STRUCT_UINT_STRING));
1249 dbus_g_type_struct_set(&value, 0, type, 1, dev_name, G_MAXUINT);
1250 g_ptr_array_add(array, g_value_get_boxed(&value));
1253 int _mh_core_set_ip_address(const char *if_name, const in_addr_t ip)
1256 struct sockaddr_in addr;
1259 SDBG("if_name : %s ip address : 0x%X\n", if_name, ip);
1261 if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
1262 ERR("socket open failed!!!\n");
1263 return MOBILE_AP_ERROR_RESOURCE;
1266 g_strlcpy(ifr.ifr_name, if_name, IFNAMSIZ);
1268 memset(&addr, 0, sizeof(struct sockaddr));
1269 addr.sin_family = AF_INET;
1271 addr.sin_addr.s_addr = htonl(ip);
1273 memcpy(&ifr.ifr_addr, &addr, sizeof(struct sockaddr));
1274 if (ioctl(sock_fd, SIOCSIFADDR, &ifr) < 0) {
1275 ERR("ioctl failed...!!!\n");
1277 return MOBILE_AP_ERROR_INTERNAL;
1280 if (ioctl(sock_fd, SIOCGIFFLAGS, &ifr) < 0) {
1281 ERR("ioctl failed...!!!\n");
1283 return MOBILE_AP_ERROR_INTERNAL;
1286 ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
1287 if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr) < 0) {
1288 ERR("ioctl failed...!!!\n");
1290 return MOBILE_AP_ERROR_INTERNAL;
1295 return MOBILE_AP_ERROR_NONE;
1298 static gboolean __send_station_event_cb(gpointer data)
1300 int sig = GPOINTER_TO_INT(data);
1303 mobile_ap_station_info_t *si = NULL;
1305 if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI))
1306 type = MOBILE_AP_TYPE_WIFI;
1307 else if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI_AP))
1308 type = MOBILE_AP_TYPE_WIFI_AP;
1312 if (sig == SIGUSR1) {
1313 DBG("STA connected(%d)\n", sig);
1314 /* STA connection is handled in the dnsmasq signal handler */
1315 } else if (sig == SIGUSR2) {
1316 DBG("STA disconnected(%d)\n", sig);
1318 /* Temporarily care only one station.
1319 * Driver team should be support detail information */
1320 if (_get_station_info((gconstpointer)type,
1321 _slist_find_station_by_interface,
1322 &si) != MOBILE_AP_ERROR_NONE) {
1325 _remove_station_info(si->mac, _slist_find_station_by_mac);
1327 _get_station_count((gconstpointer)type,
1328 _slist_find_station_by_interface, &n_station);
1329 if (n_station == 0) {
1330 if (type == MOBILE_AP_TYPE_WIFI)
1331 _start_timeout_cb(type, time(NULL) + TETHERING_CONN_TIMEOUT);
1332 else if (type == MOBILE_AP_TYPE_WIFI_AP)
1333 _start_timeout_cb(type, time(NULL) + WIFI_AP_CONN_TIMEOUT);
1340 static void __handle_station_signal(int sig)
1342 g_idle_add(__send_station_event_cb, GINT_TO_POINTER(sig));
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,