Update Boilerplate
[framework/connectivity/mobileap-agent.git] / src / mobileap_agent.c
1 /*
2  * mobileap-agent
3  * Copyright (c) 2012 Samsung Electronics Co., Ltd.
4  *
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
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  */
17
18 #include <sys/stat.h>
19 #include <sys/un.h>
20 #include <errno.h>
21 #include <sys/ioctl.h>
22 #include <glib.h>
23 #include <glib-object.h>
24 #include <dbus/dbus-glib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <stdlib.h>
29 #include <sys/wait.h>
30 #include <sys/types.h>
31 #include <fcntl.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
35 #include <linux/wireless.h>
36
37 #include <openssl/evp.h>
38 #include <openssl/sha.h>
39
40 #include "mobileap_common.h"
41 #include "mobileap_agent.h"
42 #include "mobileap_handler.h"
43
44 static pid_t dnsmasq_pid = 0;
45 static pid_t hostapd_pid = 0;
46 static int hostapd_ctrl_fd = 0;
47 static int hostapd_monitor_fd = 0;
48 static GIOChannel *hostapd_io_channel = NULL;
49 static guint hostapd_io_source = 0;
50
51 static int __issue_ioctl(int sock_fd, char *if_name, char *cmd, char *buf)
52 {
53         int ret_val = MOBILE_AP_ERROR_NONE;
54         struct iwreq iwr;
55
56         memset(buf, 0, MAX_BUF_SIZE);
57         memset(&iwr, 0, sizeof(iwr));
58
59         /* Configure ioctl parameters */
60         g_strlcpy(iwr.ifr_name, if_name, IFNAMSIZ);
61         g_strlcpy(buf, cmd, MAX_BUF_SIZE);
62         iwr.u.data.pointer = buf;
63         iwr.u.data.length = MAX_BUF_SIZE;
64
65         usleep(DRIVER_DELAY);
66
67         /* Issue ioctl */
68         if ((ioctl(sock_fd, SIOCSIWPRIV, &iwr)) < 0) {
69                 ERR("ioctl failed...!!!\n");
70                 ret_val = MOBILE_AP_ERROR_INTERNAL;
71         }
72
73         return ret_val;
74 }
75
76 static int __get_dns_server(char *dns_server, int len)
77 {
78 #ifndef __USE_CONNMAN_DNS_ADDR__
79         g_strlcpy(dns_server, GOOGLE_PUBLIC_DNS, len);
80         DBG("DNS server [%s]\n", dns_server);
81
82         return EXIT_SUCCESS;
83 #else
84         int ret = EXIT_FAILURE;
85         GError *error = NULL;
86         DBusGConnection *bus = NULL;
87         DBusGProxy *manager_proxy = NULL;
88         DBusGProxy *service_proxy = NULL;
89         gchar *service_object_path = NULL;
90
91         GHashTable *hash = NULL;
92         GValue *value;
93         const gchar *state;
94         gchar **dns_server_list = NULL;
95         GPtrArray *service_list = NULL;
96
97         bus = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
98         if (error) {
99                 ERR("Couldn't connect to the System bus[%s]", error->message);
100                 g_error_free(error);
101                 return ret;
102         }
103
104         manager_proxy = dbus_g_proxy_new_for_name(bus, "net.connman",
105                                                 "/",
106                                                 "net.connman.Manager");
107         if (!manager_proxy) {
108                 ERR("Couldn't create the proxy object");
109                 goto done;
110         }
111
112         dbus_g_proxy_call(manager_proxy, "GetProperties", &error, G_TYPE_INVALID,
113                 dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE),
114                 &hash, G_TYPE_INVALID);
115         if (error) {
116                 ERR("GetProperties failed[%s]", error->message);
117                 g_error_free(error);
118                 goto done;
119         }
120
121         /*
122         dict entry(
123                 string "Services"
124                 variant         array [
125                         object path "/profile/default/cellular_45001_cellular_Samsung3G_1"
126                         object path "/profile/default/cellular_45001_cellular_Samsung3G_MMS_2"
127                 ]
128         )
129         */
130         value = g_hash_table_lookup(hash, "Services");
131
132         service_list = g_value_get_boxed(value);
133         if (!service_list) {
134                 ERR("No service available");
135                 goto done;
136         }
137
138         service_object_path = g_ptr_array_index(service_list, 0);
139         DBG("service object path : %s\n", service_object_path);
140
141         service_proxy = dbus_g_proxy_new_for_name(bus, "net.connman",
142                                                 service_object_path,
143                                                 "net.connman.Service");
144         if (!service_proxy) {
145                 ERR("Couldn't create the proxy object");
146                 goto done;
147         }
148
149         dbus_g_proxy_call(service_proxy, "GetProperties", &error, G_TYPE_INVALID,
150                 dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE),
151                 &hash, G_TYPE_INVALID);
152         if (error) {
153                 ERR("GetProperties failed[%s]", error->message);
154                 g_error_free(error);
155                 goto done;
156         }
157
158         /*
159         dict entry(
160                 string "State"
161                 variant         string "online"
162         )
163
164         dict entry(
165                 string "Nameservers"
166                 variant         array [
167                         string "165.213.73.226"
168                         string "10.32.192.11"
169                 ]
170         )
171         */
172         value = g_hash_table_lookup(hash, "State");
173         state = value ? g_value_get_string(value) : NULL;
174         DBG("Network state : %s\n", state);
175
176         if (g_strcmp0(state, "ready") != 0 && g_strcmp0(state, "online") != 0) {
177                 ERR("Network is not connected\n");
178                 goto done;
179         }
180
181         value = g_hash_table_lookup(hash, "Nameservers");
182
183         dns_server_list = g_value_get_boxed(value);
184         if (!dns_server_list) {
185                 ERR("No Nameserver exist");
186                 goto done;
187         }
188         g_strlcpy(dns_server, *dns_server_list, len);
189         DBG("DNS server [%s]\n", dns_server);
190
191         ret = EXIT_SUCCESS;
192 done:
193         if (dns_server_list)
194                 g_strfreev(dns_server_list);
195         if (service_list)
196                 g_ptr_array_free(service_list, TRUE);
197         if (manager_proxy)
198                 g_object_unref(manager_proxy);
199         if (service_proxy)
200                 g_object_unref(service_proxy);
201         if (bus)
202                 dbus_g_connection_unref(bus);
203
204         return ret;
205 #endif
206 }
207
208 static int __get_psk_hexascii(const char *pass, const unsigned char *salt, char *psk, unsigned int psk_len)
209 {
210         if (pass == NULL || salt == NULL || psk == NULL || psk_len == 0) {
211                 ERR("Invalid parameter\n");
212                 return MOBILE_AP_ERROR_INVALID_PARAM;
213         }
214
215         if (psk_len < SHA256_DIGEST_LENGTH * 2 + 1) {
216                 ERR("Invalid parameter\n");
217                 return MOBILE_AP_ERROR_INVALID_PARAM;
218         }
219
220         int i;
221         int d_16;
222         int r_16;
223         unsigned char buf[SHA256_DIGEST_LENGTH] = {0, };
224
225         if (!PKCS5_PBKDF2_HMAC_SHA1(pass, strlen(pass),
226                                 salt, strlen((const char *)salt),
227                                 PSK_ITERATION_COUNT, sizeof(buf), buf)) {
228                 ERR("Getting psk is failed\n");
229                 return MOBILE_AP_ERROR_INTERNAL;
230         }
231
232         for (i = 0; i < SHA256_DIGEST_LENGTH; i++) {
233                 d_16 = buf[i] >> 4;
234                 r_16 = buf[i] & 0xf;
235
236                 psk[i << 1] = d_16 < 10 ? d_16 + '0' : d_16 - 10 + 'a';
237                 psk[(i << 1) + 1] = r_16 < 10 ? r_16 + '0' : r_16 - 10 + 'a';
238         }
239         psk[i << 1] = '\0';
240
241         return MOBILE_AP_ERROR_NONE;
242 }
243
244 static int __execute_hostapd(const char *ssid, const char *security,
245                 const char *key, int hide_mode)
246 {
247         DBG("+\n");
248
249         char psk[2 * SHA256_DIGEST_LENGTH + 1] = {0, };
250         char buf[HOSTAPD_CONF_LEN] = "";
251         char sec_buf[HOSTAPD_CONF_LEN] = "";
252         FILE *fp = NULL;
253         pid_t pid;
254
255         if (security != NULL && !strcmp(security, "wpa2-psk")) {
256                 if (__get_psk_hexascii(key, (const unsigned char *)ssid, psk,
257                                         sizeof(psk)) != MOBILE_AP_ERROR_NONE) {
258                         ERR("Getting PSK(Hex ascii type) is failed\n");
259                         return MOBILE_AP_ERROR_INTERNAL;
260                 }
261
262                 snprintf(sec_buf, HOSTAPD_CONF_LEN,
263                                 "\nwpa=2\nrsn_pairwise=CCMP\nwpa_psk=%s",
264                                 psk);
265         }
266
267         snprintf(buf, HOSTAPD_CONF_LEN, HOSTAPD_CONF,
268                         WIFI_IF,
269                         HOSTAPD_CTRL_INTF_DIR,
270                         ssid,
271                         MOBILE_AP_WIFI_CHANNEL,
272                         hide_mode ? 2 : 0,
273                         MOBILE_AP_MAX_WIFI_STA,
274                         sec_buf);
275
276         fp = fopen(HOSTAPD_CONF_FILE, "w");
277         if (NULL == fp) {
278                 ERR("Could not create the file.\n");
279                 return MOBILE_AP_ERROR_RESOURCE;
280         }
281         fputs(buf, fp);
282         fclose(fp);
283
284         pid = fork();
285         if (pid < 0) {
286                 ERR("fork failed\n");
287                 return MOBILE_AP_ERROR_RESOURCE;
288         }
289
290         if (pid == 0) {
291                 if (execl(HOSTAPD_BIN, HOSTAPD_BIN, "-e", HOSTAPD_ENTROPY_FILE,
292                                         HOSTAPD_CONF_FILE,
293                                         "-f", HOSTAPD_DEBUG_FILE, "-d",
294                                         (char *)NULL)) {
295                         ERR("execl failed\n");
296                 }
297
298                 ERR("Should not get here!");
299                 return MOBILE_AP_ERROR_RESOURCE;
300         }
301
302         hostapd_pid = pid;
303
304         return MOBILE_AP_ERROR_NONE;
305 }
306
307 static int __terminate_hostapd()
308 {
309         DBG("+\n");
310
311         if (hostapd_pid == 0) {
312                 DBG("There is no hostapd\n");
313                 return MOBILE_AP_ERROR_NONE;
314         }
315
316         kill(hostapd_pid, SIGTERM);
317         waitpid(hostapd_pid, NULL, 0);
318         hostapd_pid = 0;
319
320         return MOBILE_AP_ERROR_NONE;
321 }
322
323 /*
324  * number NUM_STA(void)
325  * addr STA-FIRST(void)
326  * addr STA-NEXT(addr)
327  * void DISASSOCIATE(addr)
328  * void READ_WHITELIST(filename)
329  * void SET_MAXCLIENT(number)
330  */
331 static int __send_hostapd_req(int fd, const char *req, const int req_len,
332                 char *buf, int *buf_len)
333 {
334         if (fd < 0 || req == NULL || req_len <= 0 ||
335                         buf == NULL || buf_len == NULL || *buf_len <= 0) {
336                 ERR("Invalid param\n");
337                 return MOBILE_AP_ERROR_INVALID_PARAM;
338         }
339
340         struct timeval tv = {10, 0};
341         fd_set fds;
342         int ret = 0;
343
344         ret = send(fd, req, req_len, 0);
345         if (ret < 0) {
346                 ERR("send is failed : %s\n", strerror(errno));
347                 return MOBILE_AP_ERROR_INTERNAL;
348         }
349
350         while (TRUE) {
351                 FD_ZERO(&fds);
352                 FD_SET(fd, &fds);
353                 ret = select(fd + 1, &fds, NULL, NULL, &tv);
354                 if (ret < 0) {
355                         return MOBILE_AP_ERROR_INTERNAL;
356                 } else if (ret == 0) {
357                         ERR("There is no response from hostapd\n");
358                         return MOBILE_AP_ERROR_INTERNAL;
359                 } else if (!FD_ISSET(fd, &fds)) {
360                         ERR("Unknown case\n");
361                         return MOBILE_AP_ERROR_INTERNAL;
362                 }
363
364                 ret = recv(fd, buf, (*buf_len) - 1, 0);
365                 if (ret < 0) {
366                         ERR("recv is failed\n");
367                         return MOBILE_AP_ERROR_INTERNAL;
368                 }
369
370                 if (buf[0] == '<') {
371                         DBG("Unsolicited message\n");
372                         continue;
373                 }
374
375                 *buf_len = ret;
376                 buf[ret] = '\0';
377                 if (ret == 0) {
378                         ERR("socket is closed\n");
379                 }
380
381                 break;
382         }
383
384         return MOBILE_AP_ERROR_NONE;
385 }
386
387 static int __open_hostapd_intf(int *fd, const char *intf)
388 {
389         if (fd == NULL || intf == NULL) {
390                 ERR("fd is NULL\n");
391                 return MOBILE_AP_ERROR_INVALID_PARAM;
392         }
393
394         DBG("+\n");
395
396         int retry = 0;
397         char ctrl_intf[255] = {0, };
398         struct sockaddr_un src;
399         struct sockaddr_un dest;
400         struct stat stat_buf;
401
402         *fd = socket(PF_UNIX, SOCK_DGRAM, 0);
403         if (*fd < 0) {
404                 ERR("socket is failed\n");
405                 return MOBILE_AP_ERROR_INTERNAL;
406         }
407
408         src.sun_family = AF_UNIX;
409         g_strlcpy(src.sun_path, intf, sizeof(src.sun_path));
410
411         if (stat(src.sun_path, &stat_buf) == 0) {
412                 DBG("There is already mh interface. It will be removed\n");
413                 unlink(src.sun_path);
414         }
415
416         if (bind(*fd, (struct sockaddr *)&src, sizeof(src)) < 0) {
417                 ERR("bind is failed\n");
418                 close(*fd);
419                 *fd = -1;
420                 unlink(src.sun_path);
421                 return MOBILE_AP_ERROR_INTERNAL;
422         }
423
424         snprintf(ctrl_intf, sizeof(ctrl_intf), "%s/%s",
425                         HOSTAPD_CTRL_INTF_DIR, WIFI_IF);
426         dest.sun_family = AF_UNIX;
427         g_strlcpy(dest.sun_path, ctrl_intf, sizeof(dest.sun_path));
428
429         while (connect(*fd, (struct sockaddr *)&dest, sizeof(dest)) < 0) {
430                 DBG("connect is failed : %s\n", strerror(errno));
431                 if (++retry >= HOSTAPD_RETRY_MAX)
432                         goto FAIL;
433                 usleep(HOSTAPD_RETRY_DELAY);
434         }
435
436         return MOBILE_AP_ERROR_NONE;
437
438 FAIL:
439         ERR("Cannot make connection to hostapd\n");
440         close(*fd);
441         *fd = -1;
442         unlink(src.sun_path);
443
444         return MOBILE_AP_ERROR_INTERNAL;
445 }
446
447 static int __close_hostapd_intf(int *fd)
448 {
449         DBG("+\n");
450
451         if (fd == NULL) {
452                 ERR("fd is NULL\n");
453                 return MOBILE_AP_ERROR_INVALID_PARAM;
454         }
455
456         if (*fd > 0)
457                 close(*fd);
458         *fd = -1;
459
460         return MOBILE_AP_ERROR_NONE;
461 }
462
463 static gboolean __hostapd_monitor_cb(GIOChannel *source)
464 {
465         DBG("+\n");
466
467         char buf[HOSTAPD_REQ_MAX_LEN] = {0, };
468         char *pbuf = NULL;
469         gsize read = 0;
470         int n_station = 0;
471
472 #if !GLIB_CHECK_VERSION(2, 31, 0)
473         int ret = 0;
474
475         ret = g_io_channel_read(hostapd_io_channel, buf,
476                         HOSTAPD_REQ_MAX_LEN, &read);
477         if (ret != G_IO_ERROR_NONE) {
478                 ERR("g_io_channel_read is failed\n");
479                 return FALSE;
480         }
481 #else
482         GError *err = NULL;
483
484         g_io_channel_read_chars(hostapd_io_channel, buf,
485                         HOSTAPD_REQ_MAX_LEN, &read, &err);
486         if (err != NULL) {
487                 ERR("g_io_channel_read_chars is failed : %s\n", err->message);
488                 g_error_free(err);
489                 return FALSE;
490         }
491 #endif
492
493         buf[read] = '\0';
494         pbuf = strrchr(buf, '\n');
495         if (pbuf != NULL)
496                 *pbuf = '\0';
497
498         if (buf[0] == '<' && (pbuf = strchr(buf, '>')) != NULL) {
499                 pbuf++;
500         } else {
501                 pbuf = buf;
502         }
503
504         DBG("Event : %s\n", pbuf);
505
506         if (!strncmp(pbuf, HOSTAPD_STA_DISCONN, strlen(HOSTAPD_STA_DISCONN))) {
507                 pbuf = strchr(pbuf, ' ');
508                 if (pbuf == NULL) {
509                         ERR("There is no info. for disconnected station\n");
510                         return TRUE;
511                 }
512                 pbuf++;
513
514                 DBG("Disconnected station MAC : %s\n", pbuf);
515                 _remove_station_info(pbuf, _slist_find_station_by_mac);
516
517                 _get_station_count((gconstpointer)MOBILE_AP_TYPE_WIFI,
518                                 _slist_find_station_by_interface, &n_station);
519                 if (n_station == 0)
520                         _start_timeout_cb(MOBILE_AP_TYPE_WIFI);
521
522                 return TRUE;
523         } else {
524                 DBG("Event is not handled\n");
525         }
526
527         return TRUE;
528 }
529
530 static int __open_hostapd_monitor(int *fd)
531 {
532         if (fd == NULL) {
533                 ERR("fd is NULL\n");
534                 return MOBILE_AP_ERROR_INVALID_PARAM;
535         }
536
537         DBG("+\n");
538
539         char buf[HOSTAPD_REQ_MAX_LEN] = {0, };
540         int buf_len = 0;
541
542         if (__open_hostapd_intf(fd, MH_MONITOR_INTF) != MOBILE_AP_ERROR_NONE) {
543                 ERR("__open_hostapd_intf() is failed\n");
544                 return MOBILE_AP_ERROR_INTERNAL;
545         }
546
547         hostapd_io_channel = g_io_channel_unix_new(*fd);
548         if (hostapd_io_channel == NULL) {
549                 ERR("g_io_channel_unix_new is failed\n");
550                 return MOBILE_AP_ERROR_INTERNAL;
551         }
552
553         g_io_channel_set_encoding(hostapd_io_channel, NULL, NULL);
554         g_io_channel_set_flags(hostapd_io_channel,
555                         G_IO_FLAG_APPEND | G_IO_FLAG_NONBLOCK, NULL);
556
557         hostapd_io_source = g_io_add_watch(hostapd_io_channel, G_IO_IN,
558                         (GIOFunc)__hostapd_monitor_cb, NULL);
559
560         buf_len = sizeof(buf);
561         __send_hostapd_req(*fd, HOSTAPD_MONITOR_ATTACH,
562                         strlen(HOSTAPD_MONITOR_ATTACH), buf, &buf_len);
563         DBG("return : %s\n", buf);
564
565         return MOBILE_AP_ERROR_NONE;
566 }
567
568 static int __close_hostapd_monitor(int *fd)
569 {
570         GError *err = NULL;
571         char buf[HOSTAPD_REQ_MAX_LEN] = {0, };
572         int buf_len = 0;
573
574         buf_len = sizeof(buf);
575         __send_hostapd_req(*fd, HOSTAPD_MONITOR_DETACH,
576                         strlen(HOSTAPD_MONITOR_DETACH), buf, &buf_len);
577         DBG("return : %s\n", buf);
578
579         if (hostapd_io_source != 0) {
580                 g_source_remove(hostapd_io_source);
581                 hostapd_io_source = 0;
582         }
583
584         if (hostapd_io_channel != NULL) {
585                 g_io_channel_shutdown(hostapd_io_channel, TRUE, &err);
586                 g_io_channel_unref(hostapd_io_channel);
587                 hostapd_io_channel = NULL;
588         }
589
590         __close_hostapd_intf(fd);
591
592         return MOBILE_AP_ERROR_NONE;
593 }
594
595 static mobile_ap_drv_interface_e __get_drv_interface(void)
596 {
597         static mobile_ap_drv_interface_e drv_interface = MOBILE_AP_DRV_INTERFACE_NONE;
598
599         if (drv_interface != MOBILE_AP_DRV_INTERFACE_NONE) {
600                 return drv_interface;
601         }
602
603         const char *drv_rfkill_path = "/sys/devices/platform";
604         const char *wext_drv[] = {
605                 "bcm4329-b1", "bcm4330-b0",
606                 "bcm4330-b1", "bcm4330-b2",
607                 NULL};
608
609         char path[MAX_BUF_SIZE] = { 0 };
610         struct stat stat_buf = { 0 };
611         int fd = 0;
612         int i = 0;
613
614         drv_interface = MOBILE_AP_NL80211;
615
616         for (i = 0; wext_drv[i] != NULL; i++) {
617                 snprintf(path, sizeof(path), "%s/%s",
618                                 drv_rfkill_path, wext_drv[i]);
619                 fd = open(path, O_RDONLY);
620                 if (fd < 0)
621                         continue;
622
623                 if (fstat(fd, &stat_buf) == 0 && S_ISDIR(stat_buf.st_mode)) {
624                         drv_interface = MOBILE_AP_WEXT;
625                         close(fd);
626                         break;
627                 }
628
629                 close(fd);
630         }
631
632         return drv_interface;
633 }
634
635 int _mh_core_enable_softap(const char *ssid, const char *security,
636                 const char *key, int hide_mode)
637 {
638         if (ssid == NULL || security == NULL || key == NULL) {
639                 ERR("Invalid param\n");
640                 return MOBILE_AP_ERROR_INTERNAL;
641         }
642
643         char cmd[MAX_BUF_SIZE];
644         int ret_status = MOBILE_AP_ERROR_NONE;
645         mobile_ap_drv_interface_e drv_interface = MOBILE_AP_DRV_INTERFACE_NONE;
646
647         int sock_fd;
648         char *if_name = WIFI_IF;
649         char buf[MAX_BUF_SIZE] = { 0 };
650
651         snprintf(cmd, sizeof(cmd), "%s softap", WLAN_SCRIPT);
652         if (_execute_command(cmd)) {
653                 ERR("execute script failed : %s\n", cmd);
654                 return MOBILE_AP_ERROR_INTERNAL;
655         }
656
657         drv_interface = __get_drv_interface();
658
659         switch (drv_interface) {
660         case MOBILE_AP_WEXT:
661                 if ((sock_fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
662                         ERR("Failed to open socket...!!!\n");
663                         ret_status = MOBILE_AP_ERROR_RESOURCE;
664                         break;
665                 }
666
667                 snprintf(cmd, MAX_BUF_SIZE, "ASCII_CMD=AP_CFG,"
668                                         "SSID_LEN=%d,SSID=%s,"
669                                         "SEC=%s,KEY_LEN=%d,KEY=%s,CHANNEL=%d,"
670                                         "PREAMBLE=0,MAX_SCB=%d,HIDE=%d,END",
671                                         strlen(ssid), ssid,
672                                         security, strlen(key), key,
673                                         MOBILE_AP_WIFI_CHANNEL,
674                                         MOBILE_AP_MAX_WIFI_STA, hide_mode);
675                 ret_status = __issue_ioctl(sock_fd, if_name, cmd, buf);
676                 if (ret_status != MOBILE_AP_ERROR_NONE) {
677                         ERR("__issue_ioctl failed...!!!\n");
678                         close(sock_fd);
679                         break;
680                 }
681
682                 /* Start broadcasting of BSS. */
683                 snprintf(cmd, MAX_BUF_SIZE, "ASCII_CMD=AP_BSS_START");
684                 ret_status = __issue_ioctl(sock_fd, if_name, cmd, buf);
685                 if (ret_status != MOBILE_AP_ERROR_NONE) {
686                         ERR("__issue_ioctl failed...!!!\n");
687                         close(sock_fd);
688                         break;
689                 }
690
691                 close(sock_fd);
692
693                 ret_status = _mh_core_set_ip_address(SOFTAP_IF,
694                                 IP_ADDRESS_SOFTAP);
695                 if (ret_status != MOBILE_AP_ERROR_NONE) {
696                         ERR("_mh_core_set_ip_address of SOFTAP_IF is failed\n");
697                         break;
698                 }
699
700                 DBG("Setting softap is OK\n");
701                 ret_status = _mh_core_set_ip_address(WIFI_IF,
702                                 IP_ADDRESS_WIFI);
703                 if (ret_status != MOBILE_AP_ERROR_NONE) {
704                         ERR("_mh_core_set_ip_address of WIFI_IF is failed\n");
705                         break;
706                 }
707                 break;
708
709         case MOBILE_AP_NL80211:
710                 ret_status = _mh_core_set_ip_address(WIFI_IF,
711                                 IP_ADDRESS_SOFTAP);
712                 if (ret_status != MOBILE_AP_ERROR_NONE) {
713                         ERR("_mh_core_set_ip_address is failed\n");
714                         break;
715                 }
716
717                 ret_status = __execute_hostapd(ssid, security, key, hide_mode);
718                 if (ret_status != MOBILE_AP_ERROR_NONE) {
719                         ERR("__execute_hostapd is failed\n");
720                         break;
721                 }
722
723                 ret_status = __open_hostapd_intf(&hostapd_ctrl_fd, MH_CTRL_INTF);
724                 if (ret_status != MOBILE_AP_ERROR_NONE) {
725                         ERR("__open_hostapd_intf is failed\n");
726                         __terminate_hostapd();
727                         break;
728                 }
729
730                 ret_status = __open_hostapd_monitor(&hostapd_monitor_fd);
731                 if (ret_status != MOBILE_AP_ERROR_NONE) {
732                         ERR("__open_hostapd_monitor is failed\n");
733                         __close_hostapd_intf(&hostapd_ctrl_fd);
734                         __terminate_hostapd();
735                         break;
736                 }
737
738                 break;
739
740         default:
741                 DBG("Unknown driver interface : %d\n", drv_interface);
742                 break;
743         }
744
745         if (ret_status != MOBILE_AP_ERROR_NONE) {
746                 snprintf(cmd, sizeof(cmd), "%s stop", WLAN_SCRIPT);
747                 if (_execute_command(cmd)) {
748                         ERR("execute script failed : %s\n", cmd);
749                 }
750         }
751
752         return ret_status;
753 }
754
755 int _mh_core_disable_softap(void)
756 {
757         char cmd[MAX_BUF_SIZE] = { 0 };
758         int ret_status = MOBILE_AP_ERROR_NONE;
759         mobile_ap_drv_interface_e drv_interface = MOBILE_AP_DRV_INTERFACE_NONE;
760
761         int sock_fd = 0;
762         char buf[MAX_BUF_SIZE] = { 0 };
763         char *if_name = WIFI_IF;
764
765         drv_interface = __get_drv_interface();
766
767         switch (drv_interface) {
768         case MOBILE_AP_WEXT:
769                 if ((sock_fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
770                         ERR("Failed to open socket...!!!\n");
771                         ret_status = MOBILE_AP_ERROR_RESOURCE;
772                         break;
773                 }
774
775                 /* Stop broadcasting of BSS. */
776                 snprintf(cmd, MAX_BUF_SIZE, "ASCII_CMD=AP_BSS_STOP");
777                 ret_status = __issue_ioctl(sock_fd, if_name, cmd, buf);
778                 if (ret_status != MOBILE_AP_ERROR_NONE) {
779                         ERR("__issue_ioctl failed...!!!\n");
780                         close(sock_fd);
781                         break;
782                 }
783
784                 close(sock_fd);
785                 break;
786
787         case MOBILE_AP_NL80211:
788                 ret_status = __close_hostapd_intf(&hostapd_ctrl_fd);
789                 if (ret_status != MOBILE_AP_ERROR_NONE)
790                         ERR("hostapd termination is failed\n");
791
792                 ret_status = __close_hostapd_monitor(&hostapd_monitor_fd);
793                 if (ret_status != MOBILE_AP_ERROR_NONE)
794                         ERR("hostapd termination is failed\n");
795
796                 ret_status = __terminate_hostapd();
797                 if (ret_status != MOBILE_AP_ERROR_NONE) {
798                         ERR("hostapd termination is failed\n");
799                 }
800                 break;
801
802         default:
803                 DBG("Unknown driver interface : %d\n", drv_interface);
804                 break;
805         }
806
807         snprintf(cmd, sizeof(cmd), "%s stop", WLAN_SCRIPT);
808         if (_execute_command(cmd)) {
809                 ERR("execute script failed : %s\n", cmd);
810                 ret_status = MOBILE_AP_ERROR_INTERNAL;
811         }
812
813         return ret_status;
814 }
815
816 static int __get_device_info_by_wext(softap_device_info_t *di)
817 {
818         int sock_fd = 0;
819         char *if_name = SOFTAP_IF;
820         char cmd[MAX_BUF_SIZE];
821         char buf[MAX_BUF_SIZE] = { 0 };
822         int ret = MOBILE_AP_ERROR_NONE;
823
824         char *buf_ptr = NULL;
825         int i;
826
827         if ((sock_fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
828                 ERR("Failed to open socket...!!!\n");
829                 di->number = 0;
830                 return MOBILE_AP_ERROR_RESOURCE;
831         }
832
833         snprintf(cmd, MAX_BUF_SIZE, "AP_GET_STA_LIST");
834         ret = __issue_ioctl(sock_fd, if_name, cmd, buf);
835         if (ret != MOBILE_AP_ERROR_NONE) {
836                 ERR("__issue_ioctl failed...!!!\n");
837                 di->number = 0;
838                 close(sock_fd);
839                 return ret;
840         }
841
842         buf_ptr = buf;
843
844         sscanf(buf_ptr, "%02x", &di->number);
845         DBG("connected station : %d\n", di->number);
846
847         buf_ptr += 2;
848         for (i = 0; i < di->number; i++) {
849                 unsigned int l_bssid[MOBILE_AP_WIFI_BSSID_LEN];
850                 sscanf(buf_ptr, "%02X%02X%02X%02X%02X%02X", &l_bssid[0],
851                                         &l_bssid[1], &l_bssid[2], &l_bssid[3],
852                                         &l_bssid[4], &l_bssid[5]);
853                 snprintf(di->bssid[i], MOBILE_AP_STR_INFO_LEN,
854                                         "%02X:%02X:%02X:%02X:%02X:%02X",
855                                         l_bssid[0], l_bssid[1], l_bssid[2],
856                                         l_bssid[3], l_bssid[4], l_bssid[5]);
857
858                 DBG("STA[%d] address[%s]\n", i, di->bssid[i]);
859
860                 buf_ptr += 12;
861         }
862
863         close(sock_fd);
864
865         return ret;
866 }
867
868 static int __get_device_info_by_nl80211(softap_device_info_t *di)
869 {
870         int ret = 0;
871         int no_of_sta = 0;
872         int buf_len = 0;
873         char req[HOSTAPD_REQ_MAX_LEN] = {0, };
874         char buf[MOBILE_AP_STR_INFO_LEN] = {0, };
875
876         buf_len = sizeof(buf);
877         g_strlcpy(req, "NUM_STA", sizeof(req));
878         ret = __send_hostapd_req(hostapd_ctrl_fd,
879                         req, strlen(req), buf, &buf_len);
880         if (ret != MOBILE_AP_ERROR_NONE) {
881                 ERR("__send_hostapd_req is failed : %d\n", ret);
882                 return ret;
883         }
884
885         DBG("The number of station : %s\n", buf);
886         if (atoi(buf) == 0) {
887                 DBG("There is no station\n");
888                 return MOBILE_AP_ERROR_NONE;
889         }
890
891         buf_len = sizeof(buf);
892         g_strlcpy(req, "STA-FIRST", sizeof(req));
893         ret = __send_hostapd_req(hostapd_ctrl_fd,
894                         req, strlen(req), buf, &buf_len);
895         if (ret != MOBILE_AP_ERROR_NONE) {
896                 ERR("__send_hostapd_req is failed : %d\n", ret);
897                 return ret;
898         }
899
900         do {
901                 if (!strncmp(buf, "FAIL", 4)) {
902                         ERR("FAIL is returned\n");
903                         break;
904                 }
905
906                 if (buf[0] == '\0') {
907                         ERR("NULL string\n");
908                         break;
909                 }
910
911                 DBG("Station : %s\n", buf);
912                 g_strlcpy(di->bssid[no_of_sta++], buf, MOBILE_AP_STR_INFO_LEN);
913
914                 buf_len = sizeof(buf);
915                 snprintf(req, sizeof(req), "STA-NEXT %s", buf);
916                 ret = __send_hostapd_req(hostapd_ctrl_fd,
917                                 req, strlen(req), buf, &buf_len);
918         } while (ret == MOBILE_AP_ERROR_NONE);
919
920         di->number = no_of_sta;
921
922         return ret;
923 }
924
925 int _mh_core_get_device_info(softap_device_info_t *di)
926 {
927         if (di == NULL) {
928                 ERR("Invalid param\n");
929                 return MOBILE_AP_ERROR_INVALID_PARAM;
930         }
931
932         int ret = MOBILE_AP_ERROR_NONE;
933
934         switch (__get_drv_interface()) {
935         case MOBILE_AP_WEXT:
936                 ret = __get_device_info_by_wext(di);
937                 break;
938
939         case MOBILE_AP_NL80211:
940                 ret = __get_device_info_by_nl80211(di);
941                 break;
942
943         default:
944                 ERR("Unknown interface\n");
945                 break;
946         }
947
948         return ret;
949 }
950
951 int _mh_core_execute_dhcp_server(void)
952 {
953         char buf[DNSMASQ_CONF_LEN] = "";
954         char dns_server[MOBILE_AP_STR_INFO_LEN] = {0, };
955         FILE *fp = NULL;
956         pid_t pid;
957
958         if (__get_dns_server(dns_server, sizeof(dns_server))) {
959                 ERR("Getting DNS server failed\n");
960                 return MOBILE_AP_ERROR_INTERNAL;
961         }
962
963         fp = fopen(DNSMASQ_CONF_FILE, "w");
964         if (NULL == fp) {
965                 ERR("Could not create the file.\n");
966                 return MOBILE_AP_ERROR_RESOURCE;
967         }
968         snprintf(buf, DNSMASQ_CONF_LEN, DNSMASQ_CONF, dns_server);
969         fputs(buf, fp);
970         fclose(fp);
971
972         pid = fork();
973         if (pid < 0) {
974                 ERR("fork failed\n");
975                 return MOBILE_AP_ERROR_RESOURCE;
976         }
977
978         if (pid == 0) {
979                 if (execl("/usr/bin/dnsmasq", "/usr/bin/dnsmasq", "-d",
980                                         "-p", "0", "-C", DNSMASQ_CONF_FILE,
981                                         (char *)NULL)) {
982                         ERR("execl failed\n");
983                 }
984
985                 ERR("Should not get here!");
986                 return MOBILE_AP_ERROR_RESOURCE;
987         }
988
989         dnsmasq_pid = pid;
990
991         return MOBILE_AP_ERROR_NONE;
992 }
993
994 int _mh_core_terminate_dhcp_server(void)
995 {
996         if (dnsmasq_pid == 0) {
997                 DBG("There is no dnsmasq\n");
998                 return MOBILE_AP_ERROR_NONE;
999         }
1000
1001         kill(dnsmasq_pid, SIGTERM);
1002         waitpid(dnsmasq_pid, NULL, 0);
1003         dnsmasq_pid = 0;
1004
1005         return MOBILE_AP_ERROR_NONE;
1006 }
1007
1008 int _mh_core_enable_masquerade(const char *ext_if)
1009 {
1010         int fd = -1;
1011         char cmd[MAX_BUF_SIZE] = {0, };
1012
1013         fd = open(IP_FORWARD, O_WRONLY);
1014         if (fd < 0) {
1015                 ERR("open failed\n");
1016                 return MOBILE_AP_ERROR_RESOURCE;
1017         }
1018
1019         if (write(fd, "1", 1) != 1) {
1020                 ERR("write failed\n");
1021                 close(fd);
1022                 return MOBILE_AP_ERROR_INTERNAL;
1023         }
1024         close(fd);
1025
1026         snprintf(cmd, sizeof(cmd), "%s -t nat -A POSTROUTING "MASQUERADE_RULE,
1027                         IPTABLES, ext_if);
1028         if (_execute_command(cmd)) {
1029                 ERR("iptables failed : %s\n", cmd);
1030                 return MOBILE_AP_ERROR_INTERNAL;
1031         }
1032
1033         _add_data_usage_rule(WIFI_IF, ext_if);
1034         _add_data_usage_rule(BT_IF_ALL, ext_if);
1035         _add_data_usage_rule(USB_IF, ext_if);
1036
1037         return MOBILE_AP_ERROR_NONE;
1038 }
1039
1040 int _mh_core_disable_masquerade(const char *ext_if)
1041 {
1042         int fd = -1;
1043         char cmd[MAX_BUF_SIZE] = {0, };
1044
1045         fd = open(IP_FORWARD, O_WRONLY);
1046         if (fd < 0) {
1047                 ERR("open failed\n");
1048                 return MOBILE_AP_ERROR_RESOURCE;
1049         }
1050
1051         if (write(fd, "0", 1) != 1) {
1052                 ERR("write failed\n");
1053                 close(fd);
1054                 return MOBILE_AP_ERROR_INTERNAL;
1055         }
1056         close(fd);
1057
1058         snprintf(cmd, sizeof(cmd), "%s -t nat -D POSTROUTING "MASQUERADE_RULE,
1059                         IPTABLES, ext_if);
1060         if (_execute_command(cmd)) {
1061                 ERR("iptables failed : %s\n", cmd);
1062                 return MOBILE_AP_ERROR_INTERNAL;
1063         }
1064
1065         _del_data_usage_rule(WIFI_IF, ext_if);
1066         _del_data_usage_rule(BT_IF_ALL, ext_if);
1067         _del_data_usage_rule(USB_IF, ext_if);
1068
1069         return MOBILE_AP_ERROR_NONE;
1070 }
1071
1072 void _mh_core_add_data_to_array(GPtrArray *array, guint type, gchar *dev_name)
1073 {
1074         GValue value = {0, {{0}}};
1075
1076         g_value_init(&value, DBUS_STRUCT_UINT_STRING);
1077         g_value_take_boxed(&value,
1078                         dbus_g_type_specialized_construct(DBUS_STRUCT_UINT_STRING));
1079         dbus_g_type_struct_set(&value, 0, type, 1, dev_name, G_MAXUINT);
1080         g_ptr_array_add(array, g_value_get_boxed(&value));
1081 }
1082
1083 int _mh_core_set_ip_address(const char *if_name, const in_addr_t ip)
1084 {
1085         struct ifreq ifr;
1086         struct sockaddr_in addr;
1087         int sock_fd;
1088
1089         DBG("if_name : %s ip address : 0x%X\n", if_name, ip);
1090
1091         if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
1092                 ERR("socket open failed!!!\n");
1093                 perror("ioctl fail");
1094                 return MOBILE_AP_ERROR_RESOURCE;
1095         }
1096
1097         g_strlcpy(ifr.ifr_name, if_name, IFNAMSIZ);
1098
1099         memset(&addr, 0, sizeof(struct sockaddr));
1100         addr.sin_family = AF_INET;
1101         addr.sin_port = 0;
1102         addr.sin_addr.s_addr = htonl(ip);
1103
1104         memcpy(&ifr.ifr_addr, &addr, sizeof(struct sockaddr));
1105         if (ioctl(sock_fd, SIOCSIFADDR, &ifr) < 0) {
1106                 ERR("ioctl failed...!!!\n");
1107                 perror("ioctl fail");
1108                 close(sock_fd);
1109                 return MOBILE_AP_ERROR_INTERNAL;
1110         }
1111
1112         if (ioctl(sock_fd, SIOCGIFFLAGS, &ifr) < 0) {
1113                 ERR("ioctl failed...!!!\n");
1114                 perror("ioctl fail");
1115                 close(sock_fd);
1116                 return MOBILE_AP_ERROR_INTERNAL;
1117         }
1118
1119         ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
1120         if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr) < 0) {
1121                 ERR("ioctl failed...!!!\n");
1122                 perror("ioctl fail");
1123                 close(sock_fd);
1124                 return MOBILE_AP_ERROR_INTERNAL;
1125         }
1126
1127         close(sock_fd);
1128
1129         return MOBILE_AP_ERROR_NONE;
1130 }