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